]> Git Repo - J-linux.git/commitdiff
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorDavid S. Miller <[email protected]>
Tue, 29 Sep 2020 20:22:53 +0000 (13:22 -0700)
committerDavid S. Miller <[email protected]>
Tue, 29 Sep 2020 20:22:53 +0000 (13:22 -0700)
Johan Hedberg says:

====================
pull request: bluetooth-next 2020-09-29

Here's the main bluetooth-next pull request for 5.10:

 - Multiple fixes to suspend/resume handling
 - Added mgmt events for controller suspend/resume state
 - Improved extended advertising support
 - btintel: Enhanced support for next generation controllers
 - Added Qualcomm Bluetooth SoC WCN6855 support
 - Several other smaller fixes & improvements
====================

Signed-off-by: David S. Miller <[email protected]>
1  2 
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c

diff --combined net/bluetooth/hci_core.c
index b0209e35284ab98fff414172a8b7660c0a13b9ef,f30a1f5950e15b7f5dc572585af4ffc43c9aaa10..502552d6e9aff3382eca29ebb5859f9a5c7f440b
@@@ -808,7 -808,7 +808,7 @@@ static int hci_init4_req(struct hci_req
         * Delete Stored Link Key command. They are clearly indicating its
         * absence in the bit mask of supported commands.
         *
 -       * Check the supported commands and only if the the command is marked
 +       * Check the supported commands and only if the command is marked
         * as supported send it. If not supported assume that the controller
         * does not have actual support for stored link keys which makes this
         * command redundant anyway.
@@@ -2963,7 -2963,7 +2963,7 @@@ int hci_add_adv_instance(struct hci_de
                       sizeof(adv_instance->scan_rsp_data));
        } else {
                if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets ||
-                   instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
+                   instance < 1 || instance > hdev->le_num_of_adv_sets)
                        return -EOVERFLOW;
  
                adv_instance = kzalloc(sizeof(*adv_instance), GFP_KERNEL);
@@@ -3061,6 -3061,7 +3061,7 @@@ static int free_adv_monitor(int id, voi
  
        idr_remove(&hdev->adv_monitors_idr, monitor->handle);
        hci_free_adv_monitor(monitor);
+       hdev->adv_monitors_cnt--;
  
        return 0;
  }
@@@ -3077,6 -3078,7 +3078,7 @@@ int hci_remove_adv_monitor(struct hci_d
  
                idr_remove(&hdev->adv_monitors_idr, monitor->handle);
                hci_free_adv_monitor(monitor);
+               hdev->adv_monitors_cnt--;
        } else {
                /* Remove all monitors if handle is 0. */
                idr_for_each(&hdev->adv_monitors_idr, &free_adv_monitor, hdev);
@@@ -3442,6 -3444,16 +3444,16 @@@ void hci_copy_identity_address(struct h
        }
  }
  
+ static void hci_suspend_clear_tasks(struct hci_dev *hdev)
+ {
+       int i;
+       for (i = 0; i < __SUSPEND_NUM_TASKS; i++)
+               clear_bit(i, hdev->suspend_tasks);
+       wake_up(&hdev->suspend_wait_q);
+ }
  static int hci_suspend_wait_event(struct hci_dev *hdev)
  {
  #define WAKE_COND                                                              \
@@@ -3487,12 -3499,24 +3499,24 @@@ static int hci_change_suspend_state(str
        return hci_suspend_wait_event(hdev);
  }
  
+ static void hci_clear_wake_reason(struct hci_dev *hdev)
+ {
+       hci_dev_lock(hdev);
+       hdev->wake_reason = 0;
+       bacpy(&hdev->wake_addr, BDADDR_ANY);
+       hdev->wake_addr_type = 0;
+       hci_dev_unlock(hdev);
+ }
  static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
                                void *data)
  {
        struct hci_dev *hdev =
                container_of(nb, struct hci_dev, suspend_notifier);
        int ret = 0;
+       u8 state = BT_RUNNING;
  
        /* If powering down, wait for completion. */
        if (mgmt_powering_down(hdev)) {
                 *  - Second, program event filter/whitelist and enable scan
                 */
                ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT);
+               if (!ret)
+                       state = BT_SUSPEND_DISCONNECT;
  
                /* Only configure whitelist if disconnect succeeded and wake
                 * isn't being prevented.
                 */
-               if (!ret && !(hdev->prevent_wake && hdev->prevent_wake(hdev)))
+               if (!ret && !(hdev->prevent_wake && hdev->prevent_wake(hdev))) {
                        ret = hci_change_suspend_state(hdev,
                                                BT_SUSPEND_CONFIGURE_WAKE);
+                       if (!ret)
+                               state = BT_SUSPEND_CONFIGURE_WAKE;
+               }
+               hci_clear_wake_reason(hdev);
+               mgmt_suspending(hdev, state);
        } else if (action == PM_POST_SUSPEND) {
                ret = hci_change_suspend_state(hdev, BT_RUNNING);
+               mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr,
+                             hdev->wake_addr_type);
        }
  
  done:
