All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/4] cfg80211/mac80211: move interface combinations check to mac80211
@ 2014-02-24 20:54 Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 1/4] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Luciano Coelho @ 2014-02-24 20:54 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

From: Luciano Coelho <luciano.coelho@intel.com>

Hi,

In v4:

   * rebased the remaining patches on top of what Johannes applied;
   * lots of other small changes in response to Johannes's comments.
     See each individual patch for detailed lists of changed (thanks
     Johannes!);

In v3:

   * move the "pass the mode argument..." change to the right patch;

In v2:

   * lock the chanctx mutex in ieee80211_ibss_join() before calling
     ieee80211_check_combinations().

   * pass the mode argument instead of IEEE80211_CHANCTX_SHARED to
     ieee80211_check_combinations() in ieee80211_vif_use_channel();

As Johannes suggested earlier, this patchset moves the interface
combinations check from cfg80211 to mac80211.  This is needed to
simplify the channel switch code.

There are still some cases where cfg80211 may need to check the
interface combinations (ie. when adding or changing an interface), so
I created a helper function that can be called by cfg80211 itself or
the drivers (such as mac80211).

Also, for now, I only moved the check in the cases where
ieee80211_vif_use_channel() is called and for IBSS join.  The channel
switch stuff, which will be trickier, is still missing.  These will be
handled separately and it doesn't really hurt to leave it as it is,
except because it's a bit inconsistent.

I had to shuffle some code around to make this whole thing a bit
cleaner, including the check for whether radar detection is needed.

This is not very thoroughly tested yet, I have just done some checks
with AP and STA with and without chanctx and with 1 or 2 different
channels.  This part seems to work, please test the rest. :)

I'll try to add some hwsim tests to test this more thoroughly.

Luca.

Luciano Coelho (4):
  cfg80211: refactor cfg80211_can_use_iftype_chan()
  cfg80211/mac80211: refactor cfg80211_chandef_dfs_required()
  cfg80211/mac80211: move interface counting for combination check to
    mac80211
  cfg80211/mac80211: move combination check to mac80211 for ibss

 Documentation/DocBook/80211.tmpl |   1 +
 include/net/cfg80211.h           |  41 +++++++++++--
 net/mac80211/cfg.c               |   2 -
 net/mac80211/chan.c              |  17 ++++++
 net/mac80211/ibss.c              |  61 +++++++++++++------
 net/mac80211/ieee80211_i.h       |   5 ++
 net/mac80211/mesh.c              |   9 +--
 net/mac80211/util.c              |  76 +++++++++++++++++++++++
 net/wireless/chan.c              |  77 +++++++++++++++++-------
 net/wireless/core.h              |  13 +---
 net/wireless/ibss.c              |  24 --------
 net/wireless/mesh.c              |  25 --------
 net/wireless/mlme.c              |  14 +----
 net/wireless/nl80211.c           |  53 ++++------------
 net/wireless/util.c              | 126 ++++++++++++++++++++++-----------------
 15 files changed, 329 insertions(+), 215 deletions(-)

-- 
1.8.5.3


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

* [PATCH v4 1/4] cfg80211: refactor cfg80211_can_use_iftype_chan()
  2014-02-24 20:54 [PATCH v4 0/4] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
