Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorDavid S. Miller <davem@davemloft.net>
Wed, 21 Sep 2016 02:52:50 +0000 (22:52 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 21 Sep 2016 02:52:50 +0000 (22:52 -0400)
Johan Hedberg says:

====================
pull request: bluetooth-next 2016-09-19

Here's the main bluetooth-next pull request for the 4.9 kernel.

 - Added new messages for monitor sockets for better mgmt tracing
 - Added local name and appearance support in scan response
 - Added new Qualcomm WCNSS SMD based HCI driver
 - Minor fixes & cleanup to 802.15.4 code
 - New USB ID to btusb driver
 - Added Marvell support to HCI UART driver
 - Add combined LED trigger for controller power
 - Other minor fixes here and there

Please let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
32 files changed:
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/bcm203x.c
drivers/bluetooth/btqca.c
drivers/bluetooth/btqcomsmd.c [new file with mode: 0644]
drivers/bluetooth/btrtl.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_bcm.c
drivers/bluetooth/hci_intel.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_mrvl.c [new file with mode: 0644]
drivers/bluetooth/hci_qca.c
drivers/bluetooth/hci_uart.h
drivers/net/ieee802154/fakelb.c
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_mon.h
include/net/bluetooth/mgmt.h
net/6lowpan/ndisc.c
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_core.c
net/bluetooth/hci_request.c
net/bluetooth/hci_request.h
net/bluetooth/hci_sock.c
net/bluetooth/leds.c
net/bluetooth/leds.h
net/bluetooth/mgmt.c
net/bluetooth/mgmt_util.c
net/bluetooth/smp.c
net/mac802154/iface.c
net/mac802154/rx.c

index cf50fd2..3cc9bff 100644 (file)
@@ -180,6 +180,17 @@ config BT_HCIUART_AG6XX
 
          Say Y here to compile support for Intel AG6XX protocol.
 
+config BT_HCIUART_MRVL
+       bool "Marvell protocol support"
+       depends on BT_HCIUART
+       select BT_HCIUART_H4
+       help
+         Marvell is serial protocol for communication between Bluetooth
+         device and host. This protocol is required for most Marvell Bluetooth
+         devices with UART interface.
+
+         Say Y here to compile support for HCI MRVL protocol.
+
 config BT_HCIBCM203X
        tristate "HCI BCM203x USB driver"
        depends on USB
@@ -331,4 +342,16 @@ config BT_WILINK
          Say Y here to compile support for Texas Instrument's WiLink7 driver
          into the kernel or say M to compile it as module (btwilink).
 
+config BT_QCOMSMD
+       tristate "Qualcomm SMD based HCI support"
+       depends on QCOM_SMD && QCOM_WCNSS_CTRL
+       select BT_QCA
+       help
+         Qualcomm SMD based HCI driver.
+         This driver is used to bridge HCI data onto the shared memory
+         channels to the WCNSS core.
+
+         Say Y here to compile support for HCI over Qualcomm SMD into the
+         kernel or say M to compile as a module.
+
 endmenu
index 9c18939..b1fc29a 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_BT_ATH3K)                += ath3k.o
 obj-$(CONFIG_BT_MRVL)          += btmrvl.o
 obj-$(CONFIG_BT_MRVL_SDIO)     += btmrvl_sdio.o
 obj-$(CONFIG_BT_WILINK)                += btwilink.o
+obj-$(CONFIG_BT_QCOMSMD)       += btqcomsmd.o
 obj-$(CONFIG_BT_BCM)           += btbcm.o
 obj-$(CONFIG_BT_RTL)           += btrtl.o
 obj-$(CONFIG_BT_QCA)           += btqca.o
@@ -37,6 +38,7 @@ hci_uart-$(CONFIG_BT_HCIUART_INTEL)   += hci_intel.o
 hci_uart-$(CONFIG_BT_HCIUART_BCM)      += hci_bcm.o
 hci_uart-$(CONFIG_BT_HCIUART_QCA)      += hci_qca.o
 hci_uart-$(CONFIG_BT_HCIUART_AG6XX)    += hci_ag6xx.o
+hci_uart-$(CONFIG_BT_HCIUART_MRVL)     += hci_mrvl.o
 hci_uart-objs                          := $(hci_uart-y)
 
 ccflags-y += -D__CHECK_ENDIAN__
index 5b0ef7b..5ce6d41 100644 (file)
@@ -185,10 +185,8 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
        data->state = BCM203X_LOAD_MINIDRV;
 
        data->urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!data->urb) {
-               BT_ERR("Can't allocate URB");
+       if (!data->urb)
                return -ENOMEM;
-       }
 
        if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
                BT_ERR("Mini driver request failed");
index 4a62081..28afd5d 100644 (file)
@@ -55,8 +55,8 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
        }
 
        edl = (struct edl_event_hdr *)(skb->data);
-       if (!edl || !edl->data) {
-               BT_ERR("%s: TLV with no header or no data", hdev->name);
+       if (!edl) {
+               BT_ERR("%s: TLV with no header", hdev->name);
                err = -EILSEQ;
                goto out;
        }
@@ -224,8 +224,8 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size,
        }
 
        edl = (struct edl_event_hdr *)(skb->data);
-       if (!edl || !edl->data) {
-               BT_ERR("%s: TLV with no header or no data", hdev->name);
+       if (!edl) {
+               BT_ERR("%s: TLV with no header", hdev->name);
                err = -EILSEQ;
                goto out;
        }
diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c
new file mode 100644 (file)
index 0000000..08c2c93
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2016, Linaro Ltd.
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
+#include <linux/platform_device.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btqca.h"
+
+struct btqcomsmd {
+       struct hci_dev *hdev;
+
+       struct qcom_smd_channel *acl_channel;
+       struct qcom_smd_channel *cmd_channel;
+};
+
+static int btqcomsmd_recv(struct hci_dev *hdev, unsigned int type,
+                          const void *data, size_t count)
+{
+       struct sk_buff *skb;
+
+       /* Use GFP_ATOMIC as we're in IRQ context */
+       skb = bt_skb_alloc(count, GFP_ATOMIC);
+       if (!skb) {
+               hdev->stat.err_rx++;
+               return -ENOMEM;
+       }
+
+       hci_skb_pkt_type(skb) = type;
+       memcpy(skb_put(skb, count), data, count);
+
+       return hci_recv_frame(hdev, skb);
+}
+
+static int btqcomsmd_acl_callback(struct qcom_smd_channel *channel,
+                                 const void *data, size_t count)
+{
+       struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
+
+       btq->hdev->stat.byte_rx += count;
+       return btqcomsmd_recv(btq->hdev, HCI_ACLDATA_PKT, data, count);
+}
+
+static int btqcomsmd_cmd_callback(struct qcom_smd_channel *channel,
+                                 const void *data, size_t count)
+{
+       struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
+
+       return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count);
+}
+
+static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct btqcomsmd *btq = hci_get_drvdata(hdev);
+       int ret;
+
+       switch (hci_skb_pkt_type(skb)) {
+       case HCI_ACLDATA_PKT:
+               ret = qcom_smd_send(btq->acl_channel, skb->data, skb->len);
+               hdev->stat.acl_tx++;
+               hdev->stat.byte_tx += skb->len;
+               break;
+       case HCI_COMMAND_PKT:
+               ret = qcom_smd_send(btq->cmd_channel, skb->data, skb->len);
+               hdev->stat.cmd_tx++;
+               break;
+       default:
+               ret = -EILSEQ;
+               break;
+       }
+
+       kfree_skb(skb);
+
+       return ret;
+}
+
+static int btqcomsmd_open(struct hci_dev *hdev)
+{
+       return 0;
+}
+
+static int btqcomsmd_close(struct hci_dev *hdev)
+{
+       return 0;
+}
+
+static int btqcomsmd_probe(struct platform_device *pdev)
+{
+       struct btqcomsmd *btq;
+       struct hci_dev *hdev;
+       void *wcnss;
+       int ret;
+
+       btq = devm_kzalloc(&pdev->dev, sizeof(*btq), GFP_KERNEL);
+       if (!btq)
+               return -ENOMEM;
+
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       btq->acl_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_ACL",
+                                                  btqcomsmd_acl_callback);
+       if (IS_ERR(btq->acl_channel))
+               return PTR_ERR(btq->acl_channel);
+
+       btq->cmd_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_CMD",
+                                                  btqcomsmd_cmd_callback);
+       if (IS_ERR(btq->cmd_channel))
+               return PTR_ERR(btq->cmd_channel);
+
+       qcom_smd_set_drvdata(btq->acl_channel, btq);
+       qcom_smd_set_drvdata(btq->cmd_channel, btq);
+
+       hdev = hci_alloc_dev();
+       if (!hdev)
+               return -ENOMEM;
+
+       hci_set_drvdata(hdev, btq);
+       btq->hdev = hdev;
+       SET_HCIDEV_DEV(hdev, &pdev->dev);
+
+       hdev->bus = HCI_SMD;
+       hdev->open = btqcomsmd_open;
+       hdev->close = btqcomsmd_close;
+       hdev->send = btqcomsmd_send;
+       hdev->set_bdaddr = qca_set_bdaddr_rome;
+
+       ret = hci_register_dev(hdev);
+       if (ret < 0) {
+               hci_free_dev(hdev);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, btq);
+
+       return 0;
+}
+
+static int btqcomsmd_remove(struct platform_device *pdev)
+{
+       struct btqcomsmd *btq = platform_get_drvdata(pdev);
+
+       hci_unregister_dev(btq->hdev);
+       hci_free_dev(btq->hdev);
+
+       return 0;
+}
+
+static const struct of_device_id btqcomsmd_of_match[] = {
+       { .compatible = "qcom,wcnss-bt", },
+       { },
+};
+
+static struct platform_driver btqcomsmd_driver = {
+       .probe = btqcomsmd_probe,
+       .remove = btqcomsmd_remove,
+       .driver  = {
+               .name  = "btqcomsmd",
+               .of_match_table = btqcomsmd_of_match,
+       },
+};
+
+module_platform_driver(btqcomsmd_driver);
+
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
+MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
+MODULE_LICENSE("GPL v2");
index 8428893..fc9b257 100644 (file)
@@ -33,6 +33,7 @@
 #define RTL_ROM_LMP_8723B      0x8723
 #define RTL_ROM_LMP_8821A      0x8821
 #define RTL_ROM_LMP_8761A      0x8761
