]> exis.tech > repos - linux.git/blobdiff - net/bluetooth/hci_sync.c
Merge tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groec...
[linux.git] / net / bluetooth / hci_sync.c
index c896d4edd0133e3c1ff3304cd71c984372a22732..532534bc601c5a3b19d36c15f97f9ffb38516166 100644 (file)
@@ -1054,14 +1054,19 @@ static int hci_set_random_addr_sync(struct hci_dev *hdev, bdaddr_t *rpa)
         * In this kind of scenario skip the update and let the random
         * address be updated at the next cycle.
         */
+       rcu_read_lock();
+
        if (bacmp(&hdev->random_addr, BDADDR_ANY) &&
            (hci_dev_test_flag(hdev, HCI_LE_ADV) ||
            hci_lookup_le_connect(hdev))) {
                bt_dev_dbg(hdev, "Deferring random address update");
                hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
+               rcu_read_unlock();
                return 0;
        }
 
+       rcu_read_unlock();
+
        return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_RANDOM_ADDR,
                                     6, rpa, HCI_CMD_TIMEOUT);
 }
@@ -2647,12 +2652,17 @@ static int hci_pause_addr_resolution(struct hci_dev *hdev)
        /* Cannot disable addr resolution if scanning is enabled or
         * when initiating an LE connection.
         */
+       rcu_read_lock();
+
        if (hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
            hci_lookup_le_connect(hdev)) {
+               rcu_read_unlock();
                bt_dev_err(hdev, "Command not allowed when scan/LE connect");
                return -EPERM;
        }
 
+       rcu_read_unlock();
+
        /* Cannot disable addr resolution if advertising is enabled. */
        err = hci_pause_advertising_sync(hdev);
        if (err) {
@@ -2790,6 +2800,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
        if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
                struct hci_conn *conn;
 
+               rcu_read_lock();
+
                conn = hci_conn_hash_lookup_create_pa_sync(hdev);
                if (conn) {
                        struct conn_params pa;
@@ -2799,6 +2811,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
                        bacpy(&pa.addr, &conn->dst);
                        pa.addr_type = conn->dst_type;
 
+                       rcu_read_unlock();
+
                        /* Clear first since there could be addresses left
                         * behind.
                         */
@@ -2808,6 +2822,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
                        err = hci_le_add_accept_list_sync(hdev, &pa,
                                                          &num_entries);
                        goto done;
+               } else {
+                       rcu_read_unlock();
                }
        }
 
@@ -2818,10 +2834,13 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
         * the controller.
         */
        list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) {
-               if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type))
+               rcu_read_lock();
+
+               if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) {
+                       rcu_read_unlock();
                        continue;
+               }
 
-               /* Pointers not dereferenced, no locks needed */
                pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
                                                      &b->bdaddr,
                                                      b->bdaddr_type);
@@ -2829,6 +2848,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
                                                        &b->bdaddr,
                                                        b->bdaddr_type);
 
+               rcu_read_unlock();
+
                /* If the device is not likely to connect or report,
                 * remove it from the acceptlist.
                 */
@@ -2955,6 +2976,8 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
                if (sent) {
                        struct hci_conn *conn;
 
+                       rcu_read_lock();
+
                        conn = hci_conn_hash_lookup_ba(hdev, PA_LINK,
                                                       &sent->bdaddr);
                        if (conn) {
@@ -2979,8 +3002,12 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
                                        phy++;
                                }
 
+                               rcu_read_unlock();
+
                                if (num_phy)
                                        goto done;
+                       } else {
+                               rcu_read_unlock();
                        }
                }
        }
@@ -3231,12 +3258,16 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev)
                /* If there is at least one pending LE connection, we should
                 * keep the background scan running.
                 */
+               bool exists;
 
                /* If controller is connecting, we should not start scanning
                 * since some controllers are not able to scan and connect at
                 * the same time.
                 */
-               if (hci_lookup_le_connect(hdev))
+               rcu_read_lock();
+               exists = hci_lookup_le_connect(hdev);
+               rcu_read_unlock();
+               if (exists)
                        return 0;
 
                bt_dev_dbg(hdev, "start background scanning");
@@ -3454,6 +3485,7 @@ int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable)
 }
 
 static bool disconnected_accept_list_entries(struct hci_dev *hdev)
+       __must_hold(&hdev->lock)
 {
        struct bdaddr_list *b;
 
@@ -3494,12 +3526,16 @@ int hci_update_scan_sync(struct hci_dev *hdev)
        if (hdev->scanning_paused)
                return 0;
 
+       hci_dev_lock(hdev);
+
        if (hci_dev_test_flag(hdev, HCI_CONNECTABLE) ||
            disconnected_accept_list_entries(hdev))
                scan = SCAN_PAGE;
        else
                scan = SCAN_DISABLED;
 
+       hci_dev_unlock(hdev);
+
        if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
                scan |= SCAN_INQUIRY;
 
@@ -6665,6 +6701,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
        if (!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
                hci_pause_advertising_sync(hdev);
 
+       hci_dev_lock(hdev);
+
        params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
        if (params) {
                conn->le_conn_min_interval = params->conn_min_interval;
@@ -6678,6 +6716,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
                conn->le_supv_timeout = hdev->le_supv_timeout;
        }
 
+       hci_dev_unlock(hdev);
+
        /* If controller is scanning, we stop it since some controllers are
         * not able to scan and connect at the same time. Also set the
         * HCI_LE_SCAN_INTERRUPTED flag so that the command complete
@@ -7235,13 +7275,13 @@ unlock:
 }
 
 static int hci_le_past_params_sync(struct hci_dev *hdev, struct hci_conn *conn,
-                                  struct hci_conn *acl, struct bt_iso_qos *qos)
+                                  u16 acl_handle, struct bt_iso_qos *qos)
 {
        struct hci_cp_le_past_params cp;
        int err;
 
        memset(&cp, 0, sizeof(cp));
-       cp.handle = cpu_to_le16(acl->handle);
+       cp.handle = cpu_to_le16(acl_handle);
        /* An HCI_LE_Periodic_Advertising_Sync_Transfer_Received event is sent
         * to the Host. HCI_LE_Periodic_Advertising_Report events will be
         * enabled with duplicate filtering enabled.
@@ -7306,16 +7346,28 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
         * 2. Check if that HCI_CONN_FLAG_PAST has been set which indicates that
         *    user really intended to use PAST.
         */
+       hci_dev_lock(hdev);
+
        le = hci_conn_hash_lookup_le(hdev, &conn->dst, conn->dst_type);
        if (le) {
                struct hci_conn_params *params;
+               hci_conn_flags_t flags = 0;
+               u16 le_handle = le->handle;
 
                params = hci_conn_params_lookup(hdev, &le->dst, le->dst_type);
-               if (params && params->flags & HCI_CONN_FLAG_PAST) {
-                       err = hci_le_past_params_sync(hdev, conn, le, qos);
+               if (params)
+                       flags = params->flags;
+
+               hci_dev_unlock(hdev);
+
+               if (flags & HCI_CONN_FLAG_PAST) {
+                       err = hci_le_past_params_sync(hdev, conn, le_handle,
+                                                     qos);
                        if (!err)
                                goto done;
                }
+       } else {
+               hci_dev_unlock(hdev);
        }
 
        /* SID has not been set listen for HCI_EV_LE_EXT_ADV_REPORT to update