aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-21 08:51:05 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-28 14:40:31 -0400
commit3d54d25515838543e56889aa7e48f40d00719368 (patch)
treeac8e7ab50b5fa9e9be64885f86c99a0b6c71892c /net/wireless/core.c
parentf7969969f416e593bcc7dc24abf3f9fd6c27136d (diff)
cfg80211: clean up properly on interface type change
When the interface type changes while connected, and the driver does not require the interface to be down for a type change, it is currently possible to get very strange results unless the driver takes special care, which it shouldn't have to. To fix this, take care to disconnect/leave IBSS when changing the interface type -- even if the driver may fail the call. Also process all events that may be pending to avoid running into a situation where an event is reported but only processed after the type has already changed, which would lead to missing events and warnings. A side effect of this is that you will have disconnected or left the IBSS even if the mode change ultimately fails, but since the intention was to change it and thus leave or disconnect, this is not a problem. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c54
1 files changed, 1 insertions, 53 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 9b157caa74fd..45b2be3274db 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -294,69 +294,17 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work)
294 cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); 294 cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
295} 295}
296 296
297static void cfg80211_process_events(struct wireless_dev *wdev)
298{
299 struct cfg80211_event *ev;
300 unsigned long flags;
301
302 spin_lock_irqsave(&wdev->event_lock, flags);
303 while (!list_empty(&wdev->event_list)) {
304 ev = list_first_entry(&wdev->event_list,
305 struct cfg80211_event, list);
306 list_del(&ev->list);
307 spin_unlock_irqrestore(&wdev->event_lock, flags);
308
309 wdev_lock(wdev);
310 switch (ev->type) {
311 case EVENT_CONNECT_RESULT:
312 __cfg80211_connect_result(
313 wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ?
314 NULL : ev->cr.bssid,
315 ev->cr.req_ie, ev->cr.req_ie_len,
316 ev->cr.resp_ie, ev->cr.resp_ie_len,
317 ev->cr.status,
318 ev->cr.status == WLAN_STATUS_SUCCESS,
319 NULL);
320 break;
321 case EVENT_ROAMED:
322 __cfg80211_roamed(wdev, ev->rm.bssid,
323 ev->rm.req_ie, ev->rm.req_ie_len,
324 ev->rm.resp_ie, ev->rm.resp_ie_len);
325 break;
326 case EVENT_DISCONNECTED:
327 __cfg80211_disconnected(wdev->netdev,
328 ev->dc.ie, ev->dc.ie_len,
329 ev->dc.reason, true);
330 break;
331 case EVENT_IBSS_JOINED:
332 __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
333 break;
334 }
335 wdev_unlock(wdev);
336
337 kfree(ev);
338
339 spin_lock_irqsave(&wdev->event_lock, flags);
340 }
341 spin_unlock_irqrestore(&wdev->event_lock, flags);
342}
343
344static void cfg80211_event_work(struct work_struct *work) 297static void cfg80211_event_work(struct work_struct *work)
345{ 298{
346 struct cfg80211_registered_device *rdev; 299 struct cfg80211_registered_device *rdev;
347 struct wireless_dev *wdev;
348 300
349 rdev = container_of(work, struct cfg80211_registered_device, 301 rdev = container_of(work, struct cfg80211_registered_device,
350 event_work); 302 event_work);
351 303
352 rtnl_lock(); 304 rtnl_lock();
353 cfg80211_lock_rdev(rdev); 305 cfg80211_lock_rdev(rdev);
354 mutex_lock(&rdev->devlist_mtx);
355 306
356 list_for_each_entry(wdev, &rdev->netdev_list, list) 307 cfg80211_process_rdev_events(rdev);
357 cfg80211_process_events(wdev);
358
359 mutex_unlock(&rdev->devlist_mtx);
360 cfg80211_unlock_rdev(rdev); 308 cfg80211_unlock_rdev(rdev);
361 rtnl_unlock(); 309 rtnl_unlock();
362} 310}