@ 2014-02-24 20:54 ` Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 2/4] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required() Luciano Coelho
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Luciano Coelho @ 2014-02-24 20:54 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

From: Luciano Coelho <luciano.coelho@intel.com>

Separate the code that counts the interface types and channels from
the code that check the interface combinations.  The new function that
checks for combinations is exported so it can be called by the
drivers.

This is done in preparation for moving the interface combinations
checks out of cfg80211.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
In v4:

   * rebased on top of slightly modified applied patches
   * removed the parenthesis from the comment (not needed for docbook)
   * use num[NUM_NL80211_IFTYPES] in cfg80211_check_combinations()
---
 Documentation/DocBook/80211.tmpl |   1 +
 include/net/cfg80211.h           |  29 ++++++++++
 net/wireless/util.c              | 121 ++++++++++++++++++++++-----------------
 3 files changed, 97 insertions(+), 54 deletions(-)

diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 044b764..d9b9416 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -100,6 +100,7 @@
 !Finclude/net/cfg80211.h wdev_priv
 !Finclude/net/cfg80211.h ieee80211_iface_limit
 !Finclude/net/cfg80211.h ieee80211_iface_combination
+!Finclude/net/cfg80211.h cfg80211_check_combinations
       </chapter>
       <chapter>
       <title>Actions and configuration</title>
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8c9ba44..5f5a598 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4677,6 +4677,35 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
  */
 unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
 
+/**
+ * cfg80211_check_combinations - check interface combinations
+ *
+ * @wiphy: the wiphy
+ * @num_different_channels: the number of different channels we want
+ *	to use for verification
+ * @num_interfaces: the number of different interfaces we want to use
+ *	for verification
+ * @used_iftypes: a bitmap where each bit corresponds to an interface
+ *	type, as in the definition of &struct
+ *	ieee80211_iface_limit.@types.
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ *	width where radar detection is needed, as in the definition of
+ *	&struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ *	type.  The index is the interface type as specified in &enum
+ *	nl80211_iftype.
+ *
+ * This function can be called by the driver to check whether a
+ * combination of interfaces and their types are allowed according to
+ * the interface combinations.
+ */
+int cfg80211_check_combinations(struct wiphy *wiphy,
+				const int num_different_channels,
+				const int num_interfaces,
+				const u32 used_iftypes,
+				const u8 radar_detect,
+				const int iftype_num[NUM_NL80211_IFTYPES]);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 57b3ce7..d562dd6 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1253,6 +1253,69 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 	return res;
 }
 
+int cfg80211_check_combinations(struct wiphy *wiphy,
+				const int num_different_channels,
+				const int num_interfaces,
+				const u32 used_iftypes,
+				const u8 radar_detect,
+				const int iftype_num[NUM_NL80211_IFTYPES])
+{
+	int i, j, iftype;
+
+	for (i = 0; i < wiphy->n_iface_combinations; i++) {
+		const struct ieee80211_iface_combination *c;
+		struct ieee80211_iface_limit *limits;
+		u32 all_iftypes = 0;
+
+		c = &wiphy->iface_combinations[i];
+
+		if (num_interfaces > c->max_interfaces)
+			continue;
+		if (num_different_channels > c->num_different_channels)
+			continue;
+
+		limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
+				 GFP_KERNEL);
+		if (!limits)
+			return -ENOMEM;
+
+		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+			if (wiphy->software_iftypes & BIT(iftype))
+				continue;
+			for (j = 0; j < c->n_limits; j++) {
+				all_iftypes |= limits[j].types;
+				if (!(limits[j].types & BIT(iftype)))
+					continue;
+				if (limits[j].max < iftype_num[iftype])
+					goto cont;
+				limits[j].max -= iftype_num[iftype];
+			}
+		}
+
+		if (radar_detect && !(c->radar_detect_widths & radar_detect))
+			goto cont;
+
+		/* Finally check that all iftypes that we're currently
+		 * using are actually part of this combination. If they
+		 * aren't then we can't use this combination and have
+		 * to continue to the next.
+		 */
+		if ((all_iftypes & used_iftypes) != used_iftypes)
+			goto cont;
+
+		/* This combination covered all interface types and
+		 * supported the requested numbers, so we're good.
+		 */
+		kfree(limits);
+		return 0;
+ cont:
+		kfree(limits);
+	}
+
+	return -EBUSY;
+}
+EXPORT_SYMBOL(cfg80211_check_combinations);
+
 int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 				 struct wireless_dev *wdev,
 				 enum nl80211_iftype iftype,
@@ -1269,7 +1332,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 	enum cfg80211_chan_mode chmode;
 	int num_different_channels = 0;
 	int total = 1;
-	int i, j;
+	int i;
 
 	ASSERT_RTNL();
 
@@ -1360,59 +1423,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 	if (total == 1 && !radar_detect)
 		return 0;
 
-	for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
-		const struct ieee80211_iface_combination *c;
-		struct ieee80211_iface_limit *limits;
-		u32 all_iftypes = 0;
-
-		c = &rdev->wiphy.iface_combinations[i];
-
-		if (total > c->max_interfaces)
-			continue;
-		if (num_different_channels > c->num_different_channels)
-			continue;
-
-		limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
-				 GFP_KERNEL);
-		if (!limits)
-			return -ENOMEM;
-
-		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
-			if (rdev->wiphy.software_iftypes & BIT(iftype))
-				continue;
-			for (j = 0; j < c->n_limits; j++) {
-				all_iftypes |= limits[j].types;
-				if (!(limits[j].types & BIT(iftype)))
-					continue;
-				if (limits[j].max < num[iftype])
-					goto cont;
-				limits[j].max -= num[iftype];
-			}
-		}
-
-		if (radar_detect && !(c->radar_detect_widths & radar_detect))
-			goto cont;
-
-		/*
-		 * Finally check that all iftypes that we're currently
-		 * using are actually part of this combination. If they
-		 * aren't then we can't use this combination and have
-		 * to continue to the next.
-		 */
-		if ((all_iftypes & used_iftypes) != used_iftypes)
-			goto cont;
-
-		/*
-		 * This combination covered all interface types and
-		 * supported the requested numbers, so we're good.
-		 */
-		kfree(limits);
-		return 0;
- cont:
-		kfree(limits);
-	}
-
-	return -EBUSY;
+	return cfg80211_check_combinations(&rdev->wiphy, num_different_channels,
+					   total, used_iftypes,
+					   radar_detect, num);
 }
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
-- 
1.8.5.3


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

* [PATCH v4 2/4] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required()
  2014-02-24 20:54 [PATCH v4 0/4] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 1/4] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
@ 2014-02-24 20:54 ` Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano Coelho
  3 siblings, 0 replies; 9+ messages in thread
From: Luciano Coelho @ 2014-02-24 20:54 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

From: Luciano Coelho <luciano.coelho@intel.com>

Some interface types don't require DFS (such as STATION, P2P_CLIENT
etc).  In order to centralize these decisions, make
cfg80211_chandef_dfs_required() take the iftype into consideration.

Additionally, the function now returns a bitmap with the channel width
that requires DFS.  This is done to simplify some of the calls.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
In v4:

   * rebased on top of slightly modified applied patches
   * removed the double negations when assigning err to a boolean;
---
 include/net/cfg80211.h |  8 ++++--
 net/mac80211/ibss.c    | 31 ++++++++++----------
 net/mac80211/mesh.c    |  9 +++---
 net/wireless/chan.c    | 77 +++++++++++++++++++++++++++++++++++++-------------
 net/wireless/mesh.c    | 13 +++++----
 net/wireless/nl80211.c | 41 +++++++++++----------------
 6 files changed, 106 insertions(+), 73 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5f5a598..a874ec5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -439,10 +439,14 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
  * cfg80211_chandef_dfs_required - checks if radar detection is required
  * @wiphy: the wiphy to validate against
  * @chandef: the channel definition to check
- * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
+ * @iftype: the interface type as specified in &enum nl80211_iftype
+ * Returns:
+ *	the channel bandwidth bitmask if radar detection is required,
+ *	0 if it is not, < 0 on error
  */
 int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-				  const struct cfg80211_chan_def *chandef);
+				  const struct cfg80211_chan_def *chandef,
+				  enum nl80211_iftype);
 
 /**
  * ieee80211_chandef_rate_flags - returns rate flags for a channel
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index e458ca0..bca7d09 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	struct beacon_data *presp;
 	enum nl80211_bss_scan_width scan_width;
 	bool have_higher_than_11mbit;
-	bool radar_required = false;
+	bool radar_required;
 	int err;
 
 	sdata_assert_lock(sdata);
@@ -282,21 +282,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	}
 
 	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-					    &chandef);
+					    &chandef, NL80211_IFTYPE_ADHOC);
 	if (err < 0) {
 		sdata_info(sdata,
 			   "Failed to join IBSS, invalid chandef\n");
 		return;
 	}
-	if (err > 0) {
-		if (!ifibss->userspace_handles_dfs) {
-			sdata_info(sdata,
-				   "Failed to join IBSS, DFS channel without control program\n");
-			return;
-		}
-		radar_required = true;
+	if (err > 0 && !ifibss->userspace_handles_dfs) {
+		sdata_info(sdata,
+			   "Failed to join IBSS, DFS channel without control program\n");
+		return;
 	}
 
+	radar_required = err;
+
 	mutex_lock(&local->mtx);
 	if (ieee80211_vif_use_channel(sdata, &chandef,
 				      ifibss->fixed_channel ?
@@ -775,7 +774,8 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
 	 * unavailable.
 	 */
 	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-					    &ifibss->chandef);
