All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] mac80211: some more channel switch work
@ 2014-10-08  6:48 Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 1/7] nl80211: sanity check the channel switch counter value Luca Coelho
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

Hi,

A few minor changes in v2:

  * add WARN_ON to make sure csa_active is set in
    ieee80211_chswitch_post_beacon() [Michal];
  * remove stray empty line [Michal];
  * s/vifos/vif/ in a mac80211.h declaration (no clue where the "os"
    came from :P);

---8<---

These patches contain some more channel switch work.  They have been
in use in our internal tree for some time now and are mostly adding
small details needed by the iwlmvm driver.  There's also a nice
improvement to a long-time TODO, where we wait for a beacon on the new
channel before we start transmitting again (in BSS station/P2P client
mode).

One slightly controversial change is the one that allows channel
switches with multiple channel contexts.  The problem is not with
mult-context itself, but the handling of drivers that offload the
channel switch and have, so far, not received any information about
the vif that is switching (so the assumption was that all vifs would
have to switch).

Please review.

--
Cheers,
Luca.

Luciano Coelho (7):
  nl80211: sanity check the channel switch counter value
  mac80211: add device_timestamp to the ieee80211_channel_switch struct
  mac80211: add extended channel switching capability if the driver
    supports CSA
  mac80211: add pre_channel_switch driver operation
  mac80211: add post_channel_switch driver operation
  mac80211: wait for the first beacon on the new channel after CSA
  mac80211: allow channel switch with multiple channel contexts

 drivers/net/wireless/iwlegacy/4965-mac.c    |   2 +-
 drivers/net/wireless/iwlegacy/4965.h        |   5 +-
 drivers/net/wireless/iwlwifi/dvm/mac80211.c |   1 +
 drivers/net/wireless/ti/wlcore/main.c       |  23 ++----
 include/linux/ieee80211.h                   |   5 ++
 include/net/mac80211.h                      |  17 +++++
 net/mac80211/cfg.c                          |  18 ++++-
 net/mac80211/driver-ops.h                   |  41 ++++++++++-
 net/mac80211/ieee80211_i.h                  |   5 ++
 net/mac80211/iface.c                        |   2 +
 net/mac80211/main.c                         |  20 ++---
 net/mac80211/mlme.c                         | 110 ++++++++++++++++++----------
 net/mac80211/trace.h                        |  50 ++++++++++++-
 net/wireless/nl80211.c                      |  10 ++-
 14 files changed, 237 insertions(+), 72 deletions(-)

-- 
2.1.1


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

* [PATCH v2 1/7] nl80211: sanity check the channel switch counter value
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-09  9:25   ` Johannes Berg
  2014-10-08  6:48 ` [PATCH v2 2/7] mac80211: add device_timestamp to the ieee80211_channel_switch struct Luca Coelho
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

The nl80211 channel switch count attribute
(NL80211_ATTR_CH_SWITCH_COUNT) is specified as u32, but the
specification uses u8 for the counter.  To make sure strange things
don't happen without informing the user, sanity check the value and
return -EINVAL if it doesn't fit in u8.

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

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4cce3e1..9e29053 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5927,6 +5927,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 	int err;
 	bool need_new_beacon = false;
 	int len, i;
+	u32 cs_count;
 
 	if (!rdev->ops->channel_switch ||
 	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
@@ -5963,7 +5964,14 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 	if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
 		return -EINVAL;
 
-	params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
+	/* Even though the attribute is u32, the specification says
+	 * u8, so let's make sure we don't overflow.
+	 */
+	cs_count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
+	if (cs_count > 255)
+		return -EINVAL;
+
+	params.count = cs_count;
 
 	if (!need_new_beacon)
 		goto skip_beacons;
-- 
2.1.1


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

* [PATCH v2 2/7] mac80211: add device_timestamp to the ieee80211_channel_switch struct
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 1/7] nl80211: sanity check the channel switch counter value Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 3/7] mac80211: add extended channel switching capability if the driver supports CSA Luca Coelho
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

