Skip to content

Commit 66bd095

Browse files
apusakaholtmann
authored andcommitted
Bluetooth: advmon offload MSFT remove monitor
Implements the monitor removal functionality for advertising monitor offloading to MSFT controllers. Supply handle = 0 to remove all monitors. Signed-off-by: Archie Pusaka <[email protected]> Reviewed-by: Miao-chen Chou <[email protected]> Reviewed-by: Yun-Hao Chung <[email protected]> Reported-by: kernel test robot <[email protected]> Reported-by: Dan Carpenter <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent a2a4ded commit 66bd095

File tree

5 files changed

+323
-50
lines changed

5 files changed

+323
-50
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,11 +1332,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
13321332
void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
13331333

13341334
void hci_adv_monitors_clear(struct hci_dev *hdev);
1335-
void hci_free_adv_monitor(struct adv_monitor *monitor);
1335+
void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
13361336
int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
1337+
int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
13371338
bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
13381339
int *err);
1339-
int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
1340+
bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
1341+
bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
13401342
bool hci_is_adv_monitoring(struct hci_dev *hdev);
13411343
int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
13421344

@@ -1813,8 +1815,10 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
18131815
u8 instance);
18141816
void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
18151817
u8 instance);
1818+
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
18161819
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
18171820
int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
1821+
int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
18181822

18191823
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
18201824
u16 to_multiplier);

net/bluetooth/hci_core.c

Lines changed: 96 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3051,21 +3051,34 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
30513051
int handle;
30523052

30533053
idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
3054-
hci_free_adv_monitor(monitor);
3054+
hci_free_adv_monitor(hdev, monitor);
30553055

30563056
idr_destroy(&hdev->adv_monitors_idr);
30573057
}
30583058

3059-
void hci_free_adv_monitor(struct adv_monitor *monitor)
3059+
/* Frees the monitor structure and do some bookkeepings.
3060+
* This function requires the caller holds hdev->lock.
3061+
*/
3062+
void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
30603063
{
30613064
struct adv_pattern *pattern;
30623065
struct adv_pattern *tmp;
30633066

30643067
if (!monitor)
30653068
return;
30663069

3067-
list_for_each_entry_safe(pattern, tmp, &monitor->patterns, list)
3070+
list_for_each_entry_safe(pattern, tmp, &monitor->patterns, list) {
3071+
list_del(&pattern->list);
30683072
kfree(pattern);
3073+
}
3074+
3075+
if (monitor->handle)
3076+
idr_remove(&hdev->adv_monitors_idr, monitor->handle);
3077+
3078+
if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
3079+
hdev->adv_monitors_cnt--;
3080+
mgmt_adv_monitor_removed(hdev, monitor->handle);
3081+
}
30693082

30703083
kfree(monitor);
30713084
}
@@ -3075,6 +3088,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
30753088
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
30763089
}
30773090

3091+
int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
3092+
{
3093+
return mgmt_remove_adv_monitor_complete(hdev, status);
3094+
}
3095+
30783096
/* Assigns handle to a monitor, and if offloading is supported and power is on,
30793097
* also attempts to forward the request to the controller.
30803098
* Returns true if request is forwarded (result is pending), false otherwise.
@@ -3122,39 +3140,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
31223140
return (*err == 0);
31233141
}
31243142

3125-
static int free_adv_monitor(int id, void *ptr, void *data)
3143+
/* Attempts to tell the controller and free the monitor. If somehow the
3144+
* controller doesn't have a corresponding handle, remove anyway.
3145+
* Returns true if request is forwarded (result is pending), false otherwise.
3146+
* This function requires the caller holds hdev->lock.
3147+
*/
3148+
static bool hci_remove_adv_monitor(struct hci_dev *hdev,
3149+
struct adv_monitor *monitor,
3150+
u16 handle, int *err)
31263151
{
3127-
struct hci_dev *hdev = data;
3128-
struct adv_monitor *monitor = ptr;
3152+
*err = 0;
31293153

3130-
idr_remove(&hdev->adv_monitors_idr, monitor->handle);
3131-
hci_free_adv_monitor(monitor);
3132-
hdev->adv_monitors_cnt--;
3154+
switch (hci_get_adv_monitor_offload_ext(hdev)) {
3155+
case HCI_ADV_MONITOR_EXT_NONE: /* also goes here when powered off */
3156+
goto free_monitor;
3157+
case HCI_ADV_MONITOR_EXT_MSFT:
3158+
*err = msft_remove_monitor(hdev, monitor, handle);
3159+
break;
3160+
}
31333161

3134-
return 0;
3162+
/* In case no matching handle registered, just free the monitor */
3163+
if (*err == -ENOENT)
3164+
goto free_monitor;
3165+
3166+
return (*err == 0);
3167+
3168+
free_monitor:
3169+
if (*err == -ENOENT)
3170+
bt_dev_warn(hdev, "Removing monitor with no matching handle %d",
3171+
monitor->handle);
3172+
hci_free_adv_monitor(hdev, monitor);
3173+
3174+
*err = 0;
3175+
return false;
31353176
}
31363177