+					    &ifibss->chandef,
+					    NL80211_IFTYPE_ADHOC);
 	if (err > 0)
 		cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
 				     GFP_ATOMIC);
@@ -873,16 +873,15 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 
 	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-					    &params.chandef);
+					    &params.chandef,
+					    NL80211_IFTYPE_ADHOC);
 	if (err < 0)
 		goto disconnect;
-	if (err) {
+	if (err > 0 && !ifibss->userspace_handles_dfs)
 		/* IBSS-DFS only allowed with a control program */
-		if (!ifibss->userspace_handles_dfs)
-			goto disconnect;
+		goto disconnect;
 
-		params.radar_required = true;
-	}
+	params.radar_required = err;
 
 	if (cfg80211_chandef_identical(&params.chandef,
 				       &sdata->vif.bss_conf.chandef)) {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index f70e9cd..ea0b628 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -903,14 +903,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
 	}
 
 	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
-					    &params.chandef);
+					    &params.chandef,
+					    NL80211_IFTYPE_MESH_POINT);
 	if (err < 0)
 		return false;
-	if (err) {
-		params.radar_required = true;
+	if (err > 0)
 		/* TODO: DFS not (yet) supported */
 		return false;
-	}
+
+	params.radar_required = err;
 
 	if (cfg80211_chandef_identical(&params.chandef,
 				       &sdata->vif.bss_conf.chandef)) {
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 5946450..f4b59a0 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -326,28 +326,58 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
 
 
 int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-				  const struct cfg80211_chan_def *chandef)
+				  const struct cfg80211_chan_def *chandef,
+				  enum nl80211_iftype iftype)
 {
 	int width;
-	int r;
+	int ret;
 
 	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
 		return -EINVAL;
 
-	width = cfg80211_chandef_get_width(chandef);
-	if (width < 0)
-		return -EINVAL;
+	switch (iftype) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+	case NL80211_IFTYPE_MESH_POINT:
+		width = cfg80211_chandef_get_width(chandef);
+		if (width < 0)
+			return -EINVAL;
 
-	r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
-					    width);
-	if (r)
-		return r;
+		ret = cfg80211_get_chans_dfs_required(wiphy,
+						      chandef->center_freq1,
+						      width);
+		if (ret < 0)
+			return ret;
+		else if (ret > 0)
+			return BIT(chandef->width);
 
-	if (!chandef->center_freq2)
-		return 0;
+		if (!chandef->center_freq2)
+			return 0;
+
+		ret = cfg80211_get_chans_dfs_required(wiphy,
+						      chandef->center_freq2,
+						      width);
+		if (ret < 0)
+			return ret;
+		else if (ret > 0)
+			return BIT(chandef->width);
 
-	return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
-					       width);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_P2P_DEVICE:
+		break;
+	case NUM_NL80211_IFTYPES:
+	default:
+		WARN_ON(1);
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
@@ -615,7 +645,8 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
 
 	trace_cfg80211_reg_can_beacon(wiphy, chandef);
 