Some devices may need the device timestamp in order to synchronize the
channel switch.  To pass this value back to the driver, add it to the
channel switch structure and copy the device_timestamp value received
in the rx info structure into it.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 include/net/mac80211.h |  3 +++
 net/mac80211/mlme.c    | 15 ++++++++++-----
 net/mac80211/trace.h   |  2 ++
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 0ad1f47..ec0a5b0 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1117,6 +1117,8 @@ struct ieee80211_conf {
  *	Function (TSF) timer when the frame containing the channel switch
  *	announcement was received. This is simply the rx.mactime parameter
  *	the driver passed into mac80211.
+ * @device_timestamp: arbitrary timestamp for the device, this is the
+ *	rx.device_timestamp parameter the driver passed to mac80211.
  * @block_tx: Indicates whether transmission must be blocked before the
  *	scheduled channel switch, as indicated by the AP.
  * @chandef: the new channel to switch to
@@ -1124,6 +1126,7 @@ struct ieee80211_conf {
  */
 struct ieee80211_channel_switch {
 	u64 timestamp;
+	u32 device_timestamp;
 	bool block_tx;
 	struct cfg80211_chan_def chandef;
 	u8 count;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9d4ccb2..cb4d074 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1046,7 +1046,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 static void
 ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-				 u64 timestamp, struct ieee802_11_elems *elems,
+				 u64 timestamp, u32 device_timestamp,
+				 struct ieee802_11_elems *elems,
 				 bool beacon)
 {
 	struct ieee80211_local *local = sdata->local;
@@ -1154,6 +1155,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		/* use driver's channel switch callback */
 		struct ieee80211_channel_switch ch_switch = {
 			.timestamp = timestamp,
+			.device_timestamp = device_timestamp,
 			.block_tx = csa_ie.mode,
 			.chandef = csa_ie.chandef,
 			.count = csa_ie.count,
@@ -3203,6 +3205,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 
 	ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+					 rx_status->device_timestamp,
 					 &elems, true);
 
 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
@@ -3334,8 +3337,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 				break;
 
 			ieee80211_sta_process_chanswitch(sdata,
-							 rx_status->mactime,
-							 &elems, false);
+						 rx_status->mactime,
+						 rx_status->device_timestamp,
+						 &elems, false);
 		} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
 			ies_len = skb->len -
 				  offsetof(struct ieee80211_mgmt,
@@ -3356,8 +3360,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 				&mgmt->u.action.u.ext_chan_switch.data;
 
 			ieee80211_sta_process_chanswitch(sdata,
-							 rx_status->mactime,
-							 &elems, false);
+						 rx_status->mactime,
+						 rx_status->device_timestamp,
+						 &elems, false);
 		}
 		break;
 	}
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 38fae7e..853c440 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -995,6 +995,7 @@ TRACE_EVENT(drv_channel_switch,
 		LOCAL_ENTRY
 		CHANDEF_ENTRY
 		__field(u64, timestamp)
+		__field(u32, device_timestamp)
 		__field(bool, block_tx)
 		__field(u8, count)
 	),
@@ -1003,6 +1004,7 @@ TRACE_EVENT(drv_channel_switch,
 		LOCAL_ASSIGN;
 		CHANDEF_ASSIGN(&ch_switch->chandef)
 		__entry->timestamp = ch_switch->timestamp;
+		__entry->device_timestamp = ch_switch->device_timestamp;
 		__entry->block_tx = ch_switch->block_tx;
 		__entry->count = ch_switch->count;
 	),
-- 
2.1.1


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

* [PATCH v2 3/7] mac80211: add extended channel switching capability if the driver supports CSA
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 1/7] nl80211: sanity check the channel switch counter value Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 2/7] mac80211: add device_timestamp to the ieee80211_channel_switch struct Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 4/7] mac80211: add pre_channel_switch driver operation Luca Coelho
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

The Extended Channel Switching capability bit in the extended
capabilities element must be set if the driver supports CSA on
non-beaconing interfaces.

Since this capability needs to be set during driver registration, the
extended_capabiliities global variable needs to be moved to the local
structure so that it can be modified.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 include/linux/ieee80211.h  |  5 +++++
 net/mac80211/ieee80211_i.h |  3 +++
 net/mac80211/main.c        | 20 +++++++++++---------
 3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index b1be39c..5fab17b 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1998,6 +1998,11 @@ enum ieee80211_tdls_actioncode {
 	WLAN_TDLS_DISCOVERY_REQUEST = 10,
 };
 
