@@ -4649,6 +4649,9 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
if (use_ll_privacy(hdev))
hci_resume_advertising_sync(hdev);
+ /* Sampling Period is disabled while active scanning, re-enable it */
+ msft_set_active_scan(hdev, false);
+
/* No further actions needed for LE-only discovery */
if (d->type == DISCOV_TYPE_LE)
return 0;
@@ -5139,6 +5142,9 @@ int hci_start_discovery_sync(struct hci_dev *hdev)
if (err)
return err;
+ /* Disable Sampling Period while active scanning */
+ msft_set_active_scan(hdev, true);
+
bt_dev_dbg(hdev, "timeout %u ms", jiffies_to_msecs(timeout));
/* When service discovery is used and the controller has a
@@ -101,6 +101,7 @@ struct msft_data {
struct list_head handle_map;
__u8 resuming;
__u8 suspending;
+ __u8 active_scan;
__u8 filter_enabled;
};
@@ -333,14 +334,14 @@ static int msft_remove_monitor_sync(struct hci_dev *hdev,
}
/* This function requires the caller holds hci_req_sync_lock */
-int msft_suspend_sync(struct hci_dev *hdev)
+static void remove_all_monitors(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;
struct adv_monitor *monitor;
int handle = 0;
if (!msft || !msft_monitor_supported(hdev))
- return 0;
+ return;
msft->suspending = true;
@@ -356,6 +357,12 @@ int msft_suspend_sync(struct hci_dev *hdev)
/* All monitors have been removed */
msft->suspending = false;
+}
+
+/* This function requires the caller holds hci_req_sync_lock */
+int msft_suspend_sync(struct hci_dev *hdev)
+{
+ remove_all_monitors(hdev);
return 0;
}
@@ -392,6 +399,7 @@ static bool msft_monitor_pattern_valid(struct adv_monitor *monitor)
static int msft_add_monitor_sync(struct hci_dev *hdev,
struct adv_monitor *monitor)
{
+ struct msft_data *msft = hdev->msft_data;
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
struct msft_le_monitor_advertisement_pattern *pattern;
@@ -417,7 +425,16 @@ static int msft_add_monitor_sync(struct hci_dev *hdev,
cp->rssi_high = monitor->rssi.high_threshold;
cp->rssi_low = monitor->rssi.low_threshold;
cp->rssi_low_interval = (u8)monitor->rssi.low_threshold_timeout;
- cp->rssi_sampling_period = monitor->rssi.sampling_period;
+
+ /* Some controllers apply Sampling Period even while active scanning.
+ * So, to keep the behavior consistent across all controllers, don't
+ * use Sampling Period during active scanning to force the controller
+ * to report all advertisements even if it matches the monitor.
+ */
+ if (msft->active_scan)
+ cp->rssi_sampling_period = 0;
+ else
+ cp->rssi_sampling_period = monitor->rssi.sampling_period;
cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN;
@@ -815,6 +832,28 @@ void msft_req_add_set_filter_enable(struct hci_request *req, bool enable)
hci_req_add(req, hdev->msft_opcode, sizeof(cp), &cp);
}
+/* This function requires the caller holds hci_req_sync_lock */
+void msft_set_active_scan(struct hci_dev *hdev, bool enable)
+{
+ struct msft_data *msft = hdev->msft_data;
+
+ if (!msft)
+ return;
+
+ /* Remove all monitors */
+ remove_all_monitors(hdev);
+
+ /* Clear all tracked devices */
+ hci_dev_lock(hdev);
+ hdev->advmon_pend_notify = false;
+ msft_monitor_device_del(hdev, 0, NULL, 0, true);
+ hci_dev_unlock(hdev);
+
+ /* Update active scan and reregister all monitors */
+ msft->active_scan = enable;
+ reregister_monitor(hdev);
+}
+
int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
{
struct hci_request req;
@@ -22,6 +22,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor);
int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
void msft_req_add_set_filter_enable(struct hci_request *req, bool enable);
+void msft_set_active_scan(struct hci_dev *hdev, bool enable);
int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
int msft_suspend_sync(struct hci_dev *hdev);
int msft_resume_sync(struct hci_dev *hdev);
@@ -55,6 +56,7 @@ static inline int msft_remove_monitor(struct hci_dev *hdev,
static inline void msft_req_add_set_filter_enable(struct hci_request *req,
bool enable) {}
+static inline void msft_set_active_scan(struct hci_dev *hdev, bool enable) {}
static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
{
return -EOPNOTSUPP;