-	if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
+	if (cfg80211_chandef_dfs_required(wiphy, chandef,
+					  NL80211_IFTYPE_UNSPECIFIED) > 0 &&
 	    cfg80211_chandef_dfs_available(wiphy, chandef)) {
 		/* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
 		prohibited_flags = IEEE80211_CHAN_DISABLED;
@@ -645,6 +676,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
 		        enum cfg80211_chan_mode *chanmode,
 		        u8 *radar_detect)
 {
+	int ret;
+
 	*chan = NULL;
 	*chanmode = CHAN_MODE_UNDEFINED;
 
@@ -687,9 +720,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
 			*chan = wdev->chandef.chan;
 			*chanmode = CHAN_MODE_SHARED;
 
-			if (cfg80211_chandef_dfs_required(wdev->wiphy,
-							  &wdev->chandef))
-				*radar_detect |= BIT(wdev->chandef.width);
+			ret = cfg80211_chandef_dfs_required(wdev->wiphy,
+							    &wdev->chandef,
+							    wdev->iftype);
+			WARN_ON(ret < 0);
+			*radar_detect |= ret;
 		}
 		return;
 	case NL80211_IFTYPE_MESH_POINT:
@@ -697,9 +732,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
 			*chan = wdev->chandef.chan;
 			*chanmode = CHAN_MODE_SHARED;
 
-			if (cfg80211_chandef_dfs_required(wdev->wiphy,
-							  &wdev->chandef))
-				*radar_detect |= BIT(wdev->chandef.width);
+			ret = cfg80211_chandef_dfs_required(wdev->wiphy,
+							    &wdev->chandef,
+							    wdev->iftype);
+			WARN_ON(ret < 0);
+			*radar_detect |= ret;
 		}
 		return;
 	case NL80211_IFTYPE_MONITOR:
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 5af5cc6..c9458f2 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -99,7 +99,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 			 const struct mesh_config *conf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	u8 radar_detect_width = 0;
+	u8 radar_detect_width;
 	int err;
 
 	BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
@@ -178,11 +178,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
 		return -EINVAL;
 
-	err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef);
-	if (err < 0)
-		return err;
-	if (err)
-		radar_detect_width = BIT(setup->chandef.width);
+	radar_detect_width =
+		cfg80211_chandef_dfs_required(wdev->wiphy,
+					      &setup->chandef,
+					      NL80211_IFTYPE_MESH_POINT);
+	if (radar_detect_width < 0)
+		return radar_detect_width;
 
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					   setup->chandef.chan,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2c38b28..53c627c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3257,13 +3257,13 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
 		return -EINVAL;
 
-	err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
-	if (err < 0)
-		return err;
-	if (err) {
-		radar_detect_width = BIT(params.chandef.width);
-		params.radar_required = true;
-	}
+	radar_detect_width = cfg80211_chandef_dfs_required(wdev->wiphy,
+							   &params.chandef,
+							   NL80211_IFTYPE_AP);
+	if (radar_detect_width < 0)
+		return radar_detect_width;
+
+	params.radar_required = err;
 
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					   params.chandef.chan,
@@ -5784,7 +5784,8 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
 	if (wdev->cac_started)
 		return -EBUSY;
 
-	err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef);
+	err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
+					    NL80211_IFTYPE_UNSPECIFIED);
 	if (err < 0)
 		return err;
 
@@ -5913,23 +5914,13 @@ skip_beacons:
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
 		return -EINVAL;
 
-	switch (dev->ieee80211_ptr->iftype) {
-	case NL80211_IFTYPE_AP:
-	case NL80211_IFTYPE_P2P_GO:
-	case NL80211_IFTYPE_ADHOC:
-	case NL80211_IFTYPE_MESH_POINT:
-		err = cfg80211_chandef_dfs_required(wdev->wiphy,
-						    &params.chandef);
-		if (err < 0)
-			return err;
-		if (err) {
-			radar_detect_width = BIT(params.chandef.width);
-			params.radar_required = true;
-		}
-		break;
-	default:
-		break;
-	}
+	radar_detect_width = cfg80211_chandef_dfs_required(wdev->wiphy,
+							   &params.chandef,
+							   wdev->iftype);
+	if (radar_detect_width < 0)
+		return radar_detect_width;
+
+	params.radar_required = radar_detect_width;
 
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					   params.chandef.chan,
-- 
1.8.5.3


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

* [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211
  2014-02-24 20:54 [PATCH v4 0/4] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 1/4] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
  2014-02-24 20:54 ` [PATCH v4 2/4] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required() Luciano Coelho
@ 2014-02-24 20:54 ` Luciano Coelho
  2014-02-25  9:22   ` Michal Kazior
  2014-02-24 20:54 ` [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano Coelho
  3 siblings, 1 reply; 9+ messages in thread
From: Luciano Coelho @ 2014-02-24 20:54 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

From: Luciano Coelho <luciano.coelho@intel.com>

Move the counting part of the interface combination check from
cfg80211 to mac80211.

This is needed to simplify locking when the driver has to perform a
combination check by itself (eg. with channel-switch).

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
In v3:

   * pass the mode argument instead of IEEE80211_CHANCTX_SHARED to
     ieee80211_check_combinations() in ieee80211_vif_use_channel();

In v4:

   * rebased on top of slightly modified applied patches;
   * removed WARN_ON in ieee80211_start_radar_detection();
   * removed unnecessary TODOs in ieee80211_mgd_auth() and
     ieee80211_mgd_assoc();
   * use local and sdata instead of wiphy and wdev in
     ieee80211_check_combinations();
   * check if the vif has a chanctx instead of checking the type and
     if it is running in the interfaces iterator in
     ieee80211_check_combinations();
   * combined the "continue" cases in the iteration into a single if;
   * removed cfg80211_can_use_chan() since libertas mesh, the only
     remaining caller, doesn't really need it.
---
 include/net/cfg80211.h     |  4 +--
 net/mac80211/cfg.c         |  2 --
 net/mac80211/chan.c        | 17 +++++++++++
 net/mac80211/ieee80211_i.h |  5 +++
 net/mac80211/util.c        | 76 ++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h        | 13 ++------
 net/wireless/ibss.c        |  4 +++
 net/wireless/mesh.c        | 26 ----------------
 net/wireless/mlme.c        | 14 +--------
 net/wireless/nl80211.c     | 26 +++-------------
 net/wireless/util.c        |  5 +++
 11 files changed, 117 insertions(+), 75 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a874ec5..ee2f4c4 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -656,7 +656,6 @@ struct cfg80211_acl_data {
  * @p2p_opp_ps: P2P opportunistic PS
  * @acl: ACL configuration used by the drivers which has support for
  *	MAC address based access control
- * @radar_required: set if radar detection is required
  */
 struct cfg80211_ap_settings {
 	struct cfg80211_chan_def chandef;
@@ -674,7 +673,6 @@ struct cfg80211_ap_settings {
 	u8 p2p_ctwindow;
 	bool p2p_opp_ps;
 	const struct cfg80211_acl_data *acl;
-	bool radar_required;
 };
 
 /**
@@ -687,6 +685,8 @@ struct cfg80211_ap_settings {
  * @counter_offset_beacon: offset for the counter within the beacon (tail)
  * @counter_offset_presp: offset for the counter within the probe response
  * @beacon_after: beacon data to be used on the new channel
+ * TODO: we can probably get rid of radar_required, since mac80211
+ * should check for it now
  * @radar_required: whether radar detection is required on the new channel
  * @block_tx: whether transmissions should be blocked while changing
  * @count: number of beacons until switch
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1acb291..aafaa34 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -972,7 +972,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
 	sdata->needed_rx_chains = sdata->local->rx_chains;
 
 	mutex_lock(&local->mtx);
-	sdata->radar_required = params->radar_required;
 	err = ieee80211_vif_use_channel(sdata, &params->chandef,
 					IEEE80211_CHANCTX_SHARED);
 	mutex_unlock(&local->mtx);
@@ -2930,7 +2929,6 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
 	/* whatever, but channel contexts should not complain about that one */
 	sdata->smps_mode = IEEE80211_SMPS_OFF;
 	sdata->needed_rx_chains = local->rx_chains;
-	sdata->radar_required = true;
 
 	err = ieee80211_vif_use_channel(sdata, chandef,
 					IEEE80211_CHANCTX_SHARED);
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 42c6592..f6a8d68 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -513,6 +513,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx *ctx;
+	u8 radar_detect_width;
 	int ret;
 
 	lockdep_assert_held(&local->mtx);
@@ -520,6 +521,22 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 
 	mutex_lock(&local->chanctx_mtx);
+
+	radar_detect_width = cfg80211_chandef_dfs_required(local->hw.wiphy,
+							   chandef,
+							   sdata->vif.type);
+	if (radar_detect_width < 0) {
+		ret = radar_detect_width;
+		goto out;
+	}
+
+	sdata->radar_required = radar_detect_width;
+
+	ret = ieee80211_check_combinations(local, sdata, chandef, mode,
+					   radar_detect_width);
+	if (ret < 0)
+		goto out;
+
 	__ieee80211_vif_release_channel(sdata);
 
 	ctx = ieee80211_find_chanctx(local, chandef, mode);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8603dfb..3d8c2d8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1810,6 +1810,11 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
 			  enum nl80211_iftype iftype);
 void ieee80211_recalc_dtim(struct ieee80211_local *local,
 			   struct ieee80211_sub_if_data *sdata);
+int ieee80211_check_combinations(struct ieee80211_local *local,
+				 struct ieee80211_sub_if_data *sdata,
+				 const struct cfg80211_chan_def *chandef,
+				 enum ieee80211_chanctx_mode chanmode,
+				 u8 radar_detect);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d842af5..0ea096c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2801,3 +2801,79 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 
 	ps->dtim_count = dtim_count;
 }
