aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLuciano Coelho <coelho@ti.com>2011-05-11 10:09:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-05-11 15:12:27 -0400
commit79f460ca49d8d5700756ab7071c951311c7f29cc (patch)
treeb11b62473697c6c1858b83b3abe5181990f85c19 /net
parent807f8a8c300435d5483e8d78df9dcdbc27333166 (diff)
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>
Diffstat (limited to 'net')
-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
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
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);