Skip to content

Commit a2a4ded

Browse files
apusakaholtmann
authored andcommitted
Bluetooth: advmon offload MSFT add monitor
Enables advertising monitor offloading to the controller, if MSFT extension is supported. The kernel won't adjust the monitor parameters to match what the controller supports - that is the user space's responsibility. This patch only manages the addition of monitors. Monitor removal is going to be handled by another patch. Signed-off-by: Archie Pusaka <apusaka@chromium.org> Reviewed-by: Manish Mandlik <mmandlik@chromium.org> Reviewed-by: Miao-chen Chou <mcchou@chromium.org> Reviewed-by: Yun-Hao Chung <howardchung@google.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
1 parent b4a221e commit a2a4ded

File tree

5 files changed

+356
-43
lines changed

5 files changed

+356
-43
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,20 @@ struct adv_rssi_thresholds {
261261
struct adv_monitor {
262262
struct list_head patterns;
263263
struct adv_rssi_thresholds rssi;
264-
bool active;
265264
__u16 handle;
265+
266+
enum {
267+
ADV_MONITOR_STATE_NOT_REGISTERED,
268+
ADV_MONITOR_STATE_REGISTERED,
269+
ADV_MONITOR_STATE_OFFLOADED
270+
} state;
266271
};
267272

268273
#define HCI_MIN_ADV_MONITOR_HANDLE 1
269-
#define HCI_MAX_ADV_MONITOR_NUM_HANDLES 32
274+
#define HCI_MAX_ADV_MONITOR_NUM_HANDLES 32
270275
#define HCI_MAX_ADV_MONITOR_NUM_PATTERNS 16
276+
#define HCI_ADV_MONITOR_EXT_NONE 1
277+
#define HCI_ADV_MONITOR_EXT_MSFT 2
271278

272279
#define HCI_MAX_SHORT_NAME_LENGTH 10
273280

@@ -1326,9 +1333,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
13261333

13271334
void hci_adv_monitors_clear(struct hci_dev *hdev);
13281335
void hci_free_adv_monitor(struct adv_monitor *monitor);
1329-
int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
1336+
int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
1337+
bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
1338+
int *err);
13301339
int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
13311340
bool hci_is_adv_monitoring(struct hci_dev *hdev);
1341+
int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
13321342

13331343
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
13341344

@@ -1804,6 +1814,7 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
18041814
void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
18051815
u8 instance);
18061816
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
1817+
int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
18071818

18081819
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
18091820
u16 to_multiplier);

net/bluetooth/hci_core.c

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3070,27 +3070,56 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
30703070
kfree(monitor);
30713071
}
30723072

3073-
/* This function requires the caller holds hdev->lock */
3074-
int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
3073+
int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
3074+
{
3075+
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
3076+
}
3077+
3078+
/* Assigns handle to a monitor, and if offloading is supported and power is on,
3079+
* also attempts to forward the request to the controller.
3080+
* Returns true if request is forwarded (result is pending), false otherwise.
3081+
* This function requires the caller holds hdev->lock.
3082+
*/
3083+
bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
3084+
int *err)
30753085
{
30763086
int min, max, handle;
30773087

3078-
if (!monitor)
3079-
return -EINVAL;
3088+
*err = 0;
3089+
3090+
if (!monitor) {
3091+
*err = -EINVAL;
3092+
return false;
3093+
}
30803094

30813095
min = HCI_MIN_ADV_MONITOR_HANDLE;
30823096
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
30833097
handle = idr_alloc(&hdev->adv_monitors_idr, monitor, min, max,
30843098
GFP_KERNEL);
3085-
if (handle < 0)
3086-
return handle;
3099+
if (handle < 0) {
3100+
*err = handle;
3101+
return false;
3102+
}
30873103

3088-
hdev->adv_monitors_cnt++;
30893104
monitor->handle = handle;
30903105

3091-
hci_update_background_scan(hdev);
3106+
if (!hdev_is_powered(hdev))
3107+
return false;
30923108

3093-
return 0;
3109+
switch (hci_get_adv_monitor_offload_ext(hdev)) {
3110+
case HCI_ADV_MONITOR_EXT_NONE:
3111+
hci_update_background_scan(hdev);
3112+
bt_dev_dbg(hdev, "%s add monitor status %d", hdev->name, *err);
3113+
/* Message was not forwarded to controller - not an error */
3114+
return false;
3115+
case HCI_ADV_MONITOR_EXT_MSFT:
3116+
*err = msft_add_monitor_pattern(hdev, monitor);
3117+
bt_dev_dbg(hdev, "%s add monitor msft status %d", hdev->name,
3118+
*err);
3119+
break;
3120+
}
3121+
3122+
return (*err == 0);
30943123
}
30953124

