Bluetooth: mgmt: Add MGMT Adv Monitor Device Found/Lost events

This patch introduces two new MGMT events for notifying the bluetoothd
whenever the controller starts/stops monitoring a device.

Test performed:
- Verified by logs that the MSFT Monitor Device is received from the
  controller and the bluetoothd is notified whenever the controller
  starts/stops monitoring a device.

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>
This commit is contained in:
Manish Mandlik
2022-01-11 08:14:26 -08:00
committed by Luiz Augusto von Dentz
parent 3368aa357f
commit 8d7f167752
4 changed files with 144 additions and 10 deletions

View File

@@ -601,6 +601,7 @@ struct hci_dev {
struct delayed_work interleave_scan; struct delayed_work interleave_scan;
struct list_head monitored_devices; struct list_head monitored_devices;
bool advmon_pend_notify;
#if IS_ENABLED(CONFIG_BT_LEDS) #if IS_ENABLED(CONFIG_BT_LEDS)
struct led_trigger *power_led; struct led_trigger *power_led;
@@ -1858,6 +1859,8 @@ 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_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); 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);
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
u16 to_multiplier); u16 to_multiplier);

View File

@@ -1104,3 +1104,19 @@ struct mgmt_ev_controller_resume {
#define MGMT_WAKE_REASON_NON_BT_WAKE 0x0 #define MGMT_WAKE_REASON_NON_BT_WAKE 0x0
#define MGMT_WAKE_REASON_UNEXPECTED 0x1 #define MGMT_WAKE_REASON_UNEXPECTED 0x1
#define MGMT_WAKE_REASON_REMOTE_WAKE 0x2 #define MGMT_WAKE_REASON_REMOTE_WAKE 0x2
#define MGMT_EV_ADV_MONITOR_DEVICE_FOUND 0x002f
struct mgmt_ev_adv_monitor_device_found {
__le16 monitor_handle;
struct mgmt_addr_info addr;
__s8 rssi;
__le32 flags;
__le16 eir_len;
__u8 eir[0];
} __packed;
#define MGMT_EV_ADV_MONITOR_DEVICE_LOST 0x0030
struct mgmt_ev_adv_monitor_device_lost {
__le16 monitor_handle;
struct mgmt_addr_info addr;
} __packed;

View File

@@ -174,6 +174,8 @@ static const u16 mgmt_events[] = {
MGMT_EV_ADV_MONITOR_REMOVED, MGMT_EV_ADV_MONITOR_REMOVED,
MGMT_EV_CONTROLLER_SUSPEND, MGMT_EV_CONTROLLER_SUSPEND,
MGMT_EV_CONTROLLER_RESUME, MGMT_EV_CONTROLLER_RESUME,
MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
MGMT_EV_ADV_MONITOR_DEVICE_LOST,
}; };
static const u16 mgmt_untrusted_commands[] = { static const u16 mgmt_untrusted_commands[] = {
@@ -9589,12 +9591,116 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
return true; return true;
} }
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type)
{
struct mgmt_ev_adv_monitor_device_lost ev;
ev.monitor_handle = cpu_to_le16(handle);
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = addr_type;
mgmt_event(MGMT_EV_ADV_MONITOR_DEVICE_LOST, hdev, &ev, sizeof(ev),
NULL);
}
static void mgmt_adv_monitor_device_found(struct hci_dev *hdev,
bdaddr_t *bdaddr, bool report_device,
struct sk_buff *skb,
struct sock *skip_sk)
{
struct sk_buff *advmon_skb;
size_t advmon_skb_len;
__le16 *monitor_handle;
struct monitored_device *dev, *tmp;
bool matched = false;
bool notify = false;
/* We have received the Advertisement Report because:
* 1. the kernel has initiated active discovery
* 2. if not, we have pend_le_reports > 0 in which case we are doing
* passive scanning
* 3. if none of the above is true, we have one or more active
* Advertisement Monitor
*
* For case 1 and 2, report all advertisements via MGMT_EV_DEVICE_FOUND
* and report ONLY one advertisement per device for the matched Monitor
* via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event.
*
* For case 3, since we are not active scanning and all advertisements
* received are due to a matched Advertisement Monitor, report all
* advertisements ONLY via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event.
*/
if (report_device && !hdev->advmon_pend_notify) {
mgmt_event_skb(skb, skip_sk);
return;
}
advmon_skb_len = (sizeof(struct mgmt_ev_adv_monitor_device_found) -
sizeof(struct mgmt_ev_device_found)) + skb->len;
advmon_skb = mgmt_alloc_skb(hdev, MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
advmon_skb_len);
if (!advmon_skb) {
if (report_device)
mgmt_event_skb(skb, skip_sk);
else
kfree_skb(skb);
return;
}
/* ADV_MONITOR_DEVICE_FOUND is similar to DEVICE_FOUND event except
* that it also has 'monitor_handle'. Make a copy of DEVICE_FOUND and
* store monitor_handle of the matched monitor.
*/
monitor_handle = skb_put(advmon_skb, sizeof(*monitor_handle));
skb_put_data(advmon_skb, skb->data, skb->len);
hdev->advmon_pend_notify = false;
list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) {
if (!bacmp(&dev->bdaddr, bdaddr)) {
matched = true;
if (!dev->notified) {
*monitor_handle = cpu_to_le16(dev->handle);
notify = true;
dev->notified = true;
}
}
if (!dev->notified)
hdev->advmon_pend_notify = true;
}
if (!report_device &&
((matched && !notify) || !msft_monitor_supported(hdev))) {
/* Handle 0 indicates that we are not active scanning and this
* is a subsequent advertisement report for an already matched
* Advertisement Monitor or the controller offloading support
* is not available.
*/
*monitor_handle = 0;
notify = true;
}
if (report_device)
mgmt_event_skb(skb, skip_sk);
else
kfree_skb(skb);
if (notify)
mgmt_event_skb(advmon_skb, skip_sk);
else
kfree_skb(advmon_skb);
}
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len) u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct mgmt_ev_device_found *ev; struct mgmt_ev_device_found *ev;
bool report_device = hci_discovery_active(hdev);
/* Don't send events for a non-kernel initiated discovery. With /* Don't send events for a non-kernel initiated discovery. With
* LE one exception is if we have pend_le_reports > 0 in which * LE one exception is if we have pend_le_reports > 0 in which
@@ -9603,11 +9709,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
if (!hci_discovery_active(hdev)) { if (!hci_discovery_active(hdev)) {
if (link_type == ACL_LINK) if (link_type == ACL_LINK)
return; return;
if (link_type == LE_LINK && if (link_type == LE_LINK && !list_empty(&hdev->pend_le_reports))
list_empty(&hdev->pend_le_reports) && report_device = true;
!hci_is_adv_monitoring(hdev)) { else if (!hci_is_adv_monitoring(hdev))
return; return;
}
} }
if (hdev->discovery.result_filtering) { if (hdev->discovery.result_filtering) {
@@ -9672,7 +9777,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len); ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
mgmt_event_skb(skb, NULL); mgmt_adv_monitor_device_found(hdev, bdaddr, report_device, skb, NULL);
} }
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,

View File

@@ -214,7 +214,8 @@ static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
/* This function requires the caller holds hdev->lock */ /* This function requires the caller holds hdev->lock */
static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle, static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle,
bdaddr_t *bdaddr, __u8 addr_type) bdaddr_t *bdaddr, __u8 addr_type,
bool notify)
{ {
struct monitored_device *dev, *tmp; struct monitored_device *dev, *tmp;
int count = 0; int count = 0;
@@ -227,6 +228,12 @@ static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle,
if ((!mgmt_handle || dev->handle == mgmt_handle) && if ((!mgmt_handle || dev->handle == mgmt_handle) &&
(!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) && (!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) &&
addr_type == dev->addr_type))) { addr_type == dev->addr_type))) {
if (notify && dev->notified) {
mgmt_adv_monitor_device_lost(hdev, dev->handle,
&dev->bdaddr,
dev->addr_type);
}
list_del(&dev->list); list_del(&dev->list);
kfree(dev); kfree(dev);
count++; count++;
@@ -328,7 +335,7 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
/* Clear any monitored devices by this Adv Monitor */ /* Clear any monitored devices by this Adv Monitor */
msft_monitor_device_del(hdev, handle_data->mgmt_handle, NULL, msft_monitor_device_del(hdev, handle_data->mgmt_handle, NULL,
0); 0, false);
list_del(&handle_data->list); list_del(&handle_data->list);
kfree(handle_data); kfree(handle_data);
@@ -596,8 +603,9 @@ void msft_do_close(struct hci_dev *hdev)
hci_dev_lock(hdev); hci_dev_lock(hdev);
/* Clear any devices that are being monitored */ /* Clear any devices that are being monitored and notify device lost */
msft_monitor_device_del(hdev, 0, NULL, 0); hdev->advmon_pend_notify = false;
msft_monitor_device_del(hdev, 0, NULL, 0, true);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
@@ -653,13 +661,15 @@ static void msft_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr,
INIT_LIST_HEAD(&dev->list); INIT_LIST_HEAD(&dev->list);
list_add(&dev->list, &hdev->monitored_devices); list_add(&dev->list, &hdev->monitored_devices);
hdev->advmon_pend_notify = true;
} }
/* This function requires the caller holds hdev->lock */ /* This function requires the caller holds hdev->lock */
static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr, static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr,
__u8 addr_type, __u16 mgmt_handle) __u8 addr_type, __u16 mgmt_handle)
{ {
if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type)) { if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type,
true)) {
bt_dev_err(hdev, "MSFT vendor event %u: dev %pMR not in list", bt_dev_err(hdev, "MSFT vendor event %u: dev %pMR not in list",
MSFT_EV_LE_MONITOR_DEVICE, bdaddr); MSFT_EV_LE_MONITOR_DEVICE, bdaddr);
} }