mac80211: Disallow concurrent IBSS/STA mode interfaces

Disallow having more than one IBSS interface up at any time
because of beacon distribution issues, and for now also disallow
having more than one IBSS/STA interface up at the same time
because we use the master interface's BSS struct which would
be completely corrupted when we have more than one up.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index f82ebdd..2133c9f 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -183,8 +183,52 @@
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 		struct net_device *ndev = nsdata->dev;
 
-		if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
-		    compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
+		if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+			/*
+			 * Allow only a single IBSS interface to be up at any
+			 * time. This is restricted because beacon distribution
+			 * cannot work properly if both are in the same IBSS.
+			 *
+			 * To remove this restriction we'd have to disallow them
+			 * from setting the same SSID on different IBSS interfaces
+			 * belonging to the same hardware. Then, however, we're
+			 * faced with having to adopt two different TSF timers...
+			 */
+			if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+			    nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+				return -EBUSY;
+
+			/*
+			 * Disallow multiple IBSS/STA mode interfaces.
+			 *
+			 * This is a technical restriction, it is possible although
+			 * most likely not IEEE 802.11 compliant to have multiple
+			 * STAs with just a single hardware (the TSF timer will not
+			 * be adjusted properly.)
+			 *
+			 * However, because mac80211 uses the master device's BSS
+			 * information for each STA/IBSS interface, doing this will
+			 * currently corrupt that BSS information completely, unless,
+			 * a not very useful case, both STAs are associated to the
+			 * same BSS.
+			 *
+			 * To remove this restriction, the BSS information needs to
+			 * be embedded in the STA/IBSS mode sdata instead of using
+			 * the master device's BSS structure.
+			 */
+			if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+			     sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+			    (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
+			     nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
+				return -EBUSY;
+
+			/*
+			 * The remaining checks are only performed for interfaces
+			 * with the same MAC address.
+			 */
+			if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
+				continue;
+
 			/*
 			 * check whether it may have the same address
 			 */
@@ -196,8 +240,7 @@
 			 * can only add VLANs to enabled APs
 			 */
 			if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
-			    nsdata->vif.type == IEEE80211_IF_TYPE_AP &&
-			    netif_running(nsdata->dev))
+			    nsdata->vif.type == IEEE80211_IF_TYPE_AP)
 				sdata->u.vlan.ap = nsdata;
 		}
 	}