diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index cb84a4288031..4c090d2a6eed 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2885,6 +2885,31 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n) return p; } +static struct conn_params *le_accept_list_copy(struct hci_dev *hdev, + size_t *n) +{ + struct bdaddr_list *entry; + struct conn_params *params; + size_t i = 0; + + hci_dev_lock(hdev); + + *n = list_count_nodes(&hdev->le_accept_list); + params = kvzalloc_objs(struct conn_params, *n); + if (!params) + goto unlock; + + list_for_each_entry(entry, &hdev->le_accept_list, list) { + bacpy(¶ms[i].addr, &entry->bdaddr); + params[i].addr_type = entry->bdaddr_type; + i++; + } + +unlock: + hci_dev_unlock(hdev); + return params; +} + /* Clear LE Accept List */ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) { @@ -2915,7 +2940,6 @@ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) static u8 hci_update_accept_list_sync(struct hci_dev *hdev) { struct conn_params *params; - struct bdaddr_list *b, *t; u8 num_entries = 0; bool pend_conn, pend_report; u8 filter_policy; @@ -2980,20 +3004,27 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * report. If not present in either list, then remove it from * the controller. */ - list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) { + params = le_accept_list_copy(hdev, &n); + if (!params) { + err = -ENOMEM; + goto done; + } + + for (i = 0; i < n; i++) { rcu_read_lock(); - if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) { + if (hci_conn_hash_lookup_le(hdev, ¶ms[i].addr, + params[i].addr_type)) { rcu_read_unlock(); continue; } pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, - b->bdaddr_type); - pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports, - &b->bdaddr, - b->bdaddr_type); + ¶ms[i].addr, + params[i].addr_type); + pend_report = hci_pend_le_action_lookup( + &hdev->pend_le_reports, ¶ms[i].addr, + params[i].addr_type); rcu_read_unlock(); @@ -3001,14 +3032,16 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * remove it from the acceptlist. */ if (!pend_conn && !pend_report) { - hci_le_del_accept_list_sync(hdev, &b->bdaddr, - b->bdaddr_type); + hci_le_del_accept_list_sync(hdev, ¶ms[i].addr, + params[i].addr_type); continue; } num_entries++; } + kvfree(params); + /* Since all no longer valid accept list entries have been * removed, walk through the list of pending connections * and ensure that any new device gets programmed into