All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211
@ 2014-02-20  5:10 Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 1/7] nl80211: make sure we check for DFS with mesh channel switch Luciano Coelho
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

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

Hi,

This is v2 of my patchset.  Just a couple of comments by Michal taken
into consideration.  Thanks for Your review, Michal!

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 (eg. 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.  There are
still some trickier cases such as a libertas backward-compatibility
workaround and the channel switch stuff.  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.

In this series, I have included the two previous patches I sent,
because they're somewhat related to the rest of the series.  For
"cfg80211: remove radar requirements check from
cfg80211_can_use_iftype_chan()" I have removed the excessive comments,
since they become mostly outdated with the rest of the series anyway.

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 (7):
  nl80211: make sure we check for DFS with mesh channel switch
  cfg80211: remove radar requirements check from
    cfg80211_can_use_iftype_chan()
  cfg80211: refactor cfg80211_can_use_iftype_chan()
  mac80211: ibss: handle cfg80211_chandef_dfs_required() error codes
  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               |   7 +-
 net/mac80211/chan.c              |  17 +++++
 net/mac80211/ibss.c              |  66 +++++++++++-----
 net/mac80211/ieee80211_i.h       |   5 ++
 net/mac80211/mesh.c              |   9 ++-
 net/mac80211/mlme.c              |  14 ++++
 net/mac80211/util.c              |  88 ++++++++++++++++++++++
 net/wireless/chan.c              |  77 ++++++++++++++-----
 net/wireless/core.h              |   7 ++
 net/wireless/ibss.c              |  25 -------
 net/wireless/mesh.c              |  24 +++---
 net/wireless/mlme.c              |  14 +---
 net/wireless/nl80211.c           |  48 ++++--------
 net/wireless/util.c              | 157 ++++++++++++++++++---------------------
 16 files changed, 380 insertions(+), 220 deletions(-)

-- 
1.8.5.3


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

* [PATCH v2 1/7] nl80211: make sure we check for DFS with mesh channel switch
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 2/7] cfg80211: remove radar requirements check from cfg80211_can_use_iftype_chan() Luciano Coelho
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

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

Since mesh support for DFS channels was added, we also need to check
for DFS channels when performing a channel switch with
NL80211_IFTYPE_MESHPOINT.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 net/wireless/nl80211.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1797864..b78d734 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5912,7 +5912,8 @@ skip_beacons:
 
 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
 	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO ||
-	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) {
+	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC ||
+	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_MESH_POINT) {
 		err = cfg80211_chandef_dfs_required(wdev->wiphy,
 						    &params.chandef);
 		if (err < 0) {
-- 
1.8.5.3


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

* [PATCH v2 2/7] cfg80211: remove radar requirements check from cfg80211_can_use_iftype_chan()
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 1/7] nl80211: make sure we check for DFS with mesh channel switch Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 3/7] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

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

We don't have to double check whether the parameters passed to
cfg80211_can_use_iftype_chan() are correct.  We should just make sure
they *are* when we call this function.

Remove the radar_detect argument check in
cfg80211_can_use_iftype_chan() to simplify the code.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 net/wireless/ibss.c | 10 ++++------
 net/wireless/mesh.c |  6 ++++++
 net/wireless/util.c | 31 +------------------------------
 3 files changed, 11 insertions(+), 36 deletions(-)

diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 1470b90..c66c524 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -127,14 +127,12 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 	wdev->wext.ibss.chandef = params->chandef;
 #endif
 	check_chan = params->chandef.chan;