+
+int ieee80211_check_combinations(struct ieee80211_local *local,
+				 struct ieee80211_sub_if_data *sdata,
+				 const struct cfg80211_chan_def *chandef,
+				 enum ieee80211_chanctx_mode chanmode,
+				 u8 radar_detect)
+{
+	struct ieee80211_sub_if_data *sdata_iter;
+	enum nl80211_iftype iftype = sdata->wdev.iftype;
+	u32 used_iftypes = 0;
+	int num[NUM_NL80211_IFTYPES];
+	struct ieee80211_chanctx *ctx;
+	int num_different_channels = 1;
+	int total = 1;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	if (WARN_ON(hweight32(radar_detect) > 1))
+		return -EINVAL;
+
+	if (WARN_ON(chanmode == IEEE80211_CHANCTX_SHARED && !chandef->chan))
+		return -EINVAL;
+
+	if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
+		return -EINVAL;
+
+	/* Always allow software iftypes */
+	if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
+		if (radar_detect)
+			return -EINVAL;
+		return 0;
+	}
+
+	memset(num, 0, sizeof(num));
+
+	if (iftype != NL80211_IFTYPE_UNSPECIFIED) {
+		used_iftypes = BIT(iftype);
+		num[iftype] = 1;
+	}
+
+	list_for_each_entry(ctx, &local->chanctx_list, list) {
+		if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
+			num_different_channels++;
+			continue;
+		}
+		if ((chanmode == IEEE80211_CHANCTX_SHARED) &&
+		    cfg80211_chandef_compatible(chandef,
+						&ctx->conf.def))
+			continue;
+		num_different_channels++;
+		if (ctx->conf.radar_enabled)
+			radar_detect |= BIT(ctx->conf.def.width);
+	}
+
+	list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
+		struct wireless_dev *wdev_iter;
+
+		wdev_iter = &sdata_iter->wdev;
+
+		if (sdata_iter == sdata ||
+		    rcu_access_pointer(sdata->vif.chanctx_conf) == NULL ||
+		    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
+			continue;
+
+		num[wdev_iter->iftype]++;
+		total++;
+		used_iftypes |= BIT(wdev_iter->iftype);
+	}
+
+	if (total == 1 && !radar_detect)
+		return 0;
+
+	return cfg80211_check_combinations(local->hw.wiphy,
+					   num_different_channels, total,
+					   used_iftypes, radar_detect, num);
+}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 4068300..f1a7363 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -408,6 +408,9 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 			      struct wireless_dev *wdev,
 			      enum nl80211_iftype iftype)
 {
+	/* TODO: For this function, we'll probably need to keep some
+	 * kind of interface combination check in cfg80211...
+	 */
 	return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
 					    CHAN_MODE_UNDEFINED, 0);
 }
@@ -422,16 +425,6 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
 	return cfg80211_can_change_interface(rdev, NULL, iftype);
 }
 
-static inline int
-cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
-		      struct wireless_dev *wdev,
-		      struct ieee80211_channel *chan,
-		      enum cfg80211_chan_mode chanmode)
-{
-	return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					    chan, chanmode, 0);
-}
-
 static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
 {
 	unsigned long end = jiffies;
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 349db9d..d81cb68 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -135,6 +135,10 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		radar_detect_width = BIT(params->chandef.width);
 	}
 
+	/* TODO: We need to check the combinations at this point, we
+	 * probably must move this call down to join_ibss() in
+	 * mac80211.
+	 */
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					   check_chan,
 					   (params->channel_fixed &&
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index c9458f2..b8a7a35 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -99,7 +99,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 			 const struct mesh_config *conf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	u8 radar_detect_width;
 	int err;
 
 	BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
@@ -178,20 +177,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
 		return -EINVAL;
 
-	radar_detect_width =
-		cfg80211_chandef_dfs_required(wdev->wiphy,
-					      &setup->chandef,
-					      NL80211_IFTYPE_MESH_POINT);
-	if (radar_detect_width < 0)
-		return radar_detect_width;
-
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   setup->chandef.chan,
-					   CHAN_MODE_SHARED,
-					   radar_detect_width);
-	if (err)
-		return err;
-
 	err = rdev_join_mesh(rdev, dev, conf, setup);
 	if (!err) {
 		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -237,17 +222,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
 		if (!netif_running(wdev->netdev))
 			return -ENETDOWN;
 
-		/* cfg80211_can_use_chan() calls
-		 * cfg80211_can_use_iftype_chan() with no radar
-		 * detection, so if we're trying to use a radar
-		 * channel here, something is wrong.
-		 */
-		WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR);
-		err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
-					    CHAN_MODE_SHARED);
-		if (err)
-			return err;
-
 		err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
 						     chandef->chan);
 		if (!err)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index d47c9d1..7420196 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -233,14 +233,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 	if (!req.bss)
 		return -ENOENT;
 
