Search Linux Wireless

[RFC] cfg80211: Fix incompatible interfaces combination

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mohammed Shafi Shajakhan <mohammed@xxxxxxxxxxxxxxxx>

*if any interface type is not advertised by the driver
via ieee80211_iface_combination make sure we will have it
as a single interface only. lets that we will not add
an incompatible interface if some other interface is
already present. we cannot add any other interface,
if the already present interface is an incompatible
interface. for example in ath9k we don't advertise ADHOC in
ieee80211_iface_combination structure in the driver,
so it can only exist as an single interface

*if the driver is not advertising interface combination just
return so that we don't break their multivif operation.

Signed-off-by: Mohammed Shafi Shajakhan <mohammed@xxxxxxxxxxxxxxxx>
---
 net/wireless/util.c |   62 ++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/net/wireless/util.c b/net/wireless/util.c
index c64d30f..7712ac6 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -932,22 +932,31 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 
 int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 				  struct wireless_dev *wdev,
-				  enum nl80211_iftype iftype)
+				  enum nl80211_iftype ntype)
 {
 	struct wireless_dev *wdev_iter;
 	int num[NUM_NL80211_IFTYPES];
 	int total = 1;
 	int i, j;
+	enum nl80211_iftype iftype;
+	bool ntype_single = true;
+	bool found_iface_comb = false;
+	bool iface_comb_allowed[NUM_NL80211_IFTYPES];
 
 	ASSERT_RTNL();
 
 	/* Always allow software iftypes */
-	if (rdev->wiphy.software_iftypes & BIT(iftype))
+	if (rdev->wiphy.software_iftypes & BIT(ntype))
+		return 0;
+
+	/* interface combination not advertised by the driver */
+	if (!rdev->wiphy.n_iface_combinations)
 		return 0;
 
 	memset(num, 0, sizeof(num));
+	memset(iface_comb_allowed, 0, sizeof(iface_comb_allowed));
 
-	num[iftype] = 1;
+	num[ntype] = 1;
 
 	mutex_lock(&rdev->devlist_mtx);
 	list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
@@ -967,6 +976,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 	if (total == 1)
 		return 0;
 
+
 	for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
 		const struct ieee80211_iface_combination *c;
 		struct ieee80211_iface_limit *limits;
@@ -981,24 +991,50 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 			goto cont;
 
 		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
-			if (rdev->wiphy.software_iftypes & BIT(iftype))
+
+			if (rdev->wiphy.software_iftypes & BIT(iftype)) {
+				iface_comb_allowed[iftype] = true;
 				continue;
+			}
+
 			for (j = 0; j < c->n_limits; j++) {
-				if (!(limits[j].types & BIT(iftype)))
-					continue;
-				if (limits[j].max < num[iftype])
-					goto cont;
-				limits[j].max -= num[iftype];
+
+				if (limits[j].types & BIT(ntype))
+					ntype_single = false;
+
+				if (!num[iftype] ||
+				    (limits[j].types & BIT(iftype)))
+					iface_comb_allowed[iftype] = true;
+
+				if (!found_iface_comb) {
+
+					if (!(limits[j].types & BIT(iftype)))
+						continue;
+					if (limits[j].max < num[iftype])
+						goto cont;
+					limits[j].max -= num[iftype];
+
+				}
 			}
 		}
-		/* yay, it fits */
-		kfree(limits);
-		return 0;
+
+		found_iface_comb = true;
+
  cont:
 		kfree(limits);
 	}
 
-	return -EBUSY;
+	if (ntype_single)
+		return -EOPNOTSUPP;
+
+	for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++)
+		if (!iface_comb_allowed[iftype])
+			return -EOPNOTSUPP;
+
+	if (found_iface_comb)
+		return 0;
+
+	return -EOPNOTSUPP;
 }
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux