Commit 79f460ca49d8d5700756ab7071c951311c7f29cc

Authored by Luciano Coelho
Committed by John W. Linville
1 parent 807f8a8c30

mac80211: add support for HW scheduled scan

Implement support for HW scheduled scan.  The mac80211 code doesn't perform
scheduled scans itself, but calls the driver to start and stop scheduled
scans.

This patch also creates a trace event class to be used by drv_hw_scan
and the new drv_sched_scan_start and drv_sched_stop functions, in
order to avoid duplicate code.

Signed-off-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

Showing 8 changed files with 292 additions and 22 deletions Side-by-side Diff

include/net/mac80211.h
... ... @@ -537,6 +537,21 @@
537 537 };
538 538 };
539 539  
  540 +/**
  541 + * ieee80211_sched_scan_ies - scheduled scan IEs
  542 + *
  543 + * This structure is used to pass the appropriate IEs to be used in scheduled
  544 + * scans for all bands. It contains both the IEs passed from the userspace
  545 + * and the ones generated by mac80211.
  546 + *
  547 + * @ie: array with the IEs for each supported band
  548 + * @len: array with the total length of the IEs for each band
  549 + */
  550 +struct ieee80211_sched_scan_ies {
  551 + u8 *ie[IEEE80211_NUM_BANDS];
  552 + size_t len[IEEE80211_NUM_BANDS];
  553 +};
  554 +
540 555 static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
541 556 {
542 557 return (struct ieee80211_tx_info *)skb->cb;
... ... @@ -1693,6 +1708,13 @@
1693 1708 * any error unless this callback returned a negative error code.
1694 1709 * The callback can sleep.
1695 1710 *
  1711 + * @sched_scan_start: Ask the hardware to start scanning repeatedly at
  1712 + * specific intervals. The driver must call the
  1713 + * ieee80211_sched_scan_results() function whenever it finds results.
  1714 + * This process will continue until sched_scan_stop is called.
  1715 + *
  1716 + * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan.
  1717 + *
1696 1718 * @sw_scan_start: Notifier function that is called just before a software scan
1697 1719 * is started. Can be NULL, if the driver doesn't need this notification.
1698 1720 * The callback can sleep.
... ... @@ -1877,6 +1899,12 @@
1877 1899 u32 iv32, u16 *phase1key);
1878 1900 int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1879 1901 struct cfg80211_scan_request *req);
  1902 + int (*sched_scan_start)(struct ieee80211_hw *hw,
  1903 + struct ieee80211_vif *vif,
  1904 + struct cfg80211_sched_scan_request *req,
  1905 + struct ieee80211_sched_scan_ies *ies);
  1906 + void (*sched_scan_stop)(struct ieee80211_hw *hw,
  1907 + struct ieee80211_vif *vif);
1880 1908 void (*sw_scan_start)(struct ieee80211_hw *hw);
1881 1909 void (*sw_scan_complete)(struct ieee80211_hw *hw);
1882 1910 int (*get_stats)(struct ieee80211_hw *hw,
... ... @@ -2592,6 +2620,28 @@
2592 2620 * @aborted: set to true if scan was aborted
2593 2621 */
2594 2622 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
  2623 +
  2624 +/**
  2625 + * ieee80211_sched_scan_results - got results from scheduled scan
  2626 + *
  2627 + * When a scheduled scan is running, this function needs to be called by the
  2628 + * driver whenever there are new scan results available.
  2629 + *
  2630 + * @hw: the hardware that is performing scheduled scans
  2631 + */
  2632 +void ieee80211_sched_scan_results(struct ieee80211_hw *hw);
  2633 +
  2634 +/**
  2635 + * ieee80211_sched_scan_stopped - inform that the scheduled scan has stopped
  2636 + *
  2637 + * When a scheduled scan is running, this function can be called by
  2638 + * the driver if it needs to stop the scan to perform another task.
  2639 + * Usual scenarios are drivers that cannot continue the scheduled scan
  2640 + * while associating, for instance.
  2641 + *
  2642 + * @hw: the hardware that is performing scheduled scans
  2643 + */
  2644 +void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
2595 2645  
2596 2646 /**
2597 2647 * ieee80211_iterate_active_interfaces - iterate active interfaces
... ... @@ -1362,6 +1362,31 @@
1362 1362 return ieee80211_request_scan(sdata, req);
1363 1363 }
1364 1364  
  1365 +static int
  1366 +ieee80211_sched_scan_start(struct wiphy *wiphy,
  1367 + struct net_device *dev,
  1368 + struct cfg80211_sched_scan_request *req)
  1369 +{
  1370 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  1371 +
  1372 + if (!sdata->local->ops->sched_scan_start)
  1373 + return -EOPNOTSUPP;
  1374 +
  1375 + return ieee80211_request_sched_scan_start(sdata, req);
  1376 +}
  1377 +
  1378 +static int
  1379 +ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
  1380 + bool driver_initiated)
  1381 +{
  1382 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  1383 +
  1384 + if (!sdata->local->ops->sched_scan_stop)
  1385 + return -EOPNOTSUPP;
  1386 +
  1387 + return ieee80211_request_sched_scan_stop(sdata, driver_initiated);
  1388 +}
  1389 +
1365 1390 static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
1366 1391 struct cfg80211_auth_request *req)
1367 1392 {
... ... @@ -2103,6 +2128,8 @@
2103 2128 .suspend = ieee80211_suspend,
2104 2129 .resume = ieee80211_resume,
2105 2130 .scan = ieee80211_scan,
  2131 + .sched_scan_start = ieee80211_sched_scan_start,
  2132 + .sched_scan_stop = ieee80211_sched_scan_stop,
2106 2133 .auth = ieee80211_auth,
2107 2134 .assoc = ieee80211_assoc,
2108 2135 .deauth = ieee80211_deauth,
net/mac80211/driver-ops.h
... ... @@ -212,10 +212,37 @@
212 212  
213 213 might_sleep();
214 214  
215   - trace_drv_hw_scan(local, sdata, req);
  215 + trace_drv_hw_scan(local, sdata);
216 216 ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
217 217 trace_drv_return_int(local, ret);
218 218 return ret;
  219 +}
  220 +
  221 +static inline int
  222 +drv_sched_scan_start(struct ieee80211_local *local,
  223 + struct ieee80211_sub_if_data *sdata,
  224 + struct cfg80211_sched_scan_request *req,
  225 + struct ieee80211_sched_scan_ies *ies)
  226 +{
  227 + int ret;
  228 +
  229 + might_sleep();
  230 +
  231 + trace_drv_sched_scan_start(local, sdata);
  232 + ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
  233 + req, ies);
  234 + trace_drv_return_int(local, ret);
  235 + return ret;
  236 +}
  237 +
  238 +static inline void drv_sched_scan_stop(struct ieee80211_local *local,
  239 + struct ieee80211_sub_if_data *sdata)
  240 +{
  241 + might_sleep();
  242 +
  243 + trace_drv_sched_scan_stop(local, sdata);
  244 + local->ops->sched_scan_stop(&local->hw, &sdata->vif);
  245 + trace_drv_return_void(local);
219 246 }
220 247  
221 248 static inline void drv_sw_scan_start(struct ieee80211_local *local)
net/mac80211/driver-trace.h
... ... @@ -98,6 +98,27 @@
98 98 )
99 99 );
100 100  
  101 +DECLARE_EVENT_CLASS(local_sdata_evt,
  102 + TP_PROTO(struct ieee80211_local *local,
  103 + struct ieee80211_sub_if_data *sdata),
  104 + TP_ARGS(local, sdata),
  105 +
  106 + TP_STRUCT__entry(
  107 + LOCAL_ENTRY
  108 + VIF_ENTRY
  109 + ),
  110 +
  111 + TP_fast_assign(
  112 + LOCAL_ASSIGN;
  113 + VIF_ASSIGN;
  114 + ),
  115 +
  116 + TP_printk(
  117 + LOCAL_PR_FMT VIF_PR_FMT,
  118 + LOCAL_PR_ARG, VIF_PR_ARG
  119 + )
  120 +);
  121 +
101 122 DEFINE_EVENT(local_only_evt, drv_return_void,
102 123 TP_PROTO(struct ieee80211_local *local),
103 124 TP_ARGS(local)
104 125  
105 126  
106 127  
... ... @@ -433,27 +454,22 @@
433 454 )
434 455 );
435 456  
436   -TRACE_EVENT(drv_hw_scan,
  457 +DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
437 458 TP_PROTO(struct ieee80211_local *local,
438   - struct ieee80211_sub_if_data *sdata,
439   - struct cfg80211_scan_request *req),
  459 + struct ieee80211_sub_if_data *sdata),
  460 + TP_ARGS(local, sdata)
  461 +);
440 462  
441   - TP_ARGS(local, sdata, req),
  463 +DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
  464 + TP_PROTO(struct ieee80211_local *local,
  465 + struct ieee80211_sub_if_data *sdata),
  466 + TP_ARGS(local, sdata)
  467 +);
442 468  
443   - TP_STRUCT__entry(
444   - LOCAL_ENTRY
445   - VIF_ENTRY
446   - ),
447   -
448   - TP_fast_assign(
449   - LOCAL_ASSIGN;
450   - VIF_ASSIGN;
451   - ),
452   -
453   - TP_printk(
454   - LOCAL_PR_FMT VIF_PR_FMT,
455   - LOCAL_PR_ARG,VIF_PR_ARG
456   - )
  469 +DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
  470 + TP_PROTO(struct ieee80211_local *local,
  471 + struct ieee80211_sub_if_data *sdata),
  472 + TP_ARGS(local, sdata)
457 473 );
458 474  
459 475 DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
... ... @@ -1177,6 +1193,42 @@
1177 1193 TP_printk(
1178 1194 LOCAL_PR_FMT " aborted:%d",
1179 1195 LOCAL_PR_ARG, __entry->aborted
  1196 + )
  1197 +);
  1198 +
  1199 +TRACE_EVENT(api_sched_scan_results,
  1200 + TP_PROTO(struct ieee80211_local *local),
  1201 +
  1202 + TP_ARGS(local),
  1203 +
  1204 + TP_STRUCT__entry(
  1205 + LOCAL_ENTRY
  1206 + ),
  1207 +
  1208 + TP_fast_assign(
  1209 + LOCAL_ASSIGN;
  1210 + ),
  1211 +
  1212 + TP_printk(
  1213 + LOCAL_PR_FMT, LOCAL_PR_ARG
  1214 + )
  1215 +);
  1216 +
  1217 +TRACE_EVENT(api_sched_scan_stopped,
  1218 + TP_PROTO(struct ieee80211_local *local),
  1219 +
  1220 + TP_ARGS(local),
  1221 +
  1222 + TP_STRUCT__entry(
  1223 + LOCAL_ENTRY
  1224 + ),
  1225 +
  1226 + TP_fast_assign(
  1227 + LOCAL_ASSIGN;
  1228 + ),
  1229 +
  1230 + TP_printk(
  1231 + LOCAL_PR_FMT, LOCAL_PR_ARG
1180 1232 )
1181 1233 );
1182 1234  
net/mac80211/ieee80211_i.h
... ... @@ -847,6 +847,9 @@
847 847 int scan_channel_idx;
848 848 int scan_ies_len;
849 849  
  850 + bool sched_scanning;
  851 + struct ieee80211_sched_scan_ies sched_scan_ies;
  852 +
850 853 unsigned long leave_oper_channel_time;
851 854 enum mac80211_scan_state next_scan_state;
852 855 struct delayed_work scan_work;
... ... @@ -1153,6 +1156,12 @@
1153 1156 u8 *ssid, u8 ssid_len);
1154 1157 void ieee80211_rx_bss_put(struct ieee80211_local *local,
1155 1158 struct ieee80211_bss *bss);
  1159 +
  1160 +/* scheduled scan handling */
  1161 +int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
  1162 + struct cfg80211_sched_scan_request *req);
  1163 +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
  1164 + bool driver_initiated);