-	if (params->userspace_handles_dfs) {
-		/* use channel NULL to check for radar even if the current
-		 * channel is not a radar channel - it might decide to change
-		 * to DFS channel later.
+	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);
-		check_chan = NULL;
-	}
 
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					   check_chan,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index d42a3fc..5af5cc6 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -236,6 +236,12 @@ 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)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 780b454..57b3ce7 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1269,7 +1269,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 	enum cfg80211_chan_mode chmode;
 	int num_different_channels = 0;
 	int total = 1;
-	bool radar_required = false;
 	int i, j;
 
 	ASSERT_RTNL();
@@ -1277,35 +1276,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 	if (WARN_ON(hweight32(radar_detect) > 1))
 		return -EINVAL;
 
-	switch (iftype) {
-	case NL80211_IFTYPE_ADHOC:
-	case NL80211_IFTYPE_AP:
-	case NL80211_IFTYPE_AP_VLAN:
-	case NL80211_IFTYPE_MESH_POINT:
-	case NL80211_IFTYPE_P2P_GO:
-	case NL80211_IFTYPE_WDS:
-		/* if the interface could potentially choose a DFS channel,
-		 * then mark DFS as required.
-		 */
-		if (!chan) {
-			if (chanmode != CHAN_MODE_UNDEFINED && radar_detect)
-				radar_required = true;
-			break;
-		}
-		radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
-		break;
-	case NL80211_IFTYPE_P2P_CLIENT:
-	case NL80211_IFTYPE_STATION:
-	case NL80211_IFTYPE_P2P_DEVICE:
-	case NL80211_IFTYPE_MONITOR:
-		break;
-	case NUM_NL80211_IFTYPES:
-	case NL80211_IFTYPE_UNSPECIFIED:
-	default:
-		return -EINVAL;
-	}
-
-	if (radar_required && !radar_detect)
+	if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
 		return -EINVAL;
 
 	/* Always allow software iftypes */
-- 
1.8.5.3


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

* [PATCH v2 3/7] cfg80211: refactor cfg80211_can_use_iftype_chan()
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 1/7] nl80211: make sure we check for DFS with mesh channel switch Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 2/7] cfg80211: remove radar requirements check from cfg80211_can_use_iftype_chan() Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 4/7] mac80211: ibss: handle cfg80211_chandef_dfs_required() error codes Luciano Coelho
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 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>
---
 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 46ad6fa..9135476 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -98,6 +98,7 @@
 !Finclude/net/cfg80211.h priv_to_wiphy
 !Finclude/net/cfg80211.h set_wiphy_dev
 !Finclude/net/cfg80211.h wdev_priv
+!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 9f90554..e44d62b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4667,6 +4667,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);
+
 /* 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..fbc2f8a 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)
+{
+	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] 10+ messages in thread

* [PATCH v2 4/7] mac80211: ibss: handle cfg80211_chandef_dfs_required() error codes
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
                   ` (2 preceding siblings ...)
  2014-02-20  5:10 ` [PATCH v2 3/7] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 5/7] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required() Luciano Coelho
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, michal.kazior, sw, bzhao, arend

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

Error codes returned by cfg80211_chandef_dfs_required() are ignored
when trying to join an IBSS.  Fix this by printing an error and
returning.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 net/mac80211/ibss.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 9c84b75..b558468 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -283,6 +283,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
 	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
 					    &chandef);
+	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,
-- 
1.8.5.3


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

* [PATCH v2 5/7] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required()
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
                   ` (3 preceding siblings ...)
  2014-02-20  5:10 ` [PATCH v2 4/7] mac80211: ibss: handle cfg80211_chandef_dfs_required() error codes Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
  2014-02-20  5:10 ` [PATCH v2 7/7] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano Coelho
  6 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 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>
---
 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 | 37 +++++++++++-------------
 6 files changed, 106 insertions(+), 69 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e44d62b..a1ce7cd 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 b558468..56b0dce 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 ?
@@ -778,7 +777,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);
@@ -876,16 +876,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..05eb540 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 b78d734..09ef2e1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3255,13 +3255,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,
@@ -5781,7 +5781,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;
 
@@ -5910,19 +5911,13 @@ skip_beacons:
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
 		return -EINVAL;
 
-	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
-	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO ||
-	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC ||
-	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_MESH_POINT) {
-		err = cfg80211_chandef_dfs_required(wdev->wiphy,
-						    &params.chandef);
-		if (err < 0) {
-			return err;
-		} else if (err) {
-			radar_detect_width = BIT(params.chandef.width);
-			params.radar_required = true;
-		}
-	}
+	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] 10+ messages in thread

* [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
                   ` (4 preceding siblings ...)
  2014-02-20  5:10 ` [PATCH v2 5/7] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required() Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  2014-02-20  8:40   ` Michal Kazior
  2014-02-20  5:10 ` [PATCH v2 7/7] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano Coelho
  6 siblings, 1 reply; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 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>
---
 include/net/cfg80211.h     |  4 +--
 net/mac80211/cfg.c         |  7 ++--
 net/mac80211/chan.c        | 18 ++++++++++
 net/mac80211/ieee80211_i.h |  5 +++
 net/mac80211/mlme.c        | 14 ++++++++
 net/mac80211/util.c        | 88 ++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h        |  7 ++++
 net/wireless/ibss.c        |  4 +++
 net/wireless/mesh.c        | 19 +++-------
 net/wireless/mlme.c        | 14 +-------
 net/wireless/nl80211.c     | 26 +++-----------
 net/wireless/util.c        |  5 +++
 12 files changed, 157 insertions(+), 54 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a1ce7cd..35b5eeb 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 7f01f2ae..ea7da53 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);
@@ -2928,13 +2927,17 @@ 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);
 	if (err)
 		goto out_unlock;
 
+	/* Something is wrong if cfg80211 asked us to start radar
+	 * detection but we don't think we need to.
+	 */
+	WARN_ON(!sdata->radar_required);
+
 	timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
 	ieee80211_queue_delayed_work(&sdata->local->hw,
 				     &sdata->dfs_cac_timer_work, timeout);
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 42c6592..10656f7 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,23 @@ 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->hw.wiphy, &sdata->wdev,
+					   chandef, IEEE80211_CHANCTX_SHARED,
+					   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..3c5d293 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 wiphy *wiphy,
+				 struct wireless_dev *wdev,
+				 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/mlme.c b/net/mac80211/mlme.c
index 46b62bb..4bdf49a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3949,6 +3949,13 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 	u16 auth_alg;
 	int err;
 
