]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorDavid S. Miller <davem@davemloft.net>
Thu, 30 Jul 2015 23:16:43 +0000 (16:16 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 30 Jul 2015 23:16:43 +0000 (16:16 -0700)
Johan Hedberg says:

====================
pull request: bluetooth-next 2015-07-30

Here's a set of Bluetooth & 802.15.4 patches intended for the 4.3 kernel.

 - Cleanups & fixes to mac802154
 - Refactoring of Intel Bluetooth HCI driver
 - Various coding style fixes to Bluetooth HCI drivers
 - Support for Intel Lightning Peak Bluetooth devices
 - Generic class code in interface descriptor in btusb to match more HW
 - Refactoring of Bluetooth HS code together with a new config option
 - Support for BCM4330B1 Broadcom UART controller

Let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
43 files changed:
drivers/bluetooth/Kconfig
drivers/bluetooth/bfusb.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btbcm.c
drivers/bluetooth/btintel.c
drivers/bluetooth/btintel.h
drivers/bluetooth/btmrvl_drv.h
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_h5.c
drivers/bluetooth/hci_intel.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_uart.h
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/cc2520.c
drivers/net/ieee802154/mrf24j40.c
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg802154.h
include/net/mac802154.h
net/6lowpan/iphc.c
net/bluetooth/6lowpan.c
net/bluetooth/Kconfig
net/bluetooth/Makefile
net/bluetooth/a2mp.c
net/bluetooth/a2mp.h
net/bluetooth/amp.c
net/bluetooth/amp.h
net/bluetooth/cmtp/capi.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/ieee802154/rdev-ops.h
net/ieee802154/sysfs.c
net/ieee802154/trace.h
net/mac802154/cfg.c
net/mac802154/ieee802154_i.h
net/mac802154/iface.c
net/mac802154/main.c
net/mac802154/rx.c
net/mac802154/tx.c
net/mac802154/util.c

index 2e777071e1dcb8bd544a16aedd58ca28ad2f43bc..79e8234b1aa5995eaf8b8e25d729e6da193518fe 100644 (file)
@@ -132,6 +132,7 @@ config BT_HCIUART_3WIRE
 config BT_HCIUART_INTEL
        bool "Intel protocol support"
        depends on BT_HCIUART
+       select BT_HCIUART_H4
        select BT_INTEL
        help
          The Intel protocol support enables Bluetooth HCI over serial
index fcfb72e9e0ee5948bf7e4c73e8d1b056d0723dbf..a5c4d0584389713522652c472cfd5c7b5e75dbab 100644 (file)
@@ -492,7 +492,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
        case HCI_SCODATA_PKT:
                hdev->stat.sco_tx++;
                break;
-       };
+       }
 
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
index 7aab65427d388fc4c653223915ab033904032758..a00bb82eb7c6d8322f835c8ce5689eae784bc5f2 100644 (file)
@@ -427,7 +427,7 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
        case HCI_SCODATA_PKT:
                hdev->stat.sco_tx++;
                break;
-       };
+       }
 
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
index 9ceb8ac68fdca2518c953cb6a9a36c6fd5b5f268..02ed816a18f9a2b652bbd0d179d150f50cad0294 100644 (file)
@@ -34,6 +34,7 @@
 
 #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
 #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
+#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
 
 int btbcm_check_bdaddr(struct hci_dev *hdev)
 {
@@ -66,9 +67,13 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
         *
         * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
         * with waiting for configuration state.
+        *
+        * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller
+        * with waiting for configuration state.
         */
        if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
-           !bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) {
+           !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
+           !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) {
                BT_INFO("%s: BCM: Using default device address (%pMR)",
                        hdev->name, &bda->bdaddr);
                set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
@@ -241,6 +246,7 @@ static const struct {
        u16 subver;
        const char *name;
 } bcm_uart_subver_table[] = {
+       { 0x4103, "BCM4330B1"   },      /* 002.001.003 */
        { 0x410e, "BCM43341B0"  },      /* 002.001.014 */
        { 0x4406, "BCM4324B3"   },      /* 002.004.006 */
        { 0x610c, "BCM4354"     },      /* 003.001.012 */
index 828f2f8d1568c8c50962dee7d8e77fcfcd669972..1ce4ac16c7facdd1387119619317ae8c3fcea5bc 100644 (file)
@@ -89,6 +89,86 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(btintel_set_bdaddr);
 
+void btintel_hw_error(struct hci_dev *hdev, u8 code)
+{
+       struct sk_buff *skb;
+       u8 type = 0x00;
+
+       BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
+
+       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("%s: Reset after hardware error failed (%ld)",
+                      hdev->name, PTR_ERR(skb));
+               return;
+       }
+       kfree_skb(skb);
+
+       skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
+                      hdev->name, PTR_ERR(skb));
+               return;
+       }
+
+       if (skb->len != 13) {
+               BT_ERR("%s: Exception info size mismatch", hdev->name);
+               kfree_skb(skb);
+               return;
+       }
+
+       BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
+
+       kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(btintel_hw_error);
+
+void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
+{
+       const char *variant;
+
+       switch (ver->fw_variant) {
+       case 0x06:
+               variant = "Bootloader";
+               break;
+       case 0x23:
+               variant = "Firmware";
+               break;
+       default:
+               return;
+       }
+
+       BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
+               variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
+               ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
+}
+EXPORT_SYMBOL_GPL(btintel_version_info);
+
+int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
+                       const void *param)
+{
+       while (plen > 0) {
+               struct sk_buff *skb;
+               u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
+
+               cmd_param[0] = fragment_type;
+               memcpy(cmd_param + 1, param, fragment_len);
+
+               skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
+                                    cmd_param, HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb))
+                       return PTR_ERR(skb);
+
+               kfree_skb(skb);
+
+               plen -= fragment_len;
+               param += fragment_len;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_secure_send);
+
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
 MODULE_VERSION(VERSION);
index 4bda6ab34f60292da156b79314fcac9284aa4193..b278d14758d592896db033c78af53b6565a6c88f 100644 (file)
@@ -73,6 +73,11 @@ struct intel_secure_send_result {
 
 int btintel_check_bdaddr(struct hci_dev *hdev);
 int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+void btintel_hw_error(struct hci_dev *hdev, u8 code);
+
+void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
+int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
+                       const void *param);
 
 #else
 
@@ -86,4 +91,18 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd
        return -EOPNOTSUPP;
 }
 
+static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
+{
+}
+
+static void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
+{
+}
+
+static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
+                                     u32 plen, const void *param)
+{
+       return -EOPNOTSUPP;
+}
+
 #endif
index 086f0ec89580627d4c95516c0ef912265445afef..27a9aac2558326c8f7801b891ef4b5f7441b1071 100644 (file)
@@ -95,10 +95,10 @@ struct btmrvl_private {
        struct btmrvl_device btmrvl_dev;
        struct btmrvl_adapter *adapter;
        struct btmrvl_thread main_thread;
-       int (*hw_host_to_card) (struct btmrvl_private *priv,
+       int (*hw_host_to_card)(struct btmrvl_private *priv,
                                u8 *payload, u16 nb);
-       int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
-       int (*hw_process_int_status) (struct btmrvl_private *priv);
+       int (*hw_wakeup_firmware)(struct btmrvl_private *priv);
+       int (*hw_process_int_status)(struct btmrvl_private *priv);
        void (*firmware_dump)(struct btmrvl_private *priv);
        spinlock_t driver_lock;         /* spinlock used by driver */
 #ifdef CONFIG_DEBUG_FS
index b4cf8d9c9dac29893241cb9b814879969ed0906e..cc92b0f84a5168e139435737cef2c63ab1ee68e6 100644 (file)
@@ -68,6 +68,9 @@ static const struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth AMP device */
        { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },
 
+       /* Generic Bluetooth USB interface */
+       { USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
+
        /* Apple-specific (Broadcom) devices */
        { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
          .driver_info = BTUSB_BCM_APPLE },
@@ -1878,51 +1881,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
        return -EILSEQ;
 }
 
-static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type,
-                                  u32 plen, const void *param)
-{
-       while (plen > 0) {
-               struct sk_buff *skb;
-               u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
-
-               cmd_param[0] = fragment_type;
-               memcpy(cmd_param + 1, param, fragment_len);
-
-               skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
-                                    cmd_param, HCI_INIT_TIMEOUT);
-               if (IS_ERR(skb))
-                       return PTR_ERR(skb);
-
-               kfree_skb(skb);
-
-               plen -= fragment_len;
-               param += fragment_len;
-       }
-
-       return 0;
-}
-
-static void btusb_intel_version_info(struct hci_dev *hdev,
-                                    struct intel_version *ver)
-{
-       const char *variant;
-
-       switch (ver->fw_variant) {
-       case 0x06:
-               variant = "Bootloader";
-               break;
-       case 0x23:
-               variant = "Firmware";
-               break;
-       default:
-               return;
-       }
-
-       BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
-               variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
-               ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
-}
-
 static int btusb_setup_intel_new(struct hci_dev *hdev)
 {
        static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
@@ -1984,7 +1942,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
                return -EINVAL;
        }
 
