/* Cancel all corresponding address monitors */
mutex_lock(&msft->filter_lock);
list_for_each_entry_safe(address_filter, n, &msft->address_filters,
list) { if (address_filter->pattern_handle != handle) continue;
list_del(&address_filter->list);
/* Keep the address filter and let * msft_add_address_filter_sync() remove and free the address * filter.
*/ if (address_filter->state == AF_STATE_ADDING) {
address_filter->state = AF_STATE_REMOVING; continue;
}
/* Keep the address filter and let * msft_cancel_address_filter_sync() remove and free the address * filter
*/ if (address_filter->state == AF_STATE_REMOVING) continue;
list_add_tail(&address_filter->list, &head);
}
mutex_unlock(&msft->filter_lock);
list_for_each_entry_safe(address_filter, n, &head, list) {
list_del(&address_filter->list);
if (handle_data) { if (monitor->state == ADV_MONITOR_STATE_OFFLOADED)
monitor->state = ADV_MONITOR_STATE_REGISTERED;
/* Do not free the monitor if it is being removed due to * suspend. It will be re-monitored on resume.
*/ if (!msft->suspending) {
hci_free_adv_monitor(hdev, monitor);
/* Clear any monitored devices by this Adv Monitor */
msft_monitor_device_del(hdev, handle_data->mgmt_handle,
NULL, 0, false);
}
/* High_threshold_timeout is not supported, * once high_threshold is reached, events are immediately reported.
*/ if (r->high_threshold_timeout != 0) returnfalse;
if (r->low_threshold_timeout > MSFT_RSSI_LOW_TIMEOUT_MAX) returnfalse;
/* Sampling period from 0x00 to 0xFF are all allowed */ returntrue;
}
staticbool msft_monitor_pattern_valid(struct adv_monitor *monitor)
{ return msft_monitor_rssi_valid(monitor); /* No additional check needed for pattern-based monitor */
}
/* This function requires the caller holds hci_req_sync_lock */ staticvoid reregister_monitor(struct hci_dev *hdev)
{ struct adv_monitor *monitor; struct msft_data *msft = hdev->msft_data; int handle = 0;
if (!msft) return;
msft->resuming = true;
while (1) {
monitor = idr_get_next(&hdev->adv_monitors_idr, &handle); if (!monitor) break;
msft_add_monitor_sync(hdev, monitor);
handle++;
}
/* All monitors have been reregistered */
msft->resuming = false;
}
/* This function requires the caller holds hci_req_sync_lock */ int msft_resume_sync(struct hci_dev *hdev)
{ struct msft_data *msft = hdev->msft_data;
if (!msft || !msft_monitor_supported(hdev)) return 0;
hci_dev_lock(hdev);
/* Clear already tracked devices on resume. Once the monitors are * reregistered, devices in range will be found again after resume.
*/
hdev->advmon_pend_notify = false;
msft_monitor_device_del(hdev, 0, NULL, 0, true);
hci_dev_unlock(hdev);
reregister_monitor(hdev);
return 0;
}
/* This function requires the caller holds hci_req_sync_lock */ void msft_do_open(struct hci_dev *hdev)
{ struct msft_data *msft = hdev->msft_data;
if (hdev->msft_opcode == HCI_OP_NOP) return;
if (!msft) {
bt_dev_err(hdev, "MSFT extension not registered"); return;
}
bt_dev_dbg(hdev, "Initialize MSFT extension");
/* Reset existing MSFT data before re-reading */
kfree(msft->evt_prefix);
msft->evt_prefix = NULL;
msft->evt_prefix_len = 0;
msft->features = 0;
if (!read_supported_features(hdev, msft)) {
hdev->msft_data = NULL;
kfree(msft); return;
}
if (msft_monitor_supported(hdev)) {
msft->resuming = true;
msft_set_filter_enable(hdev, true); /* Monitors get removed on power off, so we need to explicitly * tell the controller to re-monitor.
*/
reregister_monitor(hdev);
}
}
/* The controller will silently remove all monitors on power off. * Therefore, remove handle_data mapping and reset monitor state.
*/
list_for_each_entry_safe(handle_data, tmp, &msft->handle_map, list) {
monitor = idr_find(&hdev->adv_monitors_idr,
handle_data->mgmt_handle);
if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
monitor->state = ADV_MONITOR_STATE_REGISTERED;
mutex_lock(&msft->filter_lock);
list_for_each_entry_safe(address_filter, n, &msft->address_filters,
list) {
list_del(&address_filter->list);
kfree(address_filter);
}
mutex_unlock(&msft->filter_lock);
hci_dev_lock(hdev);
/* 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);
if (!msft) {
bt_dev_err(hdev, "MSFT: msft data is freed"); return -EINVAL;
}
/* The address filter has been removed by hci dev close */ if (!test_bit(HCI_UP, &hdev->flags)) return -ENODEV;
/* We are safe to use the address filter from now on. * msft_monitor_device_evt() wouldn't delete this filter because it's * not been added by now. * And all other functions that requiring hci_req_sync_lock wouldn't * touch this filter before this func completes because it's protected * by hci_req_sync_lock.
*/
/* With the above AF_STATE_ADDING, duplicated address filter can be * avoided when receiving monitor device event (found/lost) frequently * for the same device.
*/
list_add_tail(&address_filter->list, &msft->address_filters);
if (!hci_test_quirk(hdev, HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER)) { if (!handle_data) return;
mgmt_handle = handle_data->mgmt_handle; goto report_state;
}
if (handle_data) { /* Don't report any device found/lost event from pattern * monitors. Pattern monitor always has its address filters for * tracking devices.
*/
address_filter = msft_find_address_data(hdev, ev->addr_type,
&ev->bdaddr,
handle_data->msft_handle); if (address_filter) return;
if (ev->monitor_state && handle_data->cond_type ==
MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN)
msft_add_address_filter(hdev, ev->addr_type,
&ev->bdaddr, handle_data);
return;
}
/* This device event is not from pattern monitor. * Report it if there is a corresponding address_filter for it.
*/
list_for_each_entry(n, &msft->address_filters, list) { if (n->state == AF_STATE_ADDED &&
n->msft_handle == ev->monitor_handle) {
mgmt_handle = n->mgmt_handle;
address_filter = n; break;
}
}
/* When the extension has defined an event prefix, check that it * matches, and otherwise just return.
*/ if (msft->evt_prefix_len > 0) {
evt_prefix = msft_skb_pull(hdev, skb, 0, msft->evt_prefix_len); if (!evt_prefix) return;
if (memcmp(evt_prefix, msft->evt_prefix, msft->evt_prefix_len)) return;
}
/* Every event starts at least with an event code and the rest of * the data is variable and depends on the event code.
*/ if (skb->len < 1) return;
evt = msft_skb_pull(hdev, skb, 0, sizeof(*evt)); if (!evt) return;
hci_dev_lock(hdev);
switch (*evt) { case MSFT_EV_LE_MONITOR_DEVICE:
mutex_lock(&msft->filter_lock);
msft_monitor_device_evt(hdev, skb);
mutex_unlock(&msft->filter_lock); break;
/* Error 0x0C would be returned if the filter enabled status is * already set to whatever we were trying to set. * Although the default state should be disabled, some controller set * the initial value to enabled. Because there is no way to know the * actual initial value before sending this command, here we also treat * error 0x0C as success.
*/ if (status != 0x00 && status != 0x0C) return;
hci_dev_lock(hdev);
msft->filter_enabled = cp->enable;
if (status == 0x0C)
bt_dev_warn(hdev, "MSFT filter_enable is already %s",
cp->enable ? "on" : "off");
hci_dev_unlock(hdev);
}
/* This function requires the caller holds hci_req_sync_lock */ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
{ struct msft_data *msft = hdev->msft_data;
if (!msft) return -EOPNOTSUPP;
if (msft->resuming || msft->suspending) return -EBUSY;
return msft_add_monitor_sync(hdev, monitor);
}
/* This function requires the caller holds hci_req_sync_lock */ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
{ struct msft_data *msft = hdev->msft_data;
if (!msft) return -EOPNOTSUPP;
if (msft->resuming || msft->suspending) return -EBUSY;
return msft_remove_monitor_sync(hdev, monitor);
}
int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
{ struct msft_cp_le_set_advertisement_filter_enable cp; struct msft_data *msft = hdev->msft_data; int err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.