@@@ -3784,6 -3820,7 +3820,7 @@@ void hci_unregister_dev(struct hci_dev 
  
        cancel_work_sync(&hdev->power_on);
  
+       hci_suspend_clear_tasks(hdev);
        unregister_pm_notifier(&hdev->suspend_notifier);
        cancel_work_sync(&hdev->suspend_prepare);
  
index 4b7fc430793cf6aca4554333fb5b0ccc698211bc,1df95145f574ecea1ee57b0c597d92058dd4e3c5..f04963914366e0aa0f35cec25c013a3d836a85fe
@@@ -1338,9 -1338,6 +1338,9 @@@ static void store_pending_adv_report(st
  {
        struct discovery_state *d = &hdev->discovery;
  
 +      if (len > HCI_MAX_AD_LENGTH)
 +              return;
 +
        bacpy(&d->last_adv_addr, bdaddr);
        d->last_adv_addr_type = bdaddr_type;
        d->last_adv_rssi = rssi;
@@@ -2569,7 -2566,6 +2569,6 @@@ static void hci_inquiry_result_evt(stru
  static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_conn_complete *ev = (void *) skb->data;
-       struct inquiry_entry *ie;
        struct hci_conn *conn;
  
        BT_DBG("%s", hdev->name);
  
        conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
        if (!conn) {
-               /* Connection may not exist if auto-connected. Check the inquiry
-                * cache to see if we've already discovered this bdaddr before.
-                * If found and link is an ACL type, create a connection class
+               /* Connection may not exist if auto-connected. Check the bredr
+                * allowlist to see if this device is allowed to auto connect.
+                * If link is an ACL type, create a connection class
                 * automatically.
+                *
+                * Auto-connect will only occur if the event filter is
+                * programmed with a given address. Right now, event filter is
+                * only used during suspend.
                 */
-               ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
-               if (ie && ev->link_type == ACL_LINK) {
+               if (ev->link_type == ACL_LINK &&
+                   hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
+                                                     &ev->bdaddr,
+                                                     BDADDR_BREDR)) {
                        conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr,
                                            HCI_ROLE_SLAVE);
                        if (!conn) {
@@@ -5382,8 -5384,7 +5387,8 @@@ static struct hci_conn *check_pending_l
  
  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
                               u8 bdaddr_type, bdaddr_t *direct_addr,
 -                             u8 direct_addr_type, s8 rssi, u8 *data, u8 len)
 +                             u8 direct_addr_type, s8 rssi, u8 *data, u8 len,
 +                             bool ext_adv)
  {
        struct discovery_state *d = &hdev->discovery;
        struct smp_irk *irk;
                return;
        }
  
 +      if (!ext_adv && len > HCI_MAX_AD_LENGTH) {
 +              bt_dev_err_ratelimited(hdev, "legacy adv larger than 31 bytes");
 +              return;
 +      }
 +
        /* Find the end of the data in case the report contains padded zero
         * bytes at the end causing an invalid length value.
         *
         */
        conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type,
                                                                direct_addr);
 -      if (conn && type == LE_ADV_IND) {
 +      if (!ext_adv && conn && type == LE_ADV_IND && len <= HCI_MAX_AD_LENGTH) {
                /* Store report for later inclusion by
                 * mgmt_device_connected
                 */
         * event or send an immediate device found event if the data
         * should not be stored for later.
         */
 -      if (!has_pending_adv_report(hdev)) {
 +      if (!ext_adv && !has_pending_adv_report(hdev)) {
                /* If the report will trigger a SCAN_REQ store it for
                 * later merging.
                 */
                /* If the new report will trigger a SCAN_REQ store it for
                 * later merging.
                 */
 -              if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
 +              if (!ext_adv && (type == LE_ADV_IND ||
 +                               type == LE_ADV_SCAN_IND)) {
                        store_pending_adv_report(hdev, bdaddr, bdaddr_type,
                                                 rssi, flags, data, len);
                        return;
@@@ -5601,7 -5596,7 +5606,7 @@@ static void hci_le_adv_report_evt(struc
                        rssi = ev->data[ev->length];
                        process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
                                           ev->bdaddr_type, NULL, 0, rssi,
 -                                         ev->data, ev->length);
 +                                         ev->data, ev->length, false);
                } else {
                        bt_dev_err(hdev, "Dropping invalid advertising data");
                }
@@@ -5673,8 -5668,7 +5678,8 @@@ static void hci_le_ext_adv_report_evt(s
                if (legacy_evt_type != LE_ADV_INVALID) {
                        process_adv_report(hdev, legacy_evt_type, &ev->bdaddr,
                                           ev->bdaddr_type, NULL, 0, ev->rssi,
 -                                         ev->data, ev->length);
 +                                         ev->data, ev->length,
 +                                         !(evt_type & LE_EXT_ADV_LEGACY_PDU));
                }
  
                ptr += sizeof(*ev) + ev->length;
@@@ -5872,8 -5866,7 +5877,8 @@@ static void hci_le_direct_adv_report_ev
  
                process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
                                   ev->bdaddr_type, &ev->direct_addr,
 -                                 ev->direct_addr_type, ev->rssi, NULL, 0);
 +                                 ev->direct_addr_type, ev->rssi, NULL, 0,
 +                                 false);
  
                ptr += sizeof(*ev);
        }
@@@ -6012,6 -6005,75 +6017,75 @@@ static bool hci_get_cmd_complete(struc
        return true;
  }
  
+ static void hci_store_wake_reason(struct hci_dev *hdev, u8 event,
+                                 struct sk_buff *skb)
+ {
+       struct hci_ev_le_advertising_info *adv;
+       struct hci_ev_le_direct_adv_info *direct_adv;
+       struct hci_ev_le_ext_adv_report *ext_adv;
+       const struct hci_ev_conn_complete *conn_complete = (void *)skb->data;
+       const struct hci_ev_conn_request *conn_request = (void *)skb->data;
+       hci_dev_lock(hdev);
+       /* If we are currently suspended and this is the first BT event seen,
+        * save the wake reason associated with the event.
+        */
+       if (!hdev->suspended || hdev->wake_reason)
+               goto unlock;
+       /* Default to remote wake. Values for wake_reason are documented in the
+        * Bluez mgmt api docs.
+        */
+       hdev->wake_reason = MGMT_WAKE_REASON_REMOTE_WAKE;
+       /* Once configured for remote wakeup, we should only wake up for
+        * reconnections. It's useful to see which device is waking us up so
+        * keep track of the bdaddr of the connection event that woke us up.
+        */
+       if (event == HCI_EV_CONN_REQUEST) {
+               bacpy(&hdev->wake_addr, &conn_complete->bdaddr);
+               hdev->wake_addr_type = BDADDR_BREDR;
+       } else if (event == HCI_EV_CONN_COMPLETE) {
+               bacpy(&hdev->wake_addr, &conn_request->bdaddr);
+               hdev->wake_addr_type = BDADDR_BREDR;
+       } else if (event == HCI_EV_LE_META) {
+               struct hci_ev_le_meta *le_ev = (void *)skb->data;
+               u8 subevent = le_ev->subevent;
+               u8 *ptr = &skb->data[sizeof(*le_ev)];
+               u8 num_reports = *ptr;
+               if ((subevent == HCI_EV_LE_ADVERTISING_REPORT ||
+                    subevent == HCI_EV_LE_DIRECT_ADV_REPORT ||
+                    subevent == HCI_EV_LE_EXT_ADV_REPORT) &&
+                   num_reports) {
+                       adv = (void *)(ptr + 1);
+                       direct_adv = (void *)(ptr + 1);
+                       ext_adv = (void *)(ptr + 1);
+                       switch (subevent) {
+                       case HCI_EV_LE_ADVERTISING_REPORT:
+                               bacpy(&hdev->wake_addr, &adv->bdaddr);
+                               hdev->wake_addr_type = adv->bdaddr_type;
+                               break;
+                       case HCI_EV_LE_DIRECT_ADV_REPORT:
+                               bacpy(&hdev->wake_addr, &direct_adv->bdaddr);
+                               hdev->wake_addr_type = direct_adv->bdaddr_type;
+                               break;
+                       case HCI_EV_LE_EXT_ADV_REPORT:
+                               bacpy(&hdev->wake_addr, &ext_adv->bdaddr);
+                               hdev->wake_addr_type = ext_adv->bdaddr_type;
+                               break;
+                       }
+               }
+       } else {
+               hdev->wake_reason = MGMT_WAKE_REASON_UNEXPECTED;
+       }
+ unlock:
+       hci_dev_unlock(hdev);
+ }
  void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_event_hdr *hdr = (void *) skb->data;
  
        skb_pull(skb, HCI_EVENT_HDR_SIZE);
  
+       /* Store wake reason if we're suspended */
+       hci_store_wake_reason(hdev, event, skb);
        switch (event) {
        case HCI_EV_INQUIRY_COMPLETE:
                hci_inquiry_complete_evt(hdev, skb);
This page took 0.145127 seconds and 4 git commands to generate.