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 list_head monitored_devices;
bool advmon_pend_notify;
#if IS_ENABLED(CONFIG_BT_LEDS)
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_add_adv_patterns_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,
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_UNEXPECTED 0x1
#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_CONTROLLER_SUSPEND,
MGMT_EV_CONTROLLER_RESUME,
MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
MGMT_EV_ADV_MONITOR_DEVICE_LOST,
};
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;
}
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,
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
{
struct sk_buff *skb;
struct mgmt_ev_device_found *ev;
bool report_device = hci_discovery_active(hdev);
/* Don't send events for a non-kernel initiated discovery. With
* 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 (link_type == ACL_LINK)
return;
if (link_type == LE_LINK &&
list_empty(&hdev->pend_le_reports) &&
!hci_is_adv_monitoring(hdev)) {
if (link_type == LE_LINK && !list_empty(&hdev->pend_le_reports))
report_device = true;
else if (!hci_is_adv_monitoring(hdev))
return;
}
}
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);
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,

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 */
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;
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) &&
(!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) &&
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);
kfree(dev);
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 */
msft_monitor_device_del(hdev, handle_data->mgmt_handle, NULL,
0);
0, false);
list_del(&handle_data->list);
kfree(handle_data);
@ -596,8 +603,9 @@ void msft_do_close(struct hci_dev *hdev)
hci_dev_lock(hdev);
/* Clear any devices that are being monitored */
msft_monitor_device_del(hdev, 0, NULL, 0);
/* Clear any devices that are being monitored and notify device lost */
hdev->advmon_pend_notify = false;
msft_monitor_device_del(hdev, 0, NULL, 0, true);
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);
list_add(&dev->list, &hdev->monitored_devices);
hdev->advmon_pend_notify = true;
}
/* This function requires the caller holds hdev->lock */
static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr,
__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",
MSFT_EV_LE_MONITOR_DEVICE, bdaddr);
}