+#define RTL_ROM_LMP_8822B      0x8822
 
 static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
 {
@@ -78,11 +79,15 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
        const unsigned char *patch_length_base, *patch_offset_base;
        u32 patch_offset = 0;
        u16 patch_length, num_patches;
-       const u16 project_id_to_lmp_subver[] = {
-               RTL_ROM_LMP_8723A,
-               RTL_ROM_LMP_8723B,
-               RTL_ROM_LMP_8821A,
-               RTL_ROM_LMP_8761A
+       static const struct {
+               __u16 lmp_subver;
+               __u8 id;
+       } project_id_to_lmp_subver[] = {
+               { RTL_ROM_LMP_8723A, 0 },
+               { RTL_ROM_LMP_8723B, 1 },
+               { RTL_ROM_LMP_8821A, 2 },
+               { RTL_ROM_LMP_8761A, 3 },
+               { RTL_ROM_LMP_8822B, 8 },
        };
 
        ret = rtl_read_rom_version(hdev, &rom_version);
@@ -134,14 +139,20 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
                return -EINVAL;
        }
 
-       if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
+       /* Find project_id in table */
+       for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) {
+               if (project_id == project_id_to_lmp_subver[i].id)
+                       break;
+       }
+
+       if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) {
                BT_ERR("%s: unknown project id %d", hdev->name, project_id);
                return -EINVAL;
        }
 
-       if (lmp_subver != project_id_to_lmp_subver[project_id]) {
+       if (lmp_subver != project_id_to_lmp_subver[i].lmp_subver) {
                BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
-                      project_id_to_lmp_subver[project_id], lmp_subver);
+                      project_id_to_lmp_subver[i].lmp_subver, lmp_subver);
                return -EINVAL;
        }
 
@@ -257,6 +268,26 @@ out:
        return ret;
 }
 
+static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff)
+{
+       const struct firmware *fw;
+       int ret;
+
+       BT_INFO("%s: rtl: loading %s", hdev->name, name);
+       ret = request_firmware(&fw, name, &hdev->dev);
+       if (ret < 0) {
+               BT_ERR("%s: Failed to load %s", hdev->name, name);
+               return ret;
+       }
+
+       ret = fw->size;
+       *buff = kmemdup(fw->data, ret, GFP_KERNEL);
+
+       release_firmware(fw);
+
+       return ret;
+}
+
 static int btrtl_setup_rtl8723a(struct hci_dev *hdev)
 {
        const struct firmware *fw;
@@ -296,25 +327,74 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
        unsigned char *fw_data = NULL;
        const struct firmware *fw;
        int ret;
+       int cfg_sz;
+       u8 *cfg_buff = NULL;
+       u8 *tbuff;
+       char *cfg_name = NULL;
+
+       switch (lmp_subver) {
+       case RTL_ROM_LMP_8723B:
+               cfg_name = "rtl_bt/rtl8723b_config.bin";
+               break;
+       case RTL_ROM_LMP_8821A:
+               cfg_name = "rtl_bt/rtl8821a_config.bin";
+               break;
+       case RTL_ROM_LMP_8761A:
+               cfg_name = "rtl_bt/rtl8761a_config.bin";
+               break;
+       case RTL_ROM_LMP_8822B:
+               cfg_name = "rtl_bt/rtl8822b_config.bin";
+               break;
+       default:
+               BT_ERR("%s: rtl: no config according to lmp_subver %04x",
+                      hdev->name, lmp_subver);
+               break;
+       }
+
+       if (cfg_name) {
+               cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff);
+               if (cfg_sz < 0)
+                       cfg_sz = 0;
+       } else
+               cfg_sz = 0;
 
        BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
        ret = request_firmware(&fw, fw_name, &hdev->dev);
        if (ret < 0) {
                BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
-               return ret;
+               goto err_req_fw;
        }
 
        ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
        if (ret < 0)
                goto out;
 
+       if (cfg_sz) {
+               tbuff = kzalloc(ret + cfg_sz, GFP_KERNEL);
+               if (!tbuff) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               memcpy(tbuff, fw_data, ret);
+               kfree(fw_data);
+
+               memcpy(tbuff + ret, cfg_buff, cfg_sz);
+               ret += cfg_sz;
+
+               fw_data = tbuff;
+       }
+
+       BT_INFO("cfg_sz %d, total size %d", cfg_sz, ret);
+
        ret = rtl_download_firmware(hdev, fw_data, ret);
-       kfree(fw_data);
-       if (ret < 0)
-               goto out;
 
 out:
        release_firmware(fw);
+       kfree(fw_data);
+err_req_fw:
+       if (cfg_sz)
+               kfree(cfg_buff);
        return ret;
 }
 
@@ -377,6 +457,9 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
        case RTL_ROM_LMP_8761A:
                return btrtl_setup_rtl8723b(hdev, lmp_subver,
                                            "rtl_bt/rtl8761a_fw.bin");
+       case RTL_ROM_LMP_8822B:
+               return btrtl_setup_rtl8723b(hdev, lmp_subver,
+                                           "rtl_bt/rtl8822b_fw.bin");
        default:
                BT_INFO("rtl: assuming no firmware upload needed.");
                return 0;
index 811f9b9..9ebd73d 100644 (file)
@@ -62,6 +62,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_REALTEK          0x20000
 #define BTUSB_BCM2045          0x40000
 #define BTUSB_IFNUM_2          0x80000
+#define BTUSB_CW6622           0x100000
 
 static const struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
@@ -248,6 +249,7 @@ static const struct usb_device_id blacklist_table[] = {
 
        /* QCA ROME chipset */
        { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
+       { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME },
@@ -290,7 +292,8 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0400, 0x080a), .driver_info = BTUSB_BROKEN_ISOC },
 
        /* CONWISE Technology based adapters with buggy SCO support */
