diff options
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r-- | net/wireless/scan.c | 57 |
1 files changed, 27 insertions, 30 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index d4397eba5408..d1ed4aebbbb7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev, | |||
161 | dev->bss_generation++; | 161 | dev->bss_generation++; |
162 | } | 162 | } |
163 | 163 | ||
164 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | 164 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, |
165 | bool send_message) | ||
165 | { | 166 | { |
166 | struct cfg80211_scan_request *request; | 167 | struct cfg80211_scan_request *request; |
167 | struct wireless_dev *wdev; | 168 | struct wireless_dev *wdev; |
169 | struct sk_buff *msg; | ||
168 | #ifdef CONFIG_CFG80211_WEXT | 170 | #ifdef CONFIG_CFG80211_WEXT |
169 | union iwreq_data wrqu; | 171 | union iwreq_data wrqu; |
170 | #endif | 172 | #endif |
171 | 173 | ||
172 | ASSERT_RTNL(); | 174 | ASSERT_RTNL(); |
173 | 175 | ||
174 | request = rdev->scan_req; | 176 | if (rdev->scan_msg) { |
177 | nl80211_send_scan_result(rdev, rdev->scan_msg); | ||
178 | rdev->scan_msg = NULL; | ||
179 | return; | ||
180 | } | ||
175 | 181 | ||
182 | request = rdev->scan_req; | ||
176 | if (!request) | 183 | if (!request) |
177 | return; | 184 | return; |
178 | 185 | ||
@@ -186,18 +193,16 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | |||
186 | if (wdev->netdev) | 193 | if (wdev->netdev) |
187 | cfg80211_sme_scan_done(wdev->netdev); | 194 | cfg80211_sme_scan_done(wdev->netdev); |
188 | 195 | ||
189 | if (request->aborted) { | 196 | if (!request->aborted && |
190 | nl80211_send_scan_aborted(rdev, wdev); | 197 | request->flags & NL80211_SCAN_FLAG_FLUSH) { |
191 | } else { | 198 | /* flush entries from previous scans */ |
192 | if (request->flags & NL80211_SCAN_FLAG_FLUSH) { | 199 | spin_lock_bh(&rdev->bss_lock); |
193 | /* flush entries from previous scans */ | 200 | __cfg80211_bss_expire(rdev, request->scan_start); |
194 | spin_lock_bh(&rdev->bss_lock); | 201 | spin_unlock_bh(&rdev->bss_lock); |
195 | __cfg80211_bss_expire(rdev, request->scan_start); | ||
196 | spin_unlock_bh(&rdev->bss_lock); | ||
197 | } | ||
198 | nl80211_send_scan_done(rdev, wdev); | ||
199 | } | 202 | } |
200 | 203 | ||
204 | msg = nl80211_build_scan_msg(rdev, wdev, request->aborted); | ||
205 | |||
201 | #ifdef CONFIG_CFG80211_WEXT | 206 | #ifdef CONFIG_CFG80211_WEXT |
202 | if (wdev->netdev && !request->aborted) { | 207 | if (wdev->netdev && !request->aborted) { |
203 | memset(&wrqu, 0, sizeof(wrqu)); | 208 | memset(&wrqu, 0, sizeof(wrqu)); |
@@ -210,17 +215,12 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | |||
210 | dev_put(wdev->netdev); | 215 | dev_put(wdev->netdev); |
211 | 216 | ||
212 | rdev->scan_req = NULL; | 217 | rdev->scan_req = NULL; |
218 | kfree(request); | ||
213 | 219 | ||
214 | /* | 220 | if (!send_message) |
215 | * OK. If this is invoked with "leak" then we can't | 221 | rdev->scan_msg = msg; |
216 | * free this ... but we've cleaned it up anyway. The | 222 | else |
217 | * driver failed to call the scan_done callback, so | 223 | nl80211_send_scan_result(rdev, msg); |
218 | * all bets are off, it might still be trying to use | ||
219 | * the scan request or not ... if it accesses the dev | ||
220 | * in there (it shouldn't anyway) then it may crash. | ||
221 | */ | ||
222 | if (!leak) | ||
223 | kfree(request); | ||
224 | } | 224 | } |
225 | 225 | ||
226 | void __cfg80211_scan_done(struct work_struct *wk) | 226 | void __cfg80211_scan_done(struct work_struct *wk) |
@@ -231,7 +231,7 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
231 | scan_done_wk); | 231 | scan_done_wk); |
232 | 232 | ||
233 | rtnl_lock(); | 233 | rtnl_lock(); |
234 | ___cfg80211_scan_done(rdev, false); | 234 | ___cfg80211_scan_done(rdev, true); |
235 | rtnl_unlock(); | 235 | rtnl_unlock(); |
236 | } | 236 | } |
237 | 237 | ||
@@ -1089,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1089 | if (IS_ERR(rdev)) | 1089 | if (IS_ERR(rdev)) |
1090 | return PTR_ERR(rdev); | 1090 | return PTR_ERR(rdev); |
1091 | 1091 | ||
1092 | if (rdev->scan_req) { | 1092 | if (rdev->scan_req || rdev->scan_msg) { |
1093 | err = -EBUSY; | 1093 | err = -EBUSY; |
1094 | goto out; | 1094 | goto out; |
1095 | } | 1095 | } |
@@ -1099,11 +1099,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1099 | /* Determine number of channels, needed to allocate creq */ | 1099 | /* Determine number of channels, needed to allocate creq */ |
1100 | if (wreq && wreq->num_channels) | 1100 | if (wreq && wreq->num_channels) |
1101 | n_channels = wreq->num_channels; | 1101 | n_channels = wreq->num_channels; |
1102 | else { | 1102 | else |
1103 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 1103 | n_channels = ieee80211_get_num_supported_channels(wiphy); |
1104 | if (wiphy->bands[band]) | ||
1105 | n_channels += wiphy->bands[band]->n_channels; | ||
1106 | } | ||
1107 | 1104 | ||
1108 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + | 1105 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + |
1109 | n_channels * sizeof(void *), | 1106 | n_channels * sizeof(void *), |
@@ -1494,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
1494 | if (IS_ERR(rdev)) | 1491 | if (IS_ERR(rdev)) |
1495 | return PTR_ERR(rdev); | 1492 | return PTR_ERR(rdev); |
1496 | 1493 | ||
1497 | if (rdev->scan_req) | 1494 | if (rdev->scan_req || rdev->scan_msg) |
1498 | return -EAGAIN; | 1495 | return -EAGAIN; |
1499 | 1496 | ||
1500 | res = ieee80211_scan_results(rdev, info, extra, data->length); | 1497 | res = ieee80211_scan_results(rdev, info, extra, data->length); |