-       btusb_intel_version_info(hdev, ver);
+       btintel_version_info(hdev, ver);
 
        /* The firmware variant determines if the device is in bootloader
         * mode or is running operational firmware. The value 0x06 identifies
@@ -2104,7 +2062,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
        /* Start the firmware download transaction with the Init fragment
         * represented by the 128 bytes of CSS header.
         */
-       err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data);
+       err = btintel_secure_send(hdev, 0x00, 128, fw->data);
        if (err < 0) {
                BT_ERR("%s: Failed to send firmware header (%d)",
                       hdev->name, err);
@@ -2114,7 +2072,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
        /* Send the 256 bytes of public key information from the firmware
         * as the PKey fragment.
         */
-       err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128);
+       err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
        if (err < 0) {
                BT_ERR("%s: Failed to send firmware public key (%d)",
                       hdev->name, err);
@@ -2124,7 +2082,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
        /* Send the 256 bytes of signature information from the firmware
         * as the Sign fragment.
         */
-       err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388);
+       err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
        if (err < 0) {
                BT_ERR("%s: Failed to send firmware signature (%d)",
                       hdev->name, err);
@@ -2148,8 +2106,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
                 * firmware data buffer as a single Data fragement.
                 */
                if (!(frag_len % 4)) {
-                       err = btusb_intel_secure_send(hdev, 0x01, frag_len,
-                                                     fw_ptr);
+                       err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
                        if (err < 0) {
                                BT_ERR("%s: Failed to send firmware data (%d)",
                                       hdev->name, err);
@@ -2291,39 +2248,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
        return 0;
 }
 
-static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code)
-{
-       struct sk_buff *skb;
-       u8 type = 0x00;
-
-       BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
-
-       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               BT_ERR("%s: Reset after hardware error failed (%ld)",
-                      hdev->name, PTR_ERR(skb));
-               return;
-       }
-       kfree_skb(skb);
-
-       skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
-                      hdev->name, PTR_ERR(skb));
-               return;
-       }
-
-       if (skb->len != 13) {
-               BT_ERR("%s: Exception info size mismatch", hdev->name);
-               kfree_skb(skb);
-               return;
-       }
-
-       BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
-
-       kfree_skb(skb);
-}
-
 static int btusb_shutdown_intel(struct hci_dev *hdev)
 {
        struct sk_buff *skb;
@@ -2783,7 +2707,7 @@ static int btusb_probe(struct usb_interface *intf,
        if (id->driver_info & BTUSB_INTEL_NEW) {
                hdev->send = btusb_send_frame_intel;
                hdev->setup = btusb_setup_intel_new;
-               hdev->hw_error = btusb_hw_error_intel;
+               hdev->hw_error = btintel_hw_error;
                hdev->set_bdaddr = btintel_set_bdaddr;
                set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
        }
index 78e10f0c65b28dc38d30336514b92614bc7e449c..84135c54ed2e46df5111e2c2797b82fa8db4b143 100644 (file)
@@ -182,9 +182,9 @@ static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
        int i;
 
        printk(KERN_INFO "Bluetooth: Nokia control data =");
-       for (i = 0; i < skb->len; i++) {
+       for (i = 0; i < skb->len; i++)
                printk(" %02x", skb->data[i]);
-       }
+
        printk("\n");
 
        /* transition to active state */
@@ -406,7 +406,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
                break;
        default:
                return -EILSEQ;
-       };
+       }
 
        nsh.zero = 0;
        nsh.len = skb->len;
