summaryrefslogtreecommitdiff
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c453
1 files changed, 291 insertions, 162 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 1ce682038b51..c11cdef42b6f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -852,6 +852,12 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (ll_privacy_capable(hdev))
settings |= MGMT_SETTING_LL_PRIVACY;
+ if (past_sender_capable(hdev))
+ settings |= MGMT_SETTING_PAST_SENDER;
+
+ if (past_receiver_capable(hdev))
+ settings |= MGMT_SETTING_PAST_RECEIVER;
+
settings |= MGMT_SETTING_PHY_CONFIGURATION;
return settings;
@@ -922,21 +928,27 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED))
settings |= MGMT_SETTING_WIDEBAND_SPEECH;
- if (cis_central_capable(hdev))
+ if (cis_central_enabled(hdev))
settings |= MGMT_SETTING_CIS_CENTRAL;
- if (cis_peripheral_capable(hdev))
+ if (cis_peripheral_enabled(hdev))
settings |= MGMT_SETTING_CIS_PERIPHERAL;
- if (bis_capable(hdev))
+ if (bis_enabled(hdev))
settings |= MGMT_SETTING_ISO_BROADCASTER;
- if (sync_recv_capable(hdev))
+ if (sync_recv_enabled(hdev))
settings |= MGMT_SETTING_ISO_SYNC_RECEIVER;
- if (ll_privacy_capable(hdev))
+ if (ll_privacy_enabled(hdev))
settings |= MGMT_SETTING_LL_PRIVACY;
+ if (past_sender_enabled(hdev))
+ settings |= MGMT_SETTING_PAST_SENDER;
+
+ if (past_receiver_enabled(hdev))
+ settings |= MGMT_SETTING_PAST_RECEIVER;
+
return settings;
}
@@ -1323,8 +1335,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
struct mgmt_mode *cp;
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
cp = cmd->param;
@@ -1351,23 +1362,29 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
mgmt_status(err));
}
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int set_powered_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp;
+ struct mgmt_mode cp;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
/* Make sure cmd still outstanding. */
- if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
+ }
- cp = cmd->param;
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
BT_DBG("%s", hdev->name);
- return hci_set_powered_sync(hdev, cp->val);
+ return hci_set_powered_sync(hdev, cp.val);
}
static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -1516,8 +1533,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
hci_dev_lock(hdev);
@@ -1539,12 +1555,15 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk);
done:
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
hci_dev_unlock(hdev);
}
static int set_discoverable_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
BT_DBG("%s", hdev->name);
return hci_update_discoverable_sync(hdev);
@@ -1691,8 +1710,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
hci_dev_lock(hdev);
@@ -1707,7 +1725,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk);
done:
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
hci_dev_unlock(hdev);
}
@@ -1743,6 +1761,9 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
static int set_connectable_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
BT_DBG("%s", hdev->name);
return hci_update_connectable_sync(hdev);
@@ -1919,14 +1940,17 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
{
struct cmd_lookup match = { NULL, hdev };
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
- u8 enable = cp->val;
+ struct mgmt_mode *cp;
+ u8 enable;
bool changed;
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED || cmd != pending_find(MGMT_OP_SET_SSP, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
+ cp = cmd->param;
+ enable = cp->val;
+
if (err) {
u8 mgmt_err = mgmt_status(err);
@@ -1935,8 +1959,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
new_settings(hdev, NULL);
}
- mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true,
- cmd_status_rsp, &mgmt_err);
+ mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
return;
}
@@ -1946,7 +1969,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);
}
- mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match);
+ settings_rsp(cmd, &match);
if (changed)
new_settings(hdev, match.sk);
@@ -1960,14 +1983,25 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
static int set_ssp_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
+ struct mgmt_mode cp;
bool changed = false;
int err;
- if (cp->val)
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ if (cp.val)
changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
- err = hci_write_ssp_mode_sync(hdev, cp->val);
+ err = hci_write_ssp_mode_sync(hdev, cp.val);
if (!err && changed)
hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
@@ -2060,32 +2094,50 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
static void set_le_complete(struct hci_dev *hdev, void *data, int err)
{
+ struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev };
u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err);
- if (status) {
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp,
- &status);
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
return;
+
+ if (status) {
+ mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
+ goto done;
}
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match);
+ settings_rsp(cmd, &match);
new_settings(hdev, match.sk);
if (match.sk)
sock_put(match.sk);
+
+done:
+ mgmt_pending_free(cmd);
}
static int set_le_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
- u8 val = !!cp->val;
+ struct mgmt_mode cp;
+ u8 val;
int err;
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+ val = !!cp.val;
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
if (!val) {
hci_clear_adv_instance_sync(hdev, NULL, 0x00, true);
@@ -2127,23 +2179,45 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
u8 status = mgmt_status(err);
- struct sock *sk = cmd->sk;
+ struct sock *sk;
+
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
+ return;
+
+ sk = cmd->sk;
if (status) {
+ mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
+ status);
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
cmd_status_rsp, &status);
- return;
+ goto done;
}
- mgmt_pending_remove(cmd);
mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0);
+
+done:
+ mgmt_pending_free(cmd);
}
static int set_mesh_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_cp_set_mesh *cp = cmd->param;
- size_t len = cmd->param_len;
+ DEFINE_FLEX(struct mgmt_cp_set_mesh, cp, ad_types, num_ad_types,
+ sizeof(hdev->mesh_ad_types));
+ size_t len;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ len = cmd->param_len;
+ memcpy(cp, cmd->param, min(__struct_size(cp), len));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
@@ -2155,7 +2229,7 @@ static int set_mesh_sync(struct hci_dev *hdev, void *data)
hdev->le_scan_interval = __le16_to_cpu(cp->period);
hdev->le_scan_window = __le16_to_cpu(cp->window);
- len -= sizeof(*cp);
+ len -= sizeof(struct mgmt_cp_set_mesh);
/* If filters don't fit, forward all adv pkts */
if (len <= sizeof(hdev->mesh_ad_types))
@@ -3867,15 +3941,16 @@ static int name_changed_sync(struct hci_dev *hdev, void *data)
static void set_name_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_cp_set_local_name *cp = cmd->param;
+ struct mgmt_cp_set_local_name *cp;
u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err);
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
+ cp = cmd->param;
+
if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
status);
@@ -3887,13 +3962,27 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
}
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int set_name_sync(struct hci_dev *hdev, void *data)
{
+ struct mgmt_pending_cmd *cmd = data;
+ struct mgmt_cp_set_local_name cp;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
if (lmp_bredr_capable(hdev)) {
- hci_update_name_sync(hdev);
+ hci_update_name_sync(hdev, cp.name);
hci_update_eir_sync(hdev);
}
@@ -4045,12 +4134,10 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
- struct sk_buff *skb = cmd->skb;
+ struct sk_buff *skb;
u8 status = mgmt_status(err);
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev))
- return;
+ skb = cmd->skb;
if (!status) {
if (!skb)
@@ -4077,7 +4164,7 @@ static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
if (skb && !IS_ERR(skb))
kfree_skb(skb);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int set_default_phy_sync(struct hci_dev *hdev, void *data)
@@ -4085,7 +4172,9 @@ static int set_default_phy_sync(struct hci_dev *hdev, void *data)
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_phy_configuration *cp = cmd->param;
struct hci_cp_le_set_default_phy cp_phy;
- u32 selected_phys = __le32_to_cpu(cp->selected_phys);
+ u32 selected_phys;
+
+ selected_phys = __le32_to_cpu(cp->selected_phys);
memset(&cp_phy, 0, sizeof(cp_phy));
@@ -4225,7 +4314,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
+ cmd = mgmt_pending_new(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
len);
if (!cmd)
err = -ENOMEM;
@@ -4469,13 +4558,11 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
return -ENOMEM;
#ifdef CONFIG_BT_FEATURE_DEBUG
- if (!hdev) {
- flags = bt_dbg_get() ? BIT(0) : 0;
+ flags = bt_dbg_get() ? BIT(0) : 0;
- memcpy(rp->features[idx].uuid, debug_uuid, 16);
- rp->features[idx].flags = cpu_to_le32(flags);
- idx++;
- }
+ memcpy(rp->features[idx].uuid, debug_uuid, 16);
+ rp->features[idx].flags = cpu_to_le32(flags);
+ idx++;
#endif
if (hdev && hci_dev_le_state_simultaneous(hdev)) {
@@ -4513,7 +4600,7 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
}
if (IS_ENABLED(CONFIG_BT_LE)) {
- flags = iso_enabled() ? BIT(0) : 0;
+ flags = iso_inited() ? BIT(0) : 0;
memcpy(rp->features[idx].uuid, iso_socket_uuid, 16);
rp->features[idx].flags = cpu_to_le32(flags);
idx++;
@@ -5035,6 +5122,69 @@ static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
}
+static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
+{
+ struct hci_conn *conn;
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
+ if (!conn)
+ return false;
+
+ if (conn->dst_type != type)
+ return false;
+
+ if (conn->state != BT_CONNECTED)
+ return false;
+
+ return true;
+}
+
+/* This function requires the caller holds hdev->lock */
+static struct hci_conn_params *hci_conn_params_set(struct hci_dev *hdev,
+ bdaddr_t *addr, u8 addr_type,
+ u8 auto_connect)
+{
+ struct hci_conn_params *params;
+
+ params = hci_conn_params_add(hdev, addr, addr_type);
+ if (!params)
+ return NULL;
+
+ if (params->auto_connect == auto_connect)
+ return params;
+
+ hci_pend_le_list_del_init(params);
+
+ switch (auto_connect) {
+ case HCI_AUTO_CONN_DISABLED:
+ case HCI_AUTO_CONN_LINK_LOSS:
+ /* If auto connect is being disabled when we're trying to
+ * connect to device, keep connecting.
+ */
+ if (params->explicit_connect)
+ hci_pend_le_list_add(params, &hdev->pend_le_conns);
+ break;
+ case HCI_AUTO_CONN_REPORT:
+ if (params->explicit_connect)
+ hci_pend_le_list_add(params, &hdev->pend_le_conns);
+ else
+ hci_pend_le_list_add(params, &hdev->pend_le_reports);
+ break;
+ case HCI_AUTO_CONN_DIRECT:
+ case HCI_AUTO_CONN_ALWAYS:
+ if (!is_connected(hdev, addr, addr_type))
+ hci_pend_le_list_add(params, &hdev->pend_le_conns);
+ break;
+ }
+
+ params->auto_connect = auto_connect;
+
+ bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
+ addr, addr_type, auto_connect);
+
+ return params;
+}
+
static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
@@ -5078,9 +5228,16 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (!params) {
- bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
- &cp->addr.bdaddr, le_addr_type(cp->addr.type));
- goto unlock;
+ /* Create a new hci_conn_params if it doesn't exist */
+ params = hci_conn_params_set(hdev, &cp->addr.bdaddr,
+ le_addr_type(cp->addr.type),
+ HCI_AUTO_CONN_DISABLED);
+ if (!params) {
+ bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
+ &cp->addr.bdaddr,
+ le_addr_type(cp->addr.type));
+ goto unlock;
+ }
}
supported_flags = hdev->conn_flags;
@@ -5186,7 +5343,17 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
{
struct mgmt_rp_add_adv_patterns_monitor rp;
struct mgmt_pending_cmd *cmd = data;
- struct adv_monitor *monitor = cmd->user_data;
+ struct adv_monitor *monitor;
+
+ /* This is likely the result of hdev being closed and mgmt_index_removed
+ * is attempting to clean up any pending command so
+ * hci_adv_monitors_clear is about to be called which will take care of
+ * freeing the adv_monitor instances.
+ */
+ if (status == -ECANCELED && !mgmt_pending_valid(hdev, cmd))
+ return;
+
+ monitor = cmd->user_data;
hci_dev_lock(hdev);
@@ -5212,9 +5379,20 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct adv_monitor *monitor = cmd->user_data;
+ struct adv_monitor *mon;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
- return hci_add_adv_monitor(hdev, monitor);
+ mon = cmd->user_data;
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ return hci_add_adv_monitor(hdev, mon);
}
static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
@@ -5299,9 +5477,9 @@ static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
for (i = 0; i < pattern_count; i++) {
offset = patterns[i].offset;
length = patterns[i].length;
- if (offset >= HCI_MAX_EXT_AD_LENGTH ||
- length > HCI_MAX_EXT_AD_LENGTH ||
- (offset + length) > HCI_MAX_EXT_AD_LENGTH)
+ if (offset >= HCI_MAX_AD_LENGTH ||
+ length > HCI_MAX_AD_LENGTH ||
+ (offset + length) > HCI_MAX_AD_LENGTH)
return MGMT_STATUS_INVALID_PARAMS;
p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -5481,7 +5659,8 @@ unlock:
status);
}
-static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err)
+static void read_local_oob_data_complete(struct hci_dev *hdev, void *data,
+ int err)
{
struct mgmt_rp_read_local_oob_data mgmt_rp;
size_t rp_size = sizeof(mgmt_rp);
@@ -5501,7 +5680,8 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int e
bt_dev_dbg(hdev, "status %d", status);
if (status) {
- mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status);
+ mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+ status);
goto remove;
}
@@ -5783,17 +5963,12 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
- if (err == -ECANCELED)
- return;
-
- if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) &&
- cmd != pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev) &&
- cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
DISCOVERY_FINDING);
@@ -5801,6 +5976,9 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int start_discovery_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
return hci_start_discovery_sync(hdev);
}
@@ -6006,15 +6184,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
if (!err)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
@@ -6022,6 +6199,9 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int stop_discovery_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
return hci_stop_discovery_sync(hdev);
}
@@ -6231,14 +6411,18 @@ static void enable_advertising_instance(struct hci_dev *hdev, int err)
static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
{
+ struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev };
u8 instance;
struct adv_info *adv_instance;
u8 status = mgmt_status(err);
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
+ return;
+
if (status) {
- mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true,
- cmd_status_rsp, &status);
+ mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
+ mgmt_pending_free(cmd);
return;
}
@@ -6247,8 +6431,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING);
- mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp,
- &match);
+ settings_rsp(cmd, &match);
new_settings(hdev, match.sk);
@@ -6280,10 +6463,23 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
static int set_adv_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
- u8 val = !!cp->val;
+ struct mgmt_mode cp;
+ u8 val;
- if (cp->val == 0x02)
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ val = !!cp.val;
+
+ if (cp.val == 0x02)
hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
@@ -7428,68 +7624,6 @@ unlock:
return err;
}
-static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
-{
- struct hci_conn *conn;
-
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
- if (!conn)
- return false;
-
- if (conn->dst_type != type)
- return false;
-
- if (conn->state != BT_CONNECTED)
- return false;
-
- return true;
-}
-
-/* This function requires the caller holds hdev->lock */
-static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
- u8 addr_type, u8 auto_connect)
-{
- struct hci_conn_params *params;
-
- params = hci_conn_params_add(hdev, addr, addr_type);
- if (!params)
- return -EIO;
-
- if (params->auto_connect == auto_connect)
- return 0;
-
- hci_pend_le_list_del_init(params);
-
- switch (auto_connect) {
- case HCI_AUTO_CONN_DISABLED:
- case HCI_AUTO_CONN_LINK_LOSS:
- /* If auto connect is being disabled when we're trying to
- * connect to device, keep connecting.
- */
- if (params->explicit_connect)
- hci_pend_le_list_add(params, &hdev->pend_le_conns);
- break;
- case HCI_AUTO_CONN_REPORT:
- if (params->explicit_connect)
- hci_pend_le_list_add(params, &hdev->pend_le_conns);
- else
- hci_pend_le_list_add(params, &hdev->pend_le_reports);
- break;
- case HCI_AUTO_CONN_DIRECT:
- case HCI_AUTO_CONN_ALWAYS:
- if (!is_connected(hdev, addr, addr_type))
- hci_pend_le_list_add(params, &hdev->pend_le_conns);
- break;
- }
-
- params->auto_connect = auto_connect;
-
- bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
- addr, addr_type, auto_connect);
-
- return 0;
-}
-
static void device_added(struct sock *sk, struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type, u8 action)
{
@@ -7601,17 +7735,13 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
/* If the connection parameters don't exist for this device,
* they will be created and configured with defaults.
*/
- if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
- auto_conn) < 0) {
+ params = hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
+ auto_conn);
+ if (!params) {
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
MGMT_STATUS_FAILED, &cp->addr,
sizeof(cp->addr));
goto unlock;
- } else {
- params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
- addr_type);
- if (params)
- current_flags = params->flags;
}
cmd = mgmt_pending_new(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
@@ -8036,10 +8166,6 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
u8 status = mgmt_status(err);
u16 eir_len;
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev))
- return;
-
if (!status) {
if (!skb)
status = MGMT_STATUS_FAILED;
@@ -8146,7 +8272,7 @@ done:
kfree_skb(skb);
kfree(mgmt_rp);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
@@ -8155,7 +8281,7 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
struct mgmt_pending_cmd *cmd;
int err;
- cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
+ cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
cp, sizeof(*cp));
if (!cmd)
return -ENOMEM;
@@ -9387,6 +9513,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
cancel_delayed_work_sync(&hdev->discov_off);
cancel_delayed_work_sync(&hdev->service_cache);
cancel_delayed_work_sync(&hdev->rpa_expired);
+ cancel_delayed_work_sync(&hdev->mesh_send_done);
}
void mgmt_power_on(struct hci_dev *hdev, int err)
@@ -9705,7 +9832,9 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
if (!mgmt_connected)
return;
- if (link_type != ACL_LINK && link_type != LE_LINK)
+ if (link_type != ACL_LINK &&
+ link_type != LE_LINK &&
+ link_type != BIS_LINK)
return;
bacpy(&ev.addr.bdaddr, bdaddr);