Bluetooth: Store advertising handle so it can be re-enabled
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 11 Aug 2021 23:20:16 +0000 (16:20 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Mon, 16 Aug 2021 15:53:48 +0000 (17:53 +0200)
This stores the advertising handle/instance into hci_conn so it is
accessible when re-enabling the advertising once disconnected.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_event.c

index a7d06d7..a7360c8 100644 (file)
@@ -629,6 +629,7 @@ struct hci_conn {
        __u8            init_addr_type;
        bdaddr_t        resp_addr;
        __u8            resp_addr_type;
+       __u8            adv_instance;
        __u16           handle;
        __u16           state;
        __u8            mode;
index a8a199c..1ee89d9 100644 (file)
@@ -2348,19 +2348,20 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
-               u8 type = conn->type;
-
                mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
                                       conn->dst_type, status);
 
+               if (conn->type == LE_LINK) {
+                       hdev->cur_adv_instance = conn->adv_instance;
+                       hci_req_reenable_advertising(hdev);
+               }
+
                /* If the disconnection failed for any reason, the upper layer
                 * does not retry to disconnect in current implementation.
                 * Hence, we need to do some basic cleanup here and re-enable
                 * advertising if necessary.
                 */
                hci_conn_del(conn);
-               if (type == LE_LINK)
-                       hci_req_reenable_advertising(hdev);
        }
 
        hci_dev_unlock(hdev);
@@ -2886,7 +2887,6 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        struct hci_conn_params *params;
        struct hci_conn *conn;
        bool mgmt_connected;
-       u8 type;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -2941,10 +2941,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                }
        }
 
-       type = conn->type;
-
        hci_disconn_cfm(conn, ev->reason);
-       hci_conn_del(conn);
 
        /* The suspend notifier is waiting for all devices to disconnect so
         * clear the bit from pending tasks and inform the wait queue.
@@ -2964,8 +2961,12 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
         * or until a connection is created or until the Advertising
         * is timed out due to Directed Advertising."
         */
-       if (type == LE_LINK)
+       if (conn->type == LE_LINK) {
+               hdev->cur_adv_instance = conn->adv_instance;
                hci_req_reenable_advertising(hdev);
+       }
+
+       hci_conn_del(conn);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -5323,6 +5324,13 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
        conn->handle = handle;
        conn->state = BT_CONFIG;
 
+       /* Store current advertising instance as connection advertising instance
+        * when sotfware rotation is in use so it can be re-enabled when
+        * disconnected.
+        */
+       if (!ext_adv_capable(hdev))
+               conn->adv_instance = hdev->cur_adv_instance;
+
        conn->le_conn_interval = interval;
        conn->le_conn_latency = latency;
        conn->le_supv_timeout = supervision_timeout;
@@ -5406,13 +5414,13 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_evt_le_ext_adv_set_term *ev = (void *) skb->data;
        struct hci_conn *conn;
+       struct adv_info *adv;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
-       if (ev->status) {
-               struct adv_info *adv;
+       adv = hci_find_adv_instance(hdev, ev->handle);
 
-               adv = hci_find_adv_instance(hdev, ev->handle);
+       if (ev->status) {
                if (!adv)
                        return;
 
@@ -5423,9 +5431,15 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
                return;
        }
 
+       if (adv)
+               adv->enabled = false;
+
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->conn_handle));
        if (conn) {
-               struct adv_info *adv_instance;
+               /* Store handle in the connection so the correct advertising
+                * instance can be re-enabled when disconnected.
+                */
+               conn->adv_instance = ev->handle;
 
                if (hdev->adv_addr_type != ADDR_LE_DEV_RANDOM ||
                    bacmp(&conn->resp_addr, BDADDR_ANY))
@@ -5436,9 +5450,8 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
                        return;
                }
 
-               adv_instance = hci_find_adv_instance(hdev, ev->handle);
-               if (adv_instance)
-                       bacpy(&conn->resp_addr, &adv_instance->random_addr);
+               if (adv)
+                       bacpy(&conn->resp_addr, &adv->random_addr);
        }
 }