summaryrefslogtreecommitdiff
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-21 16:51:05 +0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-28 22:40:31 +0400
commit3d54d25515838543e56889aa7e48f40d00719368 (patch)
treeac8e7ab50b5fa9e9be64885f86c99a0b6c71892c /net/wireless/core.c
parentf7969969f416e593bcc7dc24abf3f9fd6c27136d (diff)
downloadlinux-3d54d25515838543e56889aa7e48f40d00719368.tar.xz
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)
cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
}
-static void cfg80211_process_events(struct wireless_dev *wdev)
-{
- struct cfg80211_event *ev;
- unsigned long flags;
-
- spin_lock_irqsave(&wdev->event_lock, flags);
- while (!list_empty(&wdev->event_list)) {
- ev = list_first_entry(&wdev->event_list,
- struct cfg80211_event, list);
- list_del(&ev->list);
- spin_unlock_irqrestore(&wdev->event_lock, flags);
-
- wdev_lock(wdev);
- switch (ev->type) {
- case EVENT_CONNECT_RESULT:
- __cfg80211_connect_result(
- wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ?
- NULL : ev->cr.bssid,
- ev->cr.req_ie, ev->cr.req_ie_len,
- ev->cr.resp_ie, ev->cr.resp_ie_len,
- ev->cr.status,
- ev->cr.status == WLAN_STATUS_SUCCESS,
- NULL);
- break;
- case EVENT_ROAMED:
- __cfg80211_roamed(wdev, ev->rm.bssid,
- ev->rm.req_ie, ev->rm.req_ie_len,
- ev->rm.resp_ie, ev->rm.resp_ie_len);
- break;
- case EVENT_DISCONNECTED:
- __cfg80211_disconnected(wdev->netdev,
- ev->dc.ie, ev->dc.ie_len,
- ev->dc.reason, true);
- break;
- case EVENT_IBSS_JOINED:
- __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
- break;
- }
- wdev_unlock(wdev);
-
- kfree(ev);
-
- spin_lock_irqsave(&wdev->event_lock, flags);
- }
- spin_unlock_irqrestore(&wdev->event_lock, flags);
-}
-
static void cfg80211_event_work(struct work_struct *work)
{
struct cfg80211_registered_device *rdev;
- struct wireless_dev *wdev;
rdev = container_of(work, struct cfg80211_registered_device,
event_work);
rtnl_lock();
cfg80211_lock_rdev(rdev);
- mutex_lock(&rdev->devlist_mtx);
- list_for_each_entry(wdev, &rdev->netdev_list, list)
- cfg80211_process_events(wdev);
-
- mutex_unlock(&rdev->devlist_mtx);
+ cfg80211_process_rdev_events(rdev);
cfg80211_unlock_rdev(rdev);
rtnl_unlock();
}