]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'bluetooth/master'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 01:01:49 +0000 (12:01 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 01:01:49 +0000 (12:01 +1100)
drivers/bluetooth/btusb.c
include/net/bluetooth/l2cap.h
net/bluetooth/hci_core.c
net/bluetooth/l2cap_core.c

index e33dacf5bd98765178ddac60f7d50d742de555ac..92f0ee388f9e0bfddd0cdf32b684edf25741d991 100644 (file)
@@ -1372,6 +1372,8 @@ static void btusb_work(struct work_struct *work)
                }
 
                if (data->isoc_altsetting != new_alts) {
+                       unsigned long flags;
+
                        clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
                        usb_kill_anchored_urbs(&data->isoc_anchor);
 
@@ -1384,10 +1386,10 @@ static void btusb_work(struct work_struct *work)
                         * Clear outstanding fragment when selecting a new
                         * alternate setting.
                         */
-                       spin_lock(&data->rxlock);
+                       spin_lock_irqsave(&data->rxlock, flags);
                        kfree_skb(data->sco_skb);
                        data->sco_skb = NULL;
-                       spin_unlock(&data->rxlock);
+                       spin_unlock_irqrestore(&data->rxlock, flags);
 
                        if (__set_isoc_interface(hdev, new_alts) < 0)
                                return;
index c98afc08cc2612e046cd070b22d25aa18a88c457..52899291f40144c0dab97e135b0c9762ade5c8d1 100644 (file)
@@ -275,6 +275,8 @@ struct l2cap_conn_rsp {
 #define L2CAP_CR_AUTHORIZATION 0x0006
 #define L2CAP_CR_BAD_KEY_SIZE  0x0007
 #define L2CAP_CR_ENCRYPTION    0x0008
+#define L2CAP_CR_INVALID_SCID  0x0009
+#define L2CAP_CR_SCID_IN_USE   0x0010
 
 /* connect/create channel status */
 #define L2CAP_CS_NO_INFO       0x0000
index 83a6aacfab31cb136745001a03fcb6368d7b259f..97734cab25382ec5328186ecbfa7fe529bfb2129 100644 (file)
@@ -508,12 +508,6 @@ static void le_setup(struct hci_request *req)
        /* Read LE Supported States */
        hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
 
-       /* Read LE White List Size */
-       hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
-
-       /* Clear LE White List */
-       hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
-
        /* LE-only controllers have LE implicitly enabled */
        if (!lmp_bredr_capable(hdev))
                hci_dev_set_flag(hdev, HCI_LE_ENABLED);
@@ -537,20 +531,30 @@ static void hci_setup_event_mask(struct hci_request *req)
 
        if (lmp_bredr_capable(hdev)) {
                events[4] |= 0x01; /* Flow Specification Complete */
-               events[4] |= 0x02; /* Inquiry Result with RSSI */
-               events[4] |= 0x04; /* Read Remote Extended Features Complete */
-               events[5] |= 0x08; /* Synchronous Connection Complete */
-               events[5] |= 0x10; /* Synchronous Connection Changed */
        } else {
                /* Use a different default for LE-only devices */
                memset(events, 0, sizeof(events));
-               events[0] |= 0x10; /* Disconnection Complete */
-               events[1] |= 0x08; /* Read Remote Version Information Complete */
                events[1] |= 0x20; /* Command Complete */
                events[1] |= 0x40; /* Command Status */
                events[1] |= 0x80; /* Hardware Error */
-               events[2] |= 0x04; /* Number of Completed Packets */
-               events[3] |= 0x02; /* Data Buffer Overflow */
+
+               /* If the controller supports the Disconnect command, enable
+                * the corresponding event. In addition enable packet flow
+                * control related events.
+                */
+               if (hdev->commands[0] & 0x20) {
+                       events[0] |= 0x10; /* Disconnection Complete */
+                       events[2] |= 0x04; /* Number of Completed Packets */
+                       events[3] |= 0x02; /* Data Buffer Overflow */
+               }
+
+               /* If the controller supports the Read Remote Version
+                * Information command, enable the corresponding event.
+                */
+               if (hdev->commands[2] & 0x80)
+                       events[1] |= 0x08; /* Read Remote Version Information
+                                           * Complete
+                                           */
 
                if (hdev->le_features[0] & HCI_LE_ENCRYPTION) {
                        events[0] |= 0x80; /* Encryption Change */
@@ -558,9 +562,18 @@ static void hci_setup_event_mask(struct hci_request *req)
                }
        }
 
-       if (lmp_inq_rssi_capable(hdev))
+       if (lmp_inq_rssi_capable(hdev) ||
+           test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks))
                events[4] |= 0x02; /* Inquiry Result with RSSI */
 
+       if (lmp_ext_feat_capable(hdev))
+               events[4] |= 0x04; /* Read Remote Extended Features Complete */
+
+       if (lmp_esco_capable(hdev)) {
+               events[5] |= 0x08; /* Synchronous Connection Complete */
+               events[5] |= 0x10; /* Synchronous Connection Changed */
+       }
+
        if (lmp_sniffsubr_capable(hdev))
                events[5] |= 0x20; /* Sniff Subrating */
 
@@ -783,7 +796,6 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
                u8 events[8];
 
                memset(events, 0, sizeof(events));
-               events[0] = 0x0f;
 
                if (hdev->le_features[0] & HCI_LE_ENCRYPTION)
                        events[0] |= 0x10;      /* LE Long Term Key Request */
@@ -810,6 +822,34 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
                                                 * Report
                                                 */
 
+               /* If the controller supports the LE Set Scan Enable command,
+                * enable the corresponding advertising report event.
+                */
+               if (hdev->commands[26] & 0x08)
+                       events[0] |= 0x02;      /* LE Advertising Report */
+
+               /* If the controller supports the LE Create Connection
+                * command, enable the corresponding event.
+                */
+               if (hdev->commands[26] & 0x10)
+                       events[0] |= 0x01;      /* LE Connection Complete */
+
+               /* If the controller supports the LE Connection Update
+                * command, enable the corresponding event.
+                */
+               if (hdev->commands[27] & 0x04)
+                       events[0] |= 0x04;      /* LE Connection Update
+                                                * Complete
+                                                */
+
+               /* If the controller supports the LE Read Remote Used Features
+                * command, enable the corresponding event.
+                */
+               if (hdev->commands[27] & 0x20)
+                       events[0] |= 0x08;      /* LE Read Remote Used
+                                                * Features Complete
+                                                */
+
                /* If the controller supports the LE Read Local P-256
                 * Public Key command, enable the corresponding event.
                 */
@@ -832,6 +872,17 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
                        hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
                }
 