+	/* TODO: in cfg80211_mlme_auth() we used to check if the
+	 * channel can be used *before* this function was called.  Do
+	 * we still need to do it or can we rely on the combinations
+	 * check that will happen later, in
+	 * ieee80211_vif_use_channel()?
+	 */
+
 	/* prepare auth data structure */
 
 	switch (req->auth_type) {
@@ -4103,6 +4110,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	const u8 *ssidie, *ht_ie, *vht_ie;
 	int i, err;
 
+	/* TODO: in cfg80211_mlme_assoc() we used to check if the
+	 * channel can be used *before* this function was called.  Do
+	 * we still need to do it or can we rely on the combinations
+	 * check that will happen later, in
+	 * ieee80211_vif_use_channel()?
+	 */
+
 	assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
 	if (!assoc_data)
 		return -ENOMEM;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d842af5..172457d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2801,3 +2801,91 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 
 	ps->dtim_count = dtim_count;
 }
+
+int ieee80211_check_combinations(struct wiphy *wiphy,
+				 struct wireless_dev *wdev,
+				 const struct cfg80211_chan_def *chandef,
+				 enum ieee80211_chanctx_mode chanmode,
+				 u8 radar_detect)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	struct ieee80211_sub_if_data *sdata;
+	struct wireless_dev *wdev_iter;
+	enum nl80211_iftype iftype = NL80211_IFTYPE_UNSPECIFIED;
+	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 (wdev)
+		iftype = wdev->iftype;
+
+	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 (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, &local->interfaces, list) {
+		wdev_iter = &sdata->wdev;
+		if (wdev_iter == wdev)
+			continue;
+		if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+			if (!wdev_iter->p2p_started)
+				continue;
+		} else if (wdev_iter->netdev) {
+			if (!netif_running(wdev_iter->netdev))
+				continue;
+		} else {
+			WARN_ON(1);
+		}
+
+		if (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(wiphy, num_different_channels,
+					   total, used_iftypes,
+					   radar_detect, num);
+}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 9895ab1..4b1a6a0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -406,6 +406,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);
 }
@@ -426,6 +429,10 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
 		      struct ieee80211_channel *chan,
 		      enum cfg80211_chan_mode chanmode)
 {
+	/* TODO: for libertas, we probably need to move the
+	 * combination check into that driver if we get rid of the
+	 * cfg80211_can_use_chan() function.
+	 */
 	return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
 					    chan, chanmode, 0);
 }
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index c66c524..6e98e49 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -134,6 +134,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..cacf79e 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);
@@ -243,6 +228,10 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
 		 * channel here, something is wrong.
 		 */
 		WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR);
+
+		/* TODO: We probably need to move this into the
+		 * libertas driver?
+		 */
 		err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
 					    CHAN_MODE_SHARED);
 		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 09ef2e1..2712d2a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3136,7 +3136,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)
@@ -3255,21 +3254,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))
@@ -5795,12 +5779,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;
@@ -5919,6 +5897,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 fbc2f8a..9d08596 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] 10+ messages in thread

