linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] cfg80211 capa/4addr improvements, disallow bridging
@ 2009-11-18 23:56 Johannes Berg
  2009-11-18 23:56 ` [PATCH 1/3] cfg80211: convert bools into flags Johannes Berg
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Johannes Berg @ 2009-11-18 23:56 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, nbd

So I wanted to move the bridging stuff into cfg80211
and ended up reworking a bunch of things to actually
make that possible.

johannes


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] cfg80211: convert bools into flags
  2009-11-18 23:56 [PATCH 0/3] cfg80211 capa/4addr improvements, disallow bridging Johannes Berg
@ 2009-11-18 23:56 ` Johannes Berg
  2009-11-18 23:56 ` [PATCH 2/3] cfg80211: introduce capability for 4addr mode Johannes Berg
  2009-11-18 23:56 ` [PATCH 3/3] cfg80211: disallow bridging managed/adhoc interfaces Johannes Berg
  2 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2009-11-18 23:56 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, nbd

We've accumulated a number of options for wiphys
which make more sense as flags as we keep adding
more. Convert the existing ones.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 drivers/net/wireless/ath/regd.c             |    5 --
 drivers/net/wireless/iwlwifi/iwl-agn.c      |    8 +--
 drivers/net/wireless/iwlwifi/iwl3945-base.c |    6 --
 drivers/net/wireless/mac80211_hwsim.c       |   18 ++++----
 drivers/net/wireless/p54/main.c             |    2 
 include/net/cfg80211.h                      |   62 +++++++++++++++-------------
 net/mac80211/main.c                         |    2 
 net/wireless/Kconfig                        |    6 --
 net/wireless/core.c                         |   13 ++++-
 net/wireless/nl80211.c                      |    2 
 net/wireless/reg.c                          |   13 +++--
 11 files changed, 70 insertions(+), 67 deletions(-)

