Revert "Bluetooth: MGMT: Protect mgmt_pending list with its own lock"

This reverts commit bdd56875c6 which is
commit 6fe26f694c824b8a4dbf50c635bee1302e3f099c upstream.

It breaks the Android kernel abi and can be brought back in the future
in an abi-safe way if it is really needed.

Bug: 161946584
Change-Id: Icc2f278181cb94ad70d566cc655c8034e24c9156
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-07-03 09:14:46 +00:00
parent 2ed4312ac3
commit 6a12f866df
5 changed files with 59 additions and 80 deletions

View File

@@ -573,7 +573,6 @@ struct hci_dev {
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
struct list_head mesh_pending; struct list_head mesh_pending;
struct mutex mgmt_pending_lock;
struct list_head mgmt_pending; struct list_head mgmt_pending;
struct list_head reject_list; struct list_head reject_list;
struct list_head accept_list; struct list_head accept_list;

View File

@@ -2490,7 +2490,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock); mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock); mutex_init(&hdev->req_lock);
mutex_init(&hdev->mgmt_pending_lock);
ida_init(&hdev->unset_handle_ida); ida_init(&hdev->unset_handle_ida);

View File

@@ -1433,17 +1433,22 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
list_del(&cmd->list);
if (match->sk == NULL) { if (match->sk == NULL) {
match->sk = cmd->sk; match->sk = cmd->sk;
sock_hold(match->sk); sock_hold(match->sk);
} }
mgmt_pending_free(cmd);
} }
static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
{ {
u8 *status = data; u8 *status = data;
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status); mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
mgmt_pending_remove(cmd);
} }
static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
@@ -1457,6 +1462,8 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
if (cmd->cmd_complete) { if (cmd->cmd_complete) {
cmd->cmd_complete(cmd, match->mgmt_status); cmd->cmd_complete(cmd, match->mgmt_status);
mgmt_pending_remove(cmd);
return; return;
} }
@@ -1465,13 +1472,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
{ {
return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
cmd->param, cmd->param_len); cmd->param, cmd->param_len);
} }
static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
{ {
return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
cmd->param, sizeof(struct mgmt_addr_info)); cmd->param, sizeof(struct mgmt_addr_info));
} }
@@ -1511,7 +1518,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
goto done; goto done;
} }
@@ -1686,7 +1693,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
goto done; goto done;
} }
@@ -1923,8 +1930,8 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
new_settings(hdev, NULL); new_settings(hdev, NULL);
} }
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
cmd_status_rsp, &mgmt_err); &mgmt_err);
return; return;
} }
@@ -1934,7 +1941,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
} }
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
if (changed) if (changed)
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@@ -2054,12 +2061,12 @@ static void set_le_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp, mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
&status); &status);
return; return;
} }
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@@ -2118,7 +2125,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
struct sock *sk = cmd->sk; struct sock *sk = cmd->sk;
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true, mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev,
cmd_status_rsp, &status); cmd_status_rsp, &status);
return; return;
} }
@@ -2559,7 +2566,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err), hdev->dev_class, 3); mgmt_status(err), hdev->dev_class, 3);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@@ -3347,7 +3354,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
bacpy(&rp.addr.bdaddr, &conn->dst); bacpy(&rp.addr.bdaddr, &conn->dst);
rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE, err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
status, &rp, sizeof(rp)); status, &rp, sizeof(rp));
/* So we don't get further callbacks for this connection */ /* So we don't get further callbacks for this connection */
@@ -5236,7 +5243,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp)); mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
@@ -5451,7 +5458,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp)); mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@@ -5850,7 +5857,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev)) cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
return; return;
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
cmd->param, 1); cmd->param, 1);
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
@@ -6088,7 +6095,7 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
cmd->param, 1); cmd->param, 1);
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
@@ -6313,7 +6320,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
cmd_status_rsp, &status); cmd_status_rsp, &status);
return; return;
} }
@@ -6323,7 +6330,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
else else
hci_dev_clear_flag(hdev, HCI_ADVERTISING); hci_dev_clear_flag(hdev, HCI_ADVERTISING);
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp, mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
&match); &match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@@ -6667,7 +6674,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
*/ */
hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED); hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
} else { } else {
send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev); send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
@@ -6804,7 +6811,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
goto done; goto done;
} }
@@ -7251,7 +7258,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
rp.max_tx_power = HCI_TX_POWER_INVALID; rp.max_tx_power = HCI_TX_POWER_INVALID;
} }
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status, mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
&rp, sizeof(rp)); &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@@ -7411,7 +7418,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
} }
complete: complete:
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
sizeof(rp)); sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@@ -8615,10 +8622,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
add_adv_complete(hdev, cmd->sk, cp->instance, err); add_adv_complete(hdev, cmd->sk, cp->instance, err);
@@ -8806,10 +8813,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
hci_remove_adv_instance(hdev, cp->instance); hci_remove_adv_instance(hdev, cp->instance);
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
} else { } else {
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
} }
@@ -8957,10 +8964,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@@ -9119,10 +9126,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@@ -9393,7 +9400,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return; return;
mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
@@ -9431,8 +9438,7 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
&match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@@ -9447,8 +9453,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 zero_cod[] = { 0, 0, 0 }; u8 zero_cod[] = { 0, 0, 0 };
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
&match);
/* If the power off is because of hdev unregistration let /* If the power off is because of hdev unregistration let
* use the appropriate INVALID_INDEX status. Otherwise use * use the appropriate INVALID_INDEX status. Otherwise use
@@ -9462,7 +9467,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
else else
match.mgmt_status = MGMT_STATUS_NOT_POWERED; match.mgmt_status = MGMT_STATUS_NOT_POWERED;
mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
@@ -9703,6 +9708,7 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
cmd->cmd_complete(cmd, 0); cmd->cmd_complete(cmd, 0);
mgmt_pending_remove(cmd);
} }
bool mgmt_powering_down(struct hci_dev *hdev) bool mgmt_powering_down(struct hci_dev *hdev)
@@ -9755,8 +9761,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
struct mgmt_cp_disconnect *cp; struct mgmt_cp_disconnect *cp;
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true, mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
unpair_device_rsp, hdev); hdev);
cmd = pending_find(MGMT_OP_DISCONNECT, hdev); cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
if (!cmd) if (!cmd)
@@ -9949,7 +9955,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
if (status) { if (status) {
u8 mgmt_err = mgmt_status(status); u8 mgmt_err = mgmt_status(status);
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
cmd_status_rsp, &mgmt_err); cmd_status_rsp, &mgmt_err);
return; return;
} }
@@ -9959,8 +9965,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
else else
changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY); changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
settings_rsp, &match); &match);
if (changed) if (changed)
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@@ -9984,12 +9990,9 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
{ {
struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup, mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
&match); mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup, mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
&match);
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup,
&match);
if (!status) { if (!status) {
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,

View File

@@ -217,47 +217,30 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
struct hci_dev *hdev) struct hci_dev *hdev)
{ {
struct mgmt_pending_cmd *cmd, *tmp; struct mgmt_pending_cmd *cmd;
mutex_lock(&hdev->mgmt_pending_lock); list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
if (hci_sock_get_channel(cmd->sk) != channel) if (hci_sock_get_channel(cmd->sk) != channel)
continue; continue;
if (cmd->opcode == opcode)
if (cmd->opcode == opcode) {
mutex_unlock(&hdev->mgmt_pending_lock);
return cmd; return cmd;
} }
}
mutex_unlock(&hdev->mgmt_pending_lock);
return NULL; return NULL;
} }
void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
void *data) void *data)
{ {
struct mgmt_pending_cmd *cmd, *tmp; struct mgmt_pending_cmd *cmd, *tmp;
mutex_lock(&hdev->mgmt_pending_lock);
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
if (opcode > 0 && cmd->opcode != opcode) if (opcode > 0 && cmd->opcode != opcode)
continue; continue;
if (remove)
list_del(&cmd->list);
cb(cmd, data); cb(cmd, data);
if (remove)
mgmt_pending_free(cmd);
} }
mutex_unlock(&hdev->mgmt_pending_lock);
} }
struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
@@ -271,7 +254,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
return NULL; return NULL;
cmd->opcode = opcode; cmd->opcode = opcode;
cmd->hdev = hdev; cmd->index = hdev->id;
cmd->param = kmemdup(data, len, GFP_KERNEL); cmd->param = kmemdup(data, len, GFP_KERNEL);
if (!cmd->param) { if (!cmd->param) {
@@ -297,9 +280,7 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
if (!cmd) if (!cmd)
return NULL; return NULL;
mutex_lock(&hdev->mgmt_pending_lock);
list_add_tail(&cmd->list, &hdev->mgmt_pending); list_add_tail(&cmd->list, &hdev->mgmt_pending);
mutex_unlock(&hdev->mgmt_pending_lock);
return cmd; return cmd;
} }
@@ -313,10 +294,7 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
{ {
mutex_lock(&cmd->hdev->mgmt_pending_lock);
list_del(&cmd->list); list_del(&cmd->list);
mutex_unlock(&cmd->hdev->mgmt_pending_lock);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
} }

View File

@@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
struct mgmt_pending_cmd { struct mgmt_pending_cmd {
struct list_head list; struct list_head list;
u16 opcode; u16 opcode;
struct hci_dev *hdev; int index;
void *param; void *param;
size_t param_len; size_t param_len;
struct sock *sk; struct sock *sk;
@@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
struct hci_dev *hdev); struct hci_dev *hdev);
void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
void *data); void *data);
struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,