3137-
/* This function requires the caller holds hdev->lock */
3138-
int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle)
3178+
/* Returns true if request is forwarded (result is pending), false otherwise.
3179+
* This function requires the caller holds hdev->lock.
3180+
*/
3181+
bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err)
3182+
{
3183+
struct adv_monitor *monitor = idr_find(&hdev->adv_monitors_idr, handle);
3184+
bool pending;
3185+
3186+
if (!monitor) {
3187+
*err = -EINVAL;
3188+
return false;
3189+
}
3190+
3191+
pending = hci_remove_adv_monitor(hdev, monitor, handle, err);
3192+
if (!*err && !pending)
3193+
hci_update_background_scan(hdev);
3194+
3195+
bt_dev_dbg(hdev, "%s remove monitor handle %d, status %d, %spending",
3196+
hdev->name, handle, *err, pending ? "" : "not ");
3197+
3198+
return pending;
3199+
}
3200+
3201+
/* Returns true if request is forwarded (result is pending), false otherwise.
3202+
* This function requires the caller holds hdev->lock.
3203+
*/
3204+
bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err)
31393205
{
31403206
struct adv_monitor *monitor;
3207+
int idr_next_id = 0;
3208+
bool pending = false;
3209+
bool update = false;
3210+
3211+
*err = 0;
31413212

3142-
if (handle) {
3143-
monitor = idr_find(&hdev->adv_monitors_idr, handle);
3213+
while (!*err && !pending) {
3214+
monitor = idr_get_next(&hdev->adv_monitors_idr, &idr_next_id);
31443215
if (!monitor)
3145-
return -ENOENT;
3216+
break;
31463217

3147-
idr_remove(&hdev->adv_monitors_idr, monitor->handle);
3148-
hci_free_adv_monitor(monitor);
3149-
hdev->adv_monitors_cnt--;
3150-
} else {
3151-
/* Remove all monitors if handle is 0. */
3152-
idr_for_each(&hdev->adv_monitors_idr, &free_adv_monitor, hdev);
3218+
pending = hci_remove_adv_monitor(hdev, monitor, 0, err);
3219+
3220+
if (!*err && !pending)
3221+
update = true;
31533222
}
31543223

3155-
hci_update_background_scan(hdev);
3224+
if (update)
3225+
hci_update_background_scan(hdev);
31563226

3157-
return 0;
3227+
bt_dev_dbg(hdev, "%s remove all monitors status %d, %spending",
3228+
hdev->name, *err, pending ? "" : "not ");
3229+
3230+
return pending;
31583231
}
31593232

31603233
/* This function requires the caller holds hdev->lock */

net/bluetooth/mgmt.c

Lines changed: 89 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4167,14 +4167,24 @@ static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
41674167
mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
41684168
}
41694169

4170-
static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
4171-
u16 handle)
4170+
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle)
41724171
{
4173-
struct mgmt_ev_adv_monitor_added ev;
4172+
struct mgmt_ev_adv_monitor_removed ev;
4173+
struct mgmt_pending_cmd *cmd;
4174+
struct sock *sk_skip = NULL;
4175+
struct mgmt_cp_remove_adv_monitor *cp;
4176+
4177+
cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4178+
if (cmd) {
4179+
cp = cmd->param;
4180+
4181+
if (cp->monitor_handle)
4182+
sk_skip = cmd->sk;
4183+
}
41744184

41754185
ev.monitor_handle = cpu_to_le16(handle);
41764186

4177-
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
4187+
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
41784188
}
41794189

