Search Linux Wireless

[RFC] cfg80211: keep track of supported interface modes

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

 



It is obviously good for userspace to know up front which interface modes
a given piece of hardware might support (even if adding such an interface
might fail later because of concurrency issues), so let's make cfg80211
aware of that. For good measure, disallow adding interfaces in all other
modes so drivers don't forget to announce support for one mode when they
add it.

This patch is incomplete as it doesn't modify all drivers. The driver
modifications should be straight-forward, I'm hoping somebody else
can pick it up and collect the necessary driver changes. Included is a
b43 change because I tested it with that. I have also pushed an iw
change to print out this information.

It's a bit ugly that it requires drivers to use nl80211 constants, but
if anything mac80211 should migrate to using those completely instead
of translating them to its own versions.

Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
---
 drivers/net/wireless/b43/main.c |   17 ++++++++++++-----
 include/linux/nl80211.h         |    6 ++++++
 include/net/wireless.h          |    3 +++
 net/mac80211/main.c             |    7 +++++++
 net/wireless/core.c             |    9 ++++++++-
 net/wireless/nl80211.c          |   22 ++++++++++++++++++++--
 6 files changed, 56 insertions(+), 8 deletions(-)

--- everything.orig/include/linux/nl80211.h	2008-08-07 16:26:44.000000000 +0200
+++ everything/include/linux/nl80211.h	2008-08-07 16:39:03.000000000 +0200
@@ -192,6 +192,10 @@ enum nl80211_commands {
  * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
  *      &enum nl80211_mntr_flags.
  *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ *	supported interface types, each a flag attribute with the number
+ *	of the interface mode.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -235,6 +239,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_MPATH_NEXT_HOP,
 	NL80211_ATTR_MPATH_INFO,
 
+	NL80211_ATTR_SUPPORTED_IFTYPES,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
--- everything.orig/include/net/wireless.h	2008-08-07 16:26:33.000000000 +0200
+++ everything/include/net/wireless.h	2008-08-07 16:28:20.000000000 +0200
@@ -185,6 +185,9 @@ struct wiphy {
 	/* permanent MAC address */
 	u8 perm_addr[ETH_ALEN];
 
+	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
+	u16 interface_modes;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
--- everything.orig/net/wireless/core.c	2008-08-07 16:32:27.000000000 +0200
+++ everything/net/wireless/core.c	2008-08-07 16:47:11.000000000 +0200
@@ -1,7 +1,7 @@
 /*
  * This is the linux wireless configuration interface.
  *
- * Copyright 2006, 2007		Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
+ * Copyright 2006-2008		Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
  */
 
 #include <linux/if.h>
@@ -259,6 +259,13 @@ int wiphy_register(struct wiphy *wiphy)
 	struct ieee80211_supported_band *sband;
 	bool have_band = false;
 	int i;
+	u16 ifmodes = wiphy->interface_modes;
+
+	/* sanity check ifmodes */
+	WARN_ON(!ifmodes);
+	ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
+	if (WARN_ON(ifmodes != wiphy->interface_modes))
+		wiphy->interface_modes = ifmodes;
 
 	/* sanity check supported bands/channels */
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
--- everything.orig/net/wireless/nl80211.c	2008-08-07 16:35:22.000000000 +0200
+++ everything/net/wireless/nl80211.c	2008-08-07 16:42:24.000000000 +0200
@@ -106,10 +106,12 @@ static int nl80211_send_wiphy(struct sk_
 	struct nlattr *nl_bands, *nl_band;
 	struct nlattr *nl_freqs, *nl_freq;
 	struct nlattr *nl_rates, *nl_rate;
+	struct nlattr *nl_modes;
 	enum ieee80211_band band;
 	struct ieee80211_channel *chan;
 	struct ieee80211_rate *rate;
 	int i;
+	u16 ifmodes = dev->wiphy.interface_modes;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
 	if (!hdr)
@@ -118,6 +120,20 @@ static int nl80211_send_wiphy(struct sk_
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
 
+	nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
+	if (!nl_modes)
+		goto nla_put_failure;
+
+	i = 0;
+	while (ifmodes) {
+		if (ifmodes & 1)
+			NLA_PUT_FLAG(msg, i);
+		ifmodes >>= 1;
+		i++;
+	}
+
+	nla_nest_end(msg, nl_modes);
+
 	nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
 	if (!nl_bands)
 		goto nla_put_failure;
@@ -408,7 +424,8 @@ static int nl80211_set_interface(struct 
 	ifindex = dev->ifindex;
 	dev_put(dev);
 
-	if (!drv->ops->change_virtual_intf) {
+	if (!drv->ops->change_virtual_intf ||
+	    !(drv->wiphy.interface_modes & (1 << type))) {
 		err = -EOPNOTSUPP;
 		goto unlock;
 	}
@@ -455,7 +472,8 @@ static int nl80211_new_interface(struct 
 	if (IS_ERR(drv))
 		return PTR_ERR(drv);
 
-	if (!drv->ops->add_virtual_intf) {
+	if (!drv->ops->add_virtual_intf ||
+	    !(drv->wiphy.interface_modes & (1 << type))) {
 		err = -EOPNOTSUPP;
 		goto unlock;
 	}
--- everything.orig/drivers/net/wireless/b43/main.c	2008-08-07 16:49:57.000000000 +0200
+++ everything/drivers/net/wireless/b43/main.c	2008-08-07 16:57:12.000000000 +0200
@@ -4165,11 +4165,11 @@ static int b43_op_add_interface(struct i
 
 	/* TODO: allow WDS/AP devices to coexist */
 
-	if (conf->type != IEEE80211_IF_TYPE_AP &&
-	    conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
-	    conf->type != IEEE80211_IF_TYPE_STA &&
-	    conf->type != IEEE80211_IF_TYPE_WDS &&
-	    conf->type != IEEE80211_IF_TYPE_IBSS)
+	if (WARN_ON(conf->type != IEEE80211_IF_TYPE_AP &&
+		    conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
+		    conf->type != IEEE80211_IF_TYPE_STA &&
+		    conf->type != IEEE80211_IF_TYPE_WDS &&
+		    conf->type != IEEE80211_IF_TYPE_IBSS))
 		return -EOPNOTSUPP;
 
 	mutex_lock(&wl->mutex);
@@ -4649,6 +4649,13 @@ static int b43_wireless_init(struct ssb_
 		    IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
 
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_MESH_POINT) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_WDS) |
+		BIT(NL80211_IFTYPE_ADHOC);
+
 	hw->queues = b43_modparam_qos ? 4 : 1;
 	SET_IEEE80211_DEV(hw, dev->dev);
 	if (is_valid_ether_addr(sprom->et1mac))
--- everything.orig/net/mac80211/main.c	2008-08-07 16:42:32.000000000 +0200
+++ everything/net/mac80211/main.c	2008-08-07 16:59:05.000000000 +0200
@@ -1263,6 +1263,13 @@ int ieee80211_register_hw(struct ieee802
 		}
 	}
 
+	/* if low-level driver supports AP, we also support VLAN */
+	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
+		local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+
+	/* mac80211 always supports monitor */
+	local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
 	result = wiphy_register(local->hw.wiphy);
 	if (result < 0)
 		return result;


--
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 Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux