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>
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index c12029b..429dd06 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -70,18 +70,8 @@
 	enum nl80211_iftype type;
 	int ret;
 
-	if (!wdev)
-		return -EOPNOTSUPP;
-
 	rdev = wiphy_to_dev(wdev->wiphy);
 
-	if (!rdev->ops->change_virtual_intf)
-		return -EOPNOTSUPP;
-
-	/* don't support changing VLANs, you just re-create them */
-	if (wdev->iftype == NL80211_IFTYPE_AP_VLAN)
-		return -EOPNOTSUPP;
-
 	switch (*mode) {
 	case IW_MODE_INFRA:
 		type = NL80211_IFTYPE_STATION;
@@ -104,9 +94,9 @@
 
 	memset(&vifparams, 0, sizeof(vifparams));
 
-	ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type,
-					     NULL, &vifparams);
-	WARN_ON(!ret && wdev->iftype != type);
+	cfg80211_lock_rdev(rdev);
+	ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
+	cfg80211_unlock_rdev(rdev);
 
 	return ret;
 }