-	err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
-				    CHAN_MODE_SHARED);
-	if (err)
-		goto out;
-
 	err = rdev_auth(rdev, dev, &req);
 
-out:
 	cfg80211_put_bss(&rdev->wiphy, req.bss);
 	return err;
 }
@@ -306,16 +300,10 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 	if (!req->bss)
 		return -ENOENT;
 
-	err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
-	if (err)
-		goto out;
-
 	err = rdev_assoc(rdev, dev, req);
 	if (!err)
 		cfg80211_hold_bss(bss_from_pub(req->bss));
-
-out:
-	if (err)
+	else
 		cfg80211_put_bss(&rdev->wiphy, req->bss);
 
 	return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 53c627c..401ba56 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3138,7 +3138,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_ap_settings params;
 	int err;
-	u8 radar_detect_width = 0;
 
 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
@@ -3257,21 +3256,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
 		return -EINVAL;
 
-	radar_detect_width = cfg80211_chandef_dfs_required(wdev->wiphy,
-							   &params.chandef,
-							   NL80211_IFTYPE_AP);
-	if (radar_detect_width < 0)
-		return radar_detect_width;
-
-	params.radar_required = err;
-
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   params.chandef.chan,
-					   CHAN_MODE_SHARED,
-					   radar_detect_width);
-	if (err)
-		return err;
-
 	if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
 		params.acl = parse_acl_data(&rdev->wiphy, info);
 		if (IS_ERR(params.acl))