+/* Extended Channel Switching capability to be set in the 1st byte of
+ * the @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING	BIT(2)
+
 /* Interworking capabilities are set in 7th bit of 4th byte of the
  * @WLAN_EID_EXT_CAPABILITY information element
  */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c2aaec4..a9cc491 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1307,6 +1307,9 @@ struct ieee80211_local {
 	/* virtual monitor interface */
 	struct ieee80211_sub_if_data __rcu *monitor_sdata;
 	struct cfg80211_chan_def monitor_chandef;
+
+	/* extended capabilities provided by mac80211 */
+	u8 ext_capa[8];
 };
 
 static inline struct ieee80211_sub_if_data *
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 0de7c93..107d1c8 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -478,11 +478,6 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
 	},
 };
 
-static const u8 extended_capabilities[] = {
-	0, 0, 0, 0, 0, 0, 0,
-	WLAN_EXT_CAPA8_OPMODE_NOTIF,
-};
-
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 					const struct ieee80211_ops *ops)
 {
@@ -539,10 +534,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 			WIPHY_FLAG_REPORTS_OBSS |
 			WIPHY_FLAG_OFFCHAN_TX;
 
-	wiphy->extended_capabilities = extended_capabilities;
-	wiphy->extended_capabilities_mask = extended_capabilities;
-	wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities);
-
 	if (ops->remain_on_channel)
 		wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
@@ -591,6 +582,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
 	wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
 
+	local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF;
+
+	wiphy->extended_capabilities = local->ext_capa;
+	wiphy->extended_capabilities_mask = local->ext_capa;
+	wiphy->extended_capabilities_len =
+		ARRAY_SIZE(local->ext_capa);
+
 	INIT_LIST_HEAD(&local->interfaces);
 
 	__hw_addr_init(&local->mc_list);
@@ -958,6 +956,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
 		local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
 
+	/* mac80211 supports eCSA, if the driver supports STA CSA at all */
+	if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)
+		local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
+
 	local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
 
 	result = wiphy_register(local->hw.wiphy);
-- 
2.1.1


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

* [PATCH v2 4/7] mac80211: add pre_channel_switch driver operation
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
                   ` (2 preceding siblings ...)
  2014-10-08  6:48 ` [PATCH v2 3/7] mac80211: add extended channel switching capability if the driver supports CSA Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 5/7] mac80211: add post_channel_switch " Luca Coelho
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

Some drivers may need to prepare for a channel switch also when it is
initiated from the remote side (eg. station, P2P client).  To make
this possible, add a generic callback that can be called for all
interface types.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 include/net/mac80211.h    |  7 +++++++
 net/mac80211/cfg.c        | 11 +++++++++++
 net/mac80211/driver-ops.h | 18 ++++++++++++++++++
 net/mac80211/mlme.c       | 25 +++++++++++++++++--------
 net/mac80211/trace.h      | 33 +++++++++++++++++++++++++++++++++
 5 files changed, 86 insertions(+), 8 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ec0a5b0..19e4159 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2832,6 +2832,10 @@ enum ieee80211_roc_type {
  *	transmitted and then call ieee80211_csa_finish().
  *	If the CSA count starts as zero or 1, this function will not be called,
  *	since there won't be any time to beacon before the switch anyway.
+ * @pre_channel_switch: This is an optional callback that is called
+ *	before a channel switch procedure is started (ie. when a STA
+ *	gets a CSA or an userspace initiated channel-switch), allowing
+ *	the driver to prepare for the channel switch.
  *
  * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
  *	information in bss_conf is set up and the beacon can be retrieved. A
@@ -3038,6 +3042,9 @@ struct ieee80211_ops {
 	void (*channel_switch_beacon)(struct ieee80211_hw *hw,
 				      struct ieee80211_vif *vif,
 				      struct cfg80211_chan_def *chandef);
+	int (*pre_channel_switch)(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_channel_switch *ch_switch);
 
 	int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 	void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fb6a150..2caa7f0 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3053,6 +3053,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_channel_switch ch_switch;
 	struct ieee80211_chanctx_conf *conf;
 	struct ieee80211_chanctx *chanctx;
 	int err, changed = 0;
@@ -3088,6 +3089,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		goto out;
 	}
 
+	err = drv_pre_channel_switch(sdata, &ch_switch);
+	if (err)
+		goto out;
+
 	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
 					    chanctx->mode,
 					    params->radar_required);