-       { USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
+       { USB_DEVICE(0x0e5e, 0x6622),
+         .driver_info = BTUSB_BROKEN_ISOC | BTUSB_CW6622},
 
        /* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
        { USB_DEVICE(0x1310, 0x0001), .driver_info = BTUSB_SWAVE },
@@ -2221,9 +2224,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
        err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
                                  TASK_INTERRUPTIBLE,
                                  msecs_to_jiffies(5000));
-       if (err == 1) {
+       if (err == -EINTR) {
                BT_ERR("%s: Firmware loading interrupted", hdev->name);
-               err = -EINTR;
                goto done;
        }
 
@@ -2275,7 +2277,7 @@ done:
                                  TASK_INTERRUPTIBLE,
                                  msecs_to_jiffies(1000));
 
-       if (err == 1) {
+       if (err == -EINTR) {
                BT_ERR("%s: Device boot interrupted", hdev->name);
                return -EINTR;
        }
@@ -2845,6 +2847,9 @@ static int btusb_probe(struct usb_interface *intf,
        hdev->send   = btusb_send_frame;
        hdev->notify = btusb_notify;
 
+       if (id->driver_info & BTUSB_CW6622)
+               set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
+
        if (id->driver_info & BTUSB_BCM2045)
                set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
 
index 1c97eda..5ccb90e 100644 (file)
@@ -798,7 +798,7 @@ static int bcm_remove(struct platform_device *pdev)
 
 static const struct hci_uart_proto bcm_proto = {
        .id             = HCI_UART_BCM,
-       .name           = "BCM",
+       .name           = "Broadcom",
        .manufacturer   = 15,
        .init_speed     = 115200,
        .oper_speed     = 4000000,
index ed0a420..9e27128 100644 (file)
@@ -128,7 +128,7 @@ static int intel_wait_booting(struct hci_uart *hu)
                                  TASK_INTERRUPTIBLE,
                                  msecs_to_jiffies(1000));
 
-       if (err == 1) {
+       if (err == -EINTR) {
                bt_dev_err(hu->hdev, "Device boot interrupted");
                return -EINTR;
        }
@@ -151,7 +151,7 @@ static int intel_wait_lpm_transaction(struct hci_uart *hu)
                                  TASK_INTERRUPTIBLE,
                                  msecs_to_jiffies(1000));
 
-       if (err == 1) {
+       if (err == -EINTR) {
                bt_dev_err(hu->hdev, "LPM transaction interrupted");
                return -EINTR;
        }
@@ -813,7 +813,7 @@ static int intel_setup(struct hci_uart *hu)
        err = wait_on_bit_timeout(&intel->flags, STATE_DOWNLOADING,
                                  TASK_INTERRUPTIBLE,
                                  msecs_to_jiffies(5000));
-       if (err == 1) {
+       if (err == -EINTR) {
                bt_dev_err(hdev, "Firmware loading interrupted");
                err = -EINTR;
                goto done;
index dda9739..9a3aab6 100644 (file)
@@ -810,6 +810,9 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_AG6XX
        ag6xx_init();
 #endif
+#ifdef CONFIG_BT_HCIUART_MRVL
+       mrvl_init();
+#endif
 
        return 0;
 }
@@ -845,6 +848,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_AG6XX
        ag6xx_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_MRVL
+       mrvl_deinit();
+#endif
 
        /* Release tty registration of line discipline */
        err = tty_unregister_ldisc(N_HCI);
diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c
new file mode 100644 (file)
index 0000000..bbc4b39
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ *
+ *  Bluetooth HCI UART driver for marvell devices
+ *
+ *  Copyright (C) 2016  Marvell International Ltd.
+ *  Copyright (C) 2016  Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+#define HCI_FW_REQ_PKT 0xA5
+#define HCI_CHIP_VER_PKT 0xAA
+
+#define MRVL_ACK 0x5A
+#define MRVL_NAK 0xBF
+#define MRVL_RAW_DATA 0x1F
+
+enum {
+       STATE_CHIP_VER_PENDING,
+       STATE_FW_REQ_PENDING,
+};
+
+struct mrvl_data {
+       struct sk_buff *rx_skb;
+       struct sk_buff_head txq;
+       struct sk_buff_head rawq;
+       unsigned long flags;
+       unsigned int tx_len;
+       u8 id, rev;
+};
+
+struct hci_mrvl_pkt {
+       __le16 lhs;
+       __le16 rhs;
+} __packed;
+#define HCI_MRVL_PKT_SIZE 4
+
+static int mrvl_open(struct hci_uart *hu)
+{
+       struct mrvl_data *mrvl;
+
+       BT_DBG("hu %p", hu);
+
+       mrvl = kzalloc(sizeof(*mrvl), GFP_KERNEL);
+       if (!mrvl)
+               return -ENOMEM;
+
+       skb_queue_head_init(&mrvl->txq);
+       skb_queue_head_init(&mrvl->rawq);
+
+       set_bit(STATE_CHIP_VER_PENDING, &mrvl->flags);
+
+       hu->priv = mrvl;
+       return 0;
+}
+
+static int mrvl_close(struct hci_uart *hu)
+{
+       struct mrvl_data *mrvl = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&mrvl->txq);
+       skb_queue_purge(&mrvl->rawq);
+       kfree_skb(mrvl->rx_skb);
+       kfree(mrvl);
+
+       hu->priv = NULL;
+       return 0;
+}
+
+static int mrvl_flush(struct hci_uart *hu)
+{
+       struct mrvl_data *mrvl = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&mrvl->txq);
+       skb_queue_purge(&mrvl->rawq);
+
+       return 0;
+}
+
+static struct sk_buff *mrvl_dequeue(struct hci_uart *hu)
+{
+       struct mrvl_data *mrvl = hu->priv;
+       struct sk_buff *skb;
+
+       skb = skb_dequeue(&mrvl->txq);
+       if (!skb) {
+               /* Any raw data ? */
+               skb = skb_dequeue(&mrvl->rawq);
+       } else {
+               /* Prepend skb with frame type */
+               memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+       }
+
+       return skb;
+}
+
+static int mrvl_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+       struct mrvl_data *mrvl = hu->priv;
+
+       skb_queue_tail(&mrvl->txq, skb);
+       return 0;
+}
+
+static void mrvl_send_ack(struct hci_uart *hu, unsigned char type)
+{
+       struct mrvl_data *mrvl = hu->priv;
+       struct sk_buff *skb;
+
+       /* No H4 payload, only 1 byte header */
+       skb = bt_skb_alloc(0, GFP_ATOMIC);
+       if (!skb) {
+               bt_dev_err(hu->hdev, "Unable to alloc ack/nak packet");
+               return;
+       }
+       hci_skb_pkt_type(skb) = type;
+
+       skb_queue_tail(&mrvl->txq, skb);
+       hci_uart_tx_wakeup(hu);
+}
+
+static int mrvl_recv_fw_req(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_mrvl_pkt *pkt = (void *)skb->data;
+       struct hci_uart *hu = hci_get_drvdata(hdev);
+       struct mrvl_data *mrvl = hu->priv;
+       int ret = 0;
+
+       if ((pkt->lhs ^ pkt->rhs) != 0xffff) {
+               bt_dev_err(hdev, "Corrupted mrvl header");
+               mrvl_send_ack(hu, MRVL_NAK);
+               ret = -EINVAL;
+               goto done;
+       }
+       mrvl_send_ack(hu, MRVL_ACK);
+
+       if (!test_bit(STATE_FW_REQ_PENDING, &mrvl->flags)) {
+               bt_dev_err(hdev, "Received unexpected firmware request");
+               ret = -EINVAL;
+               goto done;
+       }
+
+       mrvl->tx_len = le16_to_cpu(pkt->lhs);
+
+       clear_bit(STATE_FW_REQ_PENDING, &mrvl->flags);
+       smp_mb__after_atomic();
+       wake_up_bit(&mrvl->flags, STATE_FW_REQ_PENDING);
+
+done:
+       kfree_skb(skb);
+       return ret;
+}
+
+static int mrvl_recv_chip_ver(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_mrvl_pkt *pkt = (void *)skb->data;
+       struct hci_uart *hu = hci_get_drvdata(hdev);
+       struct mrvl_data *mrvl = hu->priv;
+       u16 version = le16_to_cpu(pkt->lhs);
+       int ret = 0;
+
+       if ((pkt->lhs ^ pkt->rhs) != 0xffff) {
+               bt_dev_err(hdev, "Corrupted mrvl header");
+               mrvl_send_ack(hu, MRVL_NAK);
+               ret = -EINVAL;
+               goto done;
+       }
+       mrvl_send_ack(hu, MRVL_ACK);
+
+       if (!test_bit(STATE_CHIP_VER_PENDING, &mrvl->flags)) {
+               bt_dev_err(hdev, "Received unexpected chip version");
+               goto done;
+       }
+
+       mrvl->id = version;
+       mrvl->rev = version >> 8;
+
+       bt_dev_info(hdev, "Controller id = %x, rev = %x", mrvl->id, mrvl->rev);
+
+       clear_bit(STATE_CHIP_VER_PENDING, &mrvl->flags);
+       smp_mb__after_atomic();
+       wake_up_bit(&mrvl->flags, STATE_CHIP_VER_PENDING);
+
+done:
+       kfree_skb(skb);
+       return ret;
+}
+
+#define HCI_RECV_CHIP_VER \
+       .type = HCI_CHIP_VER_PKT, \
+       .hlen = HCI_MRVL_PKT_SIZE, \
+       .loff = 0, \
+       .lsize = 0, \
+       .maxlen = HCI_MRVL_PKT_SIZE
+
+#define HCI_RECV_FW_REQ \
+       .type = HCI_FW_REQ_PKT, \
+       .hlen = HCI_MRVL_PKT_SIZE, \
+       .loff = 0, \
+       .lsize = 0, \
+       .maxlen = HCI_MRVL_PKT_SIZE
+
+static const struct h4_recv_pkt mrvl_recv_pkts[] = {
+       { H4_RECV_ACL,       .recv = hci_recv_frame     },
+       { H4_RECV_SCO,       .recv = hci_recv_frame     },
+       { H4_RECV_EVENT,     .recv = hci_recv_frame     },
+       { HCI_RECV_FW_REQ,   .recv = mrvl_recv_fw_req   },
+       { HCI_RECV_CHIP_VER, .recv = mrvl_recv_chip_ver },
+};
+
+static int mrvl_recv(struct hci_uart *hu, const void *data, int count)
+{
+       struct mrvl_data *mrvl = hu->priv;
+
+       if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+               return -EUNATCH;
+
+       mrvl->rx_skb = h4_recv_buf(hu->hdev, mrvl->rx_skb, data, count,
+                                   mrvl_recv_pkts,
+                                   ARRAY_SIZE(mrvl_recv_pkts));
+       if (IS_ERR(mrvl->rx_skb)) {
+               int err = PTR_ERR(mrvl->rx_skb);
+               bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
+               mrvl->rx_skb = NULL;
+               return err;
+       }
+
+       return count;
+}
+
+static int mrvl_load_firmware(struct hci_dev *hdev, const char *name)
+{
+       struct hci_uart *hu = hci_get_drvdata(hdev);
+       struct mrvl_data *mrvl = hu->priv;
+       const struct firmware *fw = NULL;
+       const u8 *fw_ptr, *fw_max;
+       int err;
+
+       err = request_firmware(&fw, name, &hdev->dev);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to load firmware file %s", name);
+               return err;
+       }
+
+       fw_ptr = fw->data;
+       fw_max = fw->data + fw->size;
+
+       bt_dev_info(hdev, "Loading %s", name);
+
+       set_bit(STATE_FW_REQ_PENDING, &mrvl->flags);
+
+       while (fw_ptr <= fw_max) {
+               struct sk_buff *skb;
+
+               /* Controller drives the firmware load by sending firmware
+                * request packets containing the expected fragment size.
+                */
+               err = wait_on_bit_timeout(&mrvl->flags, STATE_FW_REQ_PENDING,
+                                         TASK_INTERRUPTIBLE,
+                                         msecs_to_jiffies(2000));
+               if (err == 1) {
+                       bt_dev_err(hdev, "Firmware load interrupted");
+                       err = -EINTR;
+                       break;
+               } else if (err) {
+                       bt_dev_err(hdev, "Firmware request timeout");
+                       err = -ETIMEDOUT;
+                       break;
+               }
+
+               bt_dev_dbg(hdev, "Firmware request, expecting %d bytes",
+                          mrvl->tx_len);
+
+               if (fw_ptr == fw_max) {
+                       /* Controller requests a null size once firmware is
+                        * fully loaded. If controller expects more data, there
+                        * is an issue.
+                        */
+                       if (!mrvl->tx_len) {
+                               bt_dev_info(hdev, "Firmware loading complete");
+                       } else {
+                               bt_dev_err(hdev, "Firmware loading failure");
+                               err = -EINVAL;
+                       }
+                       break;
+               }
+
+               if (fw_ptr + mrvl->tx_len > fw_max) {
+                       mrvl->tx_len = fw_max - fw_ptr;
+                       bt_dev_dbg(hdev, "Adjusting tx_len to %d",
+                                  mrvl->tx_len);
+               }
+
+               skb = bt_skb_alloc(mrvl->tx_len, GFP_KERNEL);
+               if (!skb) {
+                       bt_dev_err(hdev, "Failed to alloc mem for FW packet");
+                       err = -ENOMEM;
+                       break;
+               }
+               bt_cb(skb)->pkt_type = MRVL_RAW_DATA;
+
+               memcpy(skb_put(skb, mrvl->tx_len), fw_ptr, mrvl->tx_len);
+               fw_ptr += mrvl->tx_len;
+
+               set_bit(STATE_FW_REQ_PENDING, &mrvl->flags);
+
+               skb_queue_tail(&mrvl->rawq, skb);
+               hci_uart_tx_wakeup(hu);
+       }
+
+       release_firmware(fw);
+       return err;
+}
+
+static int mrvl_setup(struct hci_uart *hu)
+{
+       int err;
+
+       hci_uart_set_flow_control(hu, true);
+
+       err = mrvl_load_firmware(hu->hdev, "mrvl/helper_uart_3000000.bin");
+       if (err) {
+               bt_dev_err(hu->hdev, "Unable to download firmware helper");
+               return -EINVAL;
+       }
+
+       hci_uart_set_baudrate(hu, 3000000);
+       hci_uart_set_flow_control(hu, false);
+
+       err = mrvl_load_firmware(hu->hdev, "mrvl/uart8897_bt.bin");
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static const struct hci_uart_proto mrvl_proto = {
+       .id             = HCI_UART_MRVL,
+       .name           = "Marvell",
+       .init_speed     = 115200,
+       .open           = mrvl_open,
+       .close          = mrvl_close,
+       .flush          = mrvl_flush,
+       .setup          = mrvl_setup,
+       .recv           = mrvl_recv,
+       .enqueue        = mrvl_enqueue,
+       .dequeue        = mrvl_dequeue,
+};
+
+int __init mrvl_init(void)
+{
+       return hci_uart_register_proto(&mrvl_proto);
+}
+
+int __exit mrvl_deinit(void)
+{
+       return hci_uart_unregister_proto(&mrvl_proto);
+}
index 683c2b6..6c867fb 100644 (file)
@@ -397,7 +397,7 @@ static int qca_open(struct hci_uart *hu)
        skb_queue_head_init(&qca->txq);
        skb_queue_head_init(&qca->tx_wait_q);
        spin_lock_init(&qca->hci_ibs_lock);
-       qca->workqueue = create_singlethread_workqueue("qca_wq");
+       qca->workqueue = alloc_ordered_workqueue("qca_wq", 0);
        if (!qca->workqueue) {
                BT_ERR("QCA Workqueue not initialized properly");
                kfree(qca);
index 839bad1..0701395 100644 (file)
@@ -35,7 +35,7 @@
 #define HCIUARTGETFLAGS                _IOR('U', 204, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO     10
+#define HCI_UART_MAX_PROTO     12
 
 #define HCI_UART_H4    0
 #define HCI_UART_BCSP  1
@@ -47,6 +47,8 @@
 #define HCI_UART_BCM   7
 #define HCI_UART_QCA   8
 #define HCI_UART_AG6XX 9
+#define HCI_UART_NOKIA 10
+#define HCI_UART_MRVL  11
 
 #define HCI_UART_RAW_DEVICE    0
 #define HCI_UART_RESET_ON_INIT 1
@@ -189,3 +191,8 @@ int qca_deinit(void);
 int ag6xx_init(void);
 int ag6xx_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_MRVL
+int mrvl_init(void);
+int mrvl_deinit(void);
+#endif
index 0becf0a..ec387ef 100644 (file)
@@ -30,7 +30,7 @@
 static int numlbs = 2;
 
 static LIST_HEAD(fakelb_phys);
-static DEFINE_SPINLOCK(fakelb_phys_lock);
+static DEFINE_MUTEX(fakelb_phys_lock);
 
 static LIST_HEAD(fakelb_ifup_phys);
 static DEFINE_RWLOCK(fakelb_ifup_phys_lock);
@@ -188,9 +188,9 @@ static int fakelb_add_one(struct device *dev)
        if (err)
                goto err_reg;
 
-       spin_lock(&fakelb_phys_lock);
+       mutex_lock(&fakelb_phys_lock);
        list_add_tail(&phy->list, &fakelb_phys);
-       spin_unlock(&fakelb_phys_lock);
+       mutex_unlock(&fakelb_phys_lock);
 
        return 0;
 
@@ -222,10 +222,10 @@ static int fakelb_probe(struct platform_device *pdev)
        return 0;
 
 err_slave:
-       spin_lock(&fakelb_phys_lock);
+       mutex_lock(&fakelb_phys_lock);
        list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
                fakelb_del(phy);
-       spin_unlock(&fakelb_phys_lock);
+       mutex_unlock(&fakelb_phys_lock);
        return err;
 }
 
@@ -233,10 +233,10 @@ static int fakelb_remove(struct platform_device *pdev)
 {
        struct fakelb_phy *phy, *tmp;
 
-       spin_lock(&fakelb_phys_lock);
+       mutex_lock(&fakelb_phys_lock);
        list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
                fakelb_del(phy);
-       spin_unlock(&fakelb_phys_lock);
+       mutex_unlock(&fakelb_phys_lock);
        return 0;
 }
 
index bfd1590..0a1e21d 100644 (file)
@@ -29,7 +29,8 @@
 #include <net/sock.h>
 #include <linux/seq_file.h>
 
-#define BT_SUBSYS_VERSION "2.21"
+#define BT_SUBSYS_VERSION      2
+#define BT_SUBSYS_REVISION     22
 
 #ifndef AF_BLUETOOTH
 #define AF_BLUETOOTH   31
@@ -371,6 +372,7 @@ void hci_sock_set_flag(struct sock *sk, int nr);
 void hci_sock_clear_flag(struct sock *sk, int nr);
 int hci_sock_test_flag(struct sock *sk, int nr);
 unsigned short hci_sock_get_channel(struct sock *sk);
+u32 hci_sock_get_cookie(struct sock *sk);
 
 int hci_sock_init(void);
 void hci_sock_cleanup(void);
index 003b252..99aa5e5 100644 (file)
@@ -63,6 +63,7 @@
 #define HCI_SDIO       6
 #define HCI_SPI                7
 #define HCI_I2C                8
+#define HCI_SMD                9
 
 /* HCI controller types */
 #define HCI_PRIMARY    0x00
@@ -207,7 +208,11 @@ enum {
        HCI_MGMT_INDEX_EVENTS,
        HCI_MGMT_UNCONF_INDEX_EVENTS,
        HCI_MGMT_EXT_INDEX_EVENTS,
-       HCI_MGMT_GENERIC_EVENTS,
+       HCI_MGMT_EXT_INFO_EVENTS,
+       HCI_MGMT_OPTION_EVENTS,
+       HCI_MGMT_SETTING_EVENTS,
+       HCI_MGMT_DEV_CLASS_EVENTS,
+       HCI_MGMT_LOCAL_NAME_EVENTS,
        HCI_MGMT_OOB_DATA_EVENTS,
 };
 
index ee7fc47..f00bf66 100644 (file)
@@ -211,6 +211,7 @@ struct hci_dev {
        __u8            dev_name[HCI_MAX_NAME_LENGTH];
        __u8            short_name[HCI_MAX_SHORT_NAME_LENGTH];
        __u8            eir[HCI_MAX_EIR_LENGTH];
+       __u16           appearance;
        __u8            dev_class[3];
        __u8            major_class;
        __u8            minor_class;
@@ -399,7 +400,9 @@ struct hci_dev {
        struct delayed_work     rpa_expired;
        bdaddr_t                rpa;
 
+#if IS_ENABLED(CONFIG_BT_LEDS)
        struct led_trigger      *power_led;
+#endif
 
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
@@ -1026,8 +1029,8 @@ int hci_resume_dev(struct hci_dev *hdev);
 int hci_reset_dev(struct hci_dev *hdev);
 int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
 int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb);
-void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...);
-void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...);
+__printf(2, 3) void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...);
+__printf(2, 3) void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...);
 int hci_dev_open(__u16 dev);
 int hci_dev_close(__u16 dev);
 int hci_dev_do_close(struct hci_dev *hdev);
@@ -1404,6 +1407,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
 void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
                         int flag, struct sock *skip_sk);
 void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
+void hci_send_monitor_ctrl_event(struct hci_dev *hdev, u16 event,
+                                void *data, u16 data_len, ktime_t tstamp,
+                                int flag, struct sock *skip_sk);
 
 void hci_sock_dev_event(struct hci_dev *hdev, int event);
 
@@ -1449,6 +1455,7 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
 #define DISCOV_BREDR_INQUIRY_LEN       0x08
 #define DISCOV_LE_RESTART_DELAY                msecs_to_jiffies(200)   /* msec */
 
+void mgmt_fill_version_info(void *ver);
 int mgmt_new_settings(struct hci_dev *hdev);
 void mgmt_index_added(struct hci_dev *hdev);
 void mgmt_index_removed(struct hci_dev *hdev);
index 587d013..240786b 100644 (file)
@@ -45,6 +45,10 @@ struct hci_mon_hdr {
 #define HCI_MON_VENDOR_DIAG    11
 #define HCI_MON_SYSTEM_NOTE    12
 #define HCI_MON_USER_LOGGING   13
+#define HCI_MON_CTRL_OPEN      14
+#define HCI_MON_CTRL_CLOSE     15
+#define HCI_MON_CTRL_COMMAND   16
+#define HCI_MON_CTRL_EVENT     17
 
 struct hci_mon_new_index {
        __u8            type;
index 7647964..72a456b 100644 (file)
@@ -586,6 +586,24 @@ struct mgmt_rp_get_adv_size_info {
 
 #define MGMT_OP_START_LIMITED_DISCOVERY        0x0041
 
+#define MGMT_OP_READ_EXT_INFO          0x0042
+#define MGMT_READ_EXT_INFO_SIZE                0
+struct mgmt_rp_read_ext_info {
+       bdaddr_t bdaddr;
+       __u8     version;
+       __le16   manufacturer;
+       __le32   supported_settings;
+       __le32   current_settings;
+       __le16   eir_len;
+       __u8     eir[0];
+} __packed;
+
+#define MGMT_OP_SET_APPEARANCE         0x0043
+struct mgmt_cp_set_appearance {
+       __u16   appearance;
+} __packed;
+#define MGMT_SET_APPEARANCE_SIZE       2
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        __le16  opcode;
@@ -800,3 +818,9 @@ struct mgmt_ev_advertising_added {
 struct mgmt_ev_advertising_removed {
        __u8    instance;
 } __packed;
+
+#define MGMT_EV_EXT_INFO_CHANGED       0x0025
+struct mgmt_ev_ext_info_changed {
+       __le16  eir_len;
+       __u8    eir[0];
+} __packed;
index 86450b7..941df2f 100644 (file)
@@ -101,8 +101,6 @@ static void lowpan_ndisc_802154_update(struct neighbour *n, u32 flags,
                ieee802154_be16_to_le16(&neigh->short_addr, lladdr_short);
                if (!lowpan_802154_is_valid_src_short_addr(neigh->short_addr))
                        neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
-       } else {
-               neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
        }
        write_unlock_bh(&n->lock);
 }
index 0b5f729..1aff2da 100644 (file)
 
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/stringify.h>
 #include <asm/ioctls.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <linux/proc_fs.h>
 
+#include "leds.h"
 #include "selftest.h"
 
 /* Bluetooth sockets */
@@ -712,13 +714,16 @@ static struct net_proto_family bt_sock_family_ops = {
 struct dentry *bt_debugfs;
 EXPORT_SYMBOL_GPL(bt_debugfs);
 
+#define VERSION __stringify(BT_SUBSYS_VERSION) "." \
+               __stringify(BT_SUBSYS_REVISION)
+
 static int __init bt_init(void)
 {
        int err;
 
        sock_skb_cb_check_size(sizeof(struct bt_skb_cb));
 
-       BT_INFO("Core ver %s", BT_SUBSYS_VERSION);
+       BT_INFO("Core ver %s", VERSION);
 
        err = bt_selftest();
        if (err < 0)
@@ -726,6 +731,8 @@ static int __init bt_init(void)
 
        bt_debugfs = debugfs_create_dir("bluetooth", NULL);
 
+       bt_leds_init();
+
        err = bt_sysfs_init();
        if (err < 0)
                return err;
@@ -785,6 +792,8 @@ static void __exit bt_exit(void)
 
        bt_sysfs_cleanup();
 
+       bt_leds_cleanup();
+
        debugfs_remove_recursive(bt_debugfs);
 }
 
@@ -792,7 +801,7 @@ subsys_initcall(bt_init);
 module_exit(bt_exit);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth Core ver " BT_SUBSYS_VERSION);
-MODULE_VERSION(BT_SUBSYS_VERSION);
+MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
index ddf8432..3ac89e9 100644 (file)
@@ -1562,6 +1562,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
        auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
 
        if (!auto_off && hdev->dev_type == HCI_PRIMARY &&
+           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
            hci_dev_test_flag(hdev, HCI_MGMT))
                __mgmt_power_off(hdev);
 
index b0e23df..c813568 100644 (file)
@@ -971,14 +971,14 @@ void __hci_req_enable_advertising(struct hci_request *req)
        hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
 }
 
-static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+static u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
 {
-       u8 ad_len = 0;
        size_t name_len;
+       int max_len;
 
+       max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
        name_len = strlen(hdev->dev_name);
-       if (name_len > 0) {
-               size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
+       if (name_len > 0 && max_len > 0) {
 
                if (name_len > max_len) {
                        name_len = max_len;
@@ -997,22 +997,42 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
        return ad_len;
 }
 
+static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
+{
+       return append_local_name(hdev, ptr, 0);
+}
+
 static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
                                        u8 *ptr)
 {
        struct adv_info *adv_instance;
+       u32 instance_flags;
+       u8 scan_rsp_len = 0;
 
        adv_instance = hci_find_adv_instance(hdev, instance);
        if (!adv_instance)
                return 0;
 
-       /* TODO: Set the appropriate entries based on advertising instance flags
-        * here once flags other than 0 are supported.
-        */
+       instance_flags = adv_instance->flags;
+
+       if ((instance_flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance) {
+               ptr[0] = 3;
+               ptr[1] = EIR_APPEARANCE;
+               put_unaligned_le16(hdev->appearance, ptr + 2);
+               scan_rsp_len += 4;
+               ptr += 4;
+       }
+
        memcpy(ptr, adv_instance->scan_rsp_data,
               adv_instance->scan_rsp_len);
 
-       return adv_instance->scan_rsp_len;
+       scan_rsp_len += adv_instance->scan_rsp_len;
+       ptr += adv_instance->scan_rsp_len;
+
+       if (instance_flags & MGMT_ADV_FLAG_LOCAL_NAME)
+               scan_rsp_len = append_local_name(hdev, ptr, scan_rsp_len);
+
+       return scan_rsp_len;
 }
 
 void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
@@ -1194,7 +1214,7 @@ static void adv_timeout_expire(struct work_struct *work)
 
        hci_req_init(&req, hdev);
 
-       hci_req_clear_adv_instance(hdev, &req, instance, false);
+       hci_req_clear_adv_instance(hdev, NULL, &req, instance, false);
 
        if (list_empty(&hdev->adv_instances))
                __hci_req_disable_advertising(&req);
@@ -1284,8 +1304,9 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
  *   setting.
  * - force == false: Only instances that have a timeout will be removed.
  */
-void hci_req_clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
-                               u8 instance, bool force)
+void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
+                               struct hci_request *req, u8 instance,
+                               bool force)
 {
        struct adv_info *adv_instance, *n, *next_instance = NULL;
        int err;
@@ -1311,7 +1332,7 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
                        rem_inst = adv_instance->instance;
                        err = hci_remove_adv_instance(hdev, rem_inst);
                        if (!err)
-                               mgmt_advertising_removed(NULL, hdev, rem_inst);
+                               mgmt_advertising_removed(sk, hdev, rem_inst);
                }
        } else {
                adv_instance = hci_find_adv_instance(hdev, instance);
@@ -1325,7 +1346,7 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
 
                        err = hci_remove_adv_instance(hdev, instance);
                        if (!err)
-                               mgmt_advertising_removed(NULL, hdev, instance);
+                               mgmt_advertising_removed(sk, hdev, instance);
                }
        }
 
@@ -1716,7 +1737,7 @@ void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
                         * function. To be safe hard-code one of the
                         * values that's suitable for SCO.
                         */
-                       rej.reason = HCI_ERROR_REMOTE_LOW_RESOURCES;
+                       rej.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
 
                        hci_req_add(req, HCI_OP_REJECT_SYNC_CONN_REQ,
                                    sizeof(rej), &rej);
index b2d044b..ac1e110 100644 (file)
@@ -73,8 +73,9 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance);
 
 int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
                                    bool force);
-void hci_req_clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
-                               u8 instance, bool force);
+void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
+                               struct hci_request *req, u8 instance,
+                               bool force);
 
 void __hci_req_update_class(struct hci_request *req);
 
index 96f04b7..48f9471 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/export.h>
 #include <linux/utsname.h>
+#include <linux/sched.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -38,6 +39,8 @@
 static LIST_HEAD(mgmt_chan_list);
 static DEFINE_MUTEX(mgmt_chan_list_lock);
 
+static DEFINE_IDA(sock_cookie_ida);
+
 static atomic_t monitor_promisc = ATOMIC_INIT(0);
 
 /* ----- HCI socket interface ----- */
@@ -52,6 +55,8 @@ struct hci_pinfo {
        __u32             cmsg_mask;
        unsigned short    channel;
        unsigned long     flags;
+       __u32             cookie;
+       char              comm[TASK_COMM_LEN];
 };
 
 void hci_sock_set_flag(struct sock *sk, int nr)
@@ -74,6 +79,38 @@ unsigned short hci_sock_get_channel(struct sock *sk)
        return hci_pi(sk)->channel;
 }
 
+u32 hci_sock_get_cookie(struct sock *sk)
+{
+       return hci_pi(sk)->cookie;
+}
+
+static bool hci_sock_gen_cookie(struct sock *sk)
+{
+       int id = hci_pi(sk)->cookie;
+
+       if (!id) {
+               id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL);
+               if (id < 0)
+                       id = 0xffffffff;
+
+               hci_pi(sk)->cookie = id;
+               get_task_comm(hci_pi(sk)->comm, current);
+               return true;
+       }
+
+       return false;
+}
+
+static void hci_sock_free_cookie(struct sock *sk)
+{
+       int id = hci_pi(sk)->cookie;
+
+       if (id) {
+               hci_pi(sk)->cookie = 0xffffffff;
+               ida_simple_remove(&sock_cookie_ida, id);
+       }
+}
+
 static inline int hci_test_bit(int nr, const void *addr)
 {
        return *((const __u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
@@ -305,6 +342,60 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
        kfree_skb(skb_copy);
 }
 
+void hci_send_monitor_ctrl_event(struct hci_dev *hdev, u16 event,
+                                void *data, u16 data_len, ktime_t tstamp,
+                                int flag, struct sock *skip_sk)
+{
+       struct sock *sk;
+       __le16 index;
+
+       if (hdev)
+               index = cpu_to_le16(hdev->id);
+       else
+               index = cpu_to_le16(MGMT_INDEX_NONE);
+
+       read_lock(&hci_sk_list.lock);
+
+       sk_for_each(sk, &hci_sk_list.head) {
+               struct hci_mon_hdr *hdr;
+               struct sk_buff *skb;
+
+               if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL)
+                       continue;
+
+               /* Ignore socket without the flag set */
+               if (!hci_sock_test_flag(sk, flag))
+                       continue;
+
+               /* Skip the original socket */
+               if (sk == skip_sk)
+                       continue;
+
+               skb = bt_skb_alloc(6 + data_len, GFP_ATOMIC);
+               if (!skb)
+                       continue;
+
+               put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
+               put_unaligned_le16(event, skb_put(skb, 2));
+
+               if (data)
+                       memcpy(skb_put(skb, data_len), data, data_len);
+
+               skb->tstamp = tstamp;
+
+               hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
+               hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
+               hdr->index = index;
+               hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+               hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                   HCI_SOCK_TRUSTED, NULL);
+               kfree_skb(skb);
+       }
+
+       read_unlock(&hci_sk_list.lock);
+}
+
 static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
 {
        struct hci_mon_hdr *hdr;
@@ -384,6 +475,129 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
        return skb;
 }
 
+static struct sk_buff *create_monitor_ctrl_open(struct sock *sk)
+{
+       struct hci_mon_hdr *hdr;
+       struct sk_buff *skb;
+       u16 format;
+       u8 ver[3];
+       u32 flags;
+
+       /* No message needed when cookie is not present */
+       if (!hci_pi(sk)->cookie)
+               return NULL;
+
+       switch (hci_pi(sk)->channel) {
+       case HCI_CHANNEL_RAW:
+               format = 0x0000;
+               ver[0] = BT_SUBSYS_VERSION;
+               put_unaligned_le16(BT_SUBSYS_REVISION, ver + 1);
+               break;
+       case HCI_CHANNEL_USER:
+               format = 0x0001;
+               ver[0] = BT_SUBSYS_VERSION;
+               put_unaligned_le16(BT_SUBSYS_REVISION, ver + 1);
+               break;
+       case HCI_CHANNEL_CONTROL:
+               format = 0x0002;
+               mgmt_fill_version_info(ver);
+               break;
+       default:
+               /* No message for unsupported format */
+               return NULL;
+       }
+
+       skb = bt_skb_alloc(14 + TASK_COMM_LEN , GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       flags = hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) ? 0x1 : 0x0;
+
+       put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
+       put_unaligned_le16(format, skb_put(skb, 2));
+       memcpy(skb_put(skb, sizeof(ver)), ver, sizeof(ver));
+       put_unaligned_le32(flags, skb_put(skb, 4));
+       *skb_put(skb, 1) = TASK_COMM_LEN;
+       memcpy(skb_put(skb, TASK_COMM_LEN), hci_pi(sk)->comm, TASK_COMM_LEN);
+
+       __net_timestamp(skb);
+
+       hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
+       hdr->opcode = cpu_to_le16(HCI_MON_CTRL_OPEN);
+       if (hci_pi(sk)->hdev)
+               hdr->index = cpu_to_le16(hci_pi(sk)->hdev->id);
+       else
+               hdr->index = cpu_to_le16(HCI_DEV_NONE);
+       hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+       return skb;
+}
+
+static struct sk_buff *create_monitor_ctrl_close(struct sock *sk)
+{
+       struct hci_mon_hdr *hdr;
+       struct sk_buff *skb;
+
+       /* No message needed when cookie is not present */
+       if (!hci_pi(sk)->cookie)
+               return NULL;
+
+       switch (hci_pi(sk)->channel) {
+       case HCI_CHANNEL_RAW:
+       case HCI_CHANNEL_USER:
+       case HCI_CHANNEL_CONTROL:
+               break;
+       default:
+               /* No message for unsupported format */
+               return NULL;
+       }
+
+       skb = bt_skb_alloc(4, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
+
+       __net_timestamp(skb);
+
+       hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
+       hdr->opcode = cpu_to_le16(HCI_MON_CTRL_CLOSE);
+       if (hci_pi(sk)->hdev)
+               hdr->index = cpu_to_le16(hci_pi(sk)->hdev->id);
+       else
+               hdr->index = cpu_to_le16(HCI_DEV_NONE);
+       hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+       return skb;
+}
+
+static struct sk_buff *create_monitor_ctrl_command(struct sock *sk, u16 index,
+                                                  u16 opcode, u16 len,
+                                                  const void *buf)
+{
+       struct hci_mon_hdr *hdr;
+       struct sk_buff *skb;
+
+       skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
+       put_unaligned_le16(opcode, skb_put(skb, 2));
+
+       if (buf)
+               memcpy(skb_put(skb, len), buf, len);
+
+       __net_timestamp(skb);
+
+       hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
+       hdr->opcode = cpu_to_le16(HCI_MON_CTRL_COMMAND);
+       hdr->index = cpu_to_le16(index);
+       hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+       return skb;
+}
+
 static void __printf(2, 3)
 send_monitor_note(struct sock *sk, const char *fmt, ...)
 {
@@ -458,6 +672,26 @@ static void send_monitor_replay(struct sock *sk)
        read_unlock(&hci_dev_list_lock);
 }
 
+static void send_monitor_control_replay(struct sock *mon_sk)
+{
+       struct sock *sk;
+
+       read_lock(&hci_sk_list.lock);
+
+       sk_for_each(sk, &hci_sk_list.head) {
+               struct sk_buff *skb;
+
+               skb = create_monitor_ctrl_open(sk);
+               if (!skb)
+                       continue;
+
+               if (sock_queue_rcv_skb(mon_sk, skb))
+                       kfree_skb(skb);
+       }
+
+       read_unlock(&hci_sk_list.lock);
+}
+
 /* Generate internal stack event */
 static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
 {
@@ -585,6 +819,7 @@ static int hci_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        struct hci_dev *hdev;
+       struct sk_buff *skb;
 
        BT_DBG("sock %p sk %p", sock, sk);
 
@@ -593,8 +828,24 @@ static int hci_sock_release(struct socket *sock)
 
        hdev = hci_pi(sk)->hdev;
 
-       if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR)
+       switch (hci_pi(sk)->channel) {
+       case HCI_CHANNEL_MONITOR:
                atomic_dec(&monitor_promisc);
+               break;
+       case HCI_CHANNEL_RAW:
+       case HCI_CHANNEL_USER:
+       case HCI_CHANNEL_CONTROL:
+               /* Send event to monitor */
+               skb = create_monitor_ctrl_close(sk);
+               if (skb) {
+                       hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                           HCI_SOCK_TRUSTED, NULL);
+                       kfree_skb(skb);
+               }
+
+               hci_sock_free_cookie(sk);
+               break;
+       }
 
        bt_sock_unlink(&hci_sk_list, sk);
 