* [PATCH v2 7/7] cfg80211/mac80211: move combination check to mac80211 for ibss
  2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
                   ` (5 preceding siblings ...)
  2014-02-20  5:10 ` [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
@ 2014-02-20  5:10 ` Luciano Coelho
  6 siblings, 0 replies; 10+ messages in thread
From: Luciano Coelho @ 2014-02-20  5:10 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();
---
 net/mac80211/chan.c |  3 +--
 net/mac80211/ibss.c | 30 +++++++++++++++++++++++++++---
 net/wireless/ibss.c | 27 ---------------------------
 3 files changed, 28 insertions(+), 32 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 10656f7..39cfccb 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -533,8 +533,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 	sdata->radar_required = !!(radar_detect_width);
 
 	ret = ieee80211_check_combinations(local->hw.wiphy, &sdata->wdev,
-					   chandef, IEEE80211_CHANCTX_SHARED,
-					   radar_detect_width);
+					   chandef, mode, radar_detect_width);
 	if (ret < 0)
 		goto out;
 
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 56b0dce..cf83763 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1646,7 +1646,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);
@@ -1661,7 +1685,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);
@@ -1710,9 +1734,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 6e98e49..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,31 +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] 10+ messages in thread

* Re: [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211
  2014-02-20  5:10 ` [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
@ 2014-02-20  8:40   ` Michal Kazior
  2014-02-20  9:24     ` Luca Coelho
  0 siblings, 1 reply; 10+ messages in thread
From: Michal Kazior @ 2014-02-20  8:40 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless, Johannes Berg, sw, Bing Zhao, arend

On 20 February 2014 06:10, Luciano Coelho <luca@coelho.fi> wrote:

[...]

> @@ -520,6 +521,23 @@ 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->hw.wiphy, &sdata->wdev,
> +                                          chandef, IEEE80211_CHANCTX_SHARED,
> +                                          radar_detect_width);
> +       if (ret < 0)
> +               goto out;
> +

I think you forgot to change SHARED to `mode` :-)


Michał

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

* Re: [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211
  2014-02-20  8:40   ` Michal Kazior
@ 2014-02-20  9:24     ` Luca Coelho
  0 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-02-20  9:24 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Johannes Berg, sw, Bing Zhao, arend

On Thu, 2014-02-20 at 09:40 +0100, Michal Kazior wrote:
> On 20 February 2014 06:10, Luciano Coelho <luca@coelho.fi> wrote:
> 
> [...]
> 
> > @@ -520,6 +521,23 @@ 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->hw.wiphy, &sdata->wdev,
> > +                                          chandef, IEEE80211_CHANCTX_SHARED,
> > +                                          radar_detect_width);
> > +       if (ret < 0)
> > +               goto out;
> > +
> 
> I think you forgot to change SHARED to `mode` :-)

Damn! I changed it in the wrong patch, 7/7 instead of here.

I'll resend.

--
Luca.


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

end of thread, other threads:[~2014-02-20  9:24 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-20  5:10 [PATCH v2 0/7] cfg80211/mac80211: move interface combinations check to mac80211 Luciano Coelho
2014-02-20  5:10 ` [PATCH v2 1/7] nl80211: make sure we check for DFS with mesh channel switch Luciano Coelho
2014-02-20  5:10 ` [PATCH v2 2/7] cfg80211: remove radar requirements check from cfg80211_can_use_iftype_chan() Luciano Coelho
2014-02-20  5:10 ` [PATCH v2 3/7] cfg80211: refactor cfg80211_can_use_iftype_chan() Luciano Coelho
2014-02-20  5:10 ` [PATCH v2 4/7] mac80211: ibss: handle cfg80211_chandef_dfs_required() error codes Luciano Coelho
2014-02-20  5:10 ` [PATCH v2 5/7] cfg80211/mac80211: refactor cfg80211_chandef_dfs_required() Luciano Coelho
2014-02-20  5:10 ` [PATCH v2 6/7] cfg80211/mac80211: move interface counting for combination check to mac80211 Luciano Coelho
2014-02-20  8:40   ` Michal Kazior
2014-02-20  9:24     ` Luca Coelho
2014-02-20  5:10 ` [PATCH v2 7/7] cfg80211/mac80211: move combination check to mac80211 for ibss Luciano 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.