aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h50
-rw-r--r--net/mac80211/cfg.c27
-rw-r--r--net/mac80211/driver-ops.h29
-rw-r--r--net/mac80211/driver-trace.h88
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/main.c6
-rw-r--r--net/mac80211/rx.c6
-rw-r--r--net/mac80211/scan.c99
8 files changed, 292 insertions, 22 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9e5542794b95..62a1c225b7cb 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -537,6 +537,21 @@ struct ieee80211_tx_info {
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 */
550struct ieee80211_sched_scan_ies {
551 u8 *ie[IEEE80211_NUM_BANDS];
552 size_t len[IEEE80211_NUM_BANDS];
553};
554
540static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) 555static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
541{ 556{
542 return (struct ieee80211_tx_info *)skb->cb; 557 return (struct ieee80211_tx_info *)skb->cb;
@@ -1693,6 +1708,13 @@ enum ieee80211_ampdu_mlme_action {
1693 * any error unless this callback returned a negative error code. 1708 * any error unless this callback returned a negative error code.
1694 * The callback can sleep. 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 * @sw_scan_start: Notifier function that is called just before a software scan 1718 * @sw_scan_start: Notifier function that is called just before a software scan
1697 * is started. Can be NULL, if the driver doesn't need this notification. 1719 * is started. Can be NULL, if the driver doesn't need this notification.
1698 * The callback can sleep. 1720 * The callback can sleep.
@@ -1877,6 +1899,12 @@ struct ieee80211_ops {
1877 u32 iv32, u16 *phase1key); 1899 u32 iv32, u16 *phase1key);
1878 int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1900 int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1879 struct cfg80211_scan_request *req); 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 void (*sw_scan_start)(struct ieee80211_hw *hw); 1908 void (*sw_scan_start)(struct ieee80211_hw *hw);
1881 void (*sw_scan_complete)(struct ieee80211_hw *hw); 1909 void (*sw_scan_complete)(struct ieee80211_hw *hw);
1882 int (*get_stats)(struct ieee80211_hw *hw, 1910 int (*get_stats)(struct ieee80211_hw *hw,
@@ -2594,6 +2622,28 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
2594void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted); 2622void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
2595 2623
2596/** 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 */
2632void 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 */
2644void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
2645
2646/**
2597 * ieee80211_iterate_active_interfaces - iterate active interfaces 2647 * ieee80211_iterate_active_interfaces - iterate active interfaces
2598 * 2648 *
2599 * This function iterates over the interfaces associated with a given 2649 * This function iterates over the interfaces associated with a given
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c416cce5e1ed..a2ff47493e0a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1362,6 +1362,31 @@ static int ieee80211_scan(struct wiphy *wiphy,
1362 return ieee80211_request_scan(sdata, req); 1362 return ieee80211_request_scan(sdata, req);
1363} 1363}
1364 1364
1365static int
1366ieee80211_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
1378static int
1379ieee80211_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
1365static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, 1390static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
1366 struct cfg80211_auth_request *req) 1391 struct cfg80211_auth_request *req)
1367{ 1392{
@@ -2103,6 +2128,8 @@ struct cfg80211_ops mac80211_config_ops = {
2103 .suspend = ieee80211_suspend, 2128 .suspend = ieee80211_suspend,
2104 .resume = ieee80211_resume, 2129 .resume = ieee80211_resume,
2105 .scan = ieee80211_scan, 2130 .scan = ieee80211_scan,
2131 .sched_scan_start = ieee80211_sched_scan_start,
2132 .sched_scan_stop = ieee80211_sched_scan_stop,
2106 .auth = ieee80211_auth, 2133 .auth = ieee80211_auth,
2107 .assoc = ieee80211_assoc, 2134 .assoc = ieee80211_assoc,
2108 .deauth = ieee80211_deauth, 2135 .deauth = ieee80211_deauth,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index aa16bd8ef789..eebf7a67daf7 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -212,12 +212,39 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
212 212
213 might_sleep(); 213 might_sleep();
214 214
215 trace_drv_hw_scan(local, sdata, req); 215 trace_drv_hw_scan(local, sdata);
216 ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); 216 ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
217 trace_drv_return_int(local, ret); 217 trace_drv_return_int(local, ret);
218 return ret; 218 return ret;
219} 219}
220 220
221static inline int
222drv_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
238static 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);
246}
247
221static inline void drv_sw_scan_start(struct ieee80211_local *local) 248static inline void drv_sw_scan_start(struct ieee80211_local *local)
222{ 249{
223 might_sleep(); 250 might_sleep();
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index dd9779d41d2b..ed9edcbd9aa5 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -98,6 +98,27 @@ DECLARE_EVENT_CLASS(local_u32_evt,
98 ) 98 )
99); 99);
100 100
101DECLARE_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
101DEFINE_EVENT(local_only_evt, drv_return_void, 122DEFINE_EVENT(local_only_evt, drv_return_void,
102 TP_PROTO(struct ieee80211_local *local), 123 TP_PROTO(struct ieee80211_local *local),
103 TP_ARGS(local) 124 TP_ARGS(local)
@@ -433,27 +454,22 @@ TRACE_EVENT(drv_update_tkip_key,
433 ) 454 )
434); 455);
435 456
436TRACE_EVENT(drv_hw_scan, 457DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
437 TP_PROTO(struct ieee80211_local *local, 458 TP_PROTO(struct ieee80211_local *local,
438 struct ieee80211_sub_if_data *sdata, 459 struct ieee80211_sub_if_data *sdata),
439 struct cfg80211_scan_request *req), 460 TP_ARGS(local, sdata)
440 461);
441 TP_ARGS(local, sdata, req),
442
443 TP_STRUCT__entry(
444 LOCAL_ENTRY
445 VIF_ENTRY
446 ),
447 462
448 TP_fast_assign( 463DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
449 LOCAL_ASSIGN; 464 TP_PROTO(struct ieee80211_local *local,
450 VIF_ASSIGN; 465 struct ieee80211_sub_if_data *sdata),
451 ), 466 TP_ARGS(local, sdata)
467);
452 468
453 TP_printk( 469DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
454 LOCAL_PR_FMT VIF_PR_FMT, 470 TP_PROTO(struct ieee80211_local *local,
455 LOCAL_PR_ARG,VIF_PR_ARG 471 struct ieee80211_sub_if_data *sdata),
456 ) 472 TP_ARGS(local, sdata)
457); 473);
458 474
459DEFINE_EVENT(local_only_evt, drv_sw_scan_start, 475DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
@@ -1180,6 +1196,42 @@ TRACE_EVENT(api_scan_completed,
1180 ) 1196 )
1181); 1197);
1182 1198
1199TRACE_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
1217TRACE_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
1232 )
1233);
1234
1183TRACE_EVENT(api_sta_block_awake, 1235TRACE_EVENT(api_sta_block_awake,
1184 TP_PROTO(struct ieee80211_local *local, 1236 TP_PROTO(struct ieee80211_local *local,
1185 struct ieee80211_sta *sta, bool block), 1237 struct ieee80211_sta *sta, bool block),
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7f4d0dc1d534..6f55a789c099 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -847,6 +847,9 @@ struct ieee80211_local {
847 int scan_channel_idx; 847 int scan_channel_idx;
848 int scan_ies_len; 848 int scan_ies_len;
849 849
850 bool sched_scanning;
851 struct ieee80211_sched_scan_ies sched_scan_ies;
852
850 unsigned long leave_oper_channel_time; 853 unsigned long leave_oper_channel_time;
851 enum mac80211_scan_state next_scan_state; 854 enum mac80211_scan_state next_scan_state;
852 struct delayed_work scan_work; 855 struct delayed_work scan_work;
@@ -1154,6 +1157,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
1154void ieee80211_rx_bss_put(struct ieee80211_local *local, 1157void ieee80211_rx_bss_put(struct ieee80211_local *local,
1155 struct ieee80211_bss *bss); 1158 struct ieee80211_bss *bss);
1156 1159
1160/* scheduled scan handling */
1161int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1162 struct cfg80211_sched_scan_request *req);
1163int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
1164 bool driver_initiated);
1165
1157/* off-channel helpers */ 1166/* off-channel helpers */
1158bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); 1167bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
1159void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, 1168void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ab1f464817af..30e6a682a047 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -358,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work)
358 flush_workqueue(local->workqueue); 358 flush_workqueue(local->workqueue);
359 359
360 mutex_lock(&local->mtx); 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 "%s called with hardware scan in progress\n", __func__); 363 "%s called with hardware scan in progress\n", __func__);
363 mutex_unlock(&local->mtx); 364 mutex_unlock(&local->mtx);
364 365
@@ -833,6 +834,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
833 if (!local->ops->remain_on_channel) 834 if (!local->ops->remain_on_channel)
834 local->hw.wiphy->max_remain_on_channel_duration = 5000; 835 local->hw.wiphy->max_remain_on_channel_duration = 5000;
835 836
837 if (local->ops->sched_scan_start)
838 local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
839
836 result = wiphy_register(local->hw.wiphy); 840 result = wiphy_register(local->hw.wiphy);
837 if (result < 0) 841 if (result < 0)
838 goto fail_wiphy_register; 842 goto fail_wiphy_register;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 634f3d97a279..1b9413fb3839 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -404,11 +404,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
404 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 404 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
405 struct sk_buff *skb = rx->skb; 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 return RX_CONTINUE; 409 return RX_CONTINUE;
409 410
410 if (test_bit(SCAN_HW_SCANNING, &local->scanning) || 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 return ieee80211_scan_rx(rx->sdata, skb); 414 return ieee80211_scan_rx(rx->sdata, skb);
413 415
414 /* scanning finished during invoking of handlers */ 416 /* scanning finished during invoking of handlers */
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 8acce724f0dc..ea44a8e941ec 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -15,6 +15,7 @@
15#include <linux/if_arp.h> 15#include <linux/if_arp.h>
16#include <linux/rtnetlink.h> 16#include <linux/rtnetlink.h>
17#include <linux/pm_qos_params.h> 17#include <linux/pm_qos_params.h>
18#include <linux/slab.h>
18#include <net/sch_generic.h> 19#include <net/sch_generic.h>
19#include <linux/slab.h> 20#include <linux/slab.h>
20#include <net/mac80211.h> 21#include <net/mac80211.h>
@@ -850,3 +851,101 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
850 } 851 }
851 mutex_unlock(&local->mtx); 852 mutex_unlock(&local->mtx);
852} 853}
854
855int 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
897out_free:
898 while (i > 0)
899 kfree(local->sched_scan_ies.ie[--i]);
900out:
901 mutex_unlock(&sdata->local->mtx);
902 return ret;
903}
904
905int 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
927out:
928 mutex_unlock(&sdata->local->mtx);
929
930 return ret;
931}
932
933void 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}
941EXPORT_SYMBOL(ieee80211_sched_scan_results);
942
943void 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}
951EXPORT_SYMBOL(ieee80211_sched_scan_stopped);