30963125
static int free_adv_monitor(int id, void *ptr, void *data)
@@ -3134,6 +3163,14 @@ bool hci_is_adv_monitoring(struct hci_dev *hdev)
31343163
return !idr_is_empty(&hdev->adv_monitors_idr);
31353164
}
31363165

3166+
int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev)
3167+
{
3168+
if (msft_monitor_supported(hdev))
3169+
return HCI_ADV_MONITOR_EXT_MSFT;
3170+
3171+
return HCI_ADV_MONITOR_EXT_NONE;
3172+
}
3173+
31373174
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
31383175
bdaddr_t *bdaddr, u8 type)
31393176
{

net/bluetooth/mgmt.c

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4185,19 +4185,19 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
41854185
int handle, err;
41864186
size_t rp_size = 0;
41874187
__u32 supported = 0;
4188+
__u32 enabled = 0;
41884189
__u16 num_handles = 0;
41894190
__u16 handles[HCI_MAX_ADV_MONITOR_NUM_HANDLES];
41904191

41914192
BT_DBG("request for %s", hdev->name);
41924193

41934194
hci_dev_lock(hdev);
41944195

4195-
if (msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR)
4196+
if (msft_monitor_supported(hdev))
41964197
supported |= MGMT_ADV_MONITOR_FEATURE_MASK_OR_PATTERNS;
41974198

4198-
idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle) {
4199+
idr_for_each_entry(&hdev->adv_monitors_idr, monitor, handle)
41994200
handles[num_handles++] = monitor->handle;
4200-
}
42014201

42024202
hci_dev_unlock(hdev);
42034203

@@ -4206,11 +4206,11 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
42064206
if (!rp)
42074207
return -ENOMEM;
42084208

4209-
/* Once controller-based monitoring is in place, the enabled_features
4210-
* should reflect the use.
4211-
*/
4209+
/* All supported features are currently enabled */
4210+
enabled = supported;
4211+
42124212
rp->supported_features = cpu_to_le32(supported);
4213-
rp->enabled_features = 0;
4213+
rp->enabled_features = cpu_to_le32(enabled);
42144214
rp->max_num_handles = cpu_to_le16(HCI_MAX_ADV_MONITOR_NUM_HANDLES);
42154215
rp->max_num_patterns = HCI_MAX_ADV_MONITOR_NUM_PATTERNS;
42164216
rp->num_handles = cpu_to_le16(num_handles);
@@ -4226,44 +4226,105 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
42264226
return err;
42274227
}
42284228