@@ -3101,6 +3106,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		goto out;
 	}
 
+	ch_switch.timestamp = 0;
+	ch_switch.device_timestamp = 0;
+	ch_switch.block_tx = params->block_tx;
+	ch_switch.chandef = params->chandef;
+	ch_switch.count = params->count;
+
 	err = ieee80211_set_csa_beacon(sdata, params, &changed);
 	if (err) {
 		ieee80211_vif_unreserve_chanctx(sdata);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 196d48c..5522672 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1196,6 +1196,24 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
 	}
 }
 
+static inline int
+drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
+		       struct ieee80211_channel_switch *ch_switch)
+{
+	struct ieee80211_local *local = sdata->local;
+	int ret = 0;
+
+	if (!check_sdata_in_driver(sdata))
+		return -EIO;
+
+	trace_drv_pre_channel_switch(local, sdata, ch_switch);
+	if (local->ops->pre_channel_switch)
+		ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif,
+						     ch_switch);
+	trace_drv_return_int(local, ret);
+	return ret;
+}
+
 static inline int drv_join_ibss(struct ieee80211_local *local,
 				struct ieee80211_sub_if_data *sdata)
 {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cb4d074..c5fa20f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1057,6 +1057,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_chanctx *chanctx;
 	enum ieee80211_band current_band;
 	struct ieee80211_csa_ie csa_ie;
+	struct ieee80211_channel_switch ch_switch;
 	int res;
 
 	sdata_assert_lock(sdata);
@@ -1128,6 +1129,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	ch_switch.timestamp = timestamp;
+	ch_switch.device_timestamp = device_timestamp;
+	ch_switch.block_tx = csa_ie.mode;
+	ch_switch.chandef = csa_ie.chandef;
+	ch_switch.count = csa_ie.count;
+
+	if (drv_pre_channel_switch(sdata, &ch_switch)) {
+		sdata_info(sdata,
+			   "preparing for channel switch failed, disconnecting\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		mutex_unlock(&local->chanctx_mtx);
+		mutex_unlock(&local->mtx);
+		return;
+	}
+
 	res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
 					    chanctx->mode, false);
 	if (res) {
@@ -1153,14 +1170,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
 	if (local->ops->channel_switch) {
 		/* use driver's channel switch callback */
-		struct ieee80211_channel_switch ch_switch = {
-			.timestamp = timestamp,
-			.device_timestamp = device_timestamp,
-			.block_tx = csa_ie.mode,
-			.chandef = csa_ie.chandef,
-			.count = csa_ie.count,
-		};
-
 		drv_channel_switch(local, &ch_switch);
 		return;
 	}
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 853c440..30476d2 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2108,6 +2108,39 @@ TRACE_EVENT(drv_channel_switch_beacon,
 	)
 );
 
+TRACE_EVENT(drv_pre_channel_switch,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_channel_switch *ch_switch),
+
+	TP_ARGS(local, sdata, ch_switch),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		CHANDEF_ENTRY
+		__field(u64, timestamp)
+		__field(bool, block_tx)
+		__field(u8, count)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		CHANDEF_ASSIGN(&ch_switch->chandef)
+		__entry->timestamp = ch_switch->timestamp;
+		__entry->block_tx = ch_switch->block_tx;
+		__entry->count = ch_switch->count;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to "
+		CHANDEF_PR_FMT  " count:%d block_tx:%d timestamp:%llu",
+		LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count,
+		__entry->block_tx, __entry->timestamp
+	)
+);
+
 
 #ifdef CONFIG_MAC80211_MESSAGE_TRACING
 #undef TRACE_SYSTEM
-- 
2.1.1


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

* [PATCH v2 5/7] mac80211: add post_channel_switch driver operation
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
                   ` (3 preceding siblings ...)
  2014-10-08  6:48 ` [PATCH v2 4/7] mac80211: add pre_channel_switch driver operation Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 6/7] mac80211: wait for the first beacon on the new channel after CSA Luca Coelho
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

