Bluetooth: hci_sync: Convert MGMT_OP_SET_DISCOVERABLE to use cmd_sync

This makes MGMT_OP_SET_DISCOVERABLE use hci_cmd_sync_queue instead of
use a dedicated discoverable_update work.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Luiz Augusto von Dentz 2021-11-11 16:48:42 -08:00 committed by Marcel Holtmann
parent be6c5ba2b0
commit 2bd1b23761
5 changed files with 112 additions and 38 deletions

View file

@ -496,7 +496,6 @@ struct hci_dev {
struct work_struct bg_scan_update; struct work_struct bg_scan_update;
struct work_struct scan_update; struct work_struct scan_update;
struct work_struct connectable_update; struct work_struct connectable_update;
struct work_struct discoverable_update;
struct delayed_work le_scan_disable; struct delayed_work le_scan_disable;
struct delayed_work le_scan_restart; struct delayed_work le_scan_restart;
@ -1828,7 +1827,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
void mgmt_smp_complete(struct hci_conn *conn, bool complete); void mgmt_smp_complete(struct hci_conn *conn, bool complete);
bool mgmt_get_connectable(struct hci_dev *hdev); bool mgmt_get_connectable(struct hci_dev *hdev);
void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status); void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status);
void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status);
u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev); u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev);
void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
u8 instance); u8 instance);

View file

@ -90,6 +90,9 @@ int hci_dev_close_sync(struct hci_dev *hdev);
int hci_powered_update_sync(struct hci_dev *hdev); int hci_powered_update_sync(struct hci_dev *hdev);
int hci_set_powered_sync(struct hci_dev *hdev, u8 val); int hci_set_powered_sync(struct hci_dev *hdev, u8 val);
int hci_update_discoverable_sync(struct hci_dev *hdev);
int hci_update_discoverable(struct hci_dev *hdev);
int hci_start_discovery_sync(struct hci_dev *hdev); int hci_start_discovery_sync(struct hci_dev *hdev);
int hci_stop_discovery_sync(struct hci_dev *hdev); int hci_stop_discovery_sync(struct hci_dev *hdev);

View file

