Commit 8d7f1677 authored by Manish Mandlik's avatar Manish Mandlik Committed by Luiz Augusto von Dentz
Browse files

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: default avatarManish Mandlik <mmandlik@google.com>
Reviewed-by: default avatarMiao-chen Chou <mcchou@google.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 3368aa35
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
+16 −0
Original line number Diff line number Diff line
@@ -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;
+110 −5
Original line number Diff line number Diff line
@@ -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,12 +9709,11 @@ 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) {
		/* We are using service discovery */
@@ -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,
+15 −5
Original line number Diff line number Diff line
@@ -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);
	}