All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] respect channels in iface combinations
@ 2012-06-29 10:46 Michal Kazior
  2012-06-29 10:46 ` [PATCH 01/13] cfg80211: introduce cfg80211_stop_ap Michal Kazior
                   ` (13 more replies)
  0 siblings, 14 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:46 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless

Hi,

The patchset introduces channel tracking per interface which is needed
to start enforcing num_different_channels in interface combinations.
Changes to monitor mode behaviour is also required for sane channel
accounting (considering how mac80211 handles monitor interfaces).

This prepares cfg80211 for multi-channel operation.

Remaining issue that needs addressing at a later time is CSA handling
(which is already broken anyway).

Changes since PATCH v1:
 * rebased on top of mac80211-next tree from 2012-06-29


-- Pozdrawiam / Best regards, Michal Kazior.


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

* [PATCH 01/13] cfg80211: introduce cfg80211_stop_ap
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
@ 2012-06-29 10:46 ` Michal Kazior
  2012-06-29 10:46 ` [PATCH 02/13] cfg80211: .stop_ap when interface is going down Michal Kazior
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:46 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

This functionality will be reused when interface
is going down. Avoids code duplication. Also adds
missing wdev locking.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/Makefile  |    2 +-
 net/wireless/ap.c      |   44 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h    |    4 ++++
 net/wireless/nl80211.c |   17 +----------------
 4 files changed, 50 insertions(+), 17 deletions(-)
 create mode 100644 net/wireless/ap.c

diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 55a28ab..0f7e0d6 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
new file mode 100644
index 0000000..45199cc
--- /dev/null
+++ b/net/wireless/ap.c
@@ -0,0 +1,44 @@
+#include <linux/ieee80211.h>
+#include <linux/export.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+#include "core.h"
+
+
+static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
+			      struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (!rdev->ops->stop_ap)
+		return -EOPNOTSUPP;
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+		return -EOPNOTSUPP;
+
+	if (!wdev->beacon_interval)
+		return -ENOENT;
+
+	err = rdev->ops->stop_ap(&rdev->wiphy, dev);
+	if (!err)
+		wdev->beacon_interval = 0;
+
+	return err;
+}
+
+int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
+		     struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	wdev_lock(wdev);
+	err = __cfg80211_stop_ap(rdev, dev);
+	wdev_unlock(wdev);
+
+	return err;
+}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 609a579..fef476d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -289,6 +289,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
 			   struct wireless_dev *wdev, int freq,
 			   enum nl80211_channel_type channel_type);
 
+/* AP */
+int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
+		     struct net_device *dev);
+
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5c4a720..20d0fd6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2521,23 +2521,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
-	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int err;
-
-	if (!rdev->ops->stop_ap)
-		return -EOPNOTSUPP;
 
-	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
-		return -EOPNOTSUPP;
-
-	if (!wdev->beacon_interval)
-		return -ENOENT;
-
-	err = rdev->ops->stop_ap(&rdev->wiphy, dev);
-	if (!err)
-		wdev->beacon_interval = 0;
-	return err;
+	return cfg80211_stop_ap(rdev, dev);
 }
 
 static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
-- 
1.7.0.4


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

* [PATCH 02/13] cfg80211: .stop_ap when interface is going down
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
  2012-06-29 10:46 ` [PATCH 01/13] cfg80211: introduce cfg80211_stop_ap Michal Kazior
@ 2012-06-29 10:46 ` Michal Kazior
  2012-06-29 10:46 ` [PATCH 03/13] cfg80211: add channel tracking for AP and mesh Michal Kazior
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:46 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

We'll need this for proper channel tracking (which
is going to be needed for channel context
accounting and finding matching/active interface
combination).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/core.c |    3 +++
 net/wireless/util.c |    3 +++
 2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index ddd32af..c65f59c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -810,6 +810,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		case NL80211_IFTYPE_MESH_POINT:
 			cfg80211_leave_mesh(rdev, dev);
 			break;
+		case NL80211_IFTYPE_AP:
+			cfg80211_stop_ap(rdev, dev);
+			break;
 		default:
 			break;
 		}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 316cfd0..fc948d0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -814,6 +814,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 		dev->ieee80211_ptr->mesh_id_up_len = 0;
 
 		switch (otype) {
+		case NL80211_IFTYPE_AP:
+			cfg80211_stop_ap(rdev, dev);
+			break;
 		case NL80211_IFTYPE_ADHOC:
 			cfg80211_leave_ibss(rdev, dev, false);
 			break;
-- 
1.7.0.4


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

* [PATCH 03/13] cfg80211: add channel tracking for AP and mesh
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
  2012-06-29 10:46 ` [PATCH 01/13] cfg80211: introduce cfg80211_stop_ap Michal Kazior
  2012-06-29 10:46 ` [PATCH 02/13] cfg80211: .stop_ap when interface is going down Michal Kazior
@ 2012-06-29 10:46 ` Michal Kazior
  2012-06-29 10:46 ` [PATCH 04/13] cfg80211: track ibss fixed channel Michal Kazior
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:46 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

We need to know which channel is used by a running
AP and mesh for channel context accounting and
finding matching/active interface combination.

STA/IBSS have current_bss already which allows us
to check which channel a vif is tuned to.
Non-fixed channel IBSS can be handled with
additional changes.

Monitor mode is going to be handled differently.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h |    3 +++
 net/wireless/ap.c      |    4 +++-
 net/wireless/mesh.c    |   18 ++++++++++++++----
 net/wireless/mlme.c    |    1 +
 net/wireless/nl80211.c |    1 +
 5 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1fc89c4..c62bc78 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2408,6 +2408,9 @@ struct wireless_dev {
 	struct ieee80211_channel *preset_chan;
 	enum nl80211_channel_type preset_chantype;
 
+	/* for AP and mesh channel tracking */
+	struct ieee80211_channel *channel;
+
 	bool ps;
 	int ps_timeout;
 
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index 45199cc..fcc60d8 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -24,8 +24,10 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
 		return -ENOENT;
 
 	err = rdev->ops->stop_ap(&rdev->wiphy, dev);
-	if (!err)
+	if (!err) {
 		wdev->beacon_interval = 0;
+		wdev->channel = NULL;
+	}
 
 	return err;
 }
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 3b73b07..bab3813 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -159,6 +159,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 	if (!err) {
 		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
 		wdev->mesh_id_len = setup->mesh_id_len;
+		wdev->channel = setup->channel;
 	}
 
 	return err;
@@ -184,6 +185,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
 			   enum nl80211_channel_type channel_type)
 {
 	struct ieee80211_channel *channel;
+	int err;
 
 	channel = rdev_freq_to_chan(rdev, freq, channel_type);
 	if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
@@ -205,9 +207,14 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
 
 		if (!netif_running(wdev->netdev))
 			return -ENETDOWN;
-		return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
-							    wdev->netdev,
-							    channel);
+
+		err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+							   wdev->netdev,
+							   channel);
+		if (!err)
+			wdev->channel = channel;
+
+		return err;
 	}
 
 	if (wdev->mesh_id_len)
@@ -249,8 +256,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
 		return -ENOTCONN;
 
 	err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
-	if (!err)
+	if (!err) {
 		wdev->mesh_id_len = 0;
+		wdev->channel = NULL;
+	}
+
 	return err;
 }
 
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index da4406f..a7882eb 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -947,6 +947,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
 	if (WARN_ON(!chan))
 		goto out;
 
+	wdev->channel = chan;
 	nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
 out:
 	wdev_unlock(wdev);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 20d0fd6..12096b4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2488,6 +2488,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 		wdev->preset_chan = params.channel;
 		wdev->preset_chantype = params.channel_type;
 		wdev->beacon_interval = params.beacon_interval;
+		wdev->channel = params.channel;
 	}
 	return err;
 }
-- 
1.7.0.4


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

* [PATCH 04/13] cfg80211: track ibss fixed channel
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (2 preceding siblings ...)
  2012-06-29 10:46 ` [PATCH 03/13] cfg80211: add channel tracking for AP and mesh Michal Kazior
