Skip to content

Commit

Permalink
Bluetooth: hci_sync: Refactor remove Adv Monitor
Browse files Browse the repository at this point in the history
Make use of hci_cmd_sync_queue for removing an advertisement monitor.

Signed-off-by: Manish Mandlik <mmandlik@google.com>
Reviewed-by: Miao-chen Chou <mcchou@google.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information
liveusr authored and Vudentz committed Jul 22, 2022
1 parent b747a83 commit 7cf5c29
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 178 deletions.
6 changes: 2 additions & 4 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1420,10 +1420,9 @@ bool hci_adv_instance_is_scannable(struct hci_dev *hdev, u8 instance);

void hci_adv_monitors_clear(struct hci_dev *hdev);
void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
int hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle);
int hci_remove_all_adv_monitor(struct hci_dev *hdev);
bool hci_is_adv_monitoring(struct hci_dev *hdev);
int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);

Expand Down Expand Up @@ -1883,7 +1882,6 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
u8 instance);
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type);

Expand Down
81 changes: 28 additions & 53 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1880,11 +1880,6 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
kfree(monitor);
}

int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
{
return mgmt_remove_adv_monitor_complete(hdev, status);
}

/* Assigns handle to a monitor, and if offloading is supported and power is on,
* also attempts to forward the request to the controller.
* This function requires the caller holds hci_req_sync_lock.
Expand Down Expand Up @@ -1933,92 +1928,72 @@ int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)

/* Attempts to tell the controller and free the monitor. If somehow the
* controller doesn't have a corresponding handle, remove anyway.
* Returns true if request is forwarded (result is pending), false otherwise.
* This function requires the caller holds hdev->lock.
* This function requires the caller holds hci_req_sync_lock.
*/
static bool hci_remove_adv_monitor(struct hci_dev *hdev,
struct adv_monitor *monitor,
u16 handle, int *err)
static int hci_remove_adv_monitor(struct hci_dev *hdev,
struct adv_monitor *monitor)
{
*err = 0;
int status = 0;

switch (hci_get_adv_monitor_offload_ext(hdev)) {
case HCI_ADV_MONITOR_EXT_NONE: /* also goes here when powered off */
bt_dev_dbg(hdev, "%s remove monitor %d status %d", hdev->name,
monitor->handle, status);
goto free_monitor;

case HCI_ADV_MONITOR_EXT_MSFT:
*err = msft_remove_monitor(hdev, monitor, handle);
status = msft_remove_monitor(hdev, monitor);
bt_dev_dbg(hdev, "%s remove monitor %d msft status %d",
hdev->name, monitor->handle, status);
break;
}

/* In case no matching handle registered, just free the monitor */
if (*err == -ENOENT)
if (status == -ENOENT)
goto free_monitor;

return (*err == 0);
return status;

free_monitor:
if (*err == -ENOENT)
if (status == -ENOENT)
bt_dev_warn(hdev, "Removing monitor with no matching handle %d",
monitor->handle);
hci_free_adv_monitor(hdev, monitor);

*err = 0;
return false;
return status;
}

/* Returns true if request is forwarded (result is pending), false otherwise.
* This function requires the caller holds hdev->lock.
*/
bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err)
/* This function requires the caller holds hci_req_sync_lock */
int hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle)
{
struct adv_monitor *monitor = idr_find(&hdev->adv_monitors_idr, handle);
bool pending;

if (!monitor) {
*err = -EINVAL;
return false;
}

pending = hci_remove_adv_monitor(hdev, monitor, handle, err);
if (!*err && !pending)
hci_update_passive_scan(hdev);

bt_dev_dbg(hdev, "%s remove monitor handle %d, status %d, %spending",
hdev->name, handle, *err, pending ? "" : "not ");
if (!monitor)
return -EINVAL;

return pending;
return hci_remove_adv_monitor(hdev, monitor);
}

/* Returns true if request is forwarded (result is pending), false otherwise.
* This function requires the caller holds hdev->lock.
*/
bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err)
/* This function requires the caller holds hci_req_sync_lock */
int hci_remove_all_adv_monitor(struct hci_dev *hdev)
{
struct adv_monitor *monitor;
int idr_next_id = 0;
bool pending = false;
bool update = false;

*err = 0;
int status = 0;

while (!*err && !pending) {
while (1) {
monitor = idr_get_next(&hdev->adv_monitors_idr, &idr_next_id);
if (!monitor)
break;

pending = hci_remove_adv_monitor(hdev, monitor, 0, err);
status = hci_remove_adv_monitor(hdev, monitor);
if (status)
return status;

if (!*err && !pending)
update = true;
idr_next_id++;
}

if (update)
hci_update_passive_scan(hdev);

bt_dev_dbg(hdev, "%s remove all monitors status %d, %spending",
hdev->name, *err, pending ? "" : "not ");

return pending;
return status;
}

/* This function requires the caller holds hdev->lock */
Expand Down
62 changes: 24 additions & 38 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -4861,49 +4861,46 @@ static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
}

int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
void *data, int status)
{
struct mgmt_rp_remove_adv_monitor rp;
struct mgmt_cp_remove_adv_monitor *cp;
struct mgmt_pending_cmd *cmd;
int err = 0;
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_remove_adv_monitor *cp = cmd->param;

hci_dev_lock(hdev);

cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
if (!cmd)
goto done;

cp = cmd->param;
rp.monitor_handle = cp->monitor_handle;

if (!status)
hci_update_passive_scan(hdev);

err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp));
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd);

done:
hci_dev_unlock(hdev);
bt_dev_dbg(hdev, "remove monitor %d complete, status %u",
bt_dev_dbg(hdev, "remove monitor %d complete, status %d",
rp.monitor_handle, status);
}

return err;
static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_remove_adv_monitor *cp = cmd->param;
u16 handle = __le16_to_cpu(cp->monitor_handle);

if (!handle)
return hci_remove_all_adv_monitor(hdev);

return hci_remove_single_adv_monitor(hdev, handle);
}

static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_cp_remove_adv_monitor *cp = data;
struct mgmt_rp_remove_adv_monitor rp;
struct mgmt_pending_cmd *cmd;
u16 handle = __le16_to_cpu(cp->monitor_handle);
int err, status;
bool pending;

BT_DBG("request for %s", hdev->name);
rp.monitor_handle = cp->monitor_handle;

hci_dev_lock(hdev);

Expand All @@ -4921,34 +4918,23 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

if (handle)
pending = hci_remove_single_adv_monitor(hdev, handle, &err);
else
pending = hci_remove_all_adv_monitor(hdev, &err);
err = hci_cmd_sync_queue(hdev, mgmt_remove_adv_monitor_sync, cmd,
mgmt_remove_adv_monitor_complete);

if (err) {
mgmt_pending_remove(cmd);

if (err == -ENOENT)
status = MGMT_STATUS_INVALID_INDEX;
if (err == -ENOMEM)
status = MGMT_STATUS_NO_RESOURCES;
else
status = MGMT_STATUS_FAILED;

goto unlock;
}

/* monitor can be removed without forwarding request to controller */
if (!pending) {
mgmt_pending_remove(cmd);
hci_dev_unlock(hdev);

return mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADV_MONITOR,
MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
goto unlock;
}

hci_dev_unlock(hdev);

return 0;

unlock:
Expand Down
Loading

0 comments on commit 7cf5c29

Please sign in to comment.