As a counterpart to the pre_channel_switch operation, add a
post_channel_switch operation.  This allows the drivers to go back to
a normal configuration after the channel switch is completed.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 include/net/mac80211.h    |  6 ++++++
 net/mac80211/cfg.c        |  7 ++++++-
 net/mac80211/driver-ops.h | 16 ++++++++++++++++
 net/mac80211/mlme.c       |  9 +++++++++
 net/mac80211/trace.h      |  6 ++++++
 5 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 19e4159..7861ed8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2836,6 +2836,9 @@ enum ieee80211_roc_type {
  *	before a channel switch procedure is started (ie. when a STA
  *	gets a CSA or an userspace initiated channel-switch), allowing
  *	the driver to prepare for the channel switch.
+ * @post_channel_switch: This is an optional callback that is called
+ *	after a channel switch procedure is completed, allowing the
+ *	driver to go back to a normal configuration.
  *
  * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
  *	information in bss_conf is set up and the beacon can be retrieved. A
@@ -3046,6 +3049,9 @@ struct ieee80211_ops {
 				  struct ieee80211_vif *vif,
 				  struct ieee80211_channel_switch *ch_switch);
 
+	int (*post_channel_switch)(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif);
+
 	int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 	void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 	u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 2caa7f0..ce81ff2 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2868,7 +2868,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 		return err;
 
 	ieee80211_bss_info_change_notify(sdata, changed);
-	cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 
 	if (sdata->csa_block_tx) {
 		ieee80211_wake_vif_queues(local, sdata,
@@ -2876,6 +2875,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 		sdata->csa_block_tx = false;
 	}
 
+	err = drv_post_channel_switch(sdata);
+	if (err)
+		return err;
+
+	cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
 	return 0;
 }
 
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 5522672..0a60906 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1214,6 +1214,22 @@ drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
 	return ret;
 }
 
+static inline int
+drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	int ret = 0;
+
+	if (!check_sdata_in_driver(sdata))
+		return -EIO;
+
+	trace_drv_post_channel_switch(local, sdata);
+	if (local->ops->post_channel_switch)
+		ret = local->ops->post_channel_switch(&local->hw, &sdata->vif);
+	trace_drv_return_int(local, ret);
+	return ret;
+}
+
 static inline int drv_join_ibss(struct ieee80211_local *local,
 				struct ieee80211_sub_if_data *sdata)
 {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c5fa20f..2e29cc3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1010,6 +1010,15 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 		sdata->csa_block_tx = false;
 	}
 
+	ret = drv_post_channel_switch(sdata);
+	if (ret) {
+		sdata_info(sdata,
+			   "driver post channel switch failed, disconnecting\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		goto out;
+	}
+
 	ieee80211_sta_reset_beacon_monitor(sdata);
 	ieee80211_sta_reset_conn_monitor(sdata);
 
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 30476d2..ca0e12d 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2141,6 +2141,12 @@ TRACE_EVENT(drv_pre_channel_switch,
 	)
 );
 
+DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch,
+	     TP_PROTO(struct ieee80211_local *local,
+		      struct ieee80211_sub_if_data *sdata),
+	     TP_ARGS(local, sdata)
+);
+
 
 #ifdef CONFIG_MAC80211_MESSAGE_TRACING
 #undef TRACE_SYSTEM
-- 
2.1.1


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