@@ -721,6 +972,27 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
                goto done;
        }
 
+       /* When calling an ioctl on an unbound raw socket, then ensure
+        * that the monitor gets informed. Ensure that the resulting event
+        * is only send once by checking if the cookie exists or not. The
+        * socket cookie will be only ever generated once for the lifetime
+        * of a given socket.
+        */
+       if (hci_sock_gen_cookie(sk)) {
+               struct sk_buff *skb;
+
+               if (capable(CAP_NET_ADMIN))
+                       hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
+
+               /* Send event to monitor */
+               skb = create_monitor_ctrl_open(sk);
+               if (skb) {
+                       hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                           HCI_SOCK_TRUSTED, NULL);
+                       kfree_skb(skb);
+               }
+       }
+
        release_sock(sk);
 
        switch (cmd) {
@@ -784,6 +1056,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
        struct sockaddr_hci haddr;
        struct sock *sk = sock->sk;
        struct hci_dev *hdev = NULL;
+       struct sk_buff *skb;
        int len, err = 0;
 
        BT_DBG("sock %p sk %p", sock, sk);
@@ -822,7 +1095,35 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                        atomic_inc(&hdev->promisc);
                }
 
+               hci_pi(sk)->channel = haddr.hci_channel;
+
+               if (!hci_sock_gen_cookie(sk)) {
+                       /* In the case when a cookie has already been assigned,
+                        * then there has been already an ioctl issued against
+                        * an unbound socket and with that triggerd an open
+                        * notification. Send a close notification first to
+                        * allow the state transition to bounded.
+                        */
+                       skb = create_monitor_ctrl_close(sk);
+                       if (skb) {
+                               hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                                   HCI_SOCK_TRUSTED, NULL);
+                               kfree_skb(skb);
+                       }
+               }
+
+               if (capable(CAP_NET_ADMIN))
+                       hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
+
                hci_pi(sk)->hdev = hdev;
+
+               /* Send event to monitor */
+               skb = create_monitor_ctrl_open(sk);
+               if (skb) {
+                       hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                           HCI_SOCK_TRUSTED, NULL);
+                       kfree_skb(skb);
+               }
                break;
 
        case HCI_CHANNEL_USER:
@@ -884,9 +1185,38 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                        }
                }
 
-               atomic_inc(&hdev->promisc);
+               hci_pi(sk)->channel = haddr.hci_channel;
+
+               if (!hci_sock_gen_cookie(sk)) {
+                       /* In the case when a cookie has already been assigned,
+                        * this socket will transition from a raw socket into
+                        * an user channel socket. For a clean transition, send
+                        * the close notification first.
+                        */
+                       skb = create_monitor_ctrl_close(sk);
+                       if (skb) {
+                               hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                                   HCI_SOCK_TRUSTED, NULL);
+                               kfree_skb(skb);
+                       }
+               }
+
+               /* The user channel is restricted to CAP_NET_ADMIN
+                * capabilities and with that implicitly trusted.
+                */
+               hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
 
                hci_pi(sk)->hdev = hdev;
+
+               /* Send event to monitor */
+               skb = create_monitor_ctrl_open(sk);
+               if (skb) {
+                       hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                           HCI_SOCK_TRUSTED, NULL);
+                       kfree_skb(skb);
+               }
+
+               atomic_inc(&hdev->promisc);
                break;
 
        case HCI_CHANNEL_MONITOR:
@@ -900,6 +1230,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                        goto done;
                }
 
+               hci_pi(sk)->channel = haddr.hci_channel;
+
                /* The monitor interface is restricted to CAP_NET_RAW
                 * capabilities and with that implicitly trusted.
                 */
@@ -908,9 +1240,10 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                send_monitor_note(sk, "Linux version %s (%s)",
                                  init_utsname()->release,
                                  init_utsname()->machine);
-               send_monitor_note(sk, "Bluetooth subsystem version %s",
-                                 BT_SUBSYS_VERSION);
+               send_monitor_note(sk, "Bluetooth subsystem version %u.%u",
+                                 BT_SUBSYS_VERSION, BT_SUBSYS_REVISION);
                send_monitor_replay(sk);
+               send_monitor_control_replay(sk);
 
                atomic_inc(&monitor_promisc);
                break;
@@ -925,6 +1258,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                        err = -EPERM;
                        goto done;
                }
+
+               hci_pi(sk)->channel = haddr.hci_channel;
                break;
 
        default:
@@ -946,6 +1281,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                if (capable(CAP_NET_ADMIN))
                        hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
 
+               hci_pi(sk)->channel = haddr.hci_channel;
+
                /* At the moment the index and unconfigured index events
                 * are enabled unconditionally. Setting them on each
                 * socket when binding keeps this functionality. They
@@ -956,16 +1293,40 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
                 * received by untrusted users. Example for such events
                 * are changes to settings, class of device, name etc.
                 */
-               if (haddr.hci_channel == HCI_CHANNEL_CONTROL) {
+               if (hci_pi(sk)->channel == HCI_CHANNEL_CONTROL) {
+                       if (!hci_sock_gen_cookie(sk)) {
+                               /* In the case when a cookie has already been
+                                * assigned, this socket will transtion from
+                                * a raw socket into a control socket. To
+                                * allow for a clean transtion, send the
+                                * close notification first.
+                                */
+                               skb = create_monitor_ctrl_close(sk);
+                               if (skb) {
+                                       hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                                           HCI_SOCK_TRUSTED, NULL);
+                                       kfree_skb(skb);
+                               }
+                       }
+
+                       /* Send event to monitor */
+                       skb = create_monitor_ctrl_open(sk);
+                       if (skb) {
+                               hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                                   HCI_SOCK_TRUSTED, NULL);
+                               kfree_skb(skb);
+                       }
+
                        hci_sock_set_flag(sk, HCI_MGMT_INDEX_EVENTS);
                        hci_sock_set_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
-                       hci_sock_set_flag(sk, HCI_MGMT_GENERIC_EVENTS);
+                       hci_sock_set_flag(sk, HCI_MGMT_OPTION_EVENTS);
+                       hci_sock_set_flag(sk, HCI_MGMT_SETTING_EVENTS);
+                       hci_sock_set_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
+                       hci_sock_set_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
                }
                break;
        }
 
-
-       hci_pi(sk)->channel = haddr.hci_channel;
        sk->sk_state = BT_BOUND;
 
 done:
@@ -1133,6 +1494,19 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk,
                goto done;
        }
 
+       if (chan->channel == HCI_CHANNEL_CONTROL) {
+               struct sk_buff *skb;
+
+               /* Send event to monitor */
+               skb = create_monitor_ctrl_command(sk, index, opcode, len,
+                                                 buf + sizeof(*hdr));
+               if (skb) {
+                       hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+                                           HCI_SOCK_TRUSTED, NULL);
+                       kfree_skb(skb);
+               }
+       }
+
        if (opcode >= chan->handler_count ||
            chan->handlers[opcode].func == NULL) {
                BT_DBG("Unknown op %u", opcode);
@@ -1440,6 +1814,9 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
 
        BT_DBG("sk %p, opt %d", sk, optname);
 
+       if (level != SOL_HCI)
+               return -ENOPROTOOPT;
+
        lock_sock(sk);
 
        if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
@@ -1523,6 +1900,9 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
 
        BT_DBG("sk %p, opt %d", sk, optname);
 
+       if (level != SOL_HCI)
+               return -ENOPROTOOPT;
+
        if (get_user(len, optlen))
                return -EFAULT;
 
index 8319c84..cb670b5 100644 (file)
@@ -11,6 +11,8 @@
 
 #include "leds.h"
 
+DEFINE_LED_TRIGGER(bt_power_led_trigger);
+
 struct hci_basic_led_trigger {
        struct led_trigger      led_trigger;
        struct hci_dev          *hdev;
@@ -24,6 +26,21 @@ void hci_leds_update_powered(struct hci_dev *hdev, bool enabled)
        if (hdev->power_led)
                led_trigger_event(hdev->power_led,
                                  enabled ? LED_FULL : LED_OFF);
+
+       if (!enabled) {
+               struct hci_dev *d;
+
+               read_lock(&hci_dev_list_lock);
+
+               list_for_each_entry(d, &hci_dev_list, list) {
+                       if (test_bit(HCI_UP, &d->flags))
+                               enabled = true;
+               }
+
+               read_unlock(&hci_dev_list_lock);
+       }
+
+       led_trigger_event(bt_power_led_trigger, enabled ? LED_FULL : LED_OFF);
 }
 
 static void power_activate(struct led_classdev *led_cdev)
@@ -72,3 +89,13 @@ void hci_leds_init(struct hci_dev *hdev)
        /* initialize power_led */
        hdev->power_led = led_allocate_basic(hdev, power_activate, "power");
 }