index 3455cecc9ecfe630c3331d67d22715ddb60cfcf8..b35b238a0380197fda6ee096e388a6fc09aa11a7 100644 (file)
@@ -75,7 +75,7 @@ struct h5 {
        size_t                  rx_pending;     /* Expecting more bytes */
        u8                      rx_ack;         /* Last ack number received */
 
-       int                     (*rx_func) (struct hci_uart *hu, u8 c);
+       int                     (*rx_func)(struct hci_uart *hu, u8 c);
 
        struct timer_list       timer;          /* Retransmission timer */
 
index 5dd07bf052360c15bc8631551def5e6cce687626..21dfa89751dfe6b790704d223d770d229ddf2c02 100644 (file)
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/wait.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
 #include "hci_uart.h"
+#include "btintel.h"
+
+#define STATE_BOOTLOADER       0
+#define STATE_DOWNLOADING      1
+#define STATE_FIRMWARE_LOADED  2
+#define STATE_FIRMWARE_FAILED  3
+#define STATE_BOOTING          4
+
+struct intel_data {
+       struct sk_buff *rx_skb;
+       struct sk_buff_head txq;
+       unsigned long flags;
+};
+
+static int intel_open(struct hci_uart *hu)
+{
+       struct intel_data *intel;
+
+       BT_DBG("hu %p", hu);
+
+       intel = kzalloc(sizeof(*intel), GFP_KERNEL);
+       if (!intel)
+               return -ENOMEM;
+
+       skb_queue_head_init(&intel->txq);
+
+       hu->priv = intel;
+       return 0;
+}
+
+static int intel_close(struct hci_uart *hu)
+{
+       struct intel_data *intel = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&intel->txq);
+       kfree_skb(intel->rx_skb);
+       kfree(intel);
+
+       hu->priv = NULL;
+       return 0;
+}
+
+static int intel_flush(struct hci_uart *hu)
+{
+       struct intel_data *intel = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&intel->txq);
+
+       return 0;
+}
+
+static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
+{
+       struct sk_buff *skb;
+       struct hci_event_hdr *hdr;
+       struct hci_ev_cmd_complete *evt;
+
+       skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr));
+       hdr->evt = HCI_EV_CMD_COMPLETE;
+       hdr->plen = sizeof(*evt) + 1;
+
+       evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt));
+       evt->ncmd = 0x01;
+       evt->opcode = cpu_to_le16(opcode);
+
+       *skb_put(skb, 1) = 0x00;
+
+       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+
+       return hci_recv_frame(hdev, skb);
+}
+
+static int intel_setup(struct hci_uart *hu)
+{
+       static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
+                                         0x00, 0x08, 0x04, 0x00 };
+       struct intel_data *intel = hu->priv;
+       struct hci_dev *hdev = hu->hdev;
+       struct sk_buff *skb;
+       struct intel_version *ver;
+       struct intel_boot_params *params;
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       char fwname[64];
+       u32 frag_len;
+       ktime_t calltime, delta, rettime;
+       unsigned long long duration;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       hu->hdev->set_bdaddr = btintel_set_bdaddr;
+
+       calltime = ktime_get();
+
+       set_bit(STATE_BOOTLOADER, &intel->flags);
+
+       /* Read the Intel version information to determine if the device
+        * is in bootloader mode or if it already has operational firmware
+        * loaded.
+        */
+       skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("%s: Reading Intel version information failed (%ld)",
+                      hdev->name, PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       if (skb->len != sizeof(*ver)) {
+               BT_ERR("%s: Intel version event size mismatch", hdev->name);
+               kfree_skb(skb);
+               return -EILSEQ;
+       }
+
+       ver = (struct intel_version *)skb->data;
+       if (ver->status) {
+               BT_ERR("%s: Intel version command failure (%02x)",
+                      hdev->name, ver->status);
+               err = -bt_to_errno(ver->status);
+               kfree_skb(skb);
+               return err;
+       }
+
+       /* The hardware platform number has a fixed value of 0x37 and
+        * for now only accept this single value.
+        */
+       if (ver->hw_platform != 0x37) {
+               BT_ERR("%s: Unsupported Intel hardware platform (%u)",
+                      hdev->name, ver->hw_platform);
+               kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
+        * supported by this firmware loading method. This check has been
+        * put in place to ensure correct forward compatibility options
+        * when newer hardware variants come along.
+        */
+       if (ver->hw_variant != 0x0b) {
+               BT_ERR("%s: Unsupported Intel hardware variant (%u)",
+                      hdev->name, ver->hw_variant);
+               kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       btintel_version_info(hdev, ver);
+
+       /* The firmware variant determines if the device is in bootloader
+        * mode or is running operational firmware. The value 0x06 identifies
+        * the bootloader and the value 0x23 identifies the operational
+        * firmware.
+        *
+        * When the operational firmware is already present, then only
+        * the check for valid Bluetooth device address is needed. This
+        * determines if the device will be added as configured or
+        * unconfigured controller.
+        *
+        * It is not possible to use the Secure Boot Parameters in this
+        * case since that command is only available in bootloader mode.
+        */
+       if (ver->fw_variant == 0x23) {
+               kfree_skb(skb);
+               clear_bit(STATE_BOOTLOADER, &intel->flags);
+               btintel_check_bdaddr(hdev);
+               return 0;
+       }
+
+       /* If the device is not in bootloader mode, then the only possible
+        * choice is to return an error and abort the device initialization.
+        */
+       if (ver->fw_variant != 0x06) {
+               BT_ERR("%s: Unsupported Intel firmware variant (%u)",
+                      hdev->name, ver->fw_variant);
+               kfree_skb(skb);
+               return -ENODEV;
+       }
+
+       kfree_skb(skb);
+
+       /* Read the secure boot parameters to identify the operating
+        * details of the bootloader.
+        */
+       skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("%s: Reading Intel boot parameters failed (%ld)",
+                      hdev->name, PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       if (skb->len != sizeof(*params)) {
+               BT_ERR("%s: Intel boot parameters size mismatch", hdev->name);
+               kfree_skb(skb);
+               return -EILSEQ;
+       }
+
+       params = (struct intel_boot_params *)skb->data;
+       if (params->status) {
+               BT_ERR("%s: Intel boot parameters command failure (%02x)",
+                      hdev->name, params->status);
+               err = -bt_to_errno(params->status);
+               kfree_skb(skb);
+               return err;
+       }
+
+       BT_INFO("%s: Device revision is %u", hdev->name,
+               le16_to_cpu(params->dev_revid));
+
+       BT_INFO("%s: Secure boot is %s", hdev->name,
+               params->secure_boot ? "enabled" : "disabled");
+
+       BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name,
+               params->min_fw_build_nn, params->min_fw_build_cw,
+               2000 + params->min_fw_build_yy);
+
+       /* It is required that every single firmware fragment is acknowledged
+        * with a command complete event. If the boot parameters indicate
+        * that this bootloader does not send them, then abort the setup.
+        */
+       if (params->limited_cce != 0x00) {
+               BT_ERR("%s: Unsupported Intel firmware loading method (%u)",
+                      hdev->name, params->limited_cce);
+               kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       /* If the OTP has no valid Bluetooth device address, then there will
+        * also be no valid address for the operational firmware.
+        */
+       if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
+               BT_INFO("%s: No device address configured", hdev->name);
+               set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+       }
+
+       /* With this Intel bootloader only the hardware variant and device
+        * revision information are used to select the right firmware.
+        *
+        * Currently this bootloader support is limited to hardware variant
+        * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
+        */
+       snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
+                le16_to_cpu(params->dev_revid));
+
+       err = request_firmware(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               BT_ERR("%s: Failed to load Intel firmware file (%d)",
+                      hdev->name, err);
+               kfree_skb(skb);
+               return err;
+       }
+
+       BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);
+
+       kfree_skb(skb);
+
+       if (fw->size < 644) {
+               BT_ERR("%s: Invalid size of firmware file (%zu)",
+                      hdev->name, fw->size);
+               err = -EBADF;
+               goto done;
+       }
+
+       set_bit(STATE_DOWNLOADING, &intel->flags);
+
+       /* Start the firmware download transaction with the Init fragment
+        * represented by the 128 bytes of CSS header.
+        */
+       err = btintel_secure_send(hdev, 0x00, 128, fw->data);
+       if (err < 0) {
+               BT_ERR("%s: Failed to send firmware header (%d)",
+                      hdev->name, err);
+               goto done;
+       }
+
+       /* Send the 256 bytes of public key information from the firmware
+        * as the PKey fragment.
+        */
+       err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
+       if (err < 0) {
+               BT_ERR("%s: Failed to send firmware public key (%d)",
+                      hdev->name, err);
+               goto done;
+       }
+
+       /* Send the 256 bytes of signature information from the firmware
+        * as the Sign fragment.
+        */
+       err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
+       if (err < 0) {
+               BT_ERR("%s: Failed to send firmware signature (%d)",
+                      hdev->name, err);
+               goto done;
+       }
+
+       fw_ptr = fw->data + 644;
+       frag_len = 0;
+
+       while (fw_ptr - fw->data < fw->size) {
+               struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
+
+               frag_len += sizeof(*cmd) + cmd->plen;
+
+               BT_DBG("%s: patching %td/%zu", hdev->name,
+                      (fw_ptr - fw->data), fw->size);
+
+               /* The parameter length of the secure send command requires
+                * a 4 byte alignment. It happens so that the firmware file
+                * contains proper Intel_NOP commands to align the fragments
+                * as needed.
+                *
+                * Send set of commands with 4 byte alignment from the
+                * firmware data buffer as a single Data fragement.
+                */
+               if (frag_len % 4)
+                       continue;
+
+               /* Send each command from the firmware data buffer as
+                * a single Data fragment.
+                */
+               err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
+               if (err < 0) {
+                       BT_ERR("%s: Failed to send firmware data (%d)",
+                              hdev->name, err);
+                       goto done;
+               }
+
+               fw_ptr += frag_len;
+               frag_len = 0;
+       }
+
+       set_bit(STATE_FIRMWARE_LOADED, &intel->flags);
+
+       BT_INFO("%s: Waiting for firmware download to complete", hdev->name);
+
+       /* Before switching the device into operational mode and with that
+        * booting the loaded firmware, wait for the bootloader notification
+        * that all fragments have been successfully received.
+        *
+        * When the event processing receives the notification, then the
+        * STATE_DOWNLOADING flag will be cleared.
+        *
+        * The firmware loading should not take longer than 5 seconds
+        * and thus just timeout if that happens and fail the setup
+        * of this device.
+        */
+       err = wait_on_bit_timeout(&intel->flags, STATE_DOWNLOADING,
+                                 TASK_INTERRUPTIBLE,
+                                 msecs_to_jiffies(5000));
+       if (err == 1) {
+               BT_ERR("%s: Firmware loading interrupted", hdev->name);
+               err = -EINTR;
+               goto done;
+       }
+
+       if (err) {
+               BT_ERR("%s: Firmware loading timeout", hdev->name);
+               err = -ETIMEDOUT;
+               goto done;
+       }
+
+       if (test_bit(STATE_FIRMWARE_FAILED, &intel->flags)) {
+               BT_ERR("%s: Firmware loading failed", hdev->name);
+               err = -ENOEXEC;
+               goto done;
+       }
+
+       rettime = ktime_get();
+       delta = ktime_sub(rettime, calltime);
+       duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+
+       BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration);
+
+done:
+       release_firmware(fw);
+
+       if (err < 0)
+               return err;
+
+       calltime = ktime_get();
+
+       set_bit(STATE_BOOTING, &intel->flags);
+
+       skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param,
+                            HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       kfree_skb(skb);
+
+       /* The bootloader will not indicate when the device is ready. This
+        * is done by the operational firmware sending bootup notification.
+        *
+        * Booting into operational firmware should not take longer than
+        * 1 second. However if that happens, then just fail the setup
+        * since something went wrong.
+        */
+       BT_INFO("%s: Waiting for device to boot", hdev->name);
+
+       err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING,
+                                 TASK_INTERRUPTIBLE,
+                                 msecs_to_jiffies(1000));
+
+       if (err == 1) {
+               BT_ERR("%s: Device boot interrupted", hdev->name);
+               return -EINTR;
+       }
+
+       if (err) {
+               BT_ERR("%s: Device boot timeout", hdev->name);
+               return -ETIMEDOUT;
+       }
+
+       rettime = ktime_get();
+       delta = ktime_sub(rettime, calltime);
+       duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+
+       BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration);
+
+       clear_bit(STATE_BOOTLOADER, &intel->flags);
+
+       return 0;
+}
+
+static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_uart *hu = hci_get_drvdata(hdev);
+       struct intel_data *intel = hu->priv;
+       struct hci_event_hdr *hdr;
+
+       if (!test_bit(STATE_BOOTLOADER, &intel->flags))
+               goto recv;
+
+       hdr = (void *)skb->data;
+
+       /* When the firmware loading completes the device sends
+        * out a vendor specific event indicating the result of
+        * the firmware loading.
+        */
+       if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 &&
+           skb->data[2] == 0x06) {
+               if (skb->data[3] != 0x00)
+                       set_bit(STATE_FIRMWARE_FAILED, &intel->flags);
+
+               if (test_and_clear_bit(STATE_DOWNLOADING, &intel->flags) &&
+                   test_bit(STATE_FIRMWARE_LOADED, &intel->flags)) {
+                       smp_mb__after_atomic();
+                       wake_up_bit(&intel->flags, STATE_DOWNLOADING);
+               }
+
+       /* When switching to the operational firmware the device
+        * sends a vendor specific event indicating that the bootup
+        * completed.
+        */
+       } else if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 &&
+                  skb->data[2] == 0x02) {
+               if (test_and_clear_bit(STATE_BOOTING, &intel->flags)) {
+                       smp_mb__after_atomic();
+                       wake_up_bit(&intel->flags, STATE_BOOTING);
+               }
+       }
+recv:
+       return hci_recv_frame(hdev, skb);
+}
+
+static const struct h4_recv_pkt intel_recv_pkts[] = {
+       { H4_RECV_ACL,   .recv = hci_recv_frame },
+       { H4_RECV_SCO,   .recv = hci_recv_frame },
+       { H4_RECV_EVENT, .recv = intel_recv_event },
+};
+
+static int intel_recv(struct hci_uart *hu, const void *data, int count)
+{
+       struct intel_data *intel = hu->priv;
+
+       if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+               return -EUNATCH;
+
+       intel->rx_skb = h4_recv_buf(hu->hdev, intel->rx_skb, data, count,
+                                   intel_recv_pkts,
+                                   ARRAY_SIZE(intel_recv_pkts));
+       if (IS_ERR(intel->rx_skb)) {
+               int err = PTR_ERR(intel->rx_skb);
+               BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+               intel->rx_skb = NULL;
+               return err;
+       }
+
+       return count;
+}
+
+static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+       struct intel_data *intel = hu->priv;
+
+       BT_DBG("hu %p skb %p", hu, skb);
+
+       skb_queue_tail(&intel->txq, skb);
+
+       return 0;
+}
+
+static struct sk_buff *intel_dequeue(struct hci_uart *hu)
+{
+       struct intel_data *intel = hu->priv;
+       struct sk_buff *skb;
+
+       skb = skb_dequeue(&intel->txq);
+       if (!skb)
+               return skb;
+
+       if (test_bit(STATE_BOOTLOADER, &intel->flags) &&
+           (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT)) {
+               struct hci_command_hdr *cmd = (void *)skb->data;
+               __u16 opcode = le16_to_cpu(cmd->opcode);
+
+               /* When the 0xfc01 command is issued to boot into
+                * the operational firmware, it will actually not
+                * send a command complete event. To keep the flow
+                * control working inject that event here.
+                */
+               if (opcode == 0xfc01)
+                       inject_cmd_complete(hu->hdev, opcode);
+       }
+
+       /* Prepend skb with frame type */
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+       return skb;
+}
+
+static const struct hci_uart_proto intel_proto = {
+       .id             = HCI_UART_INTEL,
+       .name           = "Intel",
+       .init_speed     = 115200,
+       .open           = intel_open,
+       .close          = intel_close,
+       .flush          = intel_flush,
+       .setup          = intel_setup,
+       .recv           = intel_recv,
+       .enqueue        = intel_enqueue,
+       .dequeue        = intel_dequeue,
+};
+
+int __init intel_init(void)
+{
+       return hci_uart_register_proto(&intel_proto);
+}
+
+int __exit intel_deinit(void)
+{
+       return hci_uart_unregister_proto(&intel_proto);
+}
index 177dd69fdd954151c3742c5cf443d439ad0edc0c..20c2ac193ff972a9ba8717092f285f81f9aaad59 100644 (file)
@@ -770,7 +770,7 @@ static int __init hci_uart_init(void)
 
        /* Register the tty discipline */
 