@ -2131,16 +2131,6 @@ static int discoverable_update(struct hci_request *req, unsigned long opt)
return 0; return 0;
} }
static void discoverable_update_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
discoverable_update);
u8 status;
hci_req_sync(hdev, discoverable_update, 0, HCI_CMD_TIMEOUT, &status);
mgmt_set_discoverable_complete(hdev, status);
}
void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn, void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
u8 reason) u8 reason)
{ {
@ -2852,7 +2842,6 @@ void hci_request_setup(struct hci_dev *hdev)
INIT_WORK(&hdev->bg_scan_update, bg_scan_update); INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
INIT_WORK(&hdev->scan_update, scan_update_work); INIT_WORK(&hdev->scan_update, scan_update_work);
INIT_WORK(&hdev->connectable_update, connectable_update_work); INIT_WORK(&hdev->connectable_update, connectable_update_work);
INIT_WORK(&hdev->discoverable_update, discoverable_update_work);
INIT_DELAYED_WORK(&hdev->discov_off, discov_off); INIT_DELAYED_WORK(&hdev->discov_off, discov_off);
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
@ -2868,7 +2857,6 @@ void hci_request_cancel_all(struct hci_dev *hdev)
cancel_work_sync(&hdev->bg_scan_update); cancel_work_sync(&hdev->bg_scan_update);
cancel_work_sync(&hdev->scan_update); cancel_work_sync(&hdev->scan_update);
cancel_work_sync(&hdev->connectable_update); cancel_work_sync(&hdev->connectable_update);
cancel_work_sync(&hdev->discoverable_update);
cancel_delayed_work_sync(&hdev->discov_off); cancel_delayed_work_sync(&hdev->discov_off);
cancel_delayed_work_sync(&hdev->le_scan_disable); cancel_delayed_work_sync(&hdev->le_scan_disable);
cancel_delayed_work_sync(&hdev->le_scan_restart); cancel_delayed_work_sync(&hdev->le_scan_restart);

View file

@ -1699,7 +1699,6 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev)
hdev->advertising_paused = false; hdev->advertising_paused = false;
if (hdev->advertising_old_state) { if (hdev->advertising_old_state) {
hci_dev_set_flag(hdev, HCI_ADVERTISING); hci_dev_set_flag(hdev, HCI_ADVERTISING);
queue_work(hdev->req_workqueue, &hdev->discoverable_update);
hdev->advertising_old_state = 0; hdev->advertising_old_state = 0;
} }
@ -4392,6 +4391,95 @@ int hci_set_powered_sync(struct hci_dev *hdev, u8 val)
return hci_power_off_sync(hdev); return hci_power_off_sync(hdev);
} }
static int hci_write_iac_sync(struct hci_dev *hdev)
{
struct hci_cp_write_current_iac_lap cp;
if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
return 0;
memset(&cp, 0, sizeof(cp));
if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
/* Limited discoverable mode */
cp.num_iac = min_t(u8, hdev->num_iac, 2);
cp.iac_lap[0] = 0x00; /* LIAC */
cp.iac_lap[1] = 0x8b;
cp.iac_lap[2] = 0x9e;
cp.iac_lap[3] = 0x33; /* GIAC */
cp.iac_lap[4] = 0x8b;
cp.iac_lap[5] = 0x9e;
} else {
/* General discoverable mode */
cp.num_iac = 1;
cp.iac_lap[0] = 0x33; /* GIAC */
cp.iac_lap[1] = 0x8b;
cp.iac_lap[2] = 0x9e;
}
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
(cp.num_iac * 3) + 1, &cp,
HCI_CMD_TIMEOUT);
}
int hci_update_discoverable_sync(struct hci_dev *hdev)
{
int err = 0;
if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
err = hci_write_iac_sync(hdev);
if (err)
return err;
err = hci_update_scan_sync(hdev);
if (err)
return err;
err = hci_update_class_sync(hdev);
if (err)
return err;
}
/* Advertising instances don't use the global discoverable setting, so
* only update AD if advertising was enabled using Set Advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
err = hci_update_adv_data_sync(hdev, 0x00);
if (err)
return err;
/* Discoverable mode affects the local advertising
* address in limited privacy mode.
*/
if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) {
if (ext_adv_capable(hdev))
err = hci_start_ext_adv_sync(hdev, 0x00);
else
err = hci_enable_advertising_sync(hdev);
}
}
return err;
}
static int update_discoverable_sync(struct hci_dev *hdev, void *data)
{
return hci_update_discoverable_sync(hdev);
}
int hci_update_discoverable(struct hci_dev *hdev)
{
/* Only queue if it would have any effect */
if (hdev_is_powered(hdev) &&
hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
return hci_cmd_sync_queue(hdev, update_discoverable_sync, NULL,
NULL);
return 0;
}
static int hci_inquiry_sync(struct hci_dev *hdev, u8 length) static int hci_inquiry_sync(struct hci_dev *hdev, u8 length)
{ {
const u8 giac[3] = { 0x33, 0x8b, 0x9e }; const u8 giac[3] = { 0x33, 0x8b, 0x9e };

View file

@ -1370,23 +1370,20 @@ static u8 mgmt_le_support(struct hci_dev *hdev)
return MGMT_STATUS_SUCCESS; return MGMT_STATUS_SUCCESS;
} }
void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status) static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
int err)
{ {
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd = data;
bt_dev_dbg(hdev, "status 0x%02x", status); bt_dev_dbg(hdev, "err %d", err);
hci_dev_lock(hdev); hci_dev_lock(hdev);
cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev); if (err) {
if (!cmd) u8 mgmt_err = mgmt_status(err);
goto unlock;
if (status) {
u8 mgmt_err = mgmt_status(status);
mgmt_cmd_status(cmd->sk, cmd->index, 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 remove_cmd; goto done;
} }
if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) && if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
@ -1398,13 +1395,18 @@ void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev); send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
remove_cmd: done:
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static int set_discoverable_sync(struct hci_dev *hdev, void *data)
{
BT_DBG("%s", hdev->name);
return hci_update_discoverable_sync(hdev);
}
static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len) u16 len)
{ {
@ -1503,7 +1505,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed; goto failed;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len); cmd = mgmt_pending_new(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
if (!cmd) { if (!cmd) {
err = -ENOMEM; err = -ENOMEM;
goto failed; goto failed;
@ -1527,8 +1529,8 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
else else
hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
queue_work(hdev->req_workqueue, &hdev->discoverable_update); err = hci_cmd_sync_queue(hdev, set_discoverable_sync, cmd,
err = 0; mgmt_set_discoverable_complete);
failed: failed:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
@ -1677,12 +1679,7 @@ static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
/* In limited privacy mode the change of bondable mode /* In limited privacy mode the change of bondable mode
* may affect the local advertising address. * may affect the local advertising address.
*/ */
if (hdev_is_powered(hdev) && hci_update_discoverable(hdev);
hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
queue_work(hdev->req_workqueue,
&hdev->discoverable_update);
err = new_settings(hdev, sk); err = new_settings(hdev, sk);
} }