+
+void bt_leds_init(void)
+{
+       led_trigger_register_simple("bluetooth-power", &bt_power_led_trigger);
+}
+
+void bt_leds_cleanup(void)
+{
+       led_trigger_unregister_simple(bt_power_led_trigger);
+}
index a9c4d6e..08725a2 100644 (file)
@@ -7,10 +7,20 @@
  */
 
 #if IS_ENABLED(CONFIG_BT_LEDS)
+
 void hci_leds_update_powered(struct hci_dev *hdev, bool enabled);
 void hci_leds_init(struct hci_dev *hdev);
+
+void bt_leds_init(void);
+void bt_leds_cleanup(void);
+
 #else
+
 static inline void hci_leds_update_powered(struct hci_dev *hdev,
                                           bool enabled) {}
 static inline void hci_leds_init(struct hci_dev *hdev) {}
+
+static inline void bt_leds_init(void) {}
+static inline void bt_leds_cleanup(void) {}
+
 #endif
index 7639290..7b2bac4 100644 (file)
@@ -38,7 +38,7 @@
 #include "mgmt_util.h"
 
 #define MGMT_VERSION   1
-#define MGMT_REVISION  13
+#define MGMT_REVISION  14
 
 static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@ -104,6 +104,8 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_REMOVE_ADVERTISING,
        MGMT_OP_GET_ADV_SIZE_INFO,
        MGMT_OP_START_LIMITED_DISCOVERY,
+       MGMT_OP_READ_EXT_INFO,
+       MGMT_OP_SET_APPEARANCE,
 };
 
 static const u16 mgmt_events[] = {
@@ -141,6 +143,7 @@ static const u16 mgmt_events[] = {
        MGMT_EV_LOCAL_OOB_DATA_UPDATED,
        MGMT_EV_ADVERTISING_ADDED,
        MGMT_EV_ADVERTISING_REMOVED,
+       MGMT_EV_EXT_INFO_CHANGED,
 };
 
 static const u16 mgmt_untrusted_commands[] = {
@@ -149,6 +152,7 @@ static const u16 mgmt_untrusted_commands[] = {
        MGMT_OP_READ_UNCONF_INDEX_LIST,
        MGMT_OP_READ_CONFIG_INFO,
        MGMT_OP_READ_EXT_INDEX_LIST,
+       MGMT_OP_READ_EXT_INFO,
 };
 
 static const u16 mgmt_untrusted_events[] = {
@@ -162,6 +166,7 @@ static const u16 mgmt_untrusted_events[] = {
        MGMT_EV_NEW_CONFIG_OPTIONS,
        MGMT_EV_EXT_INDEX_ADDED,
        MGMT_EV_EXT_INDEX_REMOVED,
+       MGMT_EV_EXT_INFO_CHANGED,
 };
 
 #define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
@@ -256,13 +261,6 @@ static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
                               flag, skip_sk);
 }
 
-static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
-                             u16 len, struct sock *skip_sk)
-{
-       return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
-                              HCI_MGMT_GENERIC_EVENTS, skip_sk);
-}
-
 static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
                      struct sock *skip_sk)
 {
@@ -278,6 +276,14 @@ static u8 le_addr_type(u8 mgmt_addr_type)
                return ADDR_LE_DEV_RANDOM;
 }
 
+void mgmt_fill_version_info(void *ver)
+{
+       struct mgmt_rp_read_version *rp = ver;
+
+       rp->version = MGMT_VERSION;
+       rp->revision = cpu_to_le16(MGMT_REVISION);
+}
+
 static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
                        u16 data_len)
 {
@@ -285,8 +291,7 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
 
        BT_DBG("sock %p", sk);
 
-       rp.version = MGMT_VERSION;
-       rp.revision = cpu_to_le16(MGMT_REVISION);
+       mgmt_fill_version_info(&rp);
 
        return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
                                 &rp, sizeof(rp));
@@ -572,8 +577,8 @@ static int new_options(struct hci_dev *hdev, struct sock *skip)
 {
        __le32 options = get_missing_options(hdev);
 
-       return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
-                                 sizeof(options), skip);
+       return mgmt_limited_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
+                                 sizeof(options), HCI_MGMT_OPTION_EVENTS, skip);
 }
 
 static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
@@ -862,6 +867,107 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
                                 sizeof(rp));
 }
 
+static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
+                                 u8 data_len)
+{
+       eir[eir_len++] = sizeof(type) + data_len;
+       eir[eir_len++] = type;
+       memcpy(&eir[eir_len], data, data_len);
+       eir_len += data_len;
+
+       return eir_len;
+}
+
+static inline u16 eir_append_le16(u8 *eir, u16 eir_len, u8 type, u16 data)
+{
+       eir[eir_len++] = sizeof(type) + sizeof(data);
+       eir[eir_len++] = type;
+       put_unaligned_le16(data, &eir[eir_len]);
+       eir_len += sizeof(data);
+
+       return eir_len;
+}
+
+static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
+{
+       u16 eir_len = 0;
+       size_t name_len;
+
+       if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
+                                         hdev->dev_class, 3);
+
+       if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
+               eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
+                                         hdev->appearance);
+
+       name_len = strlen(hdev->dev_name);
+       eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
+                                 hdev->dev_name, name_len);
+
+       name_len = strlen(hdev->short_name);
+       eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
+                                 hdev->short_name, name_len);
+
+       return eir_len;
+}
+
+static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
+                                   void *data, u16 data_len)
+{
+       char buf[512];
+       struct mgmt_rp_read_ext_info *rp = (void *)buf;
+       u16 eir_len;
+
+       BT_DBG("sock %p %s", sk, hdev->name);
+
+       memset(&buf, 0, sizeof(buf));
+
+       hci_dev_lock(hdev);
+
+       bacpy(&rp->bdaddr, &hdev->bdaddr);
+
+       rp->version = hdev->hci_ver;
+       rp->manufacturer = cpu_to_le16(hdev->manufacturer);
+
+       rp->supported_settings = cpu_to_le32(get_supported_settings(hdev));
+       rp->current_settings = cpu_to_le32(get_current_settings(hdev));
+
+
+       eir_len = append_eir_data_to_buf(hdev, rp->eir);
+       rp->eir_len = cpu_to_le16(eir_len);
+
+       hci_dev_unlock(hdev);
+
+       /* If this command is called at least once, then the events
+        * for class of device and local name changes are disabled
+        * and only the new extended controller information event
+        * is used.
+        */
+       hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
+       hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
+       hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
+
+       return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, rp,
+                                sizeof(*rp) + eir_len);
+}
+
+static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
+{
+       char buf[512];
+       struct mgmt_ev_ext_info_changed *ev = (void *)buf;
+       u16 eir_len;
+
+       memset(buf, 0, sizeof(buf));
+
+       eir_len = append_eir_data_to_buf(hdev, ev->eir);
+       ev->eir_len = cpu_to_le16(eir_len);
+
+       return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, ev,
+                                 sizeof(*ev) + eir_len,
+                                 HCI_MGMT_EXT_INFO_EVENTS, skip);
+}
+
 static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
 {
        __le32 settings = cpu_to_le32(get_current_settings(hdev));
@@ -922,7 +1028,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
                hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        }
 
-       hci_req_clear_adv_instance(hdev, NULL, 0x00, false);
+       hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
 
        if (hci_dev_test_flag(hdev, HCI_LE_ADV))
                __hci_req_disable_advertising(&req);
@@ -1000,8 +1106,8 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip)
 {
        __le32 ev = cpu_to_le32(get_current_settings(hdev));
 
-       return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
-                                 sizeof(ev), skip);
+       return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
+                                 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
 }
 
 int mgmt_new_settings(struct hci_dev *hdev)
@@ -1690,7 +1796,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
        enabled = lmp_host_le_capable(hdev);
 
        if (!val)
-               hci_req_clear_adv_instance(hdev, NULL, 0x00, true);
+               hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, true);
 
        if (!hdev_is_powered(hdev) || val == enabled) {
                bool changed = false;
@@ -2513,8 +2619,8 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
        BT_DBG("");
 
        if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
-               return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
-                                        MGMT_STATUS_INVALID_PARAMS, NULL, 0);
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
+                                      MGMT_STATUS_INVALID_PARAMS);
 
        hci_dev_lock(hdev);
 
@@ -2932,6 +3038,35 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
                                 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
 }
 
+static void adv_expire(struct hci_dev *hdev, u32 flags)
+{
+       struct adv_info *adv_instance;
+       struct hci_request req;
+       int err;
+
+       adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
+       if (!adv_instance)
+               return;
+
+       /* stop if current instance doesn't need to be changed */
+       if (!(adv_instance->flags & flags))
+               return;
+
+       cancel_adv_timeout(hdev);
+
+       adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
+       if (!adv_instance)
+               return;
+
+       hci_req_init(&req, hdev);
+       err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
+                                             true);
+       if (err)
+               return;
+
+       hci_req_run(&req, NULL);
+}
+
 static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
 {
        struct mgmt_cp_set_local_name *cp;
@@ -2947,13 +3082,17 @@ static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
 
        cp = cmd->param;
 
-       if (status)
+       if (status) {
                mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
                                mgmt_status(status));
-       else
+       } else {
                mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
                                  cp, sizeof(*cp));
 
+               if (hci_dev_test_flag(hdev, HCI_LE_ADV))
+                       adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
+       }
+
        mgmt_pending_remove(cmd);
 
 unlock:
@@ -2993,8 +3132,9 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
                if (err < 0)
                        goto failed;
 
-               err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
-                                        data, len, sk);
+               err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
+                                        len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
+               ext_info_changed(hdev, sk);
 
                goto failed;
        }
@@ -3029,6 +3169,40 @@ failed:
        return err;
 }
 
+static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
+                         u16 len)
+{
+       struct mgmt_cp_set_appearance *cp = data;
+       u16 apperance;
+       int err;
+
+       BT_DBG("");
+
+       if (!lmp_le_capable(hdev))
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_APPEARANCE,
+                                      MGMT_STATUS_NOT_SUPPORTED);
+
+       apperance = le16_to_cpu(cp->appearance);
+
+       hci_dev_lock(hdev);
+
+       if (hdev->appearance != apperance) {
+               hdev->appearance = apperance;
+
+               if (hci_dev_test_flag(hdev, HCI_LE_ADV))
+                       adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
+
+               ext_info_changed(hdev, sk);
+       }
+
+       err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL,
+                               0);
+
+       hci_dev_unlock(hdev);
+
+       return err;
+}
+
 static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
                                         u16 opcode, struct sk_buff *skb)
 {
@@ -4869,7 +5043,7 @@ static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
        int err;
 
        memset(&rp, 0, sizeof(rp));
-       memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
+       memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
 
        if (status)
                goto complete;
@@ -5501,17 +5675,6 @@ unlock:
        return err;
 }
 
-static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
-                                 u8 data_len)
-{
-       eir[eir_len++] = sizeof(type) + data_len;
-       eir[eir_len++] = type;
-       memcpy(&eir[eir_len], data, data_len);
-       eir_len += data_len;
-
-       return eir_len;
-}
-
 static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
                                             u16 opcode, struct sk_buff *skb)
 {
@@ -5815,6 +5978,8 @@ static u32 get_supported_adv_flags(struct hci_dev *hdev)
        flags |= MGMT_ADV_FLAG_DISCOV;
        flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
        flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
+       flags |= MGMT_ADV_FLAG_APPEARANCE;
+       flags |= MGMT_ADV_FLAG_LOCAL_NAME;
 
        if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
                flags |= MGMT_ADV_FLAG_TX_POWER;
@@ -5871,28 +6036,59 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
        return err;
 }
 
-static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
-                             u8 len, bool is_adv_data)
+static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
 {
        u8 max_len = HCI_MAX_AD_LENGTH;
-       int i, cur_len;
-       bool flags_managed = false;
-       bool tx_power_managed = false;
 
        if (is_adv_data) {
                if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
                                 MGMT_ADV_FLAG_LIMITED_DISCOV |
-                                MGMT_ADV_FLAG_MANAGED_FLAGS)) {
-                       flags_managed = true;
+                                MGMT_ADV_FLAG_MANAGED_FLAGS))
                        max_len -= 3;
-               }
 
-               if (adv_flags & MGMT_ADV_FLAG_TX_POWER) {
-                       tx_power_managed = true;
+               if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
                        max_len -= 3;
-               }
+       } else {
+               /* at least 1 byte of name should fit in */
+               if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
+                       max_len -= 3;
+
+               if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
+                       max_len -= 4;
        }
 
+       return max_len;
+}
+
+static bool flags_managed(u32 adv_flags)
+{
+       return adv_flags & (MGMT_ADV_FLAG_DISCOV |
+                           MGMT_ADV_FLAG_LIMITED_DISCOV |
+                           MGMT_ADV_FLAG_MANAGED_FLAGS);
+}
+
+static bool tx_power_managed(u32 adv_flags)
+{
+       return adv_flags & MGMT_ADV_FLAG_TX_POWER;
+}
+
+static bool name_managed(u32 adv_flags)
+{
+       return adv_flags & MGMT_ADV_FLAG_LOCAL_NAME;
+}
+
+static bool appearance_managed(u32 adv_flags)
+{
+       return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
+}
+
+static bool tlv_data_is_valid(u32 adv_flags, u8 *data, u8 len, bool is_adv_data)
+{
+       int i, cur_len;
+       u8 max_len;
+
+       max_len = tlv_data_max_len(adv_flags, is_adv_data);
+
        if (len > max_len)
                return false;
 
@@ -5900,10 +6096,21 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
        for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
                cur_len = data[i];
 
-               if (flags_managed && data[i + 1] == EIR_FLAGS)
+               if (data[i + 1] == EIR_FLAGS &&
+                   (!is_adv_data || flags_managed(adv_flags)))
+                       return false;
+
+               if (data[i + 1] == EIR_TX_POWER && tx_power_managed(adv_flags))
+                       return false;
+
+               if (data[i + 1] == EIR_NAME_COMPLETE && name_managed(adv_flags))
                        return false;
 
-               if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
+               if (data[i + 1] == EIR_NAME_SHORT && name_managed(adv_flags))
+                       return false;
+
+               if (data[i + 1] == EIR_APPEARANCE &&
+                   appearance_managed(adv_flags))
                        return false;
 
                /* If the current field length would exceed the total data
@@ -6027,8 +6234,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
-           !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
+       if (!tlv_data_is_valid(flags, cp->data, cp->adv_data_len, true) ||
+           !tlv_data_is_valid(flags, cp->data + cp->adv_data_len,
                               cp->scan_rsp_len, false)) {
                err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                      MGMT_STATUS_INVALID_PARAMS);
@@ -6175,7 +6382,7 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
 
        hci_req_init(&req, hdev);
 
-       hci_req_clear_adv_instance(hdev, &req, cp->instance, true);
+       hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
 
        if (list_empty(&hdev->adv_instances))
                __hci_req_disable_advertising(&req);
@@ -6211,23 +6418,6 @@ unlock:
        return err;
 }
 
-static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
-{
-       u8 max_len = HCI_MAX_AD_LENGTH;
-
-       if (is_adv_data) {
-               if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
-                                MGMT_ADV_FLAG_LIMITED_DISCOV |
-                                MGMT_ADV_FLAG_MANAGED_FLAGS))
-                       max_len -= 3;
-
-               if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
-                       max_len -= 3;
-       }
-
-       return max_len;
-}
-
 static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
                             void *data, u16 data_len)
 {
@@ -6356,6 +6546,9 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
        { remove_advertising,      MGMT_REMOVE_ADVERTISING_SIZE },
        { get_adv_size_info,       MGMT_GET_ADV_SIZE_INFO_SIZE },
        { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
+       { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
+                                               HCI_MGMT_UNTRUSTED },
+       { set_appearance,          MGMT_SET_APPEARANCE_SIZE },
 };
 
 void mgmt_index_added(struct hci_dev *hdev)
@@ -6494,9 +6687,12 @@ void __mgmt_power_off(struct hci_dev *hdev)
 
        mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
 
-       if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
-               mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
-                                  zero_cod, sizeof(zero_cod), NULL);
+       if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
+               mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
+                                  zero_cod, sizeof(zero_cod),
+                                  HCI_MGMT_DEV_CLASS_EVENTS, NULL);
+               ext_info_changed(hdev, NULL);
+       }
 
        new_settings(hdev, match.sk);
 
@@ -7092,9 +7288,11 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
        mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
        mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
 
-       if (!status)
-               mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
-                                  dev_class, 3, NULL);
+       if (!status) {
+               mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
+                                  3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
+               ext_info_changed(hdev, NULL);
+       }
 
        if (match.sk)
                sock_put(match.sk);
@@ -7123,8 +7321,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
                        return;
        }
 
-       mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
-                          cmd ? cmd->sk : NULL);
+       mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
+                          HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
+       ext_info_changed(hdev, cmd ? cmd->sk : NULL);
 }
 
 static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
index 8c30c7e..c933bd0 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
+#include <asm/unaligned.h>
+
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_mon.h>
 #include <net/bluetooth/mgmt.h>
 
 #include "mgmt_util.h"
 
+static struct sk_buff *create_monitor_ctrl_event(__le16 index, u32 cookie,
+                                                u16 opcode, u16 len, void *buf)
+{
+       struct hci_mon_hdr *hdr;
+       struct sk_buff *skb;
+
+       skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       put_unaligned_le32(cookie, skb_put(skb, 4));
+       put_unaligned_le16(opcode, skb_put(skb, 2));
+
+       if (buf)
+               memcpy(skb_put(skb, len), buf, len);
+
+       __net_timestamp(skb);
+
+       hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
+       hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
+       hdr->index = index;
+       hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+       return skb;
+}
+
 int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
                    void *data, u16 data_len, int flag, struct sock *skip_sk)
 {
@@ -52,14 +81,18 @@ int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
        __net_timestamp(skb);
 
        hci_send_to_channel(channel, skb, flag, skip_sk);
-       kfree_skb(skb);
 
+       if (channel == HCI_CHANNEL_CONTROL)
+               hci_send_monitor_ctrl_event(hdev, event, data, data_len,
+                                           skb_get_ktime(skb), flag, skip_sk);
+
+       kfree_skb(skb);
        return 0;
 }
 
 int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb, *mskb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_status *ev;
        int err;
@@ -80,17 +113,30 @@ int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
        ev->status = status;
        ev->opcode = cpu_to_le16(cmd);
 
+       mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
+                                        MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
+       if (mskb)
+               skb->tstamp = mskb->tstamp;
+       else
+               __net_timestamp(skb);
+
        err = sock_queue_rcv_skb(sk, skb);
        if (err < 0)
                kfree_skb(skb);
 
+       if (mskb) {
+               hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
+                                   HCI_SOCK_TRUSTED, NULL);
+               kfree_skb(mskb);
+       }
+
        return err;
 }
 
 int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
                      void *rp, size_t rp_len)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb, *mskb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_complete *ev;
        int err;
@@ -114,10 +160,24 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
        if (rp)
                memcpy(ev->data, rp, rp_len);
 
+       mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
+                                        MGMT_EV_CMD_COMPLETE,
+                                        sizeof(*ev) + rp_len, ev);
+       if (mskb)
+               skb->tstamp = mskb->tstamp;
+       else
+               __net_timestamp(skb);
+
        err = sock_queue_rcv_skb(sk, skb);
        if (err < 0)
                kfree_skb(skb);
 
+       if (mskb) {
+               hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
+                                   HCI_SOCK_TRUSTED, NULL);
+               kfree_skb(mskb);
+       }
+
        return err;
 }
 
index 4c1a16a..43faf2a 100644 (file)
@@ -3387,7 +3387,10 @@ int smp_register(struct hci_dev *hdev)
        if (!lmp_sc_capable(hdev)) {
                debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs,
                                    hdev, &force_bredr_smp_fops);
-               return 0;
+
+               /* Flag can be already set here (due to power toggle) */
+               if (!hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP))
+                       return 0;
        }
 
        if (WARN_ON(hdev->smp_bredr_data)) {
index 7079cd3..06019db 100644 (file)
@@ -663,6 +663,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
 
        /* TODO check this */
        SET_NETDEV_DEV(ndev, &local->phy->dev);
+       dev_net_set(ndev, wpan_phy_net(local->hw.phy));
        sdata = netdev_priv(ndev);
        ndev->ieee802154_ptr = &sdata->wpan_dev;
        memcpy(sdata->name, ndev->name, IFNAMSIZ);
index 446e130..4dcf6e1 100644 (file)
@@ -101,11 +101,16 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
        sdata->dev->stats.rx_bytes += skb->len;
 
        switch (mac_cb(skb)->type) {
+       case IEEE802154_FC_TYPE_BEACON:
+       case IEEE802154_FC_TYPE_ACK:
+       case IEEE802154_FC_TYPE_MAC_CMD:
+               goto fail;
+
        case IEEE802154_FC_TYPE_DATA:
                return ieee802154_deliver_skb(skb);
        default:
-               pr_warn("ieee802154: bad frame received (type = %d)\n",
-                       mac_cb(skb)->type);
+               pr_warn_ratelimited("ieee802154: bad frame received "
+                                   "(type = %d)\n", mac_cb(skb)->type);
                goto fail;
        }