41804190
static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
@@ -4324,8 +4334,8 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
43244334
return 0;
43254335

43264336
unlock:
4337+
hci_free_adv_monitor(hdev, m);
43274338
hci_dev_unlock(hdev);
4328-
hci_free_adv_monitor(m);
43294339
return mgmt_cmd_status(sk, hdev->id, op, status);
43304340
}
43314341

@@ -4459,42 +4469,100 @@ static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
44594469
MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
44604470
}
44614471

4472+
int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
4473+
{
4474+
struct mgmt_rp_remove_adv_monitor rp;
4475+
struct mgmt_cp_remove_adv_monitor *cp;
4476+
struct mgmt_pending_cmd *cmd;
4477+
int err = 0;
4478+
4479+
hci_dev_lock(hdev);
4480+
4481+
cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
4482+
if (!cmd)
4483+
goto done;
4484+
4485+
cp = cmd->param;
4486+
rp.monitor_handle = cp->monitor_handle;
4487+
4488+
if (!status)
4489+
hci_update_background_scan(hdev);
4490+
4491+
err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4492+
mgmt_status(status), &rp, sizeof(rp));
4493+
mgmt_pending_remove(cmd);
4494+
4495+
done:
4496+
hci_dev_unlock(hdev);
4497+
bt_dev_dbg(hdev, "remove monitor %d complete, status %d",
4498+
rp.monitor_handle, status);
4499+
4500+
return err;
4501+
}
4502+
44624503
static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
44634504
void *data, u16 len)
44644505
{
44654506
struct mgmt_cp_remove_adv_monitor *cp = data;
44664507
struct mgmt_rp_remove_adv_monitor rp;
4467-
unsigned int prev_adv_monitors_cnt;
4468-
u16 handle;
4469-
int err;
4508+
struct mgmt_pending_cmd *cmd;
4509+
u16 handle = __le16_to_cpu(cp->monitor_handle);
4510+
int err, status;
4511+
bool pending;
44704512

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

44734516
hci_dev_lock(hdev);
44744517

4475-
handle = __le16_to_cpu(cp->monitor_handle);
4476-
prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
4518+
if (pending_find(MGMT_OP_SET_LE, hdev) ||
4519+
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
4520+
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4521+
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
4522+
status = MGMT_STATUS_BUSY;
4523+
goto unlock;
4524+
}
44774525

4478-
err = hci_remove_adv_monitor(hdev, handle);
4479-
if (err == -ENOENT) {
4480-
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4481-
MGMT_STATUS_INVALID_INDEX);
4526+
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
4527+
if (!cmd) {
4528+
status = MGMT_STATUS_NO_RESOURCES;
44824529
goto unlock;
44834530
}
44844531

4485-
if (hdev->adv_monitors_cnt < prev_adv_monitors_cnt)
4486-
mgmt_adv_monitor_removed(sk, hdev, handle);
4532+
if (handle)
4533+
pending = hci_remove_single_adv_monitor(hdev, handle, &err);
4534+
else
4535+
pending = hci_remove_all_adv_monitor(hdev, &err);
44874536

4488-
hci_dev_unlock(hdev);
4537+
if (err) {
4538+
mgmt_pending_remove(cmd);
44894539

4490-
rp.monitor_handle = cp->monitor_handle;
4540+
if (err == -ENOENT)
4541+
status = MGMT_STATUS_INVALID_INDEX;
4542+
else
4543+
status = MGMT_STATUS_FAILED;
4544+
4545+
goto unlock;
4546+
}
4547+
4548+
/* monitor can be removed without forwarding request to controller */
4549+
if (!pending) {
4550+
mgmt_pending_remove(cmd);
4551+
hci_dev_unlock(hdev);
4552+
4553+
return mgmt_cmd_complete(sk, hdev->id,
4554+
MGMT_OP_REMOVE_ADV_MONITOR,
4555+
MGMT_STATUS_SUCCESS,
4556+
&rp, sizeof(rp));
4557+
}
44914558

4492-
return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4493-
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4559+
hci_dev_unlock(hdev);
4560+
return 0;
44944561

44954562
unlock:
44964563
hci_dev_unlock(hdev);
4497-
return err;
4564+
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADV_MONITOR,
4565+
status);
44984566
}
44994567

45004568
static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,

0 commit comments

Comments
 (0)