1156 1165  
1157 1166 /* off-channel helpers */
1158 1167 bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
... ... @@ -358,7 +358,8 @@
358 358 flush_workqueue(local->workqueue);
359 359  
360 360 mutex_lock(&local->mtx);
361   - WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
  361 + WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
  362 + local->sched_scanning,
362 363 "%s called with hardware scan in progress\n", __func__);
363 364 mutex_unlock(&local->mtx);
364 365  
... ... @@ -832,6 +833,9 @@
832 833  
833 834 if (!local->ops->remain_on_channel)
834 835 local->hw.wiphy->max_remain_on_channel_duration = 5000;
  836 +
  837 + if (local->ops->sched_scan_start)
  838 + local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
835 839  
836 840 result = wiphy_register(local->hw.wiphy);
837 841 if (result < 0)
... ... @@ -404,11 +404,13 @@
404 404 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
405 405 struct sk_buff *skb = rx->skb;
406 406  
407   - if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
  407 + if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
  408 + !local->sched_scanning))
408 409 return RX_CONTINUE;
409 410  
410 411 if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
411   - test_bit(SCAN_SW_SCANNING, &local->scanning))
  412 + test_bit(SCAN_SW_SCANNING, &local->scanning) ||
  413 + local->sched_scanning)
412 414 return ieee80211_scan_rx(rx->sdata, skb);
413 415  
414 416 /* scanning finished during invoking of handlers */
... ... @@ -15,6 +15,7 @@
15 15 #include <linux/if_arp.h>
16 16 #include <linux/rtnetlink.h>
17 17 #include <linux/pm_qos_params.h>
  18 +#include <linux/slab.h>
