@@ -2140,6 +2140,13 @@ int cfg80211_wext_siwpmksa(struct net_device *dev,
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
/**
+ * cfg80211_periodic_results - notify that new scan results are available
+ *
+ * @request: the corresponding periodic scan request
+ */
+void cfg80211_periodic_results(struct cfg80211_periodic_request *req);
+
+/**
* cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
*
* @wiphy: the wiphy reporting the BSS
@@ -2322,6 +2322,16 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
/**
+ * ieee80211_periodic_results - got results from periodic scan
+ *
+ * When a periodic scan is running, this function needs to be called by the
+ * driver whenever there are new scan results availble.
+ *
+ * @hw: the hardware that is performing periodic scans
+ */
+void ieee80211_periodic_results(struct ieee80211_hw *hw);
+
+/**
* ieee80211_iterate_active_interfaces - iterate active interfaces
*
* This function iterates over the interfaces associated with a given
@@ -519,6 +519,24 @@ TRACE_EVENT(drv_sw_scan_complete,
)
);
+TRACE_EVENT(drv_periodic_results,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
TRACE_EVENT(drv_get_stats,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_low_level_stats *stats,
@@ -648,6 +648,7 @@ enum queue_stop_reason {
* that the scan completed.
* @SCAN_ABORTED: Set for our scan work function when the driver reported
* a scan complete for an aborted scan.
+ * @SCAN_PERIODIC_SCANNING: We're currently performing periodic scans
*/
enum {
SCAN_SW_SCANNING,
@@ -655,6 +656,7 @@ enum {
SCAN_OFF_CHANNEL,
SCAN_COMPLETED,
SCAN_ABORTED,
+ SCAN_PERIODIC_SCANNING,
};
/**
@@ -392,7 +392,8 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
return RX_CONTINUE;
- if (test_bit(SCAN_HW_SCANNING, &local->scanning))
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+ test_bit(SCAN_PERIODIC_SCANNING, &local->scanning))
return ieee80211_scan_rx(rx->sdata, skb);
if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
@@ -2702,6 +2703,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
local->dot11ReceivedFragmentCount++;
if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+ test_bit(SCAN_PERIODIC_SCANNING, &local->scanning) ||
test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
status->rx_flags |= IEEE80211_RX_IN_SCAN;
@@ -847,7 +847,9 @@ int ieee80211_request_periodic_start(struct ieee80211_sub_if_data *sdata,
local->periodic_req = req;
ret = drv_periodic_start(local, sdata);
- if (ret)
+ if (!ret)
+ __set_bit(SCAN_PERIODIC_SCANNING, &local->scanning);
+ else
local->periodic_req = NULL;
out:
mutex_unlock(&sdata->local->mtx);
@@ -870,6 +872,7 @@ int ieee80211_request_periodic_stop(struct ieee80211_sub_if_data *sdata)
if (local->periodic_req) {
ret = drv_periodic_stop(local, sdata);
local->periodic_req = NULL;
+ __clear_bit(SCAN_PERIODIC_SCANNING, &local->scanning);
}
out:
@@ -877,3 +880,15 @@ out:
return ret;
}
+
+void ieee80211_periodic_results(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ mutex_lock(&local->mtx);
+
+ cfg80211_periodic_results(local->periodic_req);
+
+ mutex_unlock(&local->mtx);
+}
+EXPORT_SYMBOL(ieee80211_periodic_results);
@@ -363,6 +363,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
spin_lock_init(&rdev->bss_lock);
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
+ INIT_WORK(&rdev->periodic_wk, __cfg80211_periodic_results);
#ifdef CONFIG_CFG80211_WEXT
rdev->wiphy.wext = &cfg80211_wext_handler;
@@ -63,6 +63,7 @@ struct cfg80211_registered_device {
struct cfg80211_periodic_request *periodic_req; /* protected by RTNL */
unsigned long suspend_at;
struct work_struct scan_done_wk;
+ struct work_struct periodic_wk;
#ifdef CONFIG_NL80211_TESTMODE
struct genl_info *testmode_info;
@@ -384,6 +385,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
void cfg80211_sme_disassoc(struct net_device *dev, int idx);
void __cfg80211_scan_done(struct work_struct *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
+void __cfg80211_periodic_results(struct work_struct *wk);
void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype ntype,
@@ -93,6 +93,26 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
}
EXPORT_SYMBOL(cfg80211_scan_done);
+void __cfg80211_periodic_results(struct work_struct *wk)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(wk, struct cfg80211_registered_device,
+ periodic_wk);
+
+ cfg80211_lock_rdev(rdev);
+ nl80211_send_scan_done(rdev, rdev->periodic_req->dev);
+ cfg80211_unlock_rdev(rdev);
+}
+
+void cfg80211_periodic_results(struct cfg80211_periodic_request *req)
+{
+ WARN_ON(req != wiphy_to_dev(req->wiphy)->periodic_req);
+
+ queue_work(cfg80211_wq, &wiphy_to_dev(req->wiphy)->periodic_wk);
+}
+EXPORT_SYMBOL(cfg80211_periodic_results);
+
static void bss_release(struct kref *ref)
{
struct cfg80211_internal_bss *bss;