@ 2012-06-29 10:46 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 05/13] cfg80211: introduce cfg80211_get_chan_state Michal Kazior
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:46 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

IBSS may hop between channels. It is necessary to
account this special case when considering
interface combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h |    2 ++
 net/wireless/ibss.c    |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index c62bc78..e030c6a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2411,6 +2411,8 @@ struct wireless_dev {
 	/* for AP and mesh channel tracking */
 	struct ieee80211_channel *channel;
 
+	bool ibss_fixed;
+
 	bool ps;
 	int ps_timeout;
 
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 89baa33..b90fd86 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -113,6 +113,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		kfree(wdev->connect_keys);
 	wdev->connect_keys = connkeys;
 
+	wdev->ibss_fixed = params->channel_fixed;
 #ifdef CONFIG_CFG80211_WEXT
 	wdev->wext.ibss.channel = params->channel;
 #endif
-- 
1.7.0.4


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

* [PATCH 05/13] cfg80211: introduce cfg80211_get_chan_state
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (3 preceding siblings ...)
  2012-06-29 10:46 ` [PATCH 04/13] cfg80211: track ibss fixed channel Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 06/13] cfg80211: track monitor interfaces count Michal Kazior
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

Helper function for finding out which channel is
used by a given interface.

An exclusive channel can be used only by a single
interface. This is mainly for non-fixed channel
IBSS handling.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/chan.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h |   12 ++++++++++++
 2 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index c1999e4..167e7cb 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -92,3 +92,54 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
 
 	return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
 }
+
+void
+cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
+		        struct wireless_dev *wdev,
+		        struct ieee80211_channel **chan,
+		        enum cfg80211_chan_mode *chanmode)
+{
+	*chan = NULL;
+	*chanmode = CHAN_MODE_UNDEFINED;
+
+	ASSERT_RDEV_LOCK(rdev);
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (!netif_running(wdev->netdev))
+		return;
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_ADHOC:
+		if (wdev->current_bss) {
+			*chan = wdev->current_bss->pub.channel;
+			*chanmode = wdev->ibss_fixed
+				  ? CHAN_MODE_SHARED
+				  : CHAN_MODE_EXCLUSIVE;
+			return;
+		}
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		if (wdev->current_bss) {
+			*chan = wdev->current_bss->pub.channel;
+			*chanmode = CHAN_MODE_SHARED;
+			return;
+		}
+		break;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+	case NL80211_IFTYPE_MESH_POINT:
+		*chan = wdev->channel;
+		*chanmode = CHAN_MODE_SHARED;
+		return;
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+		/* these interface types don't really have a channel */
+		return;
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NUM_NL80211_IFTYPES:
+		WARN_ON(1);
+	}
+
+	return;
+}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index fef476d..56f18c2 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -241,6 +241,12 @@ struct cfg80211_cached_keys {
 	int def, defmgmt;
 };
 
+enum cfg80211_chan_mode {
+	CHAN_MODE_UNDEFINED,
+	CHAN_MODE_SHARED,
+	CHAN_MODE_EXCLUSIVE,
+};
+
 
 /* free object */
 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -419,6 +425,12 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
 	return cfg80211_can_change_interface(rdev, NULL, iftype);
 }
 
+void
+cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
+		        struct wireless_dev *wdev,
+		        struct ieee80211_channel **chan,
+		        enum cfg80211_chan_mode *chanmode);
+
 struct ieee80211_channel *
 rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
 		  int freq, enum nl80211_channel_type channel_type);
-- 
1.7.0.4


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

* [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (4 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 05/13] cfg80211: introduce cfg80211_get_chan_state Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-07-04 11:12   ` Johannes Berg
  2012-06-29 10:47 ` [PATCH 07/13] mac80211: refactor virtual monitor code Michal Kazior
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

Implements .set_monitor_enabled(wiphy, enabled).

Notifies driver upon change of interface layout.

If only monitor interfaces become present it is
called with 2nd argument being true. If
non-monitor interface appears then 2nd argument
is false. Driver is notified only upon change.

This makes it more obvious about the fact that
cfg80211 supports single monitor channel. Once we
implement multi-channel we don't want to allow
setting monitor channel while other interface
types are running. Otherwise it would be ambiguous
once we start considering num_different_channels.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h |    4 ++++
 net/wireless/core.c    |   24 ++++++++++++++++++++++++
 net/wireless/core.h    |   14 ++++++++++++++
 net/wireless/util.c    |    5 +++++
 4 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e030c6a..f0d213d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1499,6 +1499,8 @@ struct cfg80211_gtk_rekey_data {
  *	interfaces are active this callback should reject the configuration.
  *	If no interfaces are active or the device is down, the channel should
  *	be stored for when a monitor interface becomes active.
+ * @set_monitor_enabled: Notify driver that there are only monitor
+ *	interfaces running.
  * @get_channel: Get the current operating channel, should return %NULL if
  *	there's no single defined operating channel if for example the
  *	device implements channel hopping for multi-channel virtual interfaces.
@@ -1817,6 +1819,8 @@ struct cfg80211_ops {
 				struct ethtool_stats *stats, u64 *data);
 	void	(*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
 				  u32 sset, u8 *data);
+
+	void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled);
 };
 
 /*
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c65f59c..8412da7 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -717,6 +717,24 @@ static struct device_type wiphy_type = {
 	.name	= "wlan",
 };
 
+void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
+			       enum nl80211_iftype iftype, int num)
+{
+	bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
+	bool has_monitors_only_new;
+
+	ASSERT_RDEV_LOCK(rdev);
+
+	rdev->num_running_ifaces += num;
+	if (iftype == NL80211_IFTYPE_MONITOR)
+		rdev->num_running_monitor_ifaces += num;
+
+	has_monitors_only_new = cfg80211_has_monitors_only(rdev);
+	if (has_monitors_only_new != has_monitors_only_old)
+		rdev->ops->set_monitor_enabled(&rdev->wiphy,
+					       has_monitors_only_new);
+}
+
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 					 unsigned long state,
 					 void *ndev)
@@ -820,6 +838,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		break;
 	case NETDEV_DOWN:
 		dev_hold(dev);
+		cfg80211_lock_rdev(rdev);
+		cfg80211_update_iface_num(rdev, wdev->iftype, -1);
+		cfg80211_unlock_rdev(rdev);
 		queue_work(cfg80211_wq, &wdev->cleanup_work);
 		break;
 	case NETDEV_UP:
@@ -927,6 +948,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		ret = cfg80211_can_add_interface(rdev, wdev->iftype);
 		if (ret)
 			return notifier_from_errno(ret);
+		cfg80211_lock_rdev(rdev);
+		cfg80211_update_iface_num(rdev, wdev->iftype, 1);
+		cfg80211_unlock_rdev(rdev);
 		break;
 	}
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 56f18c2..99acd51 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -56,6 +56,9 @@ struct cfg80211_registered_device {
 
 	u32 ap_beacons_nlpid;
 
+	int num_running_ifaces;
+	int num_running_monitor_ifaces;
+
 	/* BSSes/scanning */
 	spinlock_t bss_lock;
 	struct list_head bss_list;
@@ -197,6 +200,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
 #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx)
 #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
 
+static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
+{
+	ASSERT_RDEV_LOCK(rdev);
+
+	return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
+	       rdev->num_running_ifaces > 0;
+}
+
 enum cfg80211_event_type {
 	EVENT_CONNECT_RESULT,
 	EVENT_ROAMED,
@@ -444,6 +455,9 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
 int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 				 u32 beacon_int);
 
+void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
+			       enum nl80211_iftype iftype, int num);
+
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
 #define CFG80211_DEV_WARN_ON(cond)	WARN_ON(cond)
 #else
diff --git a/net/wireless/util.c b/net/wireless/util.c
index fc948d0..9b92ec5 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -871,6 +871,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 		}
 	}
 
+	if (!err && ntype != otype && netif_running(dev)) {
+		cfg80211_update_iface_num(rdev, ntype, 1);
+		cfg80211_update_iface_num(rdev, otype, -1);
+	}
+
 	return err;
 }
 
-- 
1.7.0.4


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

* [PATCH 07/13] mac80211: refactor virtual monitor code
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (5 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 06/13] cfg80211: track monitor interfaces count Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 08/13] cfg80211: refuse to .set_monitor_channel when non-monitors are present Michal Kazior
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

Use cfg80211 the new .set_monitor_enabled instead
of tracking it inside mac80211.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/mac80211/cfg.c         |   11 +++++++++++
 net/mac80211/ieee80211_i.h |    4 ++++
 net/mac80211/iface.c       |   16 ++--------------
 3 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 0f02c8b..ea4b1ea 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2990,6 +2990,16 @@ ieee80211_wiphy_get_channel(struct wiphy *wiphy,
 	return local->oper_channel;
 }
 
+static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+
+	if (enabled)
+		WARN_ON(ieee80211_add_virtual_monitor(local));
+	else
+		ieee80211_del_virtual_monitor(local);
+}
+
 #ifdef CONFIG_PM
 static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
 {
@@ -3065,6 +3075,7 @@ struct cfg80211_ops mac80211_config_ops = {
 	.probe_client = ieee80211_probe_client,
 	.get_channel = ieee80211_wiphy_get_channel,
 	.set_noack_map = ieee80211_set_noack_map,
+	.set_monitor_enabled = ieee80211_set_monitor_enabled,
 #ifdef CONFIG_PM
 	.set_wakeup = ieee80211_set_wakeup,
 #endif
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6b7157d..b88bdfd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1485,6 +1485,10 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
 int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 				struct sk_buff *skb, bool need_basic);
 
+/* virtual monitor */
+int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
+void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
+
 /* channel management */
 enum ieee80211_chan_mode {
 	CHAN_MODE_UNDEFINED,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0a6b4e1..fbef7a1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -330,7 +330,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
 	sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
 }
 
-static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
+int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 {
 	struct ieee80211_sub_if_data *sdata;
 	int ret;
@@ -371,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 	return 0;
 }
 
-static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
+void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 {
 	struct ieee80211_sub_if_data *sdata;
 
@@ -487,12 +487,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 			break;
 		}
 
-		if (local->monitors == 0 && local->open_count == 0) {
-			res = ieee80211_add_virtual_monitor(local);
-			if (res)
-				goto err_stop;
-		}
-
 		/* must be before the call to ieee80211_configure_filter */
 		local->monitors++;
 		if (local->monitors == 1) {
@@ -507,8 +501,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 		break;
 	default:
 		if (coming_up) {
-			ieee80211_del_virtual_monitor(local);
-
 			res = drv_add_interface(local, sdata);
 			if (res)
 				goto err_stop;
@@ -743,7 +735,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 		if (local->monitors == 0) {
 			local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
 			hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
-			ieee80211_del_virtual_monitor(local);
 		}
 
 		ieee80211_adjust_monitor_flags(sdata, -1);
@@ -817,9 +808,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-	if (local->monitors == local->open_count && local->monitors > 0)
-		ieee80211_add_virtual_monitor(local);
 }
 
 static int ieee80211_stop(struct net_device *dev)
-- 
1.7.0.4


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

* [PATCH 08/13] cfg80211: refuse to .set_monitor_channel when non-monitors are present
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (6 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 07/13] mac80211: refactor virtual monitor code Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 09/13] cfg80211: track monitor channel Michal Kazior
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

Having .set_monitor_channel work with non-monitor
interfaces running would make interface
combinations accounting ambiguous.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/chan.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 167e7cb..019401b 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -85,6 +85,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
 
 	if (!rdev->ops->set_monitor_channel)
 		return -EOPNOTSUPP;
+	if (!cfg80211_has_monitors_only(rdev))
+		return -EBUSY;
 
 	chan = rdev_freq_to_chan(rdev, freq, chantype);
 	if (!chan)
-- 
1.7.0.4


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

* [PATCH 09/13] cfg80211: track monitor channel
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (7 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 08/13] cfg80211: refuse to .set_monitor_channel when non-monitors are present Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 10/13] cfg80211: set initial " Michal Kazior
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

Make it even more obvious we support single
monitor channel. This will allow us to remove
.get_channel.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/chan.c |    9 ++++++++-
 net/wireless/core.c |    8 +++++++-
 net/wireless/core.h |    3 +++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 019401b..434c56b 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -82,6 +82,7 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
 				 int freq, enum nl80211_channel_type chantype)
 {
 	struct ieee80211_channel *chan;
+	int err;
 
 	if (!rdev->ops->set_monitor_channel)
 		return -EOPNOTSUPP;
@@ -92,7 +93,13 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
 	if (!chan)
 		return -EINVAL;
 
-	return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
+	err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
+	if (!err) {
+		rdev->monitor_channel = chan;
+		rdev->monitor_channel_type = chantype;
+	}
+
+	return err;
 }
 
 void
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8412da7..1b5daa7 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -730,9 +730,15 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
 		rdev->num_running_monitor_ifaces += num;
 
 	has_monitors_only_new = cfg80211_has_monitors_only(rdev);
-	if (has_monitors_only_new != has_monitors_only_old)
+	if (has_monitors_only_new != has_monitors_only_old) {
 		rdev->ops->set_monitor_enabled(&rdev->wiphy,
 					       has_monitors_only_new);
+
+		if (!has_monitors_only_new) {
+			rdev->monitor_channel = NULL;
+			rdev->monitor_channel_type = NL80211_CHAN_NO_HT;
+		}
+	}
 }
 
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 99acd51..d5efe1b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -59,6 +59,9 @@ struct cfg80211_registered_device {
 	int num_running_ifaces;
 	int num_running_monitor_ifaces;
 
+	struct ieee80211_channel *monitor_channel;
+	enum nl80211_channel_type monitor_channel_type;
+
 	/* BSSes/scanning */
 	spinlock_t bss_lock;
 	struct list_head bss_list;
-- 
1.7.0.4


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

* [PATCH 10/13] cfg80211: set initial monitor channel
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (8 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 09/13] cfg80211: track monitor channel Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 11/13] cfg80211/mac80211: remove .get_channel Michal Kazior
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

Implements behaviour seen in mac80211. A running
monitor always has a channel - even before
.set_channel. This way we won't break current
behaviour.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/core.c |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 1b5daa7..580551e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -717,6 +717,35 @@ static struct device_type wiphy_type = {
 	.name	= "wlan",
 };
 
+static struct ieee80211_channel *
+cfg80211_get_any_chan(struct cfg80211_registered_device *rdev)
+{
+	struct ieee80211_supported_band *sband;
+	int i;
+
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+		sband = rdev->wiphy.bands[i];
+		if (sband && sband->n_channels > 0)
+			return &sband->channels[0];
+	}
+
+	return NULL;
+}
+
+static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev)
+{
+	struct ieee80211_channel *chan;
+
+	chan = cfg80211_get_any_chan(rdev);
+	if (WARN_ON(!chan))
+		return;
+
+	mutex_lock(&rdev->devlist_mtx);
+	WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq,
+					     NL80211_CHAN_NO_HT));
+	mutex_unlock(&rdev->devlist_mtx);
+}
+
 void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
 			       enum nl80211_iftype iftype, int num)
 {
@@ -737,6 +766,8 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
 		if (!has_monitors_only_new) {
 			rdev->monitor_channel = NULL;
 			rdev->monitor_channel_type = NL80211_CHAN_NO_HT;
+		} else {
+			cfg80211_init_mon_chan(rdev);
 		}
 	}
 }
-- 
1.7.0.4


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

* [PATCH 11/13] cfg80211/mac80211: remove .get_channel
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (9 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 10/13] cfg80211: set initial " Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 12/13] cfg80211: add channel checking for iface combinations Michal Kazior
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

We do not need it anymore since cfg80211 tracks
monitor channel and monitor channel type.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h     |    6 ------
 net/mac80211/cfg.c         |   11 -----------
 net/wireless/nl80211.c     |   15 +++++----------
 net/wireless/wext-compat.c |    9 ++-------
 4 files changed, 7 insertions(+), 34 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f0d213d..fa26934 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1501,9 +1501,6 @@ struct cfg80211_gtk_rekey_data {
  *	be stored for when a monitor interface becomes active.
  * @set_monitor_enabled: Notify driver that there are only monitor
  *	interfaces running.
- * @get_channel: Get the current operating channel, should return %NULL if
- *	there's no single defined operating channel if for example the
- *	device implements channel hopping for multi-channel virtual interfaces.
  *
  * @scan: Request to do a scan. If returning zero, the scan request is given
  *	the driver, and will be valid until passed to cfg80211_scan_done().
@@ -1810,9 +1807,6 @@ struct cfg80211_ops {
 				  struct net_device *dev,
 				  u16 noack_map);
 
-	struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy,
-					       enum nl80211_channel_type *type);
-
 	int	(*get_et_sset_count)(struct wiphy *wiphy,
 				     struct net_device *dev, int sset);
 	void	(*get_et_stats)(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ea4b1ea..ccbe241 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2980,16 +2980,6 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
 	return 0;
 }
 
-static struct ieee80211_channel *
-ieee80211_wiphy_get_channel(struct wiphy *wiphy,
-			    enum nl80211_channel_type *type)
-{
-	struct ieee80211_local *local = wiphy_priv(wiphy);
-
-	*type = local->_oper_channel_type;
-	return local->oper_channel;
-}
-
 static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -3073,7 +3063,6 @@ struct cfg80211_ops mac80211_config_ops = {
 	.tdls_oper = ieee80211_tdls_oper,
 	.tdls_mgmt = ieee80211_tdls_mgmt,
 	.probe_client = ieee80211_probe_client,
-	.get_channel = ieee80211_wiphy_get_channel,
 	.set_noack_map = ieee80211_set_noack_map,
 	.set_monitor_enabled = ieee80211_set_monitor_enabled,
 #ifdef CONFIG_PM
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 12096b4..5d29ed1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1689,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			(cfg80211_rdev_list_generation << 2)))
 		goto nla_put_failure;
 
-	if (rdev->ops->get_channel) {
-		struct ieee80211_channel *chan;
-		enum nl80211_channel_type channel_type;
-
-		chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type);
-		if (chan &&
-		    (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
-				    chan->center_freq) ||
-		     nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    channel_type)))
+	if (rdev->monitor_channel) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+				rdev->monitor_channel->center_freq) ||
+		    nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				rdev->monitor_channel_type))
 			goto nla_put_failure;
 	}
 
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index bc87983..7df42f5 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-	struct ieee80211_channel *chan;
-	enum nl80211_channel_type channel_type;
 
 	switch (wdev->iftype) {
 	case NL80211_IFTYPE_STATION:
@@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
 	case NL80211_IFTYPE_ADHOC:
 		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
 	case NL80211_IFTYPE_MONITOR:
-		if (!rdev->ops->get_channel)
+		if (!rdev->monitor_channel)
 			return -EINVAL;
 
-		chan = rdev->ops->get_channel(wdev->wiphy, &channel_type);
-		if (!chan)
-			return -EINVAL;
-		freq->m = chan->center_freq;
+		freq->m = rdev->monitor_channel->center_freq;
 		freq->e = 6;
 		return 0;
 	default:
-- 
1.7.0.4


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

* [PATCH 12/13] cfg80211: add channel checking for iface combinations
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (10 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 11/13] cfg80211/mac80211: remove .get_channel Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 10:47 ` [PATCH 13/13] cfg80211: respect iface combinations when starting operation Michal Kazior
  2012-06-29 12:22 ` [PATCH v2] respect channels in iface combinations Johannes Berg
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

.connect cannot be handled since the driver scans
and connects on its own. It is up to the driver
then to refuse a connection (with -EBUSY for
example).

Non-fixed channel IBSSes always take a single
channel resource. For example two non-fixed
channel IBSSes always take up 2
num_different_channels, even if they operate on
the same channel at a given point of time.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/core.c |    8 +++++++
 net/wireless/core.h |   29 ++++++++++++++++++++++--
 net/wireless/util.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 88 insertions(+), 8 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 580551e..b26695a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
 		if (WARN_ON(!c->num_different_channels))
 			return -EINVAL;
 
+		/*
+		 * Put a sane limit on maximum number of different
+		 * channels to simplify channel accounting code.
+		 */
+		if (WARN_ON(c->num_different_channels >
+				CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
+			return -EINVAL;
+
 		if (WARN_ON(!c->n_limits))
 			return -EINVAL;
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index d5efe1b..81fef3d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -428,9 +428,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 			  u32 *flags, struct vif_params *params);
 void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
 
-int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
-				  struct wireless_dev *wdev,
-				  enum nl80211_iftype iftype);
+int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev,
+				 enum nl80211_iftype iftype,
+				 struct ieee80211_channel *chan,
+				 enum cfg80211_chan_mode chanmode);
+
+static inline int
+cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev,
+			      enum nl80211_iftype iftype)
+{
+	return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
+					    CHAN_MODE_UNDEFINED);
+}
 
 static inline int
 cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
@@ -439,6 +450,16 @@ 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);
+}
+
 void
 cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
 		        struct wireless_dev *wdev,
@@ -461,6 +482,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
 			       enum nl80211_iftype iftype, int num);
 
+#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
+
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
 #define CFG80211_DEV_WARN_ON(cond)	WARN_ON(cond)
 #else
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 9b92ec5..4713cea 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -938,13 +938,20 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 	return res;
 }
 
-int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
-				  struct wireless_dev *wdev,
-				  enum nl80211_iftype iftype)
+int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev,
+				 enum nl80211_iftype iftype,
+				 struct ieee80211_channel *chan,
+				 enum cfg80211_chan_mode chanmode)
 {
 	struct wireless_dev *wdev_iter;
 	u32 used_iftypes = BIT(iftype);
 	int num[NUM_NL80211_IFTYPES];
+	struct ieee80211_channel
+			*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
+	struct ieee80211_channel *ch;
+	enum cfg80211_chan_mode chmode;
+	int num_different_channels = 0;
 	int total = 1;
 	int i, j;
 
@@ -955,9 +962,23 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 		return 0;
 
 	memset(num, 0, sizeof(num));
+	memset(used_channels, 0, sizeof(used_channels));
 
 	num[iftype] = 1;
 
+	switch (chanmode) {
+	case CHAN_MODE_UNDEFINED:
+		break;
+	case CHAN_MODE_SHARED:
+		WARN_ON(!chan);
+		used_channels[0] = chan;
+		num_different_channels++;
+		break;
+	case CHAN_MODE_EXCLUSIVE:
+		num_different_channels++;
+		break;
+	}
+
 	mutex_lock(&rdev->devlist_mtx);
 	list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
 		if (wdev_iter == wdev)
@@ -968,6 +989,31 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 		if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
 			continue;
 
+		cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode);
+
+		switch (chmode) {
+		case CHAN_MODE_UNDEFINED:
+			break;
+		case CHAN_MODE_SHARED:
+			for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++)
+				if (!used_channels[i] || used_channels[i] == ch)
+					break;
+
+			if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) {
+				mutex_unlock(&rdev->devlist_mtx);
+				return -EBUSY;
+			}
+
+			if (used_channels[i] == NULL) {
+				used_channels[i] = ch;
+				num_different_channels++;
+			}
+			break;
+		case CHAN_MODE_EXCLUSIVE:
+			num_different_channels++;
+			break;
+		}
+
 		num[wdev_iter->iftype]++;
 		total++;
 		used_iftypes |= BIT(wdev_iter->iftype);
@@ -984,12 +1030,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
 
 		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;
-		if (total > c->max_interfaces)
-			goto cont;
 
 		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
 			if (rdev->wiphy.software_iftypes & BIT(iftype))
-- 
1.7.0.4


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

* [PATCH 13/13] cfg80211: respect iface combinations when starting operation
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (11 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 12/13] cfg80211: add channel checking for iface combinations Michal Kazior
@ 2012-06-29 10:47 ` Michal Kazior
  2012-06-29 12:22 ` [PATCH v2] respect channels in iface combinations Johannes Berg
  13 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-29 10:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

devlist_mtx locking is changed to accomodate changes.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 net/wireless/core.c    |    2 ++
 net/wireless/ibss.c    |   10 ++++++++++
 net/wireless/mesh.c    |   12 ++++++++++++
 net/wireless/mlme.c    |   16 ++++++++++++++++
 net/wireless/nl80211.c |    8 ++++++++
 net/wireless/util.c    |    9 ++++-----
 6 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index b26695a..ca2b95f 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -990,7 +990,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 			return notifier_from_errno(-EOPNOTSUPP);
 		if (rfkill_blocked(rdev->rfkill))
 			return notifier_from_errno(-ERFKILL);
+		mutex_lock(&rdev->devlist_mtx);
 		ret = cfg80211_can_add_interface(rdev, wdev->iftype);
+		mutex_unlock(&rdev->devlist_mtx);
 		if (ret)
 			return notifier_from_errno(ret);
 		cfg80211_lock_rdev(rdev);
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index b90fd86..ca5672f 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -118,6 +118,16 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 	wdev->wext.ibss.channel = params->channel;
 #endif
 	wdev->sme_state = CFG80211_SME_CONNECTING;
+
+	err = cfg80211_can_use_chan(rdev, wdev, params->channel,
+				    params->channel_fixed
+				    ? CHAN_MODE_SHARED
+				    : CHAN_MODE_EXCLUSIVE);
+	if (err) {
+		wdev->connect_keys = NULL;
+		return err;
+	}
+
 	err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
 	if (err) {
 		wdev->connect_keys = NULL;
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index bab3813..c384e77 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -155,6 +155,11 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 					  setup->channel_type))
 		return -EINVAL;
 
+	err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
+				    CHAN_MODE_SHARED);
+	if (err)
+		return err;
+
 	err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
 	if (!err) {
 		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -173,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
 
+	mutex_lock(&rdev->devlist_mtx);
 	wdev_lock(wdev);
 	err = __cfg80211_join_mesh(rdev, dev, setup, conf);
 	wdev_unlock(wdev);
+	mutex_unlock(&rdev->devlist_mtx);
 
 	return err;
 }
@@ -208,6 +215,11 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
 		if (!netif_running(wdev->netdev))
 			return -ENETDOWN;
 
+		err = cfg80211_can_use_chan(rdev, wdev, channel,
+					    CHAN_MODE_SHARED);
+		if (err)
+			return err;
+
 		err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
 							   wdev->netdev,
 							   channel);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index a7882eb..d4fece3 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -302,8 +302,14 @@ 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->ops->auth(&rdev->wiphy, dev, &req);
 
+out:
 	cfg80211_put_bss(req.bss);
 	return err;
 }
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 {
 	int err;
 
+	mutex_lock(&rdev->devlist_mtx);
 	wdev_lock(dev->ieee80211_ptr);
 	err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
 				   ssid, ssid_len, ie, ie_len,
 				   key, key_len, key_idx);
 	wdev_unlock(dev->ieee80211_ptr);
+	mutex_unlock(&rdev->devlist_mtx);
 
 	return err;
 }
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 		return -ENOENT;
 	}
 
+	err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
+				    CHAN_MODE_SHARED);
+	if (err)
+		goto out;
+
 	err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
 
+out:
 	if (err) {
 		if (was_connected)
 			wdev->sme_state = CFG80211_SME_CONNECTED;
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
 
+	mutex_lock(&rdev->devlist_mtx);
 	wdev_lock(wdev);
 	err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
 				    ssid, ssid_len, ie, ie_len, use_mfp, crypt,
 				    assoc_flags, ht_capa, ht_capa_mask);
 	wdev_unlock(wdev);
+	mutex_unlock(&rdev->devlist_mtx);
 
 	return err;
 }
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5d29ed1..77102e6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2478,6 +2478,14 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 					  params.channel_type))
 		return -EINVAL;
 
+	mutex_lock(&rdev->devlist_mtx);
+	err = cfg80211_can_use_chan(rdev, wdev, params.channel,
+				    CHAN_MODE_SHARED);
+	mutex_unlock(&rdev->devlist_mtx);
+
+	if (err)
+		return err;
+
 	err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
 	if (!err) {
 		wdev->preset_chan = params.channel;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 4713cea..a9260ac 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -805,8 +805,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 		return -EBUSY;
 
 	if (ntype != otype && netif_running(dev)) {
+		mutex_lock(&rdev->devlist_mtx);
 		err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
 						    ntype);
+		mutex_unlock(&rdev->devlist_mtx);
 		if (err)
 			return err;
 
@@ -956,6 +958,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 	int i, j;
 
 	ASSERT_RTNL();
+	lockdep_assert_held(&rdev->devlist_mtx);
 
 	/* Always allow software iftypes */
 	if (rdev->wiphy.software_iftypes & BIT(iftype))
@@ -979,7 +982,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 		break;
 	}
 
-	mutex_lock(&rdev->devlist_mtx);
 	list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
 		if (wdev_iter == wdev)
 			continue;
@@ -999,10 +1001,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 				if (!used_channels[i] || used_channels[i] == ch)
 					break;
 
-			if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) {
-				mutex_unlock(&rdev->devlist_mtx);
+			if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS)
 				return -EBUSY;
-			}
 
 			if (used_channels[i] == NULL) {
 				used_channels[i] = ch;
@@ -1018,7 +1018,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 		total++;
 		used_iftypes |= BIT(wdev_iter->iftype);
 	}
-	mutex_unlock(&rdev->devlist_mtx);
 
 	if (total == 1)
 		return 0;
-- 
1.7.0.4


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

* Re: [PATCH v2] respect channels in iface combinations
  2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
                   ` (12 preceding siblings ...)
  2012-06-29 10:47 ` [PATCH 13/13] cfg80211: respect iface combinations when starting operation Michal Kazior
@ 2012-06-29 12:22 ` Johannes Berg
  13 siblings, 0 replies; 22+ messages in thread
From: Johannes Berg @ 2012-06-29 12:22 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless

On Fri, 2012-06-29 at 12:46 +0200, Michal Kazior wrote:
> Hi,
> 
> The patchset introduces channel tracking per interface which is needed
> to start enforcing num_different_channels in interface combinations.
> Changes to monitor mode behaviour is also required for sane channel
> accounting (considering how mac80211 handles monitor interfaces).
> 
> This prepares cfg80211 for multi-channel operation.

All applied, thanks!

johannes


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

* Re: [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-06-29 10:47 ` [PATCH 06/13] cfg80211: track monitor interfaces count Michal Kazior
@ 2012-07-04 11:12   ` Johannes Berg
  2012-07-04 11:17     ` Johannes Berg
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2012-07-04 11:12 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Manoharan, Rajkumar

Hi Michal,

A few people noticed that these patches cause deadlocks. I think the
reason is that it's not allowed to lock the device here:

>  	case NETDEV_DOWN:
>  		dev_hold(dev);
> +		cfg80211_lock_rdev(rdev);

This causes a deadlock since the interface is set down inside mac80211
when inside a handler from cfg80211 already, or so.

johannes


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

* Re: [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-07-04 11:12   ` Johannes Berg
@ 2012-07-04 11:17     ` Johannes Berg
  2012-07-04 11:26       ` Johannes Berg
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2012-07-04 11:17 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Manoharan, Rajkumar

On Wed, 2012-07-04 at 13:12 +0200, Johannes Berg wrote:
> Hi Michal,
> 
> A few people noticed that these patches cause deadlocks. I think the
> reason is that it's not allowed to lock the device here:
> 
> >  	case NETDEV_DOWN:
> >  		dev_hold(dev);
> > +		cfg80211_lock_rdev(rdev);
> 
> This causes a deadlock since the interface is set down inside mac80211
> when inside a handler from cfg80211 already, or so.

I just reproduce it -- it's because we come from nl80211_del_interface()

johannes


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

* Re: [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-07-04 11:17     ` Johannes Berg
@ 2012-07-04 11:26       ` Johannes Berg
  2012-07-04 11:27         ` Johannes Berg
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2012-07-04 11:26 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Manoharan, Rajkumar

On Wed, 2012-07-04 at 13:17 +0200, Johannes Berg wrote:
> On Wed, 2012-07-04 at 13:12 +0200, Johannes Berg wrote:
> > Hi Michal,
> > 
> > A few people noticed that these patches cause deadlocks. I think the
> > reason is that it's not allowed to lock the device here:
> > 
> > >  	case NETDEV_DOWN:
> > >  		dev_hold(dev);
> > > +		cfg80211_lock_rdev(rdev);
> > 
> > This causes a deadlock since the interface is set down inside mac80211
> > when inside a handler from cfg80211 already, or so.
> 
> I just reproduce it -- it's because we come from nl80211_del_interface()

Ok ... we don't really need to hold the rdev lock since it's all under
rtnl. Can you please confirm this is safe?

http://p.sipsolutions.net/bde4760671f3e250.txt

johannes


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

* Re: [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-07-04 11:26       ` Johannes Berg
@ 2012-07-04 11:27         ` Johannes Berg
  2012-07-04 12:34           ` Michal Kazior
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2012-07-04 11:27 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, Manoharan, Rajkumar

On Wed, 2012-07-04 at 13:26 +0200, Johannes Berg wrote:
> On Wed, 2012-07-04 at 13:17 +0200, Johannes Berg wrote:
> > On Wed, 2012-07-04 at 13:12 +0200, Johannes Berg wrote:
> > > Hi Michal,
> > > 
> > > A few people noticed that these patches cause deadlocks. I think the
> > > reason is that it's not allowed to lock the device here:
> > > 
> > > >  	case NETDEV_DOWN:
> > > >  		dev_hold(dev);
> > > > +		cfg80211_lock_rdev(rdev);
> > > 
> > > This causes a deadlock since the interface is set down inside mac80211
> > > when inside a handler from cfg80211 already, or so.
> > 
> > I just reproduce it -- it's because we come from nl80211_del_interface()
> 
> Ok ... we don't really need to hold the rdev lock since it's all under
> rtnl. Can you please confirm this is safe?
> 
> http://p.sipsolutions.net/bde4760671f3e250.txt

I guess we can remove more locking:
http://p.sipsolutions.net/8a1b875a431e72a0.txt

johannes


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

* Re: [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-07-04 11:27         ` Johannes Berg
@ 2012-07-04 12:34           ` Michal Kazior
  2012-07-04 12:46             ` Rajkumar Manoharan
  0 siblings, 1 reply; 22+ messages in thread
From: Michal Kazior @ 2012-07-04 12:34 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Manoharan, Rajkumar

Johannes Berg wrote:
> On Wed, 2012-07-04 at 13:26 +0200, Johannes Berg wrote:
>> On Wed, 2012-07-04 at 13:17 +0200, Johannes Berg wrote:
>>> On Wed, 2012-07-04 at 13:12 +0200, Johannes Berg wrote:
>>>> Hi Michal,
>>>>
>>>> A few people noticed that these patches cause deadlocks. I think the
>>>> reason is that it's not allowed to lock the device here:
>>>>
>>>>>   	case NETDEV_DOWN:
>>>>>   		dev_hold(dev);
>>>>> +		cfg80211_lock_rdev(rdev);
>>>>
>>>> This causes a deadlock since the interface is set down inside mac80211
>>>> when inside a handler from cfg80211 already, or so.
>>>
>>> I just reproduce it -- it's because we come from nl80211_del_interface()
>>
>> Ok ... we don't really need to hold the rdev lock since it's all under
>> rtnl. Can you please confirm this is safe?
>>
>> http://p.sipsolutions.net/bde4760671f3e250.txt
>
> I guess we can remove more locking:
> http://p.sipsolutions.net/8a1b875a431e72a0.txt

I can't really test it right now, but it looks good to me.


-- 
Pozdrawiam / Best regards, Michal Kazior.


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

* Re: [PATCH 06/13] cfg80211: track monitor interfaces count
  2012-07-04 12:34           ` Michal Kazior
@ 2012-07-04 12:46             ` Rajkumar Manoharan
  0 siblings, 0 replies; 22+ messages in thread
From: Rajkumar Manoharan @ 2012-07-04 12:46 UTC (permalink / raw)
  To: Michal Kazior; +Cc: Johannes Berg, linux-wireless

On Wed, Jul 04, 2012 at 02:34:00PM +0200, Michal Kazior wrote:
> Johannes Berg wrote:
> >On Wed, 2012-07-04 at 13:26 +0200, Johannes Berg wrote:
> >>On Wed, 2012-07-04 at 13:17 +0200, Johannes Berg wrote:
> >>>On Wed, 2012-07-04 at 13:12 +0200, Johannes Berg wrote:
> >>>>Hi Michal,
> >>>>
> >>>>A few people noticed that these patches cause deadlocks. I think the
> >>>>reason is that it's not allowed to lock the device here:
> >>>>
> >>>>>  	case NETDEV_DOWN:
> >>>>>  		dev_hold(dev);
> >>>>>+		cfg80211_lock_rdev(rdev);
> >>>>
> >>>>This causes a deadlock since the interface is set down inside mac80211
> >>>>when inside a handler from cfg80211 already, or so.
> >>>
> >>>I just reproduce it -- it's because we come from nl80211_del_interface()
> >>
> >>Ok ... we don't really need to hold the rdev lock since it's all under
> >>rtnl. Can you please confirm this is safe?
> >>
> >>http://p.sipsolutions.net/bde4760671f3e250.txt
> >
> >I guess we can remove more locking:
> >http://p.sipsolutions.net/8a1b875a431e72a0.txt
> 
> I can't really test it right now, but it looks good to me.
> 
The patch fixes the issue. Works for me.

-Rajkumar

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

* [PATCH 11/13] cfg80211/mac80211: remove .get_channel
  2012-06-28 10:06 [PATCH] " Michal Kazior
@ 2012-06-28 10:07 ` Michal Kazior
  0 siblings, 0 replies; 22+ messages in thread
From: Michal Kazior @ 2012-06-28 10:07 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Michal Kazior

We do not need it anymore since cfg80211 tracks
monitor channel and monitor channel type.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 include/net/cfg80211.h     |    6 ------
 net/mac80211/cfg.c         |   11 -----------
 net/wireless/nl80211.c     |   15 +++++----------
 net/wireless/wext-compat.c |    9 ++-------
 4 files changed, 7 insertions(+), 34 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 120eae0..7672552 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1430,9 +1430,6 @@ struct cfg80211_gtk_rekey_data {
  *	be stored for when a monitor interface becomes active.
  * @set_monitor_enabled: Notify driver that there are only monitor
  *	interfaces running.
- * @get_channel: Get the current operating channel, should return %NULL if
- *	there's no single defined operating channel if for example the
- *	device implements channel hopping for multi-channel virtual interfaces.
  *
  * @scan: Request to do a scan. If returning zero, the scan request is given
  *	the driver, and will be valid until passed to cfg80211_scan_done().
@@ -1739,9 +1736,6 @@ struct cfg80211_ops {
 				  struct net_device *dev,
 				  u16 noack_map);
 
-	struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy,
-					       enum nl80211_channel_type *type);
-
 	int	(*get_et_sset_count)(struct wiphy *wiphy,
 				     struct net_device *dev, int sset);
 	void	(*get_et_stats)(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index df7332e..4efc1ff 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2933,16 +2933,6 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
 	return 0;
 }
 
-static struct ieee80211_channel *
-ieee80211_wiphy_get_channel(struct wiphy *wiphy,
-			    enum nl80211_channel_type *type)
-{
-	struct ieee80211_local *local = wiphy_priv(wiphy);
-
-	*type = local->_oper_channel_type;
-	return local->oper_channel;
-}
-
 static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -3026,7 +3016,6 @@ struct cfg80211_ops mac80211_config_ops = {
 	.tdls_oper = ieee80211_tdls_oper,
 	.tdls_mgmt = ieee80211_tdls_mgmt,
 	.probe_client = ieee80211_probe_client,
-	.get_channel = ieee80211_wiphy_get_channel,
 	.set_noack_map = ieee80211_set_noack_map,
 	.set_monitor_enabled = ieee80211_set_monitor_enabled,
 #ifdef CONFIG_PM
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5d36124..6773488 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1588,16 +1588,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			(cfg80211_rdev_list_generation << 2)))
 		goto nla_put_failure;
 
-	if (rdev->ops->get_channel) {
-		struct ieee80211_channel *chan;
-		enum nl80211_channel_type channel_type;
-
-		chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type);
-		if (chan &&
-		    (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
-				    chan->center_freq) ||
-		     nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    channel_type)))
+	if (rdev->monitor_channel) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+				rdev->monitor_channel->center_freq) ||
+		    nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				rdev->monitor_channel_type))
 			goto nla_put_failure;
 	}
 
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index bc87983..7df42f5 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-	struct ieee80211_channel *chan;
-	enum nl80211_channel_type channel_type;
 
 	switch (wdev->iftype) {
 	case NL80211_IFTYPE_STATION:
@@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
 	case NL80211_IFTYPE_ADHOC:
 		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
 	case NL80211_IFTYPE_MONITOR:
-		if (!rdev->ops->get_channel)
+		if (!rdev->monitor_channel)
 			return -EINVAL;
 
-		chan = rdev->ops->get_channel(wdev->wiphy, &channel_type);
-		if (!chan)
-			return -EINVAL;
-		freq->m = chan->center_freq;
+		freq->m = rdev->monitor_channel->center_freq;
 		freq->e = 6;
 		return 0;
 	default:
-- 
1.7.0.4


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

end of thread, other threads:[~2012-07-04 12:44 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-29 10:46 [PATCH v2] respect channels in iface combinations Michal Kazior
2012-06-29 10:46 ` [PATCH 01/13] cfg80211: introduce cfg80211_stop_ap Michal Kazior
2012-06-29 10:46 ` [PATCH 02/13] cfg80211: .stop_ap when interface is going down Michal Kazior
2012-06-29 10:46 ` [PATCH 03/13] cfg80211: add channel tracking for AP and mesh Michal Kazior
2012-06-29 10:46 ` [PATCH 04/13] cfg80211: track ibss fixed channel Michal Kazior
2012-06-29 10:47 ` [PATCH 05/13] cfg80211: introduce cfg80211_get_chan_state Michal Kazior
2012-06-29 10:47 ` [PATCH 06/13] cfg80211: track monitor interfaces count Michal Kazior
2012-07-04 11:12   ` Johannes Berg
2012-07-04 11:17     ` Johannes Berg
2012-07-04 11:26       ` Johannes Berg
2012-07-04 11:27         ` Johannes Berg
2012-07-04 12:34           ` Michal Kazior
2012-07-04 12:46             ` Rajkumar Manoharan
2012-06-29 10:47 ` [PATCH 07/13] mac80211: refactor virtual monitor code Michal Kazior
2012-06-29 10:47 ` [PATCH 08/13] cfg80211: refuse to .set_monitor_channel when non-monitors are present Michal Kazior
2012-06-29 10:47 ` [PATCH 09/13] cfg80211: track monitor channel Michal Kazior
2012-06-29 10:47 ` [PATCH 10/13] cfg80211: set initial " Michal Kazior
2012-06-29 10:47 ` [PATCH 11/13] cfg80211/mac80211: remove .get_channel Michal Kazior
2012-06-29 10:47 ` [PATCH 12/13] cfg80211: add channel checking for iface combinations Michal Kazior
2012-06-29 10:47 ` [PATCH 13/13] cfg80211: respect iface combinations when starting operation Michal Kazior
2012-06-29 12:22 ` [PATCH v2] respect channels in iface combinations Johannes Berg
  -- strict thread matches above, loose matches on Subject: below --
2012-06-28 10:06 [PATCH] " Michal Kazior
2012-06-28 10:07 ` [PATCH 11/13] cfg80211/mac80211: remove .get_channel Michal Kazior

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.