18 19 #include <net/sch_generic.h>
19 20 #include <linux/slab.h>
20 21 #include <net/mac80211.h>
... ... @@ -850,4 +851,102 @@
850 851 }
851 852 mutex_unlock(&local->mtx);
852 853 }
  854 +
  855 +int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
  856 + struct cfg80211_sched_scan_request *req)
  857 +{
  858 + struct ieee80211_local *local = sdata->local;
  859 + int ret, i;
  860 +
  861 + mutex_lock(&sdata->local->mtx);
  862 +
  863 + if (local->sched_scanning) {
  864 + ret = -EBUSY;
  865 + goto out;
  866 + }
  867 +
  868 + if (!local->ops->sched_scan_start) {
  869 + ret = -ENOTSUPP;
  870 + goto out;
  871 + }
  872 +
  873 + for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
  874 + local->sched_scan_ies.ie[i] = kzalloc(2 +
  875 + IEEE80211_MAX_SSID_LEN +
  876 + local->scan_ies_len,
  877 + GFP_KERNEL);
  878 + if (!local->sched_scan_ies.ie[i]) {
  879 + ret = -ENOMEM;
  880 + goto out_free;
  881 + }
  882 +
  883 + local->sched_scan_ies.len[i] =
  884 + ieee80211_build_preq_ies(local,
  885 + local->sched_scan_ies.ie[i],
  886 + req->ie, req->ie_len, i,
  887 + (u32) -1, 0);
  888 + }
  889 +
  890 + ret = drv_sched_scan_start(local, sdata, req,
  891 + &local->sched_scan_ies);
  892 + if (ret == 0) {
  893 + local->sched_scanning = true;
  894 + goto out;
  895 + }
  896 +
  897 +out_free:
  898 + while (i > 0)
  899 + kfree(local->sched_scan_ies.ie[--i]);
  900 +out:
  901 + mutex_unlock(&sdata->local->mtx);
  902 + return ret;
  903 +}
  904 +
  905 +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
  906 + bool driver_initiated)
  907 +{
  908 + struct ieee80211_local *local = sdata->local;
  909 + int ret = 0, i;
  910 +
  911 + mutex_lock(&sdata->local->mtx);
  912 +
  913 + if (!local->ops->sched_scan_stop) {
  914 + ret = -ENOTSUPP;
  915 + goto out;
  916 + }
  917 +
  918 + if (local->sched_scanning) {
  919 + for (i = 0; i < IEEE80211_NUM_BANDS; i++)
  920 + kfree(local->sched_scan_ies.ie[i]);
  921 +
  922 + if (!driver_initiated)
  923 + drv_sched_scan_stop(local, sdata);
  924 + local->sched_scanning = false;
  925 + }
  926 +
  927 +out:
  928 + mutex_unlock(&sdata->local->mtx);
  929 +
  930 + return ret;
  931 +}
  932 +
  933 +void ieee80211_sched_scan_results(struct ieee80211_hw *hw)
  934 +{
  935 + struct ieee80211_local *local = hw_to_local(hw);
  936 +
  937 + trace_api_sched_scan_results(local);
  938 +
  939 + cfg80211_sched_scan_results(hw->wiphy);
  940 +}
  941 +EXPORT_SYMBOL(ieee80211_sched_scan_results);
  942 +
  943 +void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
  944 +{
  945 + struct ieee80211_local *local = hw_to_local(hw);
  946 +
  947 + trace_api_sched_scan_stopped(local);
  948 +
  949 + cfg80211_sched_scan_stopped(hw->wiphy);
  950 +}
  951 +EXPORT_SYMBOL(ieee80211_sched_scan_stopped);