* [PATCH v2 6/7] mac80211: wait for the first beacon on the new channel after CSA
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
                   ` (4 preceding siblings ...)
  2014-10-08  6:48 ` [PATCH v2 5/7] mac80211: add post_channel_switch " Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-08  6:48 ` [PATCH v2 7/7] mac80211: allow channel switch with multiple channel contexts Luca Coelho
  2014-10-09  9:30 ` [PATCH v2 0/7] mac80211: some more channel switch work Johannes Berg
  7 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

Instead of immediately reopening the queues (in case of block_tx),
calling the post_channel_switch operation and sending the
notification, wait for the first beacon on the new channel.  This
makes sure that we don't lose packets if the AP/GO is not on the new
channel yet.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/iface.c       |  2 ++
 net/mac80211/mlme.c        | 45 ++++++++++++++++++++++++++++++++-------------
 3 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a9cc491..78d6121 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -434,6 +434,8 @@ struct ieee80211_if_managed {
 
 	unsigned int flags;
 
+	bool csa_waiting_bcn;
+
 	bool beacon_crc_valid;
 	u32 beacon_crc;
 
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index af23722..e469b33 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -842,6 +842,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 	sdata_lock(sdata);
 	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+	if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		sdata->u.mgd.csa_waiting_bcn = false;
 	if (sdata->csa_block_tx) {
 		ieee80211_wake_vif_queues(local, sdata,
 					  IEEE80211_QUEUE_STOP_REASON_CSA);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2e29cc3..109812f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1001,31 +1001,44 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 	/* XXX: shouldn't really modify cfg80211-owned data! */
 	ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-	sdata->vif.csa_active = false;
+	ifmgd->csa_waiting_bcn = true;
+
+	ieee80211_sta_reset_beacon_monitor(sdata);
+	ieee80211_sta_reset_conn_monitor(sdata);
+
+out:
+	mutex_unlock(&local->chanctx_mtx);
+	mutex_unlock(&local->mtx);
+	sdata_unlock(sdata);
+}
+
+static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	int ret;
+
+	sdata_assert_lock(sdata);
+
+	WARN_ON(!sdata->vif.csa_active);
 
-	/* XXX: wait for a beacon first? */
 	if (sdata->csa_block_tx) {
 		ieee80211_wake_vif_queues(local, sdata,
 					  IEEE80211_QUEUE_STOP_REASON_CSA);
 		sdata->csa_block_tx = false;
 	}
 
+	sdata->vif.csa_active = false;
+	ifmgd->csa_waiting_bcn = false;
+
 	ret = drv_post_channel_switch(sdata);
 	if (ret) {
 		sdata_info(sdata,
 			   "driver post channel switch failed, disconnecting\n");
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
-		goto out;
+		return;
 	}
-
-	ieee80211_sta_reset_beacon_monitor(sdata);
-	ieee80211_sta_reset_conn_monitor(sdata);
-
-out:
-	mutex_unlock(&local->chanctx_mtx);
-	mutex_unlock(&local->mtx);
-	sdata_unlock(sdata);
 }
 
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
@@ -1943,6 +1956,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	ieee80211_vif_release_channel(sdata);
 
 	sdata->vif.csa_active = false;
+	ifmgd->csa_waiting_bcn = false;
 	if (sdata->csa_block_tx) {
 		ieee80211_wake_vif_queues(local, sdata,
 					  IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -2191,6 +2205,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
 			       true, frame_buf);
 	mutex_lock(&local->mtx);
 	sdata->vif.csa_active = false;
+	ifmgd->csa_waiting_bcn = false;
 	if (sdata->csa_block_tx) {
 		ieee80211_wake_vif_queues(local, sdata,
 					  IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3215,6 +3230,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	if (ifmgd->csa_waiting_bcn)
+		ieee80211_chswitch_post_beacon(sdata);
+
 	if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
 		return;
 	ifmgd->beacon_crc = ncrc;
@@ -3687,11 +3705,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
 	struct ieee80211_sub_if_data *sdata =
 		(struct ieee80211_sub_if_data *) data;
 	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
 	if (local->quiescing)
 		return;
 
-	if (sdata->vif.csa_active)
+	if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
 		return;
 
 	sdata->u.mgd.connection_loss = false;
@@ -3709,7 +3728,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
 	if (local->quiescing)
 		return;
 
-	if (sdata->vif.csa_active)
+	if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
 		return;
 
 	ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
-- 
2.1.1


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

* [PATCH v2 7/7] mac80211: allow channel switch with multiple channel contexts
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
                   ` (5 preceding siblings ...)
  2014-10-08  6:48 ` [PATCH v2 6/7] mac80211: wait for the first beacon on the new channel after CSA Luca Coelho
@ 2014-10-08  6:48 ` Luca Coelho
  2014-10-09  9:30 ` [PATCH v2 0/7] mac80211: some more channel switch work Johannes Berg
  7 siblings, 0 replies; 10+ messages in thread
From: Luca Coelho @ 2014-10-08  6:48 UTC (permalink / raw)
  To: johannes; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

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

Channel switch with multiple channel contexts should now work fine.
Remove check that disallows switches when multiple contexts are in
use.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
---
Note: the driver changes are only compile-tested.
---
 drivers/net/wireless/iwlegacy/4965-mac.c    |  2 +-
 drivers/net/wireless/iwlegacy/4965.h        |  5 +++--
 drivers/net/wireless/iwlwifi/dvm/mac80211.c |  1 +
 drivers/net/wireless/ti/wlcore/main.c       | 23 ++++++++---------------
 include/net/mac80211.h                      |  1 +
 net/mac80211/driver-ops.h                   |  7 ++++---
 net/mac80211/mlme.c                         | 26 ++++++++++----------------
 net/mac80211/trace.h                        |  9 ++++++---
 8 files changed, 34 insertions(+), 40 deletions(-)

diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 9f930a0..42c4e39 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -6063,7 +6063,7 @@ il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 }
 
 void
-il4965_mac_channel_switch(struct ieee80211_hw *hw,
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			  struct ieee80211_channel_switch *ch_switch)
 {
 	struct il_priv *il = hw->priv;
diff --git a/drivers/net/wireless/iwlegacy/4965.h b/drivers/net/wireless/iwlegacy/4965.h
index 337dfcf..3a57f71 100644
--- a/drivers/net/wireless/iwlegacy/4965.h
+++ b/drivers/net/wireless/iwlegacy/4965.h
@@ -187,8 +187,9 @@ int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			    u8 buf_size);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta);
-void il4965_mac_channel_switch(struct ieee80211_hw *hw,
-			       struct ieee80211_channel_switch *ch_switch);
+void
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			  struct ieee80211_channel_switch *ch_switch);
 
 void il4965_led_enable(struct il_priv *il);
 
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 2364a3c..a967bf8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -941,6 +941,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
 }
 
 static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
 				      struct ieee80211_channel_switch *ch_switch)
 {
 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 575c8f6..6ad3fce 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5177,10 +5177,11 @@ out:
 }
 
 static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
 				     struct ieee80211_channel_switch *ch_switch)
 {
 	struct wl1271 *wl = hw->priv;
-	struct wl12xx_vif *wlvif;
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int ret;
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
@@ -5190,14 +5191,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 	mutex_lock(&wl->mutex);
 
 	if (unlikely(wl->state == WLCORE_STATE_OFF)) {
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
-			if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-				continue;
-
+		if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 			ieee80211_chswitch_done(vif, false);
-		}
 		goto out;
 	} else if (unlikely(wl->state != WLCORE_STATE_ON)) {
 		goto out;
@@ -5208,11 +5203,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 		goto out;
 
 	/* TODO: change mac80211 to pass vif as param */
-	wl12xx_for_each_wlvif_sta(wl, wlvif) {
-		unsigned long delay_usec;
 
-		if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-			continue;
+	if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
+		unsigned long delay_usec;
 
 		ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
 		if (ret)
@@ -5222,10 +5215,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
 		/* indicate failure 5 seconds after channel switch time */
 		delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
-			     ch_switch->count;
+			ch_switch->count;
 		ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
-				usecs_to_jiffies(delay_usec) +
-				msecs_to_jiffies(5000));
+					     usecs_to_jiffies(delay_usec) +
+					     msecs_to_jiffies(5000));
 	}
 
 out_sleep:
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 7861ed8..9bb2fc7 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2969,6 +2969,7 @@ struct ieee80211_ops {
 	void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		      u32 queues, bool drop);
 	void (*channel_switch)(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
 			       struct ieee80211_channel_switch *ch_switch);
 	int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
 	int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 0a60906..1bbb079 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -764,12 +764,13 @@ static inline void drv_flush(struct ieee80211_local *local,
 }
 
 static inline void drv_channel_switch(struct ieee80211_local *local,
-				     struct ieee80211_channel_switch *ch_switch)
+				      struct ieee80211_sub_if_data *sdata,
+				      struct ieee80211_channel_switch *ch_switch)
 {
 	might_sleep();
 
-	trace_drv_channel_switch(local, ch_switch);
-	local->ops->channel_switch(&local->hw, ch_switch);
+	trace_drv_channel_switch(local, sdata, ch_switch);
+	local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch);
 	trace_drv_return_void(local);
 }
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 109812f..28baccb 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1134,21 +1134,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-	if (local->use_chanctx) {
-		u32 num_chanctx = 0;
-		list_for_each_entry(chanctx, &local->chanctx_list, list)
-		       num_chanctx++;
-
-		if (num_chanctx > 1 ||
-		    !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
-			sdata_info(sdata,
-				   "not handling chan-switch with channel contexts\n");
-			ieee80211_queue_work(&local->hw,
-					     &ifmgd->csa_connection_drop_work);
-			mutex_unlock(&local->chanctx_mtx);
-			mutex_unlock(&local->mtx);
-			return;
-		}
+	if (local->use_chanctx &&
+	    !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+		sdata_info(sdata,
+			   "driver doesn't support chan-switch with channel contexts\n");
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+		mutex_unlock(&local->chanctx_mtx);
+		mutex_unlock(&local->mtx);
+		return;
 	}
 
 	ch_switch.timestamp = timestamp;
@@ -1192,7 +1186,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
 	if (local->ops->channel_switch) {
 		/* use driver's channel switch callback */
-		drv_channel_switch(local, &ch_switch);
+		drv_channel_switch(local, sdata, &ch_switch);
 		return;
 	}
 
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index ca0e12d..976606a 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -987,12 +987,14 @@ TRACE_EVENT(drv_flush,
 
 TRACE_EVENT(drv_channel_switch,
 	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
 		 struct ieee80211_channel_switch *ch_switch),
 
-	TP_ARGS(local, ch_switch),
+	TP_ARGS(local, sdata, ch_switch),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
+		VIF_ENTRY
 		CHANDEF_ENTRY
 		__field(u64, timestamp)
 		__field(u32, device_timestamp)
@@ -1002,6 +1004,7 @@ TRACE_EVENT(drv_channel_switch,
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
+		VIF_ASSIGN;
 		CHANDEF_ASSIGN(&ch_switch->chandef)
 		__entry->timestamp = ch_switch->timestamp;
 		__entry->device_timestamp = ch_switch->device_timestamp;
@@ -1010,8 +1013,8 @@ TRACE_EVENT(drv_channel_switch,
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
-		LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
+		LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count
 	)
 );
 
-- 
2.1.1


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

* Re: [PATCH v2 1/7] nl80211: sanity check the channel switch counter value
  2014-10-08  6:48 ` [PATCH v2 1/7] nl80211: sanity check the channel switch counter value Luca Coelho
@ 2014-10-09  9:25   ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2014-10-09  9:25 UTC (permalink / raw)
  To: Luca Coelho; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

On Wed, 2014-10-08 at 09:48 +0300, Luca Coelho wrote:
> From: Luciano Coelho <luciano.coelho@intel.com>
> 
> The nl80211 channel switch count attribute
> (NL80211_ATTR_CH_SWITCH_COUNT) is specified as u32, but the
> specification uses u8 for the counter.  To make sure strange things
> don't happen without informing the user, sanity check the value and
> return -EINVAL if it doesn't fit in u8.

Applied for 3.18.

johannes


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

* Re: [PATCH v2 0/7] mac80211: some more channel switch work
  2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
                   ` (6 preceding siblings ...)
  2014-10-08  6:48 ` [PATCH v2 7/7] mac80211: allow channel switch with multiple channel contexts Luca Coelho
@ 2014-10-09  9:30 ` Johannes Berg
  7 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2014-10-09  9:30 UTC (permalink / raw)
  To: Luca Coelho; +Cc: emmanuel.grumbach, michal.kazior, linux-wireless

All applied.

johannes


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

end of thread, other threads:[~2014-10-09  9:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-08  6:48 [PATCH v2 0/7] mac80211: some more channel switch work Luca Coelho
2014-10-08  6:48 ` [PATCH v2 1/7] nl80211: sanity check the channel switch counter value Luca Coelho
2014-10-09  9:25   ` Johannes Berg
2014-10-08  6:48 ` [PATCH v2 2/7] mac80211: add device_timestamp to the ieee80211_channel_switch struct Luca Coelho
2014-10-08  6:48 ` [PATCH v2 3/7] mac80211: add extended channel switching capability if the driver supports CSA Luca Coelho
2014-10-08  6:48 ` [PATCH v2 4/7] mac80211: add pre_channel_switch driver operation Luca Coelho
2014-10-08  6:48 ` [PATCH v2 5/7] mac80211: add post_channel_switch " Luca Coelho
2014-10-08  6:48 ` [PATCH v2 6/7] mac80211: wait for the first beacon on the new channel after CSA Luca Coelho
2014-10-08  6:48 ` [PATCH v2 7/7] mac80211: allow channel switch with multiple channel contexts Luca Coelho
2014-10-09  9:30 ` [PATCH v2 0/7] mac80211: some more channel switch work Johannes Berg

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.