Commit 85a9994a0a6cba1a6cc6af4bd3ebd85f778be0fe

Authored by Luciano Coelho
Committed by John W. Linville
1 parent a3836e02ba

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>

Showing 8 changed files with 43 additions and 30 deletions Side-by-side Diff

include/net/cfg80211.h
... ... @@ -1515,8 +1515,7 @@
1515 1515 int (*sched_scan_start)(struct wiphy *wiphy,
1516 1516 struct net_device *dev,
1517 1517 struct cfg80211_sched_scan_request *request);
1518   - int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev,
1519   - bool driver_initiated);
  1518 + int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);
1520 1519 };
1521 1520  
1522 1521 /*
... ... @@ -1372,15 +1372,14 @@
1372 1372 }
1373 1373  
1374 1374 static int
1375   -ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
1376   - bool driver_initiated)
  1375 +ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
1377 1376 {
1378 1377 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1379 1378  
1380 1379 if (!sdata->local->ops->sched_scan_stop)
1381 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  
1386 1385 static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
net/mac80211/ieee80211_i.h
... ... @@ -849,6 +849,7 @@
849 849  
850 850 bool sched_scanning;
851 851 struct ieee80211_sched_scan_ies sched_scan_ies;
  852 + struct work_struct sched_scan_stopped_work;
852 853  
853 854 unsigned long leave_oper_channel_time;
854 855 enum mac80211_scan_state next_scan_state;
... ... @@ -1160,8 +1161,8 @@
1160 1161 /* scheduled scan handling */
1161 1162 int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
1162 1163 struct cfg80211_sched_scan_request *req);
1163   -int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
1164   - bool driver_initiated);
  1164 +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
  1165 +void ieee80211_sched_scan_stopped_work(struct work_struct *work);
1165 1166  
1166 1167 /* off-channel helpers */
1167 1168 bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
... ... @@ -652,6 +652,9 @@
652 652 setup_timer(&local->dynamic_ps_timer,
653 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 658 sta_info_init(local);
656 659  
657 660 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
... ... @@ -902,8 +902,7 @@
902 902 return ret;
903 903 }
904 904  
905   -int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
906   - bool driver_initiated)
  905 +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
907 906 {
908 907 struct ieee80211_local *local = sdata->local;
909 908 int ret = 0, i;
910 909  
... ... @@ -919,11 +918,9 @@
919 918 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
920 919 kfree(local->sched_scan_ies.ie[i]);
921 920  
922   - if (!driver_initiated)
923   - drv_sched_scan_stop(local, sdata);
  921 + drv_sched_scan_stop(local, sdata);
924 922 local->sched_scanning = false;
925 923 }
926   -
927 924 out:
928 925 mutex_unlock(&sdata->local->mtx);
929 926  
930 927  
... ... @@ -940,13 +937,37 @@
940 937 }
941 938 EXPORT_SYMBOL(ieee80211_sched_scan_results);
942 939  
  940 +void 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 +
943 964 void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
944 965 {
945 966 struct ieee80211_local *local = hw_to_local(hw);
946 967  
947 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 }
951 972 EXPORT_SYMBOL(ieee80211_sched_scan_stopped);
... ... @@ -371,7 +371,6 @@
371 371 INIT_LIST_HEAD(&rdev->bss_list);
372 372 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
373 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 374 #ifdef CONFIG_CFG80211_WEXT
376 375 rdev->wiphy.wext = &cfg80211_wext_handler;
377 376 #endif
... ... @@ -64,7 +64,6 @@
64 64 unsigned long suspend_at;
65 65 struct work_struct scan_done_wk;
66 66 struct work_struct sched_scan_results_wk;
67   - struct work_struct sched_scan_stopped_wk;
68 67  
69 68 #ifdef CONFIG_NL80211_TESTMODE
70 69 struct genl_info *testmode_info;
... ... @@ -417,7 +416,6 @@
417 416 void __cfg80211_sched_scan_results(struct work_struct *wk);
418 417 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
419 418 bool driver_initiated);
420   -void __cfg80211_sched_scan_stopped(struct work_struct *wk);
421 419 void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
422 420 int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
423 421 struct net_device *dev, enum nl80211_iftype ntype,
... ... @@ -119,22 +119,14 @@
119 119 }
120 120 EXPORT_SYMBOL(cfg80211_sched_scan_results);
121 121  
122   -void __cfg80211_sched_scan_stopped(struct work_struct *wk)
  122 +void 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 125  
126   - rdev = container_of(wk, struct cfg80211_registered_device,
127   - sched_scan_stopped_wk);
128   -
129 126 cfg80211_lock_rdev(rdev);
130 127 __cfg80211_stop_sched_scan(rdev, true);
131 128 cfg80211_unlock_rdev(rdev);
132 129 }
133   -
134   -void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
135   -{
136   - queue_work(cfg80211_wq, &wiphy_to_dev(wiphy)->sched_scan_stopped_wk);
137   -}
138 130 EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
139 131  
140 132 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
... ... @@ -150,10 +142,11 @@
150 142  
151 143 dev = rdev->sched_scan_req->dev;
152 144  
153   - err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev,
154   - driver_initiated);
155   - if (err)
156   - return err;
  145 + if (!driver_initiated) {
  146 + err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
  147 + if (err)
  148 + return err;
  149 + }
157 150  
158 151 nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
159 152