Commit 51d7a94d authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann

Bluetooth: Don't wait for HCI in Add/Remove Device

There's no point in waiting for HCI activity in Add/Remove Device
since the effects of these calls are long-lasting and we can anyway
not report up to the application all HCI failures.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 2e93e53b
...@@ -6076,10 +6076,9 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) ...@@ -6076,10 +6076,9 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
} }
/* This function requires the caller holds hdev->lock */ /* This function requires the caller holds hdev->lock */
static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr, static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
u8 addr_type, u8 auto_connect) u8 addr_type, u8 auto_connect)
{ {
struct hci_dev *hdev = req->hdev;
struct hci_conn_params *params; struct hci_conn_params *params;
params = hci_conn_params_add(hdev, addr, addr_type); params = hci_conn_params_add(hdev, addr, addr_type);
...@@ -6099,26 +6098,17 @@ static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr, ...@@ -6099,26 +6098,17 @@ static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
*/ */
if (params->explicit_connect) if (params->explicit_connect)
list_add(&params->action, &hdev->pend_le_conns); list_add(&params->action, &hdev->pend_le_conns);
__hci_update_background_scan(req);
break; break;
case HCI_AUTO_CONN_REPORT: case HCI_AUTO_CONN_REPORT:
if (params->explicit_connect) if (params->explicit_connect)
list_add(&params->action, &hdev->pend_le_conns); list_add(&params->action, &hdev->pend_le_conns);
else else
list_add(&params->action, &hdev->pend_le_reports); list_add(&params->action, &hdev->pend_le_reports);
__hci_update_background_scan(req);
break; break;
case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_DIRECT:
case HCI_AUTO_CONN_ALWAYS: case HCI_AUTO_CONN_ALWAYS:
if (!is_connected(hdev, addr, addr_type)) { if (!is_connected(hdev, addr, addr_type))
list_add(&params->action, &hdev->pend_le_conns); list_add(&params->action, &hdev->pend_le_conns);
/* If we are in scan phase of connecting, we were
* already added to pend_le_conns and scanning.
*/
if (params->auto_connect != HCI_AUTO_CONN_EXPLICIT)
__hci_update_background_scan(req);
}
break; break;
} }
...@@ -6142,25 +6132,6 @@ static void device_added(struct sock *sk, struct hci_dev *hdev, ...@@ -6142,25 +6132,6 @@ static void device_added(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk); mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
} }
static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
{
struct mgmt_pending_cmd *cmd;
BT_DBG("status 0x%02x", status);
hci_dev_lock(hdev);
cmd = pending_find(MGMT_OP_ADD_DEVICE, hdev);
if (!cmd)
goto unlock;
cmd->cmd_complete(cmd, mgmt_status(status));
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
}
static int add_device(struct sock *sk, struct hci_dev *hdev, static int add_device(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len) void *data, u16 len)
{ {
...@@ -6198,9 +6169,10 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6198,9 +6169,10 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
if (cp->addr.type == BDADDR_BREDR) { if (cp->addr.type == BDADDR_BREDR) {
/* Only incoming connections action is supported for now */ /* Only incoming connections action is supported for now */
if (cp->action != 0x01) { if (cp->action != 0x01) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_ADD_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
...@@ -6229,33 +6201,31 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6229,33 +6201,31 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
* hci_conn_params_lookup. * hci_conn_params_lookup.
*/ */
if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) { if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
err = cmd->cmd_complete(cmd, MGMT_STATUS_INVALID_PARAMS); err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
/* If the connection parameters don't exist for this device, /* If the connection parameters don't exist for this device,
* they will be created and configured with defaults. * they will be created and configured with defaults.
*/ */
if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type, if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
auto_conn) < 0) { auto_conn) < 0) {
err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED); err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_FAILED, &cp->addr,
sizeof(cp->addr));
goto unlock; goto unlock;
} }
hci_update_background_scan(hdev);
added: added:
device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
err = hci_req_run(&req, add_device_complete); err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
if (err < 0) { MGMT_STATUS_SUCCESS, &cp->addr,
/* ENODATA means no HCI commands were needed (e.g. if sizeof(cp->addr));
* the adapter is powered off).
*/
if (err == -ENODATA)
err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
mgmt_pending_remove(cmd);
}
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -6273,55 +6243,25 @@ static void device_removed(struct sock *sk, struct hci_dev *hdev, ...@@ -6273,55 +6243,25 @@ static void device_removed(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk); mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
} }
static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
{
struct mgmt_pending_cmd *cmd;
BT_DBG("status 0x%02x", status);
hci_dev_lock(hdev);
cmd = pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
if (!cmd)
goto unlock;
cmd->cmd_complete(cmd, mgmt_status(status));
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
}
static int remove_device(struct sock *sk, struct hci_dev *hdev, static int remove_device(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len) void *data, u16 len)
{ {
struct mgmt_cp_remove_device *cp = data; struct mgmt_cp_remove_device *cp = data;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
int err; int err;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
hci_req_init(&req, hdev);
hci_dev_lock(hdev); hci_dev_lock(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto unlock;
}
cmd->cmd_complete = addr_cmd_complete;
if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) { if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
struct hci_conn_params *params; struct hci_conn_params *params;
u8 addr_type; u8 addr_type;
if (!bdaddr_type_is_valid(cp->addr.type)) { if (!bdaddr_type_is_valid(cp->addr.type)) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_REMOVE_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
...@@ -6330,13 +6270,15 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6330,13 +6270,15 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
&cp->addr.bdaddr, &cp->addr.bdaddr,
cp->addr.type); cp->addr.type);
if (err) { if (err) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_REMOVE_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr,
sizeof(cp->addr));
goto unlock; goto unlock;
} }
__hci_update_page_scan(&req); hci_update_page_scan(hdev);
device_removed(sk, hdev, &cp->addr.bdaddr, device_removed(sk, hdev, &cp->addr.bdaddr,
cp->addr.type); cp->addr.type);
...@@ -6351,33 +6293,36 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6351,33 +6293,36 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
* hci_conn_params_lookup. * hci_conn_params_lookup.
*/ */
if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) { if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_REMOVE_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
addr_type); addr_type);
if (!params) { if (!params) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_REMOVE_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
if (params->auto_connect == HCI_AUTO_CONN_DISABLED || if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
params->auto_connect == HCI_AUTO_CONN_EXPLICIT) { params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_REMOVE_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
list_del(&params->action); list_del(&params->action);
list_del(&params->list); list_del(&params->list);
kfree(params); kfree(params);
__hci_update_background_scan(&req); hci_update_background_scan(hdev);
device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
} else { } else {
...@@ -6385,9 +6330,10 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6385,9 +6330,10 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
struct bdaddr_list *b, *btmp; struct bdaddr_list *b, *btmp;
if (cp->addr.type) { if (cp->addr.type) {
err = cmd->cmd_complete(cmd, err = mgmt_cmd_complete(sk, hdev->id,
MGMT_STATUS_INVALID_PARAMS); MGMT_OP_REMOVE_DEVICE,
mgmt_pending_remove(cmd); MGMT_STATUS_INVALID_PARAMS,
&cp->addr, sizeof(cp->addr));
goto unlock; goto unlock;
} }
...@@ -6397,7 +6343,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6397,7 +6343,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
kfree(b); kfree(b);
} }
__hci_update_page_scan(&req); hci_update_page_scan(hdev);
list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
if (p->auto_connect == HCI_AUTO_CONN_DISABLED) if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
...@@ -6414,20 +6360,13 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6414,20 +6360,13 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
BT_DBG("All LE connection parameters were removed"); BT_DBG("All LE connection parameters were removed");
__hci_update_background_scan(&req); hci_update_background_scan(hdev);
} }
complete: complete:
err = hci_req_run(&req, remove_device_complete); err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
if (err < 0) { MGMT_STATUS_SUCCESS, &cp->addr,
/* ENODATA means no HCI commands were needed (e.g. if sizeof(cp->addr));
* the adapter is powered off).
*/
if (err == -ENODATA)
err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
mgmt_pending_remove(cmd);
}
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment