diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 27 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 29 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 88 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 9 | ||||
-rw-r--r-- | net/mac80211/main.c | 6 | ||||
-rw-r--r-- | net/mac80211/rx.c | 6 | ||||
-rw-r--r-- | net/mac80211/scan.c | 99 |
7 files changed, 242 insertions, 22 deletions
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 | ||
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 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1390 | static 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 | ||
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); | ||
246 | } | ||
247 | |||
221 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 248 | static 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 | ||
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 | DEFINE_EVENT(local_only_evt, drv_return_void, | 122 | DEFINE_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 | ||
436 | TRACE_EVENT(drv_hw_scan, | 457 | DEFINE_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( | 463 | DEFINE_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( | 469 | DEFINE_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 | ||
459 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 475 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, |
@@ -1180,6 +1196,42 @@ TRACE_EVENT(api_scan_completed, | |||
1180 | ) | 1196 | ) |
1181 | ); | 1197 | ); |
1182 | 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 | ||
1232 | ) | ||
1233 | ); | ||
1234 | |||
1183 | TRACE_EVENT(api_sta_block_awake, | 1235 | TRACE_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, | |||
1154 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 1157 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
1155 | struct ieee80211_bss *bss); | 1158 | struct ieee80211_bss *bss); |
1156 | 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); | ||
1165 | |||
1157 | /* off-channel helpers */ | 1166 | /* off-channel helpers */ |
1158 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); | 1167 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); |
1159 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, | 1168 | void 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 | |||
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); | ||