+               if (hdev->commands[26] & 0x40) {
+                       /* Read LE White List Size */
+                       hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE,
+                                   0, NULL);
+               }
+
+               if (hdev->commands[26] & 0x80) {
+                       /* Clear LE White List */
+                       hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
+               }
+
                if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
                        /* Read LE Maximum Data Length */
                        hci_req_add(req, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL);
index 7c65ee200c29215c6b3f050cfbb881873be4946a..66e8b6ee19a525d8cc54032843934b0fedb11dc7 100644 (file)
@@ -239,7 +239,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
        else
                dyn_end = L2CAP_CID_DYN_END;
 
-       for (cid = L2CAP_CID_DYN_START; cid < dyn_end; cid++) {
+       for (cid = L2CAP_CID_DYN_START; cid <= dyn_end; cid++) {
                if (!__l2cap_get_chan_by_scid(conn, cid))
                        return cid;
        }
@@ -5250,7 +5250,9 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
        credits = __le16_to_cpu(rsp->credits);
        result  = __le16_to_cpu(rsp->result);
 
-       if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23))
+       if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23 ||
+                                          dcid < L2CAP_CID_DYN_START ||
+                                          dcid > L2CAP_CID_LE_DYN_END))
                return -EPROTO;
 
        BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x",
@@ -5270,6 +5272,11 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
 
        switch (result) {
        case L2CAP_CR_SUCCESS:
+               if (__l2cap_get_chan_by_dcid(conn, dcid)) {
+                       err = -EBADSLT;
+                       break;
+               }
+
                chan->ident = 0;
                chan->dcid = dcid;
                chan->omtu = mtu;
@@ -5437,9 +5444,16 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
                goto response_unlock;
        }
 
+       /* Check for valid dynamic CID range */
+       if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
+               result = L2CAP_CR_INVALID_SCID;
+               chan = NULL;
+               goto response_unlock;
+       }
+
        /* Check if we already have channel with that dcid */
        if (__l2cap_get_chan_by_dcid(conn, scid)) {
-               result = L2CAP_CR_NO_MEM;
+               result = L2CAP_CR_SCID_IN_USE;
                chan = NULL;
                goto response_unlock;
        }