-       memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
+       memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc));
        hci_uart_ldisc.magic            = TTY_LDISC_MAGIC;
        hci_uart_ldisc.name             = "n_hci";
        hci_uart_ldisc.open             = hci_uart_tty_open;
@@ -804,6 +804,9 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_3WIRE
        h5_init();
 #endif
+#ifdef CONFIG_BT_HCIUART_INTEL
+       intel_init();
+#endif
 #ifdef CONFIG_BT_HCIUART_BCM
        bcm_init();
 #endif
@@ -830,6 +833,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_3WIRE
        h5_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_INTEL
+       intel_deinit();
+#endif
 #ifdef CONFIG_BT_HCIUART_BCM
        bcm_deinit();
 #endif
index ce9c670956f54d414aadaec5f9810fac7e058abd..496587a73a9daa4a2a70ef92bd9fc04b0ef72dbf 100644 (file)
@@ -167,6 +167,11 @@ int h5_init(void);
 int h5_deinit(void);
 #endif
 
+#ifdef CONFIG_BT_HCIUART_INTEL
+int intel_init(void);
+int intel_deinit(void);
+#endif
+
 #ifdef CONFIG_BT_HCIUART_BCM
 int bcm_init(void);
 int bcm_deinit(void);
index f7bd9f3ddaac8c2044e2ea3215e02b98fdc3587d..d0d5bf6cbb686a357e4e5ed98ad652c0dbf6908a 100644 (file)
@@ -545,7 +545,9 @@ at86rf230_async_state_delay(void *context)
        }
 
        /* Default delay is 1us in the most cases */
-       tim = ktime_set(0, NSEC_PER_USEC);
+       udelay(1);
+       at86rf230_async_state_timer(&ctx->timer);
+       return;
 
 change:
        hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL);