@@ -5798,12 +5782,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
 	if (!rdev->ops->start_radar_detection)
 		return -EOPNOTSUPP;
 
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   chandef.chan, CHAN_MODE_SHARED,
-					   BIT(chandef.width));
-	if (err)
-		return err;
-
 	err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
 	if (!err) {
 		wdev->chandef = chandef;
@@ -5922,6 +5900,10 @@ skip_beacons:
 
 	params.radar_required = radar_detect_width;
 
+	/* TODO: I left this here for now.  With channel switch, the
+	 * verification is a bit more complicated, because we only do
+	 * it later when the channel switch really happens.
+	 */
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					   params.chandef.chan,
 					   CHAN_MODE_SHARED,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index d562dd6..be6ebf7 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1354,6 +1354,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 
 	num[iftype] = 1;
 
+	/* TODO: We'll probably not need this anymore, since this
+	 * should only be called with CHAN_MODE_UNDEFINED. There are
+	 * still a couple of pending calls where other chanmodes are
+	 * used, but we should get rid of them.
+	 */
 	switch (chanmode) {
 	case CHAN_MODE_UNDEFINED:
 		break;
-- 
1.8.5.3


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

* [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss
  2014-02-24 20:54 [PATCH v4 0/4] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
                   ` (2 preceding siblings ...)
  2014-02-24 20:54 ` [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
@ 2014-02-24 20:54 ` Luciano Coelho
  2014-02-25  7:49   ` Michal Kazior
  3 siblings, 1 reply; 9+ messages in thread
From: Luciano Coelho @ 2014-02-24 20:54 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

From: Luciano Coelho <luciano.coelho@intel.com>

Now that mac80211 can check the interface combinations itself, move
the combinations check from cfg80211 to mac80211 when joining an IBSS.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
In v2:

   * lock the chanctx mutex in ieee80211_ibss_join() before calling
     ieee80211_check_combinations(). (Thanks Michal);

   * pass the mode argument instead of IEEE80211_CHANCTX_SHARED to
     ieee80211_check_combinations() in ieee80211_vif_use_channel();

In v3:

   * moved the second change from v2 (pass the mode argument...) to
     the previous patch, where it should be;

In v4:

   * rebased on top of slightly modified applied patches
---
 net/mac80211/ibss.c | 30 +++++++++++++++++++++++++++---
 net/wireless/ibss.c | 28 ----------------------------
 2 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index bca7d09..745b445 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1643,7 +1643,31 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 	u32 changed = 0;
 	u32 rate_flags;
 	struct ieee80211_supported_band *sband;
+	enum ieee80211_chanctx_mode chanmode;
+	struct ieee80211_local *local = sdata->local;
+	int radar_detect_width;
 	int i;
+	int ret;
+
+	radar_detect_width = cfg80211_chandef_dfs_required(local->hw.wiphy,
+							   &params->chandef,
+							   sdata->vif.type);
+	if (radar_detect_width < 0)
+		return radar_detect_width;
+
+	if (radar_detect_width > 0 && !params->userspace_handles_dfs)
+		return -EINVAL;
+
+	chanmode = (params->channel_fixed && !radar_detect_width) ?
+		IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
+
+	mutex_lock(&local->chanctx_mtx);
+	ret = ieee80211_check_combinations(local->hw.wiphy, &sdata->wdev,
+					   &params->chandef, chanmode,
+					   radar_detect_width);
+	mutex_unlock(&local->chanctx_mtx);
+	if (ret < 0)
+		return ret;
 
 	if (params->bssid) {
 		memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
@@ -1658,7 +1682,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 
 	/* fix basic_rates if channel does not support these rates */
 	rate_flags = ieee80211_chandef_rate_flags(&params->chandef);
-	sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band];
+	sband = local->hw.wiphy->bands[params->chandef.chan->band];
 	for (i = 0; i < sband->n_bitrates; i++) {
 		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
 			sdata->u.ibss.basic_rates &= ~BIT(i);
@@ -1707,9 +1731,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 	ieee80211_bss_info_change_notify(sdata, changed);
 
 	sdata->smps_mode = IEEE80211_SMPS_OFF;
-	sdata->needed_rx_chains = sdata->local->rx_chains;
+	sdata->needed_rx_chains = local->rx_chains;
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	ieee80211_queue_work(&local->hw, &sdata->work);
 
 	return 0;
 }
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index d81cb68..8282de8 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -88,8 +88,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	struct ieee80211_channel *check_chan;
-	u8 radar_detect_width = 0;
 	int err;
 
 	ASSERT_WDEV_LOCK(wdev);
@@ -126,32 +124,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 #ifdef CONFIG_CFG80211_WEXT
 	wdev->wext.ibss.chandef = params->chandef;
 #endif
-	check_chan = params->chandef.chan;
-	if (params->userspace_handles_dfs) {
-		/* Check for radar even if the current channel is not
-		 * a radar channel - it might decide to change to DFS
-		 * channel later.
-		 */
-		radar_detect_width = BIT(params->chandef.width);
-	}
-
-	/* TODO: We need to check the combinations at this point, we
-	 * probably must move this call down to join_ibss() in
-	 * mac80211.
-	 */
-	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
-					   check_chan,
-					   (params->channel_fixed &&
-					    !radar_detect_width)
-					   ? CHAN_MODE_SHARED
-					   : CHAN_MODE_EXCLUSIVE,
-					   radar_detect_width);
-
-	if (err) {
-		wdev->connect_keys = NULL;
-		return err;
-	}
-
 	err = rdev_join_ibss(rdev, dev, params);
 	if (err) {
 		wdev->connect_keys = NULL;
-- 
1.8.5.3


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

* Re: [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss
  2014-02-24 20:54 ` [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano Coelho
@ 2014-02-25  7:49   ` Michal Kazior
  2014-02-25 11:16     ` Luca Coelho
  0 siblings, 1 reply; 9+ messages in thread
From: Michal Kazior @ 2014-02-25  7:49 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless, Johannes Berg, sw, Bing Zhao, arend

On 24 February 2014 21:54, Luciano Coelho <luca@coelho.fi> wrote:
> From: Luciano Coelho <luciano.coelho@intel.com>
>
> Now that mac80211 can check the interface combinations itself, move
> the combinations check from cfg80211 to mac80211 when joining an IBSS.
>
> Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
> ---
> In v2:
>
>    * lock the chanctx mutex in ieee80211_ibss_join() before calling
>      ieee80211_check_combinations(). (Thanks Michal);
>
>    * pass the mode argument instead of IEEE80211_CHANCTX_SHARED to
>      ieee80211_check_combinations() in ieee80211_vif_use_channel();
>
> In v3:
>
>    * moved the second change from v2 (pass the mode argument...) to
>      the previous patch, where it should be;
>
> In v4:
>
>    * rebased on top of slightly modified applied patches
> ---
>  net/mac80211/ibss.c | 30 +++++++++++++++++++++++++++---
>  net/wireless/ibss.c | 28 ----------------------------
>  2 files changed, 27 insertions(+), 31 deletions(-)
>
> diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
> index bca7d09..745b445 100644
> --- a/net/mac80211/ibss.c
> +++ b/net/mac80211/ibss.c
> @@ -1643,7 +1643,31 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
>         u32 changed = 0;
>         u32 rate_flags;
>         struct ieee80211_supported_band *sband;
> +       enum ieee80211_chanctx_mode chanmode;
> +       struct ieee80211_local *local = sdata->local;
> +       int radar_detect_width;
>         int i;
> +       int ret;
> +
> +       radar_detect_width = cfg80211_chandef_dfs_required(local->hw.wiphy,
> +                                                          &params->chandef,
> +                                                          sdata->vif.type);
> +       if (radar_detect_width < 0)
> +               return radar_detect_width;
> +
> +       if (radar_detect_width > 0 && !params->userspace_handles_dfs)
> +               return -EINVAL;
> +
> +       chanmode = (params->channel_fixed && !radar_detect_width) ?
> +               IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
> +
> +       mutex_lock(&local->chanctx_mtx);
> +       ret = ieee80211_check_combinations(local->hw.wiphy, &sdata->wdev,
> +                                          &params->chandef, chanmode,
> +                                          radar_detect_width);

I think you forgot to update this call - you should be passing `local`
and `sdata` here, no?


Michał

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

* Re: [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211
  2014-02-24 20:54 ` [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
@ 2014-02-25  9:22   ` Michal Kazior
  2014-02-25 11:51     ` Luca Coelho
  0 siblings, 1 reply; 9+ messages in thread
From: Michal Kazior @ 2014-02-25  9:22 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless, Johannes Berg, sw, Bing Zhao, arend

On 24 February 2014 21:54, Luciano Coelho <luca@coelho.fi> wrote:

[...]

> --- a/net/mac80211/util.c
> +++ b/net/mac80211/util.c
> @@ -2801,3 +2801,79 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
>
>         ps->dtim_count = dtim_count;
>  }
> +
> +int ieee80211_check_combinations(struct ieee80211_local *local,
> +                                struct ieee80211_sub_if_data *sdata,
> +                                const struct cfg80211_chan_def *chandef,
> +                                enum ieee80211_chanctx_mode chanmode,
> +                                u8 radar_detect)
> +{
> +       struct ieee80211_sub_if_data *sdata_iter;
> +       enum nl80211_iftype iftype = sdata->wdev.iftype;
> +       u32 used_iftypes = 0;
> +       int num[NUM_NL80211_IFTYPES];
> +       struct ieee80211_chanctx *ctx;
> +       int num_different_channels = 1;
> +       int total = 1;
> +
> +       lockdep_assert_held(&local->chanctx_mtx);
> +
> +       if (WARN_ON(hweight32(radar_detect) > 1))
> +               return -EINVAL;
> +
> +       if (WARN_ON(chanmode == IEEE80211_CHANCTX_SHARED && !chandef->chan))
> +               return -EINVAL;
> +
> +       if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
> +               return -EINVAL;
> +
> +       /* Always allow software iftypes */
> +       if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
> +               if (radar_detect)
> +                       return -EINVAL;
> +               return 0;
> +       }
> +
> +       memset(num, 0, sizeof(num));
> +
> +       if (iftype != NL80211_IFTYPE_UNSPECIFIED) {
> +               used_iftypes = BIT(iftype);
> +               num[iftype] = 1;
> +       }
> +

> +       list_for_each_entry(ctx, &local->chanctx_list, list) {
> +               if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
> +                       num_different_channels++;
> +                       continue;
> +               }
> +               if ((chanmode == IEEE80211_CHANCTX_SHARED) &&
> +                   cfg80211_chandef_compatible(chandef,
> +                                               &ctx->conf.def))
> +                       continue;
> +               num_different_channels++;
> +               if (ctx->conf.radar_enabled)
> +                       radar_detect |= BIT(ctx->conf.def.width);
> +       }

Hmm.. now that I think about it -- is it correct to skip updating
radar_detect when a chanctx is exclusive? Shouldn't the radar_enabled
check be done at the beginning of each iteration?


Michał

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

* Re: [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss
  2014-02-25  7:49   ` Michal Kazior
@ 2014-02-25 11:16     ` Luca Coelho
  0 siblings, 0 replies; 9+ messages in thread
From: Luca Coelho @ 2014-02-25 11:16 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg, sw, Bing Zhao, arend

On Tue, 2014-02-25 at 08:49 +0100, Michal Kazior wrote:
> On 24 February 2014 21:54, Luciano Coelho <luca@coelho.fi> wrote:
> > diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
> > index bca7d09..745b445 100644
> > --- a/net/mac80211/ibss.c
> > +++ b/net/mac80211/ibss.c
> > @@ -1643,7 +1643,31 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
> >         u32 changed = 0;
> >         u32 rate_flags;
> >         struct ieee80211_supported_band *sband;
> > +       enum ieee80211_chanctx_mode chanmode;
> > +       struct ieee80211_local *local = sdata->local;
> > +       int radar_detect_width;
> >         int i;
> > +       int ret;
> > +
> > +       radar_detect_width = cfg80211_chandef_dfs_required(local->hw.wiphy,
> > +                                                          &params->chandef,
> > +                                                          sdata->vif.type);
> > +       if (radar_detect_width < 0)
> > +               return radar_detect_width;
> > +
> > +       if (radar_detect_width > 0 && !params->userspace_handles_dfs)
> > +               return -EINVAL;
> > +
> > +       chanmode = (params->channel_fixed && !radar_detect_width) ?
> > +               IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
> > +
> > +       mutex_lock(&local->chanctx_mtx);
> > +       ret = ieee80211_check_combinations(local->hw.wiphy, &sdata->wdev,
> > +                                          &params->chandef, chanmode,
> > +                                          radar_detect_width);
> 
> I think you forgot to update this call - you should be passing `local`
> and `sdata` here, no?

Definitely.  Forgot to commit. :(

I'll commit and send v5.

--
Luca.


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

* Re: [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211
  2014-02-25  9:22   ` Michal Kazior
@ 2014-02-25 11:51     ` Luca Coelho
  0 siblings, 0 replies; 9+ messages in thread
From: Luca Coelho @ 2014-02-25 11:51 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg, sw, Bing Zhao, arend

On Tue, 2014-02-25 at 10:22 +0100, Michal Kazior wrote:
> On 24 February 2014 21:54, Luciano Coelho <luca@coelho.fi> wrote:
> 
> [...]
> 
> > --- a/net/mac80211/util.c
> > +++ b/net/mac80211/util.c
> > @@ -2801,3 +2801,79 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
> >
> >         ps->dtim_count = dtim_count;
> >  }
> > +
> > +int ieee80211_check_combinations(struct ieee80211_local *local,
> > +                                struct ieee80211_sub_if_data *sdata,
> > +                                const struct cfg80211_chan_def *chandef,
> > +                                enum ieee80211_chanctx_mode chanmode,
> > +                                u8 radar_detect)
> > +{
> > +       struct ieee80211_sub_if_data *sdata_iter;
> > +       enum nl80211_iftype iftype = sdata->wdev.iftype;
> > +       u32 used_iftypes = 0;
> > +       int num[NUM_NL80211_IFTYPES];
> > +       struct ieee80211_chanctx *ctx;
> > +       int num_different_channels = 1;
> > +       int total = 1;
> > +
> > +       lockdep_assert_held(&local->chanctx_mtx);
> > +
> > +       if (WARN_ON(hweight32(radar_detect) > 1))
> > +               return -EINVAL;
> > +
> > +       if (WARN_ON(chanmode == IEEE80211_CHANCTX_SHARED && !chandef->chan))
> > +               return -EINVAL;
> > +
> > +       if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
> > +               return -EINVAL;
> > +
> > +       /* Always allow software iftypes */
> > +       if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
> > +               if (radar_detect)
> > +                       return -EINVAL;
> > +               return 0;
> > +       }
> > +
> > +       memset(num, 0, sizeof(num));
> > +
> > +       if (iftype != NL80211_IFTYPE_UNSPECIFIED) {
> > +               used_iftypes = BIT(iftype);
> > +               num[iftype] = 1;
> > +       }
> > +
> 
> > +       list_for_each_entry(ctx, &local->chanctx_list, list) {
> > +               if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
> > +                       num_different_channels++;
> > +                       continue;
> > +               }
> > +               if ((chanmode == IEEE80211_CHANCTX_SHARED) &&
> > +                   cfg80211_chandef_compatible(chandef,
> > +                                               &ctx->conf.def))
> > +                       continue;
> > +               num_different_channels++;
> > +               if (ctx->conf.radar_enabled)
> > +                       radar_detect |= BIT(ctx->conf.def.width);
> > +       }
> 
> Hmm.. now that I think about it -- is it correct to skip updating
> radar_detect when a chanctx is exclusive? Shouldn't the radar_enabled
> check be done at the beginning of each iteration?

Yes, you're right.  It makes sense also for shared, because we need to
take into consideration the existing context's width, because the
channels may be compatible but with different widths.

I'll fix and send v5.

--
Luca.


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

end of thread, other threads:[~2014-02-25 11:51 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-24 20:54 [PATCH v4 0/4] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
2014-02-24 20:54 ` [PATCH v4 1/4] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
2014-02-24 20:54 ` [PATCH v4 2/4] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required() Luciano Coelho
2014-02-24 20:54 ` [PATCH v4 3/4] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
2014-02-25  9:22   ` Michal Kazior
2014-02-25 11:51     ` Luca Coelho
2014-02-24 20:54 ` [PATCH v4 4/4] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano Coelho
2014-02-25  7:49   ` Michal Kazior
2014-02-25 11:16     ` Luca Coelho

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.