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:
committed by
Luiz Augusto von Dentz
parent
3368aa357f
commit
8d7f167752
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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,
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user