cfg80211: clear WEXT SSID when clearing IBSS

When we leave an IBSS, we should clear the SSID and not just the
BSSID, but since WEXT allows configuring while the interface is
down we must not clear it when leaving due to taking the iface
down, so some complications are needed.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f256b4f..2006a4e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -464,7 +464,7 @@
 			break;
 		if (!dev->ieee80211_ptr->ssid_len)
 			break;
-		cfg80211_leave_ibss(rdev, dev);
+		cfg80211_leave_ibss(rdev, dev, true);
 		break;
 	case NETDEV_UP:
 #ifdef CONFIG_WIRELESS_EXT
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 89a8159..3e49d33 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -147,8 +147,8 @@
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
 		       struct cfg80211_ibss_params *params);
-void cfg80211_clear_ibss(struct net_device *dev);
+void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
-			struct net_device *dev);
+			struct net_device *dev, bool nowext);
 
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 4e1fcb0..b5c601e 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -76,7 +76,7 @@
 	return 0;
 }
 
-void cfg80211_clear_ibss(struct net_device *dev)
+void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 
@@ -88,10 +88,14 @@
 	wdev->current_bss = NULL;
 	wdev->ssid_len = 0;
 	memset(wdev->bssid, 0, ETH_ALEN);
+#ifdef CONFIG_WIRELESS_EXT
+	if (!nowext)
+		wdev->wext.ssid_len = 0;
+#endif
 }
 
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
-			struct net_device *dev)
+			struct net_device *dev, bool nowext)
 {
 	int err;
 
@@ -100,7 +104,7 @@
 	if (err)
 		return err;
 
-	cfg80211_clear_ibss(dev);
+	cfg80211_clear_ibss(dev, nowext);
 
 	return 0;
 }
@@ -179,7 +183,8 @@
 		return 0;
 
 	if (wdev->ssid_len) {
-		err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
+		err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+					  dev, true);
 		if (err)
 			return err;
 	}
@@ -241,7 +246,8 @@
 		return -EOPNOTSUPP;
 
 	if (wdev->ssid_len) {
-		err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
+		err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+					  dev, true);
 		if (err)
 			return err;
 	}
@@ -275,7 +281,7 @@
 		data->flags = 1;
 		data->length = wdev->ssid_len;
 		memcpy(ssid, wdev->ssid, data->length);
-	} else if (wdev->wext.ssid) {
+	} else if (wdev->wext.ssid && wdev->wext.ssid_len) {
 		data->flags = 1;
 		data->length = wdev->wext.ssid_len;
 		memcpy(ssid, wdev->wext.ssid, data->length);
@@ -318,7 +324,8 @@
 		return 0;
 
 	if (wdev->ssid_len) {
-		err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), dev);
+		err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+					  dev, true);
 		if (err)
 			return err;
 	}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5a9a5c6..97bb5c8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -833,7 +833,7 @@
 
 	if (dev && !err && (ntype != otype)) {
 		if (otype == NL80211_IFTYPE_ADHOC)
-			cfg80211_clear_ibss(dev);
+			cfg80211_clear_ibss(dev, false);
 	}
 
  unlock:
@@ -3249,7 +3249,7 @@
 		goto out;
 	}
 
-	err = cfg80211_leave_ibss(drv, dev);
+	err = cfg80211_leave_ibss(drv, dev, false);
 
 out:
 	cfg80211_put_dev(drv);