--- wireless-testing.orig/include/net/cfg80211.h	2009-11-18 23:02:38.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h	2009-11-18 23:27:51.000000000 +0100
@@ -1108,27 +1108,45 @@ struct cfg80211_ops {
  */
 
 /**
- * struct wiphy - wireless hardware description
- * @idx: the wiphy index assigned to this item
- * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
- * @custom_regulatory: tells us the driver for this device
+ * enum wiphy_flags - wiphy capability flags
+ *
+ * @WIPHY_FLAG_CUSTOM_REGULATORY:  tells us the driver for this device
  * 	has its own custom regulatory domain and cannot identify the
  * 	ISO / IEC 3166 alpha2 it belongs to. When this is enabled
  * 	we will disregard the first regulatory hint (when the
  * 	initiator is %REGDOM_SET_BY_CORE).
- * @strict_regulatory: tells us the driver for this device will ignore
- * 	regulatory domain settings until it gets its own regulatory domain
- * 	via its regulatory_hint(). After its gets its own regulatory domain
- * 	it will only allow further regulatory domain settings to further
- * 	enhance compliance. For example if channel 13 and 14 are disabled
- * 	by this regulatory domain no user regulatory domain can enable these
- * 	channels at a later time. This can be used for devices which do not
- * 	have calibration information gauranteed for frequencies or settings
- * 	outside of its regulatory domain.
- * @disable_beacon_hints: enable this if your driver needs to ensure that
- *	passive scan flags and beaconing flags may not be lifted by cfg80211
- *	due to regulatory beacon hints. For more information on beacon
+ * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
+ *	ignore regulatory domain settings until it gets its own regulatory
+ *	domain via its regulatory_hint(). After its gets its own regulatory
+ *	domain it will only allow further regulatory domain settings to
+ *	further enhance compliance. For example if channel 13 and 14 are
+ *	disabled by this regulatory domain no user regulatory domain can
+ *	enable these channels at a later time. This can be used for devices
+ *	which do not have calibration information gauranteed for frequencies
+ *	or settings outside of its regulatory domain.
+ * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
+ *	that passive scan flags and beaconing flags may not be lifted by
+ *	cfg80211 due to regulatory beacon hints. For more information on beacon
  *	hints read the documenation for regulatory_hint_found_beacon()
+ * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
+ *	wiphy at all
+ * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
+ *	by default -- this flag will be set depending on the kernel's default
+ *	on wiphy_new(), but can be changed by the driver if it has a good
+ *	reason to override the default
+ */
+enum wiphy_flags {
+	WIPHY_FLAG_CUSTOM_REGULATORY	= BIT(0),
+	WIPHY_FLAG_STRICT_REGULATORY	= BIT(1),
+	WIPHY_FLAG_DISABLE_BEACON_HINTS	= BIT(2),
+	WIPHY_FLAG_NETNS_OK		= BIT(3),
+	WIPHY_FLAG_PS_ON_BY_DEFAULT	= BIT(4),
+};
+
+/**
+ * struct wiphy - wireless hardware description
+ * @idx: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
  * @reg_notifier: the driver's regulatory notification callback
  * @regd: the driver's regulatory domain, if one was requested via
  * 	the regulatory_hint() API. This can be used by the driver
@@ -1143,11 +1161,6 @@ struct cfg80211_ops {
  *	-1 = fragmentation disabled, only odd values >= 256 used
  * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
  * @net: the network namespace this wiphy currently lives in
- * @netnsok: if set to false, do not allow changing the netns of this
- *	wiphy at all
- * @ps_default: default for powersave, will be set depending on the
- *	kernel's default on wiphy_new(), but can be changed by the
- *	driver if it has a good reason to override the default
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -1158,12 +1171,7 @@ struct wiphy {
 	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
 	u16 interface_modes;
 
-	bool custom_regulatory;
-	bool strict_regulatory;
-	bool disable_beacon_hints;
-
-	bool netnsok;
-	bool ps_default;
+	u32 flags;
 
 	enum cfg80211_signal_type signal_type;
 
--- wireless-testing.orig/net/wireless/Kconfig	2009-11-18 23:09:26.000000000 +0100
+++ wireless-testing/net/wireless/Kconfig	2009-11-18 23:10:12.000000000 +0100
@@ -74,12 +74,6 @@ config CFG80211_REG_DEBUG
 
 	  If unsure, say N.
 
-config CFG80211_DEFAULT_PS_VALUE
-	int
-	default 1 if CFG80211_DEFAULT_PS
-	default 0
-	depends on CFG80211
-
 config CFG80211_DEFAULT_PS
 	bool "enable powersave by default"
 	depends on CFG80211
--- wireless-testing.orig/net/wireless/core.c	2009-11-18 23:08:48.000000000 +0100
+++ wireless-testing/net/wireless/core.c	2009-11-18 23:11:05.000000000 +0100
@@ -231,7 +231,7 @@ int cfg80211_switch_netns(struct cfg8021
 	struct wireless_dev *wdev;
 	int err = 0;
 
-	if (!rdev->wiphy.netnsok)
+	if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
 		return -EOPNOTSUPP;
 
 	list_for_each_entry(wdev, &rdev->netdev_list, list) {
@@ -368,7 +368,9 @@ struct wiphy *wiphy_new(const struct cfg
 	rdev->wiphy.dev.class = &ieee80211_class;
 	rdev->wiphy.dev.platform_data = rdev;
 
-	rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE;
+#ifdef CONFIG_CFG80211_DEFAULT_PS
+	rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#endif
 
 	wiphy_net_set(&rdev->wiphy, &init_net);
 
@@ -483,7 +485,7 @@ int wiphy_register(struct wiphy *wiphy)
 	if (IS_ERR(rdev->wiphy.debugfsdir))
 		rdev->wiphy.debugfsdir = NULL;
 
-	if (wiphy->custom_regulatory) {
+	if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
 		struct regulatory_request request;
 
 		request.wiphy_idx = get_wiphy_idx(wiphy);
@@ -674,7 +676,10 @@ static int cfg80211_netdev_notifier_call
 		wdev->wext.default_key = -1;
 		wdev->wext.default_mgmt_key = -1;
 		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-		wdev->wext.ps = wdev->wiphy->ps_default;
+		if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
+			wdev->wext.ps = true;
+		else
+			wdev->wext.ps = false;
 		wdev->wext.ps_timeout = 100;
 		if (rdev->ops->set_power_mgmt)
 			if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
--- wireless-testing.orig/net/wireless/nl80211.c	2009-11-18 23:12:55.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2009-11-18 23:27:51.000000000 +0100
@@ -561,7 +561,7 @@ static int nl80211_send_wiphy(struct sk_
 	CMD(deauth, DEAUTHENTICATE);
 	CMD(disassoc, DISASSOCIATE);
 	CMD(join_ibss, JOIN_IBSS);
-	if (dev->wiphy.netnsok) {
+	if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
 		i++;
 		NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
 	}
--- wireless-testing.orig/net/wireless/reg.c	2009-11-18 23:11:16.000000000 +0100
+++ wireless-testing/net/wireless/reg.c	2009-11-18 23:12:44.000000000 +0100
@@ -1008,7 +1008,7 @@ static void handle_channel(struct wiphy 
 
 	if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
 	    request_wiphy && request_wiphy == wiphy &&
-	    request_wiphy->strict_regulatory) {
+	    request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
 		/*
 		 * This gaurantees the driver's requested regulatory domain
 		 * will always be used as a base for further regulatory
@@ -1051,13 +1051,13 @@ static bool ignore_reg_update(struct wip
 	if (!last_request)
 		return true;
 	if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-		  wiphy->custom_regulatory)
+	    wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
 		return true;
 	/*
 	 * wiphy->regd will be set once the device has its own
 	 * desired regulatory domain set
 	 */
-	if (wiphy->strict_regulatory && !wiphy->regd &&
+	if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
 	    !is_world_regdom(last_request->alpha2))
 		return true;
 	return false;
@@ -1093,7 +1093,7 @@ static void handle_reg_beacon(struct wip
 
 	chan->beacon_found = true;
 
-	if (wiphy->disable_beacon_hints)
+	if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
 		return;
 
 	chan_before.center_freq = chan->center_freq;
@@ -1164,7 +1164,7 @@ static bool reg_is_world_roaming(struct 
 		return true;
 	if (last_request &&
 	    last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-	    wiphy->custom_regulatory)
+	    wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
 		return true;
 	return false;
 }
@@ -1591,7 +1591,8 @@ static void reg_process_hint(struct regu
 
 	r = __regulatory_hint(wiphy, reg_request);
 	/* This is required so that the orig_* parameters are saved */
-	if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
+	if (r == -EALREADY && wiphy &&
+	    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
 		wiphy_update_regulatory(wiphy, reg_request->initiator);
 out:
 	mutex_unlock(&reg_mutex);
--- wireless-testing.orig/drivers/net/wireless/ath/regd.c	2009-11-18 23:15:06.000000000 +0100
+++ wireless-testing/drivers/net/wireless/ath/regd.c	2009-11-18 23:23:56.000000000 +0100
@@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulator
 	const struct ieee80211_regdomain *regd;
 
 	wiphy->reg_notifier = reg_notifier;
-	wiphy->strict_regulatory = true;
+	wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 
 	if (ath_is_world_regd(reg)) {
 		/*
@@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulator
 		 * saved on the wiphy orig_* parameters
 		 */
 		regd = ath_world_regdomain(reg);
-		wiphy->custom_regulatory = true;
-		wiphy->strict_regulatory = false;
+		wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 	} else {
 		/*
 		 * This gets applied in the case of the absense of CRDA,
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-agn.c	2009-11-18 23:15:06.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-agn.c	2009-11-18 23:17:26.000000000 +0100
@@ -2401,16 +2401,14 @@ static int iwl_setup_mac(struct iwl_priv
 		BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC);
 
-	hw->wiphy->custom_regulatory = true;
-
-	/* Firmware does not support this */
-	hw->wiphy->disable_beacon_hints = true;
+	hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
+			    WIPHY_FLAG_DISABLE_BEACON_HINTS;
 
 	/*
 	 * For now, disable PS by default because it affects
 	 * RX performance significantly.
 	 */
-	hw->wiphy->ps_default = false;
+	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
 	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
 	/* we create the 802.11 header and a zero-length SSID element */
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c	2009-11-18 23:15:06.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl3945-base.c	2009-11-18 23:17:38.000000000 +0100
@@ -3905,10 +3905,8 @@ static int iwl3945_setup_mac(struct iwl_
 		BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC);
 
-	hw->wiphy->custom_regulatory = true;
-
-	/* Firmware does not support this */
-	hw->wiphy->disable_beacon_hints = true;
+	hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
+			    WIPHY_FLAG_DISABLE_BEACON_HINTS;
 
 	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
 	/* we create the 802.11 header and a zero-length SSID element */
--- wireless-testing.orig/drivers/net/wireless/mac80211_hwsim.c	2009-11-18 23:15:06.000000000 +0100
+++ wireless-testing/drivers/net/wireless/mac80211_hwsim.c	2009-11-18 23:16:25.000000000 +0100
@@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(vo
 			break;
 		case HWSIM_REGTEST_WORLD_ROAM:
 			if (i == 0) {
-				hw->wiphy->custom_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 				wiphy_apply_custom_regulatory(hw->wiphy,
 					&hwsim_world_regdom_custom_01);
 			}
 			break;
 		case HWSIM_REGTEST_CUSTOM_WORLD:
-			hw->wiphy->custom_regulatory = true;
+			hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 			wiphy_apply_custom_regulatory(hw->wiphy,
 				&hwsim_world_regdom_custom_01);
 			break;
 		case HWSIM_REGTEST_CUSTOM_WORLD_2:
 			if (i == 0) {
-				hw->wiphy->custom_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 				wiphy_apply_custom_regulatory(hw->wiphy,
 					&hwsim_world_regdom_custom_01);
 			} else if (i == 1) {
-				hw->wiphy->custom_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 				wiphy_apply_custom_regulatory(hw->wiphy,
 					&hwsim_world_regdom_custom_02);
 			}
 			break;
 		case HWSIM_REGTEST_STRICT_ALL:
-			hw->wiphy->strict_regulatory = true;
+			hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 			break;
 		case HWSIM_REGTEST_STRICT_FOLLOW:
 		case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
 			if (i == 0)
-				hw->wiphy->strict_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 			break;
 		case HWSIM_REGTEST_ALL:
 			if (i == 0) {
-				hw->wiphy->custom_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 				wiphy_apply_custom_regulatory(hw->wiphy,
 					&hwsim_world_regdom_custom_01);
 			} else if (i == 1) {
-				hw->wiphy->custom_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 				wiphy_apply_custom_regulatory(hw->wiphy,
 					&hwsim_world_regdom_custom_02);
 			} else if (i == 4)
-				hw->wiphy->strict_regulatory = true;
+				hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 			break;
 		default:
 			break;
--- wireless-testing.orig/net/mac80211/main.c	2009-11-18 23:13:50.000000000 +0100
+++ wireless-testing/net/mac80211/main.c	2009-11-18 23:14:01.000000000 +0100
@@ -664,7 +664,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	if (!wiphy)
 		return NULL;
 
-	wiphy->netnsok = true;
+	wiphy->flags |= WIPHY_FLAG_NETNS_OK;
 	wiphy->privid = mac80211_wiphy_privid;
 
 	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
--- wireless-testing.orig/drivers/net/wireless/p54/main.c	2009-11-18 23:28:03.000000000 +0100
+++ wireless-testing/drivers/net/wireless/p54/main.c	2009-11-18 23:28:19.000000000 +0100
@@ -579,7 +579,7 @@ struct ieee80211_hw *p54_init_common(siz
 	 * For now, disable PS by default because it affects
 	 * link stability significantly.
 	 */
-	dev->wiphy->ps_default = false;
+	dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
 	mutex_init(&priv->conf_mutex);
 	mutex_init(&priv->eeprom_mutex);



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/3] cfg80211: introduce capability for 4addr mode
  2009-11-18 23:56 [PATCH 0/3] cfg80211 capa/4addr improvements, disallow bridging Johannes Berg
  2009-11-18 23:56 ` [PATCH 1/3] cfg80211: convert bools into flags Johannes Berg
@ 2009-11-18 23:56 ` Johannes Berg
  2009-11-19 10:54   ` Johannes Berg
  2009-11-19 10:55   ` [PATCH 2/3 v2] " Johannes Berg
  2009-11-18 23:56 ` [PATCH 3/3] cfg80211: disallow bridging managed/adhoc interfaces Johannes Berg
  2 siblings, 2 replies; 6+ messages in thread
From: Johannes Berg @ 2009-11-18 23:56 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, nbd

It's very likely that not many devices will support
four-address mode in station or AP mode so introduce
capability bits for both modes, set them in mac80211
and check them when userspace tries to use the mode.
Also, keep track of 4addr in cfg80211 (wireless_dev)
and not in mac80211 any more. mac80211 can also be
improved for the VLAN case by not looking at the
4addr flag but maintaining the station pointer for
it correctly. However, keep track of use_4addr for
station mode in mac80211 to avoid all the derefs.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 include/net/cfg80211.h     |   11 +++++++++++
 net/mac80211/cfg.c         |   21 ++++++++-------------
 net/mac80211/ieee80211_i.h |    4 ++--
 net/mac80211/iface.c       |   12 ++++++++----
 net/mac80211/main.c        |    4 +++-
 net/mac80211/rx.c          |   14 +++++++++-----
 net/mac80211/tx.c          |    7 +++----
 net/wireless/nl80211.c     |   34 +++++++++++++++++++++++++++++++++-
 net/wireless/util.c        |    5 +++++
 9 files changed, 82 insertions(+), 30 deletions(-)

--- wireless-testing.orig/include/net/cfg80211.h	2009-11-18 23:27:51.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h	2009-11-19 00:23:03.000000000 +0100
@@ -1134,6 +1134,9 @@ struct cfg80211_ops {
  *	by default -- this flag will be set depending on the kernel's default
  *	on wiphy_new(), but can be changed by the driver if it has a good
  *	reason to override the default
+ * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
+ *	on a VLAN interface)
+ * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
  */
 enum wiphy_flags {
 	WIPHY_FLAG_CUSTOM_REGULATORY	= BIT(0),
@@ -1141,6 +1144,8 @@ enum wiphy_flags {
 	WIPHY_FLAG_DISABLE_BEACON_HINTS	= BIT(2),
 	WIPHY_FLAG_NETNS_OK		= BIT(3),
 	WIPHY_FLAG_PS_ON_BY_DEFAULT	= BIT(4),
+	WIPHY_FLAG_4ADDR_AP		= BIT(5),
+	WIPHY_FLAG_4ADDR_STATION	= BIT(6),
 };
 
 /**
@@ -1366,6 +1371,10 @@ struct cfg80211_cached_keys;
  * @ssid_len: (private) Used by the internal configuration code
  * @wext: (private) Used by the internal wireless extensions compat code
  * @wext_bssid: (private) Used by the internal wireless extensions compat code
+ * @use_4addr: indicates 4addr mode is used on this interface, must be
+ *	set by driver (if supported) on add_interface BEFORE registering the
+ *	netdev and may otherwise be used by driver read-only, will be update
+ *	by cfg80211 on change_interface
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -1379,6 +1388,8 @@ struct wireless_dev {
 
 	struct work_struct cleanup_work;
 
+	bool use_4addr;
+
 	/* currently used for IBSS and SME - might be rearranged later */
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ssid_len;
--- wireless-testing.orig/net/wireless/nl80211.c	2009-11-18 23:27:51.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2009-11-18 23:46:06.000000000 +0100
@@ -968,6 +968,28 @@ static int parse_monitor_flags(struct nl
 	return 0;
 }
 
+static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
+			       u8 use_4addr, enum nl80211_iftype iftype)
+{
+	if (!use_4addr)
+		return 0;
+
+	switch (iftype) {
+	case NL80211_IFTYPE_AP_VLAN:
+		if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
+			return 0;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
+			return 0;
+		break;
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
@@ -1011,6 +1033,9 @@ static int nl80211_set_interface(struct 
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
 		change = true;
+		err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
+		if (err)
+			goto unlock;
 	} else {
 		params.use_4addr = -1;
 	}
@@ -1034,6 +1059,9 @@ static int nl80211_set_interface(struct 
 	else
 		err = 0;
 
+	if (!err && params.use_4addr != -1)
+		dev->ieee80211_ptr->use_4addr = params.use_4addr;
+
  unlock:
 	dev_put(dev);
 	cfg80211_unlock_rdev(rdev);
@@ -1081,8 +1109,12 @@ static int nl80211_new_interface(struct 
 		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
 	}
 
-	if (info->attrs[NL80211_ATTR_4ADDR])
+	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
+		err = nl80211_valid_4addr(rdev, params.use_4addr, type);
+		if (err)
+			goto unlock;
+	}
 
 	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
 				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
--- wireless-testing.orig/net/mac80211/main.c	2009-11-18 23:33:16.000000000 +0100
+++ wireless-testing/net/mac80211/main.c	2009-11-18 23:33:41.000000000 +0100
@@ -664,7 +664,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	if (!wiphy)
 		return NULL;
 
-	wiphy->flags |= WIPHY_FLAG_NETNS_OK;
+	wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+			WIPHY_FLAG_4ADDR_AP |
+			WIPHY_FLAG_4ADDR_STATION;
 	wiphy->privid = mac80211_wiphy_privid;
 
 	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
--- wireless-testing.orig/net/mac80211/cfg.c	2009-11-18 23:44:18.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c	2009-11-19 00:04:55.000000000 +0100
@@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl
 	if (!nl80211_type_check(type))
 		return false;
 
-	if (params->use_4addr > 0) {
-		switch(type) {
-		case NL80211_IFTYPE_AP_VLAN:
-		case NL80211_IFTYPE_STATION:
-			break;
-		default:
-			return false;
-		}
-	}
 	return true;
 }
 
@@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct
 					    params->mesh_id_len,
 					    params->mesh_id);
 
-	if (params->use_4addr >= 0)
-		sdata->use_4addr = !!params->use_4addr;
-
 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
 		return 0;
 
+	if (type == NL80211_IFTYPE_AP_VLAN &&
+	    params && params->use_4addr == 0)
+		rcu_assign_pointer(sdata->u.vlan.sta, NULL);
+	else if (type == NL80211_IFTYPE_STATION &&
+		 params && params->use_4addr >= 0)
+		sdata->u.mgd.use_4addr = params->use_4addr;
+
 	sdata->u.mntr_flags = *flags;
 	return 0;
 }
@@ -827,7 +822,7 @@ static int ieee80211_change_station(stru
 			return -EINVAL;
 		}
 
-		if (vlansdata->use_4addr) {
+		if (params->vlan->ieee80211_ptr->use_4addr) {
 			if (vlansdata->u.vlan.sta)
 				return -EBUSY;
 
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-11-18 23:47:49.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-11-19 00:01:50.000000000 +0100
@@ -311,6 +311,8 @@ struct ieee80211_if_managed {
 	} mfp; /* management frame protection */
 
 	int wmm_last_param_set;
+
+	u8 use_4addr;
 };
 
 enum ieee80211_ibss_request {
@@ -458,8 +460,6 @@ struct ieee80211_sub_if_data {
 	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
 	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 
-	bool use_4addr; /* use 4-address frames */
-
 	union {
 		struct ieee80211_if_ap ap;
 		struct ieee80211_if_wds wds;
--- wireless-testing.orig/net/mac80211/iface.c	2009-11-18 23:46:12.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c	2009-11-19 00:20:00.000000000 +0100
@@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee
 		ieee80211_mandatory_rates(sdata->local,
 			sdata->local->hw.conf.channel->band);
 	sdata->drop_unencrypted = 0;
-	sdata->use_4addr = 0;
+	if (type == NL80211_IFTYPE_STATION)
+		sdata->u.mgd.use_4addr = false;
 
 	return 0;
 }
@@ -815,6 +816,12 @@ int ieee80211_if_add(struct ieee80211_lo
 	/* setup type-dependent data */
 	ieee80211_setup_sdata(sdata, type);
 
+	if (params) {
+		ndev->ieee80211_ptr->use_4addr = params->use_4addr;
+		if (type == NL80211_IFTYPE_STATION)
+			sdata->u.mgd.use_4addr = params->use_4addr;
+	}
+
 	ret = register_netdevice(ndev);
 	if (ret)
 		goto fail;
@@ -825,9 +832,6 @@ int ieee80211_if_add(struct ieee80211_lo
 					    params->mesh_id_len,
 					    params->mesh_id);
 
-	if (params && params->use_4addr >= 0)
-		sdata->use_4addr = !!params->use_4addr;
-
 	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
 	mutex_unlock(&local->iflist_mtx);
--- wireless-testing.orig/net/mac80211/rx.c	2009-11-18 23:49:42.000000000 +0100
+++ wireless-testing/net/mac80211/rx.c	2009-11-19 00:12:23.000000000 +0100
@@ -1192,10 +1192,13 @@ __ieee80211_data_to_8023(struct ieee8021
 	struct net_device *dev = sdata->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
-	    ieee80211_has_a4(hdr->frame_control))
+	if (ieee80211_has_a4(hdr->frame_control) &&
+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
 		return -1;
-	if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
+
+	if (is_multicast_ether_addr(hdr->addr1) &&
+	    ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) ||
+	     (sdata->vif.type == NL80211_IFTYPE_STATION && !sdata->u.mgd.use_4addr)))
 		return -1;
 
 	return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
@@ -1245,7 +1248,8 @@ ieee80211_deliver_skb(struct ieee80211_r
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
 	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
 	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
-	    (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) {
+	    (rx->flags & IEEE80211_RX_RA_MATCH) &&
+	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
 		if (is_multicast_ether_addr(ehdr->h_dest)) {
 			/*
 			 * send multicast frames both to higher layers in
@@ -2007,7 +2011,7 @@ static int prepare_for_handlers(struct i
 
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_STATION:
-		if (!bssid && !sdata->use_4addr)
+		if (!bssid && !sdata->u.mgd.use_4addr)
 			return 0;
 		if (!multicast &&
 		    compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
--- wireless-testing.orig/net/mac80211/tx.c	2009-11-18 23:52:13.000000000 +0100
+++ wireless-testing/net/mac80211/tx.c	2009-11-19 00:05:46.000000000 +0100
@@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_su
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 
-	if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 		tx->sta = rcu_dereference(sdata->u.vlan.sta);
 	if (!tx->sta)
 		tx->sta = sta_info_get(local, hdr->addr1);
@@ -1632,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_AP_VLAN:
 		rcu_read_lock();
-		if (sdata->use_4addr)
-			sta = rcu_dereference(sdata->u.vlan.sta);
+		sta = rcu_dereference(sdata->u.vlan.sta);
 		if (sta) {
 			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 			/* RA TA DA SA */
@@ -1727,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s
 #endif
 	case NL80211_IFTYPE_STATION:
 		memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-		if (sdata->use_4addr && ethertype != ETH_P_PAE) {
+		if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
 			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 			/* RA TA DA SA */
 			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
--- wireless-testing.orig/net/wireless/util.c	2009-11-18 23:48:22.000000000 +0100
+++ wireless-testing/net/wireless/util.c	2009-11-19 00:22:18.000000000 +0100
@@ -659,6 +659,8 @@ int cfg80211_change_iface(struct cfg8021
 		return -EOPNOTSUPP;
 
 	if (ntype != otype) {
+		dev->ieee80211_ptr->use_4addr = false;
+
 		switch (otype) {
 		case NL80211_IFTYPE_ADHOC:
 			cfg80211_leave_ibss(rdev, dev, false);
@@ -682,5 +684,8 @@ int cfg80211_change_iface(struct cfg8021
 
 	WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
+	if (!err && params && params->use_4addr != -1)
+		dev->ieee80211_ptr->use_4addr = params->use_4addr;
+
 	return err;
 }



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/3] cfg80211: disallow bridging managed/adhoc interfaces
  2009-11-18 23:56 [PATCH 0/3] cfg80211 capa/4addr improvements, disallow bridging Johannes Berg
  2009-11-18 23:56 ` [PATCH 1/3] cfg80211: convert bools into flags Johannes Berg
  2009-11-18 23:56 ` [PATCH 2/3] cfg80211: introduce capability for 4addr mode Johannes Berg
@ 2009-11-18 23:56 ` Johannes Berg
  2 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2009-11-18 23:56 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, nbd, Stephen Hemminger

A number of people have tried to add a wireless interface
(in managed mode) to a bridge and then complained that it
doesn't work. It cannot work, however, because in 802.11
networks all packets need to be acknowledged and as such
need to be sent to the right address. Promiscuous doesn't
help here. The wireless address format used for these
links has only space for three addresses, the
 * transmitter, which must be equal to the sender (origin)
 * receiver (on the wireless medium), which is the AP in
   the case of managed mode
 * the recipient (destination), which is on the APs local
   network segment

In an IBSS, it is similar, but the receiver and recipient
must match and the third address is used as the BSSID.

To avoid such mistakes in the future, disallow adding a
wireless interface to a bridge.

Felix has recently added a four-address mode to the AP
and client side that can be used (after negotiating that
it is possible, which must happen out-of-band by setting
up both sides) for bridging, so allow that case.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
---
 include/linux/if.h     |    1 +
 net/bridge/br_if.c     |    4 ++++
 net/wireless/core.c    |    4 ++++
 net/wireless/nl80211.c |   12 ++++++++----
 net/wireless/util.c    |   31 +++++++++++++++++++++++++++++++
 5 files changed, 48 insertions(+), 4 deletions(-)

--- wireless-testing.orig/include/linux/if.h	2009-11-19 00:22:18.000000000 +0100
+++ wireless-testing/include/linux/if.h	2009-11-19 00:23:17.000000000 +0100
@@ -70,6 +70,7 @@
 #define IFF_XMIT_DST_RELEASE 0x400	/* dev_hard_start_xmit() is allowed to
 					 * release skb->dst
 					 */
+#define IFF_DONT_BRIDGE 0x800		/* disallow bridging this ether dev */
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
--- wireless-testing.orig/net/bridge/br_if.c	2009-11-19 00:22:18.000000000 +0100
+++ wireless-testing/net/bridge/br_if.c	2009-11-19 00:23:17.000000000 +0100
@@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, str
 	if (dev->br_port != NULL)
 		return -EBUSY;
 
+	/* No bridging devices that dislike that (e.g. wireless) */
+	if (dev->priv_flags & IFF_DONT_BRIDGE)
+		return -EOPNOTSUPP;
+
 	p = new_nbp(br, dev);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
--- wireless-testing.orig/net/wireless/util.c	2009-11-19 00:22:18.000000000 +0100
+++ wireless-testing/net/wireless/util.c	2009-11-19 00:23:17.000000000 +0100
@@ -658,6 +658,11 @@ int cfg80211_change_iface(struct cfg8021
 	    !(rdev->wiphy.interface_modes & (1 << ntype)))
 		return -EOPNOTSUPP;
 
+	/* if it's part of a bridge, reject changing type to station/ibss */
+	if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
+			     ntype == NL80211_IFTYPE_STATION))
+		return -EBUSY;
+
 	if (ntype != otype) {
 		dev->ieee80211_ptr->use_4addr = false;
 
@@ -687,5 +692,31 @@ int cfg80211_change_iface(struct cfg8021
 	if (!err && params && params->use_4addr != -1)
 		dev->ieee80211_ptr->use_4addr = params->use_4addr;
 
+	if (!err) {
+		dev->priv_flags &= ~IFF_DONT_BRIDGE;
+		switch (ntype) {
+		case NL80211_IFTYPE_STATION:
+			if (dev->ieee80211_ptr->use_4addr)
+				break;
+			/* fall through */
+		case NL80211_IFTYPE_ADHOC:
+			dev->priv_flags |= IFF_DONT_BRIDGE;
+			break;
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_AP_VLAN:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
+			/* bridging OK */
+			break;
+		case NL80211_IFTYPE_MONITOR:
+			/* monitor can't bridge anyway */
+			break;
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case __NL80211_IFTYPE_AFTER_LAST:
+			/* not happening */
+			break;
+		}
+	}
+
 	return err;
 }
--- wireless-testing.orig/net/wireless/core.c	2009-11-19 00:22:18.000000000 +0100
+++ wireless-testing/net/wireless/core.c	2009-11-19 00:23:17.000000000 +0100
@@ -691,6 +691,10 @@ static int cfg80211_netdev_notifier_call
 #endif
 		if (!dev->ethtool_ops)
 			dev->ethtool_ops = &cfg80211_ethtool_ops;
+
+		if ((wdev->iftype == NL80211_IFTYPE_STATION ||
+		     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
+			dev->priv_flags |= IFF_DONT_BRIDGE;
 		break;
 	case NETDEV_GOING_DOWN:
 		switch (wdev->iftype) {
--- wireless-testing.orig/net/wireless/nl80211.c	2009-11-19 00:23:43.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2009-11-19 00:26:04.000000000 +0100
@@ -969,10 +969,14 @@ static int parse_monitor_flags(struct nl
 }
 
 static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
-			       u8 use_4addr, enum nl80211_iftype iftype)
+			       struct net_device *netdev, u8 use_4addr,
+			       enum nl80211_iftype iftype)
 {
-	if (!use_4addr)
+	if (!use_4addr) {
+		if (netdev && netdev->br_port)
+			return -EBUSY;
 		return 0;
+	}
 
 	switch (iftype) {
 	case NL80211_IFTYPE_AP_VLAN:
@@ -1033,7 +1037,7 @@ static int nl80211_set_interface(struct 
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
 		change = true;
-		err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
+		err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
 		if (err)
 			goto unlock;
 	} else {
@@ -1111,7 +1115,7 @@ static int nl80211_new_interface(struct 
 
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
-		err = nl80211_valid_4addr(rdev, params.use_4addr, type);
+		err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
 		if (err)
 			goto unlock;
 	}



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] cfg80211: introduce capability for 4addr mode
  2009-11-18 23:56 ` [PATCH 2/3] cfg80211: introduce capability for 4addr mode Johannes Berg
@ 2009-11-19 10:54   ` Johannes Berg
  2009-11-19 10:55   ` [PATCH 2/3 v2] " Johannes Berg
  1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2009-11-19 10:54 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, nbd

[-- Attachment #1: Type: text/plain, Size: 709 bytes --]

On Thu, 2009-11-19 at 00:56 +0100, Johannes Berg wrote:

> -	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
> -	    ieee80211_has_a4(hdr->frame_control))
> +	if (ieee80211_has_a4(hdr->frame_control) &&
> +	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
>  		return -1;
> -	if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
> +
> +	if (is_multicast_ether_addr(hdr->addr1) &&
> +	    ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) ||
> +	     (sdata->vif.type == NL80211_IFTYPE_STATION && !sdata->u.mgd.use_4addr)))
>  		return -1;

This is wrong, of course. Felix, can you explain what this actually
does?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/3 v2] cfg80211: introduce capability for 4addr mode
  2009-11-18 23:56 ` [PATCH 2/3] cfg80211: introduce capability for 4addr mode Johannes Berg
  2009-11-19 10:54   ` Johannes Berg
@ 2009-11-19 10:55   ` Johannes Berg
  1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2009-11-19 10:55 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, nbd

It's very likely that not many devices will support
four-address mode in station or AP mode so introduce
capability bits for both modes, set them in mac80211
and check them when userspace tries to use the mode.
Also, keep track of 4addr in cfg80211 (wireless_dev)
and not in mac80211 any more. mac80211 can also be
improved for the VLAN case by not looking at the
4addr flag but maintaining the station pointer for
it correctly. However, keep track of use_4addr for
station mode in mac80211 to avoid all the derefs.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v2: fix logic error

 include/net/cfg80211.h     |   11 +++++++++++
 net/mac80211/cfg.c         |   21 ++++++++-------------
 net/mac80211/ieee80211_i.h |    4 ++--
 net/mac80211/iface.c       |   12 ++++++++----
 net/mac80211/main.c        |    4 +++-
 net/mac80211/rx.c          |   14 +++++++++-----
 net/mac80211/tx.c          |    7 +++----
 net/wireless/nl80211.c     |   34 +++++++++++++++++++++++++++++++++-
 net/wireless/util.c        |    5 +++++
 9 files changed, 82 insertions(+), 30 deletions(-)

--- wireless-testing.orig/include/net/cfg80211.h	2009-11-19 11:15:52.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h	2009-11-19 11:16:05.000000000 +0100
@@ -1134,6 +1134,9 @@ struct cfg80211_ops {
  *	by default -- this flag will be set depending on the kernel's default
  *	on wiphy_new(), but can be changed by the driver if it has a good
  *	reason to override the default
+ * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
+ *	on a VLAN interface)
+ * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
  */
 enum wiphy_flags {
 	WIPHY_FLAG_CUSTOM_REGULATORY	= BIT(0),
@@ -1141,6 +1144,8 @@ enum wiphy_flags {
 	WIPHY_FLAG_DISABLE_BEACON_HINTS	= BIT(2),
 	WIPHY_FLAG_NETNS_OK		= BIT(3),
 	WIPHY_FLAG_PS_ON_BY_DEFAULT	= BIT(4),
+	WIPHY_FLAG_4ADDR_AP		= BIT(5),
+	WIPHY_FLAG_4ADDR_STATION	= BIT(6),
 };
 
 /**
@@ -1366,6 +1371,10 @@ struct cfg80211_cached_keys;
  * @ssid_len: (private) Used by the internal configuration code
  * @wext: (private) Used by the internal wireless extensions compat code
  * @wext_bssid: (private) Used by the internal wireless extensions compat code
+ * @use_4addr: indicates 4addr mode is used on this interface, must be
+ *	set by driver (if supported) on add_interface BEFORE registering the
+ *	netdev and may otherwise be used by driver read-only, will be update
+ *	by cfg80211 on change_interface
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -1379,6 +1388,8 @@ struct wireless_dev {
 
 	struct work_struct cleanup_work;
 
+	bool use_4addr;
+
 	/* currently used for IBSS and SME - might be rearranged later */
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ssid_len;
--- wireless-testing.orig/net/wireless/nl80211.c	2009-11-19 11:15:52.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2009-11-19 11:54:24.000000000 +0100
@@ -968,6 +968,28 @@ static int parse_monitor_flags(struct nl
 	return 0;
 }
 
+static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
+			       u8 use_4addr, enum nl80211_iftype iftype)
+{
+	if (!use_4addr)
+		return 0;
+
+	switch (iftype) {
+	case NL80211_IFTYPE_AP_VLAN:
+		if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP)
+			return 0;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION)
+			return 0;
+		break;
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
@@ -1011,6 +1033,9 @@ static int nl80211_set_interface(struct 
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
 		change = true;
+		err = nl80211_valid_4addr(rdev, params.use_4addr, ntype);
+		if (err)
+			goto unlock;
 	} else {
 		params.use_4addr = -1;
 	}
@@ -1034,6 +1059,9 @@ static int nl80211_set_interface(struct 
 	else
 		err = 0;
 
+	if (!err && params.use_4addr != -1)
+		dev->ieee80211_ptr->use_4addr = params.use_4addr;
+
  unlock:
 	dev_put(dev);
 	cfg80211_unlock_rdev(rdev);
@@ -1081,8 +1109,12 @@ static int nl80211_new_interface(struct 
 		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
 	}
 
-	if (info->attrs[NL80211_ATTR_4ADDR])
+	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
+		err = nl80211_valid_4addr(rdev, params.use_4addr, type);
+		if (err)
+			goto unlock;
+	}
 
 	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
 				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
--- wireless-testing.orig/net/mac80211/main.c	2009-11-19 11:15:52.000000000 +0100
+++ wireless-testing/net/mac80211/main.c	2009-11-19 11:16:05.000000000 +0100
@@ -328,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	if (!wiphy)
 		return NULL;
 
-	wiphy->flags |= WIPHY_FLAG_NETNS_OK;
+	wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+			WIPHY_FLAG_4ADDR_AP |
+			WIPHY_FLAG_4ADDR_STATION;
 	wiphy->privid = mac80211_wiphy_privid;
 
 	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
--- wireless-testing.orig/net/mac80211/cfg.c	2009-11-19 11:04:52.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c	2009-11-19 11:16:05.000000000 +0100
@@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl
 	if (!nl80211_type_check(type))
 		return false;
 
-	if (params->use_4addr > 0) {
-		switch(type) {
-		case NL80211_IFTYPE_AP_VLAN:
-		case NL80211_IFTYPE_STATION:
-			break;
-		default:
-			return false;
-		}
-	}
 	return true;
 }
 
@@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct
 					    params->mesh_id_len,
 					    params->mesh_id);
 
-	if (params->use_4addr >= 0)
-		sdata->use_4addr = !!params->use_4addr;
-
 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
 		return 0;
 
+	if (type == NL80211_IFTYPE_AP_VLAN &&
+	    params && params->use_4addr == 0)
+		rcu_assign_pointer(sdata->u.vlan.sta, NULL);
+	else if (type == NL80211_IFTYPE_STATION &&
+		 params && params->use_4addr >= 0)
+		sdata->u.mgd.use_4addr = params->use_4addr;
+
 	sdata->u.mntr_flags = *flags;
 	return 0;
 }
@@ -827,7 +822,7 @@ static int ieee80211_change_station(stru
 			return -EINVAL;
 		}
 
-		if (vlansdata->use_4addr) {
+		if (params->vlan->ieee80211_ptr->use_4addr) {
 			if (vlansdata->u.vlan.sta)
 				return -EBUSY;
 
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-11-19 11:04:52.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-11-19 11:16:05.000000000 +0100
@@ -312,6 +312,8 @@ struct ieee80211_if_managed {
 	} mfp; /* management frame protection */
 
 	int wmm_last_param_set;
+
+	u8 use_4addr;
 };
 
 enum ieee80211_ibss_request {
@@ -459,8 +461,6 @@ struct ieee80211_sub_if_data {
 	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
 	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 
-	bool use_4addr; /* use 4-address frames */
-
 	union {
 		struct ieee80211_if_ap ap;
 		struct ieee80211_if_wds wds;
--- wireless-testing.orig/net/mac80211/iface.c	2009-11-19 11:04:52.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c	2009-11-19 11:16:05.000000000 +0100
@@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee
 		ieee80211_mandatory_rates(sdata->local,
 			sdata->local->hw.conf.channel->band);
 	sdata->drop_unencrypted = 0;
-	sdata->use_4addr = 0;
+	if (type == NL80211_IFTYPE_STATION)
+		sdata->u.mgd.use_4addr = false;
 
 	return 0;
 }
@@ -815,6 +816,12 @@ int ieee80211_if_add(struct ieee80211_lo
 	/* setup type-dependent data */
 	ieee80211_setup_sdata(sdata, type);
 
+	if (params) {
+		ndev->ieee80211_ptr->use_4addr = params->use_4addr;
+		if (type == NL80211_IFTYPE_STATION)
+			sdata->u.mgd.use_4addr = params->use_4addr;
+	}
+
 	ret = register_netdevice(ndev);
 	if (ret)
 		goto fail;
@@ -825,9 +832,6 @@ int ieee80211_if_add(struct ieee80211_lo
 					    params->mesh_id_len,
 					    params->mesh_id);
 
-	if (params && params->use_4addr >= 0)
-		sdata->use_4addr = !!params->use_4addr;
-
 	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
 	mutex_unlock(&local->iflist_mtx);
--- wireless-testing.orig/net/mac80211/rx.c	2009-11-19 11:04:52.000000000 +0100
+++ wireless-testing/net/mac80211/rx.c	2009-11-19 11:50:55.000000000 +0100
@@ -1192,10 +1192,13 @@ __ieee80211_data_to_8023(struct ieee8021
 	struct net_device *dev = sdata->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
-	    ieee80211_has_a4(hdr->frame_control))
+	if (ieee80211_has_a4(hdr->frame_control) &&
+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
 		return -1;
-	if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
+
+	if (is_multicast_ether_addr(hdr->addr1) &&
+	    ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) ||
+	     (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
 		return -1;
 
 	return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
@@ -1245,7 +1248,8 @@ ieee80211_deliver_skb(struct ieee80211_r
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
 	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
 	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
-	    (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) {
+	    (rx->flags & IEEE80211_RX_RA_MATCH) &&
+	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
 		if (is_multicast_ether_addr(ehdr->h_dest)) {
 			/*
 			 * send multicast frames both to higher layers in
@@ -2007,7 +2011,7 @@ static int prepare_for_handlers(struct i
 
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_STATION:
-		if (!bssid && !sdata->use_4addr)
+		if (!bssid && !sdata->u.mgd.use_4addr)
 			return 0;
 		if (!multicast &&
 		    compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
--- wireless-testing.orig/net/mac80211/tx.c	2009-11-19 11:04:52.000000000 +0100
+++ wireless-testing/net/mac80211/tx.c	2009-11-19 11:16:05.000000000 +0100
@@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_su
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 
-	if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 		tx->sta = rcu_dereference(sdata->u.vlan.sta);
 	if (!tx->sta)
 		tx->sta = sta_info_get(local, hdr->addr1);
@@ -1632,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_AP_VLAN:
 		rcu_read_lock();
-		if (sdata->use_4addr)
-			sta = rcu_dereference(sdata->u.vlan.sta);
+		sta = rcu_dereference(sdata->u.vlan.sta);
 		if (sta) {
 			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 			/* RA TA DA SA */
@@ -1727,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s
 #endif
 	case NL80211_IFTYPE_STATION:
 		memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-		if (sdata->use_4addr && ethertype != ETH_P_PAE) {
+		if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
 			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 			/* RA TA DA SA */
 			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
--- wireless-testing.orig/net/wireless/util.c	2009-11-19 11:04:52.000000000 +0100
+++ wireless-testing/net/wireless/util.c	2009-11-19 11:54:24.000000000 +0100
@@ -659,6 +659,8 @@ int cfg80211_change_iface(struct cfg8021
 		return -EOPNOTSUPP;
 
 	if (ntype != otype) {
+		dev->ieee80211_ptr->use_4addr = false;
+
 		switch (otype) {
 		case NL80211_IFTYPE_ADHOC:
 			cfg80211_leave_ibss(rdev, dev, false);
@@ -682,5 +684,8 @@ int cfg80211_change_iface(struct cfg8021
 
 	WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
+	if (!err && params && params->use_4addr != -1)
+		dev->ieee80211_ptr->use_4addr = params->use_4addr;
+
 	return err;
 }



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2009-11-19 10:55 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-18 23:56 [PATCH 0/3] cfg80211 capa/4addr improvements, disallow bridging Johannes Berg
2009-11-18 23:56 ` [PATCH 1/3] cfg80211: convert bools into flags Johannes Berg
2009-11-18 23:56 ` [PATCH 2/3] cfg80211: introduce capability for 4addr mode Johannes Berg
2009-11-19 10:54   ` Johannes Berg
2009-11-19 10:55   ` [PATCH 2/3 v2] " Johannes Berg
2009-11-18 23:56 ` [PATCH 3/3] cfg80211: disallow bridging managed/adhoc interfaces Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).