index b6fc295796679554fc8a9d499eb349dc1bdd662f..613dae559925f947586f8f011aad315d0705866c 100644 (file)
@@ -1151,7 +1151,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids);
 static struct spi_driver cc2520_driver = {
        .driver = {
                .name = "cc2520",
-               .bus = &spi_bus_type,
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(cc2520_of_ids),
        },
index 2549760e039fd803fc747f501d74c336fac71b58..997724b8e4343b3ab068a86463393e8008f6ee91 100644 (file)
@@ -812,7 +812,6 @@ MODULE_DEVICE_TABLE(spi, mrf24j40_ids);
 static struct spi_driver mrf24j40_driver = {
        .driver = {
                .name = "mrf24j40",
-               .bus = &spi_bus_type,
                .owner = THIS_MODULE,
        },
        .id_table = mrf24j40_ids,
index 3bd618d3e55dcf8735fb878a1d59bc8cf18bcc2d..2a6b0919e23f71af5f4660fce0a349bfa09b2fd9 100644 (file)
@@ -1297,7 +1297,7 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
        if (max >= to_multiplier * 8)
                return -EINVAL;
 
-       max_latency = (to_multiplier * 8 / max) - 1;
+       max_latency = (to_multiplier * 4 / max) - 1;
        if (latency > 499 || latency > max_latency)
                return -EINVAL;
 
index 2239a37530922682008d9bbe312e6cbfbe97fd4d..c98afc08cc2612e046cd070b22d25aa18a88c457 100644 (file)
@@ -55,6 +55,8 @@
 #define L2CAP_INFO_TIMEOUT             msecs_to_jiffies(4000)
 #define L2CAP_MOVE_TIMEOUT             msecs_to_jiffies(4000)
 #define L2CAP_MOVE_ERTX_TIMEOUT                msecs_to_jiffies(60000)
+#define L2CAP_WAIT_ACK_POLL_PERIOD     msecs_to_jiffies(200)
+#define L2CAP_WAIT_ACK_TIMEOUT         msecs_to_jiffies(10000)
 
 #define L2CAP_A2MP_DEFAULT_MTU         670
 
index 290a9a69af0788794619b0ededc4a6ccfbab5e07..382f94b59f2f706eab23f2f6ebe9c2f007c5ed2e 100644 (file)
@@ -34,6 +34,8 @@ struct cfg802154_ops {
                                                           int type);
        void    (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
                                               struct net_device *dev);
+       int     (*suspend)(struct wpan_phy *wpan_phy);
+       int     (*resume)(struct wpan_phy *wpan_phy);
        int     (*add_virtual_intf)(struct wpan_phy *wpan_phy,
                                    const char *name,
                                    unsigned char name_assign_type,
index f534a46911dc3967e78700f30f8e7e47ca9acec8..b7f99615224bd05d7e4cb926aca27f14f44aab81 100644 (file)
@@ -320,23 +320,6 @@ int ieee802154_register_hw(struct ieee802154_hw *hw);
  */
 void ieee802154_unregister_hw(struct ieee802154_hw *hw);
 
-/**
- * ieee802154_rx - receive frame
- *
- * Use this function to hand received frames to mac802154. The receive
- * buffer in @skb must start with an IEEE 802.15.4 header. In case of a
- * paged @skb is used, the driver is recommended to put the ieee802154
- * header of the frame on the linear part of the @skb to avoid memory
- * allocation and/or memcpy by the stack.
- *
- * This function may not be called in IRQ context. Calls to this function
- * for a single hardware must be synchronized against each other.
- *
- * @hw: the hardware this frame came in on
- * @skb: the buffer to receive, owned by mac802154 after this call
- */
-void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb);
-
 /**
  * ieee802154_rx_irqsafe - receive frame
  *
index 94a375c04f21cd5a9b525f7dffb4a14657deea89..9055d7b9d1129d69e34f8ed255922b2e340fcbb1 100644 (file)
@@ -613,6 +613,8 @@ EXPORT_SYMBOL_GPL(lowpan_header_compress);
 
 static int __init lowpan_module_init(void)
 {
+       request_module_nowait("ipv6");
+
        request_module_nowait("nhc_dest");
        request_module_nowait("nhc_fragment");
        request_module_nowait("nhc_hop");
index 2fb7b306490424c62bafd0fe7de6fd83176ed698..0ffe2e24020aa86b80115221811f324511cc1385 100644 (file)
@@ -859,9 +859,22 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
        SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev);
        SET_NETDEV_DEVTYPE(netdev, &bt_type);
 
+       *dev = netdev_priv(netdev);
+       (*dev)->netdev = netdev;
+       (*dev)->hdev = chan->conn->hcon->hdev;
+       INIT_LIST_HEAD(&(*dev)->peers);
+
+       spin_lock(&devices_lock);
+       INIT_LIST_HEAD(&(*dev)->list);
+       list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
+       spin_unlock(&devices_lock);
+
        err = register_netdev(netdev);
        if (err < 0) {
                BT_INFO("register_netdev failed %d", err);
+               spin_lock(&devices_lock);
+               list_del_rcu(&(*dev)->list);
+               spin_unlock(&devices_lock);
                free_netdev(netdev);
                goto out;
        }
@@ -871,16 +884,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
               &chan->src, chan->src_type);
        set_bit(__LINK_STATE_PRESENT, &netdev->state);
 
-       *dev = netdev_priv(netdev);
-       (*dev)->netdev = netdev;
-       (*dev)->hdev = chan->conn->hcon->hdev;
-       INIT_LIST_HEAD(&(*dev)->peers);
-
-       spin_lock(&devices_lock);
-       INIT_LIST_HEAD(&(*dev)->list);
-       list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
-       spin_unlock(&devices_lock);
-
        return 0;
 
 out:
index b8c794b87523857b9a658526ebb92dd21b22dd57..95d1a66ba03aa20095932a1c45f9f76af2cc1393 100644 (file)
@@ -53,6 +53,11 @@ source "net/bluetooth/cmtp/Kconfig"
 
 source "net/bluetooth/hidp/Kconfig"
 
+config BT_HS
+       bool "Bluetooth High Speed (HS) features"
+       depends on BT_BREDR
+       default y
+
 config BT_LE
        bool "Bluetooth Low Energy (LE) features"
        depends on BT
index 29c12ae72a665bf8c730ee5472036fd673dc8f5a..2b15ae8c1def06642682c488a9439f0e57feeb13 100644 (file)
@@ -13,9 +13,10 @@ bluetooth_6lowpan-y := 6lowpan.o
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
        hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
-       a2mp.o amp.o ecc.o hci_request.o mgmt_util.o
+       ecc.o hci_request.o mgmt_util.o
 
 bluetooth-$(CONFIG_BT_BREDR) += sco.o
+bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
 bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
 bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
 
index 5a04eb1a7e5762c82109255c2aa035bec9a840dc..5f123c3320a7be1f355d31f1023d3e3996853339 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
+#include "hci_request.h"
 #include "a2mp.h"
 #include "amp.h"
 
@@ -286,11 +287,21 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
        return 0;
 }
 
+static void read_local_amp_info_complete(struct hci_dev *hdev, u8 status,
+                                        u16 opcode)
+{
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       a2mp_send_getinfo_rsp(hdev);
+}
+
 static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
                            struct a2mp_cmd *hdr)
 {
        struct a2mp_info_req *req  = (void *) skb->data;
        struct hci_dev *hdev;
+       struct hci_request hreq;
+       int err = 0;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
@@ -311,7 +322,11 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
        }
 
        set_bit(READ_LOC_AMP_INFO, &mgr->state);
-       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+       hci_req_init(&hreq, hdev);
+       hci_req_add(&hreq, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+       err = hci_req_run(&hreq, read_local_amp_info_complete);
+       if (err < 0)
+               a2mp_send_getinfo_rsp(hdev);
 
 done:
        if (hdev)
index 296f665adb09d01c0ffc7fe421bf8a75115bf1ff..a4ff3ea9b38a6e3cfe1a4ea63105458cd07e06a9 100644 (file)
@@ -130,10 +130,29 @@ struct a2mp_physlink_rsp {
 #define A2MP_STATUS_SECURITY_VIOLATION         0x06
 
 struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
+
+#if IS_ENABLED(CONFIG_BT_HS)
 int amp_mgr_put(struct amp_mgr *mgr);
 struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
                                       struct sk_buff *skb);
 void a2mp_discover_amp(struct l2cap_chan *chan);
+#else
+static inline int amp_mgr_put(struct amp_mgr *mgr)
+{
+       return 0;
+}
+
+static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+                                                    struct sk_buff *skb)
+{
+       return NULL;
+}
+
+static inline void a2mp_discover_amp(struct l2cap_chan *chan)
+{
+}
+#endif
+
 void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
 void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
 void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
index ee016f03910005de87cc45a7d04b2a3989d90c2e..238ddd3cf95fb660d41f751821a09550f977f067 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <crypto/hash.h>
 
+#include "hci_request.h"
 #include "a2mp.h"
 #include "amp.h"
 
@@ -220,10 +221,49 @@ int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
        return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
 }
 
+static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status,
+                                         u16 opcode, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data;
+       struct amp_assoc *assoc = &hdev->loc_assoc;
+       size_t rem_len, frag_len;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               goto send_rsp;
+
+       frag_len = skb->len - sizeof(*rp);
+       rem_len = __le16_to_cpu(rp->rem_len);
+
+       if (rem_len > frag_len) {
+               BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
+
+               memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
+               assoc->offset += frag_len;
+
+               /* Read other fragments */
+               amp_read_loc_assoc_frag(hdev, rp->phy_handle);
+
+               return;
+       }
+
+       memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
+       assoc->len = assoc->offset + rem_len;
+       assoc->offset = 0;
+
+send_rsp:
+       /* Send A2MP Rsp when all fragments are received */
+       a2mp_send_getampassoc_rsp(hdev, rp->status);
+       a2mp_send_create_phy_link_req(hdev, rp->status);
+}
+
 void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
 {
        struct hci_cp_read_local_amp_assoc cp;
        struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+       struct hci_request req;
+       int err = 0;
 
        BT_DBG("%s handle %d", hdev->name, phy_handle);
 
@@ -231,12 +271,18 @@ void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
        cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
        cp.len_so_far = cpu_to_le16(loc_assoc->offset);
 
-       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+       hci_req_init(&req, hdev);
+       hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+       err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
+       if (err < 0)
+               a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
 }
 
 void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
 {
        struct hci_cp_read_local_amp_assoc cp;
+       struct hci_request req;
+       int err = 0;
 
        memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
        memset(&cp, 0, sizeof(cp));
@@ -244,7 +290,11 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
        cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
 
        set_bit(READ_LOC_AMP_ASSOC, &mgr->state);
-       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+       hci_req_init(&req, hdev);
+       hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+       hci_req_run_skb(&req, read_local_amp_assoc_complete);
+       if (err < 0)
+               a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
 }
 
 void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
@@ -252,6 +302,8 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
 {
        struct hci_cp_read_local_amp_assoc cp;
        struct amp_mgr *mgr = hcon->amp_mgr;
+       struct hci_request req;
+       int err = 0;
 
        cp.phy_handle = hcon->handle;
        cp.len_so_far = cpu_to_le16(0);
@@ -260,7 +312,25 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
        set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);
 
        /* Read Local AMP Assoc final link information data */
-       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+       hci_req_init(&req, hdev);
+       hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+       hci_req_run_skb(&req, read_local_amp_assoc_complete);
+       if (err < 0)
+               a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
+}
+
+static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status,
+                                           u16 opcode, struct sk_buff *skb)
+{
+       struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data;
+
+       BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
+              hdev->name, rp->status, rp->phy_handle);
+
+       if (rp->status)
+               return;
+
+       amp_write_rem_assoc_continue(hdev, rp->phy_handle);
 }
 
 /* Write AMP Assoc data fragments, returns true with last fragment written*/
@@ -270,6 +340,7 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
        struct hci_cp_write_remote_amp_assoc *cp;
        struct amp_mgr *mgr = hcon->amp_mgr;
        struct amp_ctrl *ctrl;
+       struct hci_request req;
        u16 frag_len, len;
 
        ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
@@ -307,7 +378,9 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
 
        amp_ctrl_put(ctrl);
 
-       hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
+       hci_req_init(&req, hdev);
+       hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, sizeof(cp), &cp);
+       hci_req_run_skb(&req, write_remote_amp_assoc_complete);
 
        kfree(cp);
 
@@ -344,10 +417,37 @@ void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
        amp_write_rem_assoc_frag(hdev, hcon);
 }
 
+static void create_phylink_complete(struct hci_dev *hdev, u8 status,
+                                   u16 opcode)
+{
+       struct hci_cp_create_phy_link *cp;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if (status) {
+               struct hci_conn *hcon;
+
+               hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
+               if (hcon)
+                       hci_conn_del(hcon);
+       } else {
+               amp_write_remote_assoc(hdev, cp->phy_handle);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
 void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                        struct hci_conn *hcon)
 {
        struct hci_cp_create_phy_link cp;
+       struct hci_request req;
 
        cp.phy_handle = hcon->handle;
 
@@ -360,13 +460,33 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                return;
        }
 
-       hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
+       hci_req_init(&req, hdev);
+       hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
+       hci_req_run(&req, create_phylink_complete);
+}
+
+static void accept_phylink_complete(struct hci_dev *hdev, u8 status,
+                                   u16 opcode)
+{
+       struct hci_cp_accept_phy_link *cp;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
+       if (!cp)
+               return;
+
+       amp_write_remote_assoc(hdev, cp->phy_handle);
 }
 
 void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                        struct hci_conn *hcon)
 {
        struct hci_cp_accept_phy_link cp;
+       struct hci_request req;
 
        cp.phy_handle = hcon->handle;
 
@@ -379,7 +499,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                return;
        }
 
-       hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
+       hci_req_init(&req, hdev);
+       hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
+       hci_req_run(&req, accept_phylink_complete);
 }
 
 void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
index 7ea3db77ba890a18876fd3a57ddf6aa27fa9269c..8848f8158ae45d61013b5373ce4d882969178c25 100644 (file)
@@ -44,6 +44,20 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                        struct hci_conn *hcon);
 void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                        struct hci_conn *hcon);
+
+#if IS_ENABLED(CONFIG_BT_HS)
+void amp_create_logical_link(struct l2cap_chan *chan);
+void amp_disconnect_logical_link(struct hci_chan *hchan);
+#else
+static inline void amp_create_logical_link(struct l2cap_chan *chan)
+{
+}
+
+static inline void amp_disconnect_logical_link(struct hci_chan *hchan)
+{
+}
+#endif
+
 void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
 void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
 void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
index b0c6c6af76ef07c311ea940d482b3d45ab83696d..9a50338772f3af9875c83f628e110ffa6458781a 100644 (file)
@@ -100,9 +100,9 @@ static void cmtp_application_del(struct cmtp_session *session, struct cmtp_appli
 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
 {
        struct cmtp_application *app;
-       struct list_head *p, *n;
+       struct list_head *p;
 
-       list_for_each_safe(p, n, &session->applications) {
+       list_for_each(p, &session->applications) {
                app = list_entry(p, struct cmtp_application, list);
                switch (pattern) {
                case CMTP_MSGNUM:
@@ -511,13 +511,13 @@ static int cmtp_proc_show(struct seq_file *m, void *v)
        struct capi_ctr *ctrl = m->private;
        struct cmtp_session *session = ctrl->driverdata;
        struct cmtp_application *app;
-       struct list_head *p, *n;
+       struct list_head *p;
 
        seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
        seq_printf(m, "addr %s\n", session->name);
        seq_printf(m, "ctrl %d\n", session->num);
 
-       list_for_each_safe(p, n, &session->applications) {
+       list_for_each(p, &session->applications) {
                app = list_entry(p, struct cmtp_application, list);
                seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
        }
index 2f8fb33067e1c48fedf3055ddf29a3be68161c9f..bc43b6490555c7d75dae8ac452a7b012c8f1ffa1 100644 (file)
@@ -2822,10 +2822,6 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
 {
        struct hci_conn_params *params;
 
-       /* The conn params list only contains identity addresses */
-       if (!hci_is_identity_address(addr, addr_type))
-               return NULL;
-
        list_for_each_entry(params, &hdev->le_conn_params, list) {
                if (bacmp(&params->addr, addr) == 0 &&
                    params->addr_type == addr_type) {
@@ -2842,10 +2838,6 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
 {
        struct hci_conn_params *param;
 
-       /* The list only contains identity addresses */
-       if (!hci_is_identity_address(addr, addr_type))
-               return NULL;
-
        list_for_each_entry(param, list, action) {
                if (bacmp(&param->addr, addr) == 0 &&
                    param->addr_type == addr_type)
@@ -2861,9 +2853,6 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
 {
        struct hci_conn_params *params;
 
-       if (!hci_is_identity_address(addr, addr_type))
-               return NULL;
-
        params = hci_conn_params_lookup(hdev, addr, addr_type);
        if (params)
                return params;
index 32363c2b7f83d7b458eb303e2fbe7a8b050539b5..218d7dfc342f484b0b9b18c4208a2ccc5efc0cb8 100644 (file)
@@ -823,7 +823,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
        if (rp->status)
-               goto a2mp_rsp;
+               return;
 
        hdev->amp_status = rp->amp_status;
        hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
@@ -835,46 +835,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
        hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
        hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
-
-a2mp_rsp:
-       a2mp_send_getinfo_rsp(hdev);
-}
-
-static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
-{
-       struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
-       struct amp_assoc *assoc = &hdev->loc_assoc;
-       size_t rem_len, frag_len;
-
-       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
-
-       if (rp->status)
-               goto a2mp_rsp;
-
-       frag_len = skb->len - sizeof(*rp);
-       rem_len = __le16_to_cpu(rp->rem_len);
-
-       if (rem_len > frag_len) {
-               BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
-
-               memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
-               assoc->offset += frag_len;
-
-               /* Read other fragments */
-               amp_read_loc_assoc_frag(hdev, rp->phy_handle);
-
-               return;
-       }
-
-       memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
-       assoc->len = assoc->offset + rem_len;
-       assoc->offset = 0;
-
-a2mp_rsp:
-       /* Send A2MP Rsp when all fragments are received */
-       a2mp_send_getampassoc_rsp(hdev, rp->status);
-       a2mp_send_create_phy_link_req(hdev, rp->status);
 }
 
 static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
@@ -1409,20 +1369,6 @@ static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
-                                         struct sk_buff *skb)
-{
-       struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
-
-       BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
-              hdev->name, rp->status, rp->phy_handle);
-
-       if (rp->status)
-               return;
-
-       amp_write_rem_assoc_continue(hdev, rp->phy_handle);
-}
-
 static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_read_rssi *rp = (void *) skb->data;
@@ -1944,47 +1890,6 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
-{
-       struct hci_cp_create_phy_link *cp;
-
-       BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
-       cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
-       if (!cp)
-               return;
-
-       hci_dev_lock(hdev);
-
-       if (status) {
-               struct hci_conn *hcon;
-
-               hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
-               if (hcon)
-                       hci_conn_del(hcon);
-       } else {
-               amp_write_remote_assoc(hdev, cp->phy_handle);
-       }
-
-       hci_dev_unlock(hdev);
-}
-
-static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
-{
-       struct hci_cp_accept_phy_link *cp;
-
-       BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
-       if (status)
-               return;
-
-       cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
-       if (!cp)
-               return;
-
-       amp_write_remote_assoc(hdev, cp->phy_handle);
-}
-
 static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
 {
        struct hci_cp_le_create_conn *cp;
@@ -2998,10 +2903,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cc_read_clock(hdev, skb);
                break;
 
-       case HCI_OP_READ_LOCAL_AMP_ASSOC:
-               hci_cc_read_local_amp_assoc(hdev, skb);
-               break;
-
        case HCI_OP_READ_INQ_RSP_TX_POWER:
                hci_cc_read_inq_rsp_tx_power(hdev, skb);
                break;
@@ -3106,10 +3007,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cc_set_adv_param(hdev, skb);
                break;
 
-       case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
-               hci_cc_write_remote_amp_assoc(hdev, skb);
-               break;
-
        case HCI_OP_READ_RSSI:
                hci_cc_read_rssi(hdev, skb);
                break;
@@ -3193,14 +3090,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cs_setup_sync_conn(hdev, ev->status);
                break;
 
-       case HCI_OP_CREATE_PHY_LINK:
-               hci_cs_create_phylink(hdev, ev->status);
-               break;
-
-       case HCI_OP_ACCEPT_PHY_LINK:
-               hci_cs_accept_phylink(hdev, ev->status);
-               break;
-
        case HCI_OP_SNIFF_MODE:
                hci_cs_sniff_mode(hdev, ev->status);
                break;
@@ -4399,6 +4288,23 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
+#if IS_ENABLED(CONFIG_BT_HS)
+static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_channel_selected *ev = (void *)skb->data;
+       struct hci_conn *hcon;
+
+       BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
+
+       skb_pull(skb, sizeof(*ev));
+
+       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+       if (!hcon)
+               return;
+
+       amp_read_loc_assoc_final_data(hdev, hcon);
+}
+
 static void hci_phy_link_complete_evt(struct hci_dev *hdev,
                                      struct sk_buff *skb)
 {
@@ -4522,6 +4428,7 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
 
        hci_dev_unlock(hdev);
 }
+#endif
 
 static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
@@ -5206,22 +5113,6 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
-static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_channel_selected *ev = (void *) skb->data;
-       struct hci_conn *hcon;
-
-       BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
-
-       skb_pull(skb, sizeof(*ev));
-
-       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
-       if (!hcon)
-               return;
-
-       amp_read_loc_assoc_final_data(hdev, hcon);
-}
-
 static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
                                 u8 event, struct sk_buff *skb)
 {
@@ -5442,14 +5333,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_le_meta_evt(hdev, skb);
                break;
 
-       case HCI_EV_CHANNEL_SELECTED:
-               hci_chan_selected_evt(hdev, skb);
-               break;
-
        case HCI_EV_REMOTE_OOB_DATA_REQUEST:
                hci_remote_oob_data_request_evt(hdev, skb);
                break;
 
+#if IS_ENABLED(CONFIG_BT_HS)
+       case HCI_EV_CHANNEL_SELECTED:
+               hci_chan_selected_evt(hdev, skb);
+               break;
+
        case HCI_EV_PHY_LINK_COMPLETE:
                hci_phy_link_complete_evt(hdev, skb);
                break;
@@ -5465,6 +5357,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
        case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
                hci_disconn_phylink_complete_evt(hdev, skb);
                break;
+#endif
 
        case HCI_EV_NUM_COMP_BLOCKS:
                hci_num_comp_blocks_evt(hdev, skb);
index 244287706f910bdaf69afaef98cf2706cd301654..586b3d580cfcba0422828cab1843363178dfe85c 100644 (file)
@@ -1054,18 +1054,23 @@ static void l2cap_sock_kill(struct sock *sk)
        sock_put(sk);
 }
 
-static int __l2cap_wait_ack(struct sock *sk)
+static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan)
 {
-       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
        DECLARE_WAITQUEUE(wait, current);
        int err = 0;
-       int timeo = HZ/5;
+       int timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
+       /* Timeout to prevent infinite loop */
+       unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT;
 
        add_wait_queue(sk_sleep(sk), &wait);
        set_current_state(TASK_INTERRUPTIBLE);
-       while (chan->unacked_frames > 0 && chan->conn) {
+       do {
+               BT_DBG("Waiting for %d ACKs, timeout %04d ms",
+                      chan->unacked_frames, time_after(jiffies, timeout) ? 0 :
+                      jiffies_to_msecs(timeout - jiffies));
+
                if (!timeo)
-                       timeo = HZ/5;
+                       timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
 
                if (signal_pending(current)) {
                        err = sock_intr_errno(timeo);
@@ -1080,7 +1085,15 @@ static int __l2cap_wait_ack(struct sock *sk)
                err = sock_error(sk);
                if (err)
                        break;
-       }
+
+               if (time_after(jiffies, timeout)) {
+                       err = -ENOLINK;
+                       break;
+               }
+
+       } while (chan->unacked_frames > 0 &&
+                chan->state == BT_CONNECTED);
+
        set_current_state(TASK_RUNNING);
        remove_wait_queue(sk_sleep(sk), &wait);
        return err;
@@ -1098,7 +1111,12 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
        if (!sk)
                return 0;
 
+       /* prevent sk structure from being freed whilst unlocked */
+       sock_hold(sk);
+
        chan = l2cap_pi(sk)->chan;
+       /* prevent chan structure from being freed whilst unlocked */
+       l2cap_chan_hold(chan);
        conn = chan->conn;
 
        BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
@@ -1110,8 +1128,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
        lock_sock(sk);
 
        if (!sk->sk_shutdown) {
-               if (chan->mode == L2CAP_MODE_ERTM)
-                       err = __l2cap_wait_ack(sk);
+               if (chan->mode == L2CAP_MODE_ERTM &&
+                   chan->unacked_frames > 0 &&
+                   chan->state == BT_CONNECTED)
+                       err = __l2cap_wait_ack(sk, chan);
 
                sk->sk_shutdown = SHUTDOWN_MASK;
 
@@ -1134,6 +1154,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
        if (conn)
                mutex_unlock(&conn->chan_lock);
 
+       l2cap_chan_put(chan);
+       sock_put(sk);
+
+       BT_DBG("err: %d", err);
+
        return err;
 }
 
index 7998fb27916568da087b2734a017355158044a75..7ab191589541c8fab56d47ab9f0e21f050751de9 100644 (file)
@@ -6226,6 +6226,17 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
        else
                auto_conn = HCI_AUTO_CONN_REPORT;
 
+       /* Kernel internally uses conn_params with resolvable private
+        * address, but Add Device allows only identity addresses.
+        * Make sure it is enforced before calling
+        * hci_conn_params_lookup.
+        */
+       if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
+               err = cmd->cmd_complete(cmd, MGMT_STATUS_INVALID_PARAMS);
+               mgmt_pending_remove(cmd);
+               goto unlock;
+       }
+
        /* If the connection parameters don't exist for this device,
         * they will be created and configured with defaults.
         */
@@ -6340,6 +6351,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                else
                        addr_type = ADDR_LE_DEV_RANDOM;
 
+               /* Kernel internally uses conn_params with resolvable private
+                * address, but Remove Device allows only identity addresses.
+                * Make sure it is enforced before calling
+                * hci_conn_params_lookup.
+                */
+               if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
+                       err = cmd->cmd_complete(cmd,
+                                               MGMT_STATUS_INVALID_PARAMS);
+                       mgmt_pending_remove(cmd);
+                       goto unlock;
+               }
+
                params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
                                                addr_type);
                if (!params) {
index b2155a123f6c88980c180eeb7b4ffdcf68bea4fb..8d5960a37195136380032644b65a8b741a03ab00 100644 (file)
@@ -23,6 +23,26 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
        rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev);
 }
 
+static inline int
+rdev_suspend(struct cfg802154_registered_device *rdev)
+{
+       int ret;
+       trace_802154_rdev_suspend(&rdev->wpan_phy);
+       ret = rdev->ops->suspend(&rdev->wpan_phy);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
+}
+
+static inline int
+rdev_resume(struct cfg802154_registered_device *rdev)
+{
+       int ret;
+       trace_802154_rdev_resume(&rdev->wpan_phy);
+       ret = rdev->ops->resume(&rdev->wpan_phy);
+       trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+       return ret;
+}
+
 static inline int
 rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name,
                      unsigned char name_assign_type,
index 133b4280660cfc2f9b651a56a95502991e21840b..bd88525b041e79c62a0458c499968315c5a56e4e 100644 (file)
  */
 
 #include <linux/device.h>
+#include <linux/rtnetlink.h>
 
 #include <net/cfg802154.h>
 
 #include "core.h"
 #include "sysfs.h"
+#include "rdev-ops.h"
 
 static inline struct cfg802154_registered_device *
 dev_to_rdev(struct device *dev)
@@ -62,10 +64,46 @@ static struct attribute *pmib_attrs[] = {
 };
 ATTRIBUTE_GROUPS(pmib);
 
+#ifdef CONFIG_PM_SLEEP
+static int wpan_phy_suspend(struct device *dev)
+{
+       struct cfg802154_registered_device *rdev = dev_to_rdev(dev);
+       int ret = 0;
+
+       if (rdev->ops->suspend) {
+               rtnl_lock();
+               ret = rdev_suspend(rdev);
+               rtnl_unlock();
+       }
+
+       return ret;
+}
+
+static int wpan_phy_resume(struct device *dev)
+{
+       struct cfg802154_registered_device *rdev = dev_to_rdev(dev);
+       int ret = 0;
+
+       if (rdev->ops->resume) {
+               rtnl_lock();
+               ret = rdev_resume(rdev);
+               rtnl_unlock();
+       }
+
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(wpan_phy_pm_ops, wpan_phy_suspend, wpan_phy_resume);
+#define WPAN_PHY_PM_OPS (&wpan_phy_pm_ops)
+#else
+#define WPAN_PHY_PM_OPS NULL
+#endif
+
 struct class wpan_phy_class = {
        .name = "ieee802154",
        .dev_release = wpan_phy_release,
        .dev_groups = pmib_groups,
+       .pm = WPAN_PHY_PM_OPS,
 };
 
 int wpan_phy_sysfs_init(void)
index 9b5f0eb366969c0c968935389b97ad0893b41cf1..4399b7fbaa31481c402079680e3509ed05fb9479 100644 (file)
  *                     rdev->ops traces                     *
  *************************************************************/
 
+DECLARE_EVENT_CLASS(wpan_phy_only_evt,
+       TP_PROTO(struct wpan_phy *wpan_phy),
+       TP_ARGS(wpan_phy),
+       TP_STRUCT__entry(
+               WPAN_PHY_ENTRY
+       ),
+       TP_fast_assign(
+               WPAN_PHY_ASSIGN;
+       ),
+       TP_printk(WPAN_PHY_PR_FMT, WPAN_PHY_PR_ARG)
+);
+
+DEFINE_EVENT(wpan_phy_only_evt, 802154_rdev_suspend,
+       TP_PROTO(struct wpan_phy *wpan_phy),
+       TP_ARGS(wpan_phy)
+);
+
+DEFINE_EVENT(wpan_phy_only_evt, 802154_rdev_resume,
+       TP_PROTO(struct wpan_phy *wpan_phy),
+       TP_ARGS(wpan_phy)
+);
+
 TRACE_EVENT(802154_rdev_add_virtual_intf,
        TP_PROTO(struct wpan_phy *wpan_phy, char *name,
                 enum nl802154_iftype type, __le64 extended_addr),
index 317c4662e544679ab37dcc8cfa92fc8108c4820b..f7ba51e8b4cafbf720c5ee3096c1102cbf2a4438 100644 (file)
@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
        ieee802154_if_remove(sdata);
 }
 
+#ifdef CONFIG_PM
+static int ieee802154_suspend(struct wpan_phy *wpan_phy)
+{
+       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+
+       if (!local->open_count)
+               goto suspend;
+
+       ieee802154_stop_queue(&local->hw);
+       synchronize_net();
+
+       /* stop hardware - this must stop RX */
+       ieee802154_stop_device(local);
+
+suspend:
+       local->suspended = true;
+       return 0;
+}
+
+static int ieee802154_resume(struct wpan_phy *wpan_phy)
+{
+       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+       int ret;
+
+       /* nothing to do if HW shouldn't run */
+       if (!local->open_count)
+               goto wake_up;
+
+       /* restart hardware */
+       ret = drv_start(local);
+       if (ret)
+               return ret;
+
+wake_up:
+       ieee802154_wake_queue(&local->hw);
+       local->suspended = false;
+       return 0;
+}
+#else
+#define ieee802154_suspend NULL
+#define ieee802154_resume NULL
+#endif
+
 static int
 ieee802154_add_iface(struct wpan_phy *phy, const char *name,
                     unsigned char name_assign_type,
@@ -145,13 +188,18 @@ static int
 ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
                      __le16 pan_id)
 {
+       int ret;
+
        ASSERT_RTNL();
 
        if (wpan_dev->pan_id == pan_id)
                return 0;
 
-       wpan_dev->pan_id = pan_id;
-       return 0;
+       ret = mac802154_wpan_update_llsec(wpan_dev->netdev);
+       if (!ret)
+               wpan_dev->pan_id = pan_id;
+
+       return ret;
 }
 
 static int
@@ -227,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 const struct cfg802154_ops mac802154_config_ops = {
        .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated,
        .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated,
+       .suspend = ieee802154_suspend,
+       .resume = ieee802154_resume,
        .add_virtual_intf = ieee802154_add_iface,
        .del_virtual_intf = ieee802154_del_iface,
        .set_channel = ieee802154_set_channel,
index 34755d5751a4681c65d09cb7487e5b98350cedfe..56ccffa3f2bfc7731adfaabb1026ef7e8af68d32 100644 (file)
@@ -56,9 +56,13 @@ struct ieee802154_local {
        struct hrtimer ifs_timer;
 
        bool started;
+       bool suspended;
 
        struct tasklet_struct tasklet;
        struct sk_buff_head skb_queue;
+
+       struct sk_buff *tx_skb;
+       struct work_struct tx_work;
 };
 
 enum {
@@ -94,8 +98,6 @@ struct ieee802154_sub_if_data {
        struct mac802154_llsec sec;
 };
 
-#define MAC802154_CHAN_NONE            0xff /* No channel is assigned */
-
 /* utility functions/constants */
 extern const void *const mac802154_wpan_phy_privid; /*  for wpan_phy privid */
 
@@ -125,6 +127,8 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
 
 extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
 
+void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
+void ieee802154_xmit_worker(struct work_struct *work);
 netdev_tx_t
 ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
 netdev_tx_t
@@ -167,6 +171,8 @@ void mac802154_get_table(struct net_device *dev,
                         struct ieee802154_llsec_table **t);
 void mac802154_unlock_table(struct net_device *dev);
 
+int mac802154_wpan_update_llsec(struct net_device *dev);
+
 /* interface handling */
 int ieee802154_iface_init(void);
 void ieee802154_iface_exit(void);
@@ -176,5 +182,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
                  unsigned char name_assign_type, enum nl802154_iftype type,
                  __le64 extended_addr);
 void ieee802154_remove_interfaces(struct ieee802154_local *local);
+void ieee802154_stop_device(struct ieee802154_local *local);
 
 #endif /* __IEEE802154_I_H */
index 8b698246a51b6d304c209442ca0ecd0c3e652c79..416de903e46757cfead3fe54106efa07ce6e6245 100644 (file)
@@ -30,7 +30,7 @@
 #include "ieee802154_i.h"
 #include "driver-ops.h"
 
-static int mac802154_wpan_update_llsec(struct net_device *dev)
+int mac802154_wpan_update_llsec(struct net_device *dev)
 {
        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
@@ -314,11 +314,8 @@ static int mac802154_slave_close(struct net_device *dev)
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
-       if (!local->open_count) {
-               flush_workqueue(local->workqueue);
-               hrtimer_cancel(&local->ifs_timer);
-               drv_stop(local);
-       }
+       if (!local->open_count)
+               ieee802154_stop_device(local);
 
        return 0;
 }
@@ -471,6 +468,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
                       enum nl802154_iftype type)
 {
        struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+       int ret;
        u8 tmp;
 
        /* set some type-dependent values */
@@ -505,6 +503,10 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
                mutex_init(&sdata->sec_mtx);
 
                mac802154_llsec_init(&sdata->sec);
+               ret = mac802154_wpan_update_llsec(sdata->dev);
+               if (ret < 0)
+                       return ret;
+
                break;
        case NL802154_IFTYPE_MONITOR:
                sdata->dev->destructor = free_netdev;
index 356b346e1ee86fdeadebf7be5d318c70dbc0d969..9e55431b9a5cc0baf0c40fa9e7a96c3381617ad5 100644 (file)
@@ -40,7 +40,7 @@ static void ieee802154_tasklet_handler(unsigned long data)
                         * netstack.
                         */
                        skb->pkt_type = 0;
-                       ieee802154_rx(&local->hw, skb);
+                       ieee802154_rx(local, skb);
                        break;
                default:
                        WARN(1, "mac802154: Packet is of unknown type %d\n",
@@ -58,11 +58,9 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
        struct ieee802154_local *local;
        size_t priv_size;
 
-       if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
-           !ops->start || !ops->stop || !ops->set_channel) {
-               pr_err("undefined IEEE802.15.4 device operations\n");
+       if (WARN_ON(!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
+                   !ops->start || !ops->stop || !ops->set_channel))
                return NULL;
-       }
 
        /* Ensure 32-byte alignment of our private data and hw private data.
         * We use the wpan_phy priv data for both our ieee802154_local and for
@@ -107,6 +105,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
 
        skb_queue_head_init(&local->skb_queue);
 
+       INIT_WORK(&local->tx_work, ieee802154_xmit_worker);
+
        /* init supported flags with 802.15.4 default ranges */
        phy->supported.max_minbe = 8;
        phy->supported.min_maxbe = 3;
index d93ad2d4a4fc2a8cf103d0a87337e2eb115fddd0..d1c33c1d6b9b3dcd74dc077b5de5b5556a18901e 100644 (file)
@@ -246,13 +246,15 @@ ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
        }
 }
 
-void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
+void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
 {
-       struct ieee802154_local *local = hw_to_local(hw);
        u16 crc;
 
        WARN_ON_ONCE(softirq_count() == 0);
 
+       if (local->suspended)
+               goto drop;
+
        /* TODO: When a transceiver omits the checksum here, we
         * add an own calculated one. This is currently an ugly
         * solution because the monitor needs a crc here.
@@ -273,8 +275,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
                crc = crc_ccitt(0, skb->data, skb->len);
                if (crc) {
                        rcu_read_unlock();
-                       kfree_skb(skb);
-                       return;
+                       goto drop;
                }
        }
        /* remove crc */
@@ -283,8 +284,11 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
        __ieee802154_rx_handle_packet(local, skb);
 
        rcu_read_unlock();
+
+       return;
+drop:
+       kfree_skb(skb);
 }
-EXPORT_SYMBOL(ieee802154_rx);
 
 void
 ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
index c62e95695c7843947c8643cb268f95f2e64c3da9..7ed439172f30809d59fb5673131957ca8c25c56c 100644 (file)
 #include "ieee802154_i.h"
 #include "driver-ops.h"
 
-/* IEEE 802.15.4 transceivers can sleep during the xmit session, so process
- * packets through the workqueue.
- */
-struct ieee802154_xmit_cb {
-       struct sk_buff *skb;
-       struct work_struct work;
-       struct ieee802154_local *local;
-};
-
-static struct ieee802154_xmit_cb ieee802154_xmit_cb;
-
-static void ieee802154_xmit_worker(struct work_struct *work)
+void ieee802154_xmit_worker(struct work_struct *work)
 {
-       struct ieee802154_xmit_cb *cb =
-               container_of(work, struct ieee802154_xmit_cb, work);
-       struct ieee802154_local *local = cb->local;
-       struct sk_buff *skb = cb->skb;
+       struct ieee802154_local *local =
+               container_of(work, struct ieee802154_local, tx_work);
+       struct sk_buff *skb = local->tx_skb;
        struct net_device *dev = skb->dev;
        int res;
 
@@ -106,11 +94,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
                dev->stats.tx_packets++;
                dev->stats.tx_bytes += skb->len;
        } else {
-               INIT_WORK(&ieee802154_xmit_cb.work, ieee802154_xmit_worker);
-               ieee802154_xmit_cb.skb = skb;
-               ieee802154_xmit_cb.local = local;
-
-               queue_work(local->workqueue, &ieee802154_xmit_cb.work);
+               local->tx_skb = skb;
+               queue_work(local->workqueue, &local->tx_work);
        }
 
        return NETDEV_TX_OK;
index 583435f3893037e45d4a5879b66b4cda3bb6f27f..f9fd0957ab67f256d10e80563bb68ce88334f911 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "ieee802154_i.h"
+#include "driver-ops.h"
 
 /* privid for wpan_phys to determine whether they belong to us or not */
 const void *const mac802154_wpan_phy_privid = &mac802154_wpan_phy_privid;
@@ -92,3 +93,10 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
        dev_consume_skb_any(skb);
 }
 EXPORT_SYMBOL(ieee802154_xmit_complete);
+
+void ieee802154_stop_device(struct ieee802154_local *local)
+{
+       flush_workqueue(local->workqueue);
+       hrtimer_cancel(&local->ifs_timer);
+       drv_stop(local);
+}