4229+
int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
4230+
{
4231+
struct mgmt_rp_add_adv_patterns_monitor rp;
4232+
struct mgmt_pending_cmd *cmd;
4233+
struct adv_monitor *monitor;
4234+
int err = 0;
4235+
4236+
hci_dev_lock(hdev);
4237+
4238+
cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev);
4239+
if (!cmd) {
4240+
cmd = pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev);
4241+
if (!cmd)
4242+
goto done;
4243+
}
4244+
4245+
monitor = cmd->user_data;
4246+
rp.monitor_handle = cpu_to_le16(monitor->handle);
4247+
4248+
if (!status) {
4249+
mgmt_adv_monitor_added(cmd->sk, hdev, monitor->handle);
4250+
hdev->adv_monitors_cnt++;
4251+
if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
4252+
monitor->state = ADV_MONITOR_STATE_REGISTERED;
4253+
hci_update_background_scan(hdev);
4254+
}
4255+
4256+
err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
4257+
mgmt_status(status), &rp, sizeof(rp));
4258+
mgmt_pending_remove(cmd);
4259+
4260+
done:
4261+
hci_dev_unlock(hdev);
4262+
bt_dev_dbg(hdev, "add monitor %d complete, status %d",
4263+
rp.monitor_handle, status);
4264+
4265+
return err;
4266+
}
4267+
42294268
static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
4230-
struct adv_monitor *m, u8 status, u16 op)
4269+
struct adv_monitor *m, u8 status,
4270+
void *data, u16 len, u16 op)
42314271
{
42324272
struct mgmt_rp_add_adv_patterns_monitor rp;
4233-
unsigned int prev_adv_monitors_cnt;
4273+
struct mgmt_pending_cmd *cmd;
42344274
int err;
4275+
bool pending;
4276+
4277+
hci_dev_lock(hdev);
42354278

42364279
if (status)
4237-
goto failed;
4280+
goto unlock;
42384281

4239-
hci_dev_lock(hdev);
4282+
if (pending_find(MGMT_OP_SET_LE, hdev) ||
4283+
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
4284+
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
4285+
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
4286+
status = MGMT_STATUS_BUSY;
4287+
goto unlock;
4288+
}
42404289

4241-
prev_adv_monitors_cnt = hdev->adv_monitors_cnt;
4290+
cmd = mgmt_pending_add(sk, op, hdev, data, len);
4291+
if (!cmd) {
4292+
status = MGMT_STATUS_NO_RESOURCES;
4293+
goto unlock;
4294+
}
42424295

4243-
err = hci_add_adv_monitor(hdev, m);
4296+
pending = hci_add_adv_monitor(hdev, m, &err);
42444297
if (err) {
4245-
if (err == -ENOSPC)
4298+
if (err == -ENOSPC || err == -ENOMEM)
42464299
status = MGMT_STATUS_NO_RESOURCES;
4300+
else if (err == -EINVAL)
4301+
status = MGMT_STATUS_INVALID_PARAMS;
42474302
else
42484303
status = MGMT_STATUS_FAILED;
42494304

4305+
mgmt_pending_remove(cmd);
42504306
goto unlock;
42514307
}
42524308

4253-
if (hdev->adv_monitors_cnt > prev_adv_monitors_cnt)
4309+
if (!pending) {
4310+
mgmt_pending_remove(cmd);
4311+
rp.monitor_handle = cpu_to_le16(m->handle);
42544312
mgmt_adv_monitor_added(sk, hdev, m->handle);
4313+
m->state = ADV_MONITOR_STATE_REGISTERED;
4314+
hdev->adv_monitors_cnt++;
42554315

4256-
hci_dev_unlock(hdev);
4316+
hci_dev_unlock(hdev);
4317+
return mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_SUCCESS,
4318+
&rp, sizeof(rp));
4319+
}
42574320

4258-
rp.monitor_handle = cpu_to_le16(m->handle);
4321+
hci_dev_unlock(hdev);
42594322

4260-
return mgmt_cmd_complete(sk, hdev->id, op,
4261-
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
4323+
cmd->user_data = m;
4324+
return 0;
42624325

42634326
unlock:
42644327
hci_dev_unlock(hdev);
4265-
4266-
failed:
42674328
hci_free_adv_monitor(m);
42684329
return mgmt_cmd_status(sk, hdev->id, op, status);
42694330
}
@@ -4298,13 +4359,9 @@ static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
42984359
{
42994360
u8 offset = 0, length = 0;
43004361
struct adv_pattern *p = NULL;
4301-
unsigned int mp_cnt = 0;
43024362
int i;
43034363

43044364
for (i = 0; i < pattern_count; i++) {
4305-
if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS)
4306-
return MGMT_STATUS_INVALID_PARAMS;
4307-
43084365
offset = patterns[i].offset;
43094366
length = patterns[i].length;
43104367
if (offset >= HCI_MAX_AD_LENGTH ||
@@ -4325,9 +4382,6 @@ static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
43254382
list_add(&p->list, &m->patterns);
43264383
}
43274384

4328-
if (mp_cnt != pattern_count)
4329-
return MGMT_STATUS_INVALID_PARAMS;
4330-
43314385
return MGMT_STATUS_SUCCESS;
43324386
}
43334387

@@ -4364,7 +4418,7 @@ static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
43644418
status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
43654419

43664420
done:
4367-
return __add_adv_patterns_monitor(sk, hdev, m, status,
4421+
return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
43684422
MGMT_OP_ADD_ADV_PATTERNS_MONITOR);
43694423
}
43704424

@@ -4401,7 +4455,7 @@ static int add_adv_patterns_monitor_rssi(struct sock *sk, struct hci_dev *hdev,
44014455
status = parse_adv_monitor_pattern(m, cp->pattern_count, cp->patterns);
44024456

44034457
done:
4404-
return __add_adv_patterns_monitor(sk, hdev, m, status,
4458+
return __add_adv_patterns_monitor(sk, hdev, m, status, data, len,
44054459
MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI);
44064460
}
44074461

0 commit comments

Comments
 (0)