aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLuciano Coelho <coelho@ti.com>2011-05-12 09:28:29 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-05-12 14:10:55 -0400
commit85a9994a0a6cba1a6cc6af4bd3ebd85f778be0fe (patch)
treee9dd8fff75d9c0ee2f5aec129bb6132499c72461 /net
parenta3836e02ba4c50db958d32d710b226f2408623dc (diff)
cfg80211/mac80211: avoid bounce back mac->cfg->mac on sched_scan_stopped
When sched_scan_stopped was called by the driver, mac80211 calls cfg80211, which in turn was calling mac80211 back with a flag "driver_initiated". This flag was used so that mac80211 would do the necessary cleanup but would not call the driver. This was enough to prevent the bounce back between the driver and mac80211, but not between mac80211 and cfg80211. To fix this, we now do the cleanup in mac80211 before calling cfg80211. To help with locking issues, the workqueue was moved from cfg80211 to mac80211. Reported-by: Johannes Berg <johannes@sipsolutions.net> 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.c5
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/scan.c33
-rw-r--r--net/wireless/core.c1
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/scan.c21
7 files changed, 42 insertions, 28 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 303f33fcb84..2d1c1a5f3c5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1372,15 +1372,14 @@ ieee80211_sched_scan_start(struct wiphy *wiphy,
1372} 1372}
1373 1373
1374static int 1374static int
1375ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, 1375ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
1376 bool driver_initiated)
1377{ 1376{
1378 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1377 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1379 1378
1380 if (!sdata->local->ops->sched_scan_stop) 1379 if (!sdata->local->ops->sched_scan_stop)
1381 return -EOPNOTSUPP; 1380 return -EOPNOTSUPP;
1382 1381
1383 return ieee80211_request_sched_scan_stop(sdata, driver_initiated); 1382 return ieee80211_request_sched_scan_stop(sdata);
1384} 1383}
1385 1384
1386static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, 1385static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6f55a789c09..82f90ff8bb1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -849,6 +849,7 @@ struct ieee80211_local {
849 849
850 bool sched_scanning; 850 bool sched_scanning;
851 struct ieee80211_sched_scan_ies sched_scan_ies; 851 struct ieee80211_sched_scan_ies sched_scan_ies;
852 struct work_struct sched_scan_stopped_work;
852 853
853 unsigned long leave_oper_channel_time; 854 unsigned long leave_oper_channel_time;
854 enum mac80211_scan_state next_scan_state; 855 enum mac80211_scan_state next_scan_state;
@@ -1160,8 +1161,8 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
1160/* scheduled scan handling */ 1161/* scheduled scan handling */
1161int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, 1162int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1162 struct cfg80211_sched_scan_request *req); 1163 struct cfg80211_sched_scan_request *req);
1163int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, 1164int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
1164 bool driver_initiated); 1165void ieee80211_sched_scan_stopped_work(struct work_struct *work);
1165 1166
1166/* off-channel helpers */ 1167/* off-channel helpers */
1167bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); 1168bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 30e6a682a04..7f89011fa22 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -652,6 +652,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
652 setup_timer(&local->dynamic_ps_timer, 652 setup_timer(&local->dynamic_ps_timer,
653 ieee80211_dynamic_ps_timer, (unsigned long) local); 653 ieee80211_dynamic_ps_timer, (unsigned long) local);
654 654
655 INIT_WORK(&local->sched_scan_stopped_work,
656 ieee80211_sched_scan_stopped_work);
657
655 sta_info_init(local); 658 sta_info_init(local);
656 659
657 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { 660 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ea44a8e941e..d20046b5d8f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -902,8 +902,7 @@ out:
902 return ret; 902 return ret;
903} 903}
904 904
905int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, 905int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
906 bool driver_initiated)
907{ 906{
908 struct ieee80211_local *local = sdata->local; 907 struct ieee80211_local *local = sdata->local;
909 int ret = 0, i; 908 int ret = 0, i;
@@ -919,11 +918,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
919 for (i = 0; i < IEEE80211_NUM_BANDS; i++) 918 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
920 kfree(local->sched_scan_ies.ie[i]); 919 kfree(local->sched_scan_ies.ie[i]);
921 920
922 if (!driver_initiated) 921 drv_sched_scan_stop(local, sdata);
923 drv_sched_scan_stop(local, sdata);
924 local->sched_scanning = false; 922 local->sched_scanning = false;
925 } 923 }
926
927out: 924out:
928 mutex_unlock(&sdata->local->mtx); 925 mutex_unlock(&sdata->local->mtx);
929 926
@@ -940,12 +937,36 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw)
940} 937}
941EXPORT_SYMBOL(ieee80211_sched_scan_results); 938EXPORT_SYMBOL(ieee80211_sched_scan_results);
942 939
940void ieee80211_sched_scan_stopped_work(struct work_struct *work)
941{
942 struct ieee80211_local *local =
943 container_of(work, struct ieee80211_local,
944 sched_scan_stopped_work);
945 int i;
946
947 mutex_lock(&local->mtx);
948
949 if (!local->sched_scanning) {
950 mutex_unlock(&local->mtx);
951 return;
952 }
953
954 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
955 kfree(local->sched_scan_ies.ie[i]);
956
957 local->sched_scanning = false;
958
959 mutex_unlock(&local->mtx);
960
961 cfg80211_sched_scan_stopped(local->hw.wiphy);
962}
963
943void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) 964void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
944{ 965{
945 struct ieee80211_local *local = hw_to_local(hw); 966 struct ieee80211_local *local = hw_to_local(hw);
946 967
947 trace_api_sched_scan_stopped(local); 968 trace_api_sched_scan_stopped(local);
948 969
949 cfg80211_sched_scan_stopped(hw->wiphy); 970 ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work);
950} 971}
951EXPORT_SYMBOL(ieee80211_sched_scan_stopped); 972EXPORT_SYMBOL(ieee80211_sched_scan_stopped);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index e2ab65d7c86..18b002f1686 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -371,7 +371,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
371 INIT_LIST_HEAD(&rdev->bss_list); 371 INIT_LIST_HEAD(&rdev->bss_list);
372 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 372 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
373 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); 373 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
374 INIT_WORK(&rdev->sched_scan_stopped_wk, __cfg80211_sched_scan_stopped);
375#ifdef CONFIG_CFG80211_WEXT 374#ifdef CONFIG_CFG80211_WEXT
376 rdev->wiphy.wext = &cfg80211_wext_handler; 375 rdev->wiphy.wext = &cfg80211_wext_handler;
377#endif 376#endif
diff --git a/net/wireless/core.h b/net/wireless/core.h
index fd9135f9b5b..d4b8f4c0bbb 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -64,7 +64,6 @@ struct cfg80211_registered_device {
64 unsigned long suspend_at; 64 unsigned long suspend_at;
65 struct work_struct scan_done_wk; 65 struct work_struct scan_done_wk;
66 struct work_struct sched_scan_results_wk; 66 struct work_struct sched_scan_results_wk;
67 struct work_struct sched_scan_stopped_wk;
68 67
69#ifdef CONFIG_NL80211_TESTMODE 68#ifdef CONFIG_NL80211_TESTMODE
70 struct genl_info *testmode_info; 69 struct genl_info *testmode_info;
@@ -417,7 +416,6 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
417void __cfg80211_sched_scan_results(struct work_struct *wk); 416void __cfg80211_sched_scan_results(struct work_struct *wk);
418int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, 417int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
419 bool driver_initiated); 418 bool driver_initiated);
420void __cfg80211_sched_scan_stopped(struct work_struct *wk);
421void cfg80211_upload_connect_keys(struct wireless_dev *wdev); 419void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
422int cfg80211_change_iface(struct cfg80211_registered_device *rdev, 420int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
423 struct net_device *dev, enum nl80211_iftype ntype, 421 struct net_device *dev, enum nl80211_iftype ntype,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 65dfae3b9d4..73a441d237b 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -119,22 +119,14 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
119} 119}
120EXPORT_SYMBOL(cfg80211_sched_scan_results); 120EXPORT_SYMBOL(cfg80211_sched_scan_results);
121 121
122void __cfg80211_sched_scan_stopped(struct work_struct *wk) 122void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
123{ 123{
124 struct cfg80211_registered_device *rdev; 124 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
125
126 rdev = container_of(wk, struct cfg80211_registered_device,
127 sched_scan_stopped_wk);
128 125
129 cfg80211_lock_rdev(rdev); 126 cfg80211_lock_rdev(rdev);
130 __cfg80211_stop_sched_scan(rdev, true); 127 __cfg80211_stop_sched_scan(rdev, true);
131 cfg80211_unlock_rdev(rdev); 128 cfg80211_unlock_rdev(rdev);
132} 129}
133
134void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
135{
136 queue_work(cfg80211_wq, &wiphy_to_dev(wiphy)->sched_scan_stopped_wk);
137}
138EXPORT_SYMBOL(cfg80211_sched_scan_stopped); 130EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
139 131
140int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, 132int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
@@ -150,10 +142,11 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
150 142
151 dev = rdev->sched_scan_req->dev; 143 dev = rdev->sched_scan_req->dev;
152 144
153 err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev, 145 if (!driver_initiated) {
154 driver_initiated); 146 err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
155 if (err) 147 if (err)
156 return err; 148 return err;
149 }
157 150
158 nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); 151 nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
159 152