Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-net-2025-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

- MGMT: Fix UAF on mgmt_remove_adv_monitor_complete
- MGMT: Protect mgmt_pending list with its own lock
- hci_core: fix list_for_each_entry_rcu usage
- btintel_pcie: Increase the tx and rx descriptor count
- btintel_pcie: Reduce driver buffer posting to prevent race condition
- btintel_pcie: Fix driver not posting maximum rx buffers

* tag 'for-net-2025-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
Bluetooth: MGMT: Protect mgmt_pending list with its own lock
Bluetooth: MGMT: Fix UAF on mgmt_remove_adv_monitor_complete
Bluetooth: btintel_pcie: Reduce driver buffer posting to prevent race condition
Bluetooth: btintel_pcie: Increase the tx and rx descriptor count
Bluetooth: btintel_pcie: Fix driver not posting maximum rx buffers
Bluetooth: hci_core: fix list_for_each_entry_rcu usage
====================

Link: https://patch.msgid.link/20250605191136.904411-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+118 -115
+18 -13
drivers/bluetooth/btintel_pcie.c
··· 396 396 static int btintel_pcie_start_rx(struct btintel_pcie_data *data) 397 397 { 398 398 int i, ret; 399 + struct rxq *rxq = &data->rxq; 399 400 400 - for (i = 0; i < BTINTEL_PCIE_RX_MAX_QUEUE; i++) { 401 + /* Post (BTINTEL_PCIE_RX_DESCS_COUNT - 3) buffers to overcome the 402 + * hardware issues leading to race condition at the firmware. 403 + */ 404 + 405 + for (i = 0; i < rxq->count - 3; i++) { 401 406 ret = btintel_pcie_submit_rx(data); 402 407 if (ret) 403 408 return ret; ··· 1787 1782 * + size of index * Number of queues(2) * type of index array(4) 1788 1783 * + size of context information 1789 1784 */ 1790 - total = (sizeof(struct tfd) + sizeof(struct urbd0) + sizeof(struct frbd) 1791 - + sizeof(struct urbd1)) * BTINTEL_DESCS_COUNT; 1785 + total = (sizeof(struct tfd) + sizeof(struct urbd0)) * BTINTEL_PCIE_TX_DESCS_COUNT; 1786 + total += (sizeof(struct frbd) + sizeof(struct urbd1)) * BTINTEL_PCIE_RX_DESCS_COUNT; 1792 1787 1793 1788 /* Add the sum of size of index array and size of ci struct */ 1794 1789 total += (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4) + sizeof(struct ctx_info); ··· 1813 1808 data->dma_v_addr = v_addr; 1814 1809 1815 1810 /* Setup descriptor count */ 1816 - data->txq.count = BTINTEL_DESCS_COUNT; 1817 - data->rxq.count = BTINTEL_DESCS_COUNT; 1811 + data->txq.count = BTINTEL_PCIE_TX_DESCS_COUNT; 1812 + data->rxq.count = BTINTEL_PCIE_RX_DESCS_COUNT; 1818 1813 1819 1814 /* Setup tfds */ 1820 1815 data->txq.tfds_p_addr = p_addr; 1821 1816 data->txq.tfds = v_addr; 1822 1817 1823 - p_addr += (sizeof(struct tfd) * BTINTEL_DESCS_COUNT); 1824 - v_addr += (sizeof(struct tfd) * BTINTEL_DESCS_COUNT); 1818 + p_addr += (sizeof(struct tfd) * BTINTEL_PCIE_TX_DESCS_COUNT); 1819 + v_addr += (sizeof(struct tfd) * BTINTEL_PCIE_TX_DESCS_COUNT); 1825 1820 1826 1821 /* Setup urbd0 */ 1827 1822 data->txq.urbd0s_p_addr = p_addr; 1828 1823 data->txq.urbd0s = v_addr; 1829 1824 1830 - p_addr += (sizeof(struct urbd0) * BTINTEL_DESCS_COUNT); 1831 - v_addr += (sizeof(struct urbd0) * BTINTEL_DESCS_COUNT); 1825 + p_addr += (sizeof(struct urbd0) * BTINTEL_PCIE_TX_DESCS_COUNT); 1826 + v_addr += (sizeof(struct urbd0) * BTINTEL_PCIE_TX_DESCS_COUNT); 1832 1827 1833 1828 /* Setup FRBD*/ 1834 1829 data->rxq.frbds_p_addr = p_addr; 1835 1830 data->rxq.frbds = v_addr; 1836 1831 1837 - p_addr += (sizeof(struct frbd) * BTINTEL_DESCS_COUNT); 1838 - v_addr += (sizeof(struct frbd) * BTINTEL_DESCS_COUNT); 1832 + p_addr += (sizeof(struct frbd) * BTINTEL_PCIE_RX_DESCS_COUNT); 1833 + v_addr += (sizeof(struct frbd) * BTINTEL_PCIE_RX_DESCS_COUNT); 1839 1834 1840 1835 /* Setup urbd1 */ 1841 1836 data->rxq.urbd1s_p_addr = p_addr; 1842 1837 data->rxq.urbd1s = v_addr; 1843 1838 1844 - p_addr += (sizeof(struct urbd1) * BTINTEL_DESCS_COUNT); 1845 - v_addr += (sizeof(struct urbd1) * BTINTEL_DESCS_COUNT); 1839 + p_addr += (sizeof(struct urbd1) * BTINTEL_PCIE_RX_DESCS_COUNT); 1840 + v_addr += (sizeof(struct urbd1) * BTINTEL_PCIE_RX_DESCS_COUNT); 1846 1841 1847 1842 /* Setup data buffers for txq */ 1848 1843 err = btintel_pcie_setup_txq_bufs(data, &data->txq);
+5 -5
drivers/bluetooth/btintel_pcie.h
··· 154 154 /* Default interrupt timeout in msec */ 155 155 #define BTINTEL_DEFAULT_INTR_TIMEOUT_MS 3000 156 156 157 - /* The number of descriptors in TX/RX queues */ 158 - #define BTINTEL_DESCS_COUNT 16 157 + /* The number of descriptors in TX queues */ 158 + #define BTINTEL_PCIE_TX_DESCS_COUNT 32 159 + 160 + /* The number of descriptors in RX queues */ 161 + #define BTINTEL_PCIE_RX_DESCS_COUNT 64 159 162 160 163 /* Number of Queue for TX and RX 161 164 * It indicates the index of the IA(Index Array) ··· 179 176 180 177 /* Doorbell vector for TFD */ 181 178 #define BTINTEL_PCIE_TX_DB_VEC 0 182 - 183 - /* Number of pending RX requests for downlink */ 184 - #define BTINTEL_PCIE_RX_MAX_QUEUE 6 185 179 186 180 /* Doorbell vector for FRBD */ 187 181 #define BTINTEL_PCIE_RX_DB_VEC 513
+1 -1
include/net/bluetooth/hci_core.h
··· 546 546 struct hci_conn_hash conn_hash; 547 547 548 548 struct list_head mesh_pending; 549 + struct mutex mgmt_pending_lock; 549 550 struct list_head mgmt_pending; 550 551 struct list_head reject_list; 551 552 struct list_head accept_list; ··· 2401 2400 u8 instance); 2402 2401 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, 2403 2402 u8 instance); 2404 - void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); 2405 2403 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); 2406 2404 void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, 2407 2405 bdaddr_t *bdaddr, u8 addr_type);
+5 -11
net/bluetooth/hci_core.c
··· 1877 1877 if (monitor->handle) 1878 1878 idr_remove(&hdev->adv_monitors_idr, monitor->handle); 1879 1879 1880 - if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) { 1880 + if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) 1881 1881 hdev->adv_monitors_cnt--; 1882 - mgmt_adv_monitor_removed(hdev, monitor->handle); 1883 - } 1884 1882 1885 1883 kfree(monitor); 1886 1884 } ··· 2485 2487 2486 2488 mutex_init(&hdev->lock); 2487 2489 mutex_init(&hdev->req_lock); 2490 + mutex_init(&hdev->mgmt_pending_lock); 2488 2491 2489 2492 ida_init(&hdev->unset_handle_ida); 2490 2493 ··· 3416 3417 3417 3418 bt_dev_err(hdev, "link tx timeout"); 3418 3419 3419 - rcu_read_lock(); 3420 + hci_dev_lock(hdev); 3420 3421 3421 3422 /* Kill stalled connections */ 3422 - list_for_each_entry_rcu(c, &h->list, list) { 3423 + list_for_each_entry(c, &h->list, list) { 3423 3424 if (c->type == type && c->sent) { 3424 3425 bt_dev_err(hdev, "killing stalled connection %pMR", 3425 3426 &c->dst); 3426 - /* hci_disconnect might sleep, so, we have to release 3427 - * the RCU read lock before calling it. 3428 - */ 3429 - rcu_read_unlock(); 3430 3427 hci_disconnect(c, HCI_ERROR_REMOTE_USER_TERM); 3431 - rcu_read_lock(); 3432 3428 } 3433 3429 } 3434 3430 3435 - rcu_read_unlock(); 3431 + hci_dev_unlock(hdev); 3436 3432 } 3437 3433 3438 3434 static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+60 -78
net/bluetooth/mgmt.c
··· 1447 1447 1448 1448 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); 1449 1449 1450 - list_del(&cmd->list); 1451 - 1452 1450 if (match->sk == NULL) { 1453 1451 match->sk = cmd->sk; 1454 1452 sock_hold(match->sk); 1455 1453 } 1456 - 1457 - mgmt_pending_free(cmd); 1458 1454 } 1459 1455 1460 1456 static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) 1461 1457 { 1462 1458 u8 *status = data; 1463 1459 1464 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); 1465 - mgmt_pending_remove(cmd); 1460 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status); 1466 1461 } 1467 1462 1468 1463 static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) ··· 1471 1476 1472 1477 if (cmd->cmd_complete) { 1473 1478 cmd->cmd_complete(cmd, match->mgmt_status); 1474 - mgmt_pending_remove(cmd); 1475 - 1476 1479 return; 1477 1480 } 1478 1481 ··· 1479 1486 1480 1487 static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) 1481 1488 { 1482 - return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, 1489 + return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, 1483 1490 cmd->param, cmd->param_len); 1484 1491 } 1485 1492 1486 1493 static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) 1487 1494 { 1488 - return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, 1495 + return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, 1489 1496 cmd->param, sizeof(struct mgmt_addr_info)); 1490 1497 } 1491 1498 ··· 1525 1532 1526 1533 if (err) { 1527 1534 u8 mgmt_err = mgmt_status(err); 1528 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 1535 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 1529 1536 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); 1530 1537 goto done; 1531 1538 } ··· 1700 1707 1701 1708 if (err) { 1702 1709 u8 mgmt_err = mgmt_status(err); 1703 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 1710 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 1704 1711 goto done; 1705 1712 } 1706 1713 ··· 1936 1943 new_settings(hdev, NULL); 1937 1944 } 1938 1945 1939 - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, 1940 - &mgmt_err); 1946 + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, 1947 + cmd_status_rsp, &mgmt_err); 1941 1948 return; 1942 1949 } 1943 1950 ··· 1947 1954 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); 1948 1955 } 1949 1956 1950 - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); 1957 + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match); 1951 1958 1952 1959 if (changed) 1953 1960 new_settings(hdev, match.sk); ··· 2067 2074 bt_dev_dbg(hdev, "err %d", err); 2068 2075 2069 2076 if (status) { 2070 - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, 2071 - &status); 2077 + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp, 2078 + &status); 2072 2079 return; 2073 2080 } 2074 2081 2075 - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); 2082 + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match); 2076 2083 2077 2084 new_settings(hdev, match.sk); 2078 2085 ··· 2131 2138 struct sock *sk = cmd->sk; 2132 2139 2133 2140 if (status) { 2134 - mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, 2141 + mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true, 2135 2142 cmd_status_rsp, &status); 2136 2143 return; 2137 2144 } ··· 2631 2638 2632 2639 bt_dev_dbg(hdev, "err %d", err); 2633 2640 2634 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 2641 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 2635 2642 mgmt_status(err), hdev->dev_class, 3); 2636 2643 2637 2644 mgmt_pending_free(cmd); ··· 3420 3427 bacpy(&rp.addr.bdaddr, &conn->dst); 3421 3428 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); 3422 3429 3423 - err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, 3430 + err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE, 3424 3431 status, &rp, sizeof(rp)); 3425 3432 3426 3433 /* So we don't get further callbacks for this connection */ ··· 5101 5108 mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk); 5102 5109 } 5103 5110 5104 - void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle) 5111 + static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev, 5112 + u16 handle) 5105 5113 { 5106 5114 struct mgmt_ev_adv_monitor_removed ev; 5107 - struct mgmt_pending_cmd *cmd; 5108 - struct sock *sk_skip = NULL; 5109 - struct mgmt_cp_remove_adv_monitor *cp; 5110 - 5111 - cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); 5112 - if (cmd) { 5113 - cp = cmd->param; 5114 - 5115 - if (cp->monitor_handle) 5116 - sk_skip = cmd->sk; 5117 - } 5118 5115 5119 5116 ev.monitor_handle = cpu_to_le16(handle); 5120 5117 5121 - mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip); 5118 + mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk); 5122 5119 } 5123 5120 5124 5121 static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, ··· 5179 5196 hci_update_passive_scan(hdev); 5180 5197 } 5181 5198 5182 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 5199 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 5183 5200 mgmt_status(status), &rp, sizeof(rp)); 5184 5201 mgmt_pending_remove(cmd); 5185 5202 ··· 5210 5227 5211 5228 if (pending_find(MGMT_OP_SET_LE, hdev) || 5212 5229 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || 5213 - pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) || 5214 - pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) { 5230 + pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) { 5215 5231 status = MGMT_STATUS_BUSY; 5216 5232 goto unlock; 5217 5233 } ··· 5380 5398 struct mgmt_pending_cmd *cmd = data; 5381 5399 struct mgmt_cp_remove_adv_monitor *cp; 5382 5400 5383 - if (status == -ECANCELED || 5384 - cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) 5401 + if (status == -ECANCELED) 5385 5402 return; 5386 5403 5387 5404 hci_dev_lock(hdev); ··· 5389 5408 5390 5409 rp.monitor_handle = cp->monitor_handle; 5391 5410 5392 - if (!status) 5411 + if (!status) { 5412 + mgmt_adv_monitor_removed(cmd->sk, hdev, cp->monitor_handle); 5393 5413 hci_update_passive_scan(hdev); 5414 + } 5394 5415 5395 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 5416 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 5396 5417 mgmt_status(status), &rp, sizeof(rp)); 5397 - mgmt_pending_remove(cmd); 5418 + mgmt_pending_free(cmd); 5398 5419 5399 5420 hci_dev_unlock(hdev); 5400 5421 bt_dev_dbg(hdev, "remove monitor %d complete, status %d", ··· 5406 5423 static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data) 5407 5424 { 5408 5425 struct mgmt_pending_cmd *cmd = data; 5409 - 5410 - if (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) 5411 - return -ECANCELED; 5412 - 5413 5426 struct mgmt_cp_remove_adv_monitor *cp = cmd->param; 5414 5427 u16 handle = __le16_to_cpu(cp->monitor_handle); 5415 5428 ··· 5424 5445 hci_dev_lock(hdev); 5425 5446 5426 5447 if (pending_find(MGMT_OP_SET_LE, hdev) || 5427 - pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) || 5428 5448 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || 5429 5449 pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) { 5430 5450 status = MGMT_STATUS_BUSY; 5431 5451 goto unlock; 5432 5452 } 5433 5453 5434 - cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); 5454 + cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); 5435 5455 if (!cmd) { 5436 5456 status = MGMT_STATUS_NO_RESOURCES; 5437 5457 goto unlock; ··· 5440 5462 mgmt_remove_adv_monitor_complete); 5441 5463 5442 5464 if (err) { 5443 - mgmt_pending_remove(cmd); 5465 + mgmt_pending_free(cmd); 5444 5466 5445 5467 if (err == -ENOMEM) 5446 5468 status = MGMT_STATUS_NO_RESOURCES; ··· 5770 5792 cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev)) 5771 5793 return; 5772 5794 5773 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), 5795 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), 5774 5796 cmd->param, 1); 5775 5797 mgmt_pending_remove(cmd); 5776 5798 ··· 5991 6013 5992 6014 bt_dev_dbg(hdev, "err %d", err); 5993 6015 5994 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), 6016 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), 5995 6017 cmd->param, 1); 5996 6018 mgmt_pending_remove(cmd); 5997 6019 ··· 6216 6238 u8 status = mgmt_status(err); 6217 6239 6218 6240 if (status) { 6219 - mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, 6241 + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, 6220 6242 cmd_status_rsp, &status); 6221 6243 return; 6222 6244 } ··· 6226 6248 else 6227 6249 hci_dev_clear_flag(hdev, HCI_ADVERTISING); 6228 6250 6229 - mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, 6251 + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp, 6230 6252 &match); 6231 6253 6232 6254 new_settings(hdev, match.sk); ··· 6570 6592 */ 6571 6593 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED); 6572 6594 6573 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 6595 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 6574 6596 } else { 6575 6597 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev); 6576 6598 new_settings(hdev, cmd->sk); ··· 6707 6729 if (err) { 6708 6730 u8 mgmt_err = mgmt_status(err); 6709 6731 6710 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 6732 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 6711 6733 goto done; 6712 6734 } 6713 6735 ··· 7154 7176 rp.max_tx_power = HCI_TX_POWER_INVALID; 7155 7177 } 7156 7178 7157 - mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, 7179 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status, 7158 7180 &rp, sizeof(rp)); 7159 7181 7160 7182 mgmt_pending_free(cmd); ··· 7314 7336 } 7315 7337 7316 7338 complete: 7317 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, 7339 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp, 7318 7340 sizeof(rp)); 7319 7341 7320 7342 mgmt_pending_free(cmd); ··· 8564 8586 rp.instance = cp->instance; 8565 8587 8566 8588 if (err) 8567 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 8589 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 8568 8590 mgmt_status(err)); 8569 8591 else 8570 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 8592 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 8571 8593 mgmt_status(err), &rp, sizeof(rp)); 8572 8594 8573 8595 add_adv_complete(hdev, cmd->sk, cp->instance, err); ··· 8755 8777 8756 8778 hci_remove_adv_instance(hdev, cp->instance); 8757 8779 8758 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 8780 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 8759 8781 mgmt_status(err)); 8760 8782 } else { 8761 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 8783 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 8762 8784 mgmt_status(err), &rp, sizeof(rp)); 8763 8785 } 8764 8786 ··· 8905 8927 rp.instance = cp->instance; 8906 8928 8907 8929 if (err) 8908 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 8930 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 8909 8931 mgmt_status(err)); 8910 8932 else 8911 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 8933 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 8912 8934 mgmt_status(err), &rp, sizeof(rp)); 8913 8935 8914 8936 mgmt_pending_free(cmd); ··· 9067 9089 rp.instance = cp->instance; 9068 9090 9069 9091 if (err) 9070 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 9092 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 9071 9093 mgmt_status(err)); 9072 9094 else 9073 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 9095 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 9074 9096 MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); 9075 9097 9076 9098 mgmt_pending_free(cmd); ··· 9342 9364 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) 9343 9365 return; 9344 9366 9345 - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); 9367 + mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); 9346 9368 9347 9369 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { 9348 9370 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, ··· 9380 9402 hci_update_passive_scan(hdev); 9381 9403 } 9382 9404 9383 - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); 9405 + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, 9406 + &match); 9384 9407 9385 9408 new_settings(hdev, match.sk); 9386 9409 ··· 9396 9417 struct cmd_lookup match = { NULL, hdev }; 9397 9418 u8 zero_cod[] = { 0, 0, 0 }; 9398 9419 9399 - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); 9420 + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, 9421 + &match); 9400 9422 9401 9423 /* If the power off is because of hdev unregistration let 9402 9424 * use the appropriate INVALID_INDEX status. Otherwise use ··· 9411 9431 else 9412 9432 match.mgmt_status = MGMT_STATUS_NOT_POWERED; 9413 9433 9414 - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); 9434 + mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); 9415 9435 9416 9436 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { 9417 9437 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, ··· 9652 9672 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); 9653 9673 9654 9674 cmd->cmd_complete(cmd, 0); 9655 - mgmt_pending_remove(cmd); 9656 9675 } 9657 9676 9658 9677 bool mgmt_powering_down(struct hci_dev *hdev) ··· 9707 9728 struct mgmt_cp_disconnect *cp; 9708 9729 struct mgmt_pending_cmd *cmd; 9709 9730 9710 - mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, 9711 - hdev); 9731 + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true, 9732 + unpair_device_rsp, hdev); 9712 9733 9713 9734 cmd = pending_find(MGMT_OP_DISCONNECT, hdev); 9714 9735 if (!cmd) ··· 9901 9922 9902 9923 if (status) { 9903 9924 u8 mgmt_err = mgmt_status(status); 9904 - mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, 9925 + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, 9905 9926 cmd_status_rsp, &mgmt_err); 9906 9927 return; 9907 9928 } ··· 9911 9932 else 9912 9933 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY); 9913 9934 9914 - mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, 9915 - &match); 9935 + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, 9936 + settings_rsp, &match); 9916 9937 9917 9938 if (changed) 9918 9939 new_settings(hdev, match.sk); ··· 9936 9957 { 9937 9958 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; 9938 9959 9939 - mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match); 9940 - mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match); 9941 - mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match); 9960 + mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup, 9961 + &match); 9962 + mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup, 9963 + &match); 9964 + mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup, 9965 + &match); 9942 9966 9943 9967 if (!status) { 9944 9968 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
+27 -5
net/bluetooth/mgmt_util.c
··· 217 217 struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, 218 218 struct hci_dev *hdev) 219 219 { 220 - struct mgmt_pending_cmd *cmd; 220 + struct mgmt_pending_cmd *cmd, *tmp; 221 221 222 - list_for_each_entry(cmd, &hdev->mgmt_pending, list) { 222 + mutex_lock(&hdev->mgmt_pending_lock); 223 + 224 + list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { 223 225 if (hci_sock_get_channel(cmd->sk) != channel) 224 226 continue; 225 - if (cmd->opcode == opcode) 227 + 228 + if (cmd->opcode == opcode) { 229 + mutex_unlock(&hdev->mgmt_pending_lock); 226 230 return cmd; 231 + } 227 232 } 233 + 234 + mutex_unlock(&hdev->mgmt_pending_lock); 228 235 229 236 return NULL; 230 237 } 231 238 232 - void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 239 + void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, 233 240 void (*cb)(struct mgmt_pending_cmd *cmd, void *data), 234 241 void *data) 235 242 { 236 243 struct mgmt_pending_cmd *cmd, *tmp; 237 244 245 + mutex_lock(&hdev->mgmt_pending_lock); 246 + 238 247 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { 239 248 if (opcode > 0 && cmd->opcode != opcode) 240 249 continue; 241 250 251 + if (remove) 252 + list_del(&cmd->list); 253 + 242 254 cb(cmd, data); 255 + 256 + if (remove) 257 + mgmt_pending_free(cmd); 243 258 } 259 + 260 + mutex_unlock(&hdev->mgmt_pending_lock); 244 261 } 245 262 246 263 struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, ··· 271 254 return NULL; 272 255 273 256 cmd->opcode = opcode; 274 - cmd->index = hdev->id; 257 + cmd->hdev = hdev; 275 258 276 259 cmd->param = kmemdup(data, len, GFP_KERNEL); 277 260 if (!cmd->param) { ··· 297 280 if (!cmd) 298 281 return NULL; 299 282 283 + mutex_lock(&hdev->mgmt_pending_lock); 300 284 list_add_tail(&cmd->list, &hdev->mgmt_pending); 285 + mutex_unlock(&hdev->mgmt_pending_lock); 301 286 302 287 return cmd; 303 288 } ··· 313 294 314 295 void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) 315 296 { 297 + mutex_lock(&cmd->hdev->mgmt_pending_lock); 316 298 list_del(&cmd->list); 299 + mutex_unlock(&cmd->hdev->mgmt_pending_lock); 300 + 317 301 mgmt_pending_free(cmd); 318 302 } 319 303
+2 -2
net/bluetooth/mgmt_util.h
··· 33 33 struct mgmt_pending_cmd { 34 34 struct list_head list; 35 35 u16 opcode; 36 - int index; 36 + struct hci_dev *hdev; 37 37 void *param; 38 38 size_t param_len; 39 39 struct sock *sk; ··· 54 54 55 55 struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, 56 56 struct hci_dev *hdev); 57 - void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 57 + void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, 58 58 void (*cb)(struct mgmt_pending_cmd *cmd, void *data), 59 59 void *data); 60 60 struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,