Discussion:
[PATCH 1/5] mac80211: process the CSA frame for mesh accordingly
(too old to reply)
Chun-Yeow Yeoh
2013-09-13 23:36:08 UTC
Permalink
Process the CSA frame according to the procedures define in IEEE Std
802.11-2012 section 10.9.8.4.3 as follow:
* The mesh channel switch parameters element (MCSP) must be availabe.
* If the MCSP's TTL is 1, drop the frame but still process the CSA.
* If the MCSP's precedence value is less than or equal to the current
precedence value, drop the frame and do not process the CSA.
* The CSA frame is forwarded after TTL is decremented by 1 and the
initiator field is set to 0. Transmit restrict field and others
are maintained as is.
* No beacon or probe response frame are handled here.

Also, introduce the debug message used for mesh CSA purpose.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow-W/***@public.gmane.org>
---
include/linux/ieee80211.h | 20 +++++++++++
net/mac80211/Kconfig | 11 ++++++
net/mac80211/debug.h | 10 ++++++
net/mac80211/ieee80211_i.h | 4 +++
net/mac80211/mesh.c | 83 ++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/util.c | 9 +++++
6 files changed, 134 insertions(+), 3 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 23a8877..f117427 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -696,6 +696,18 @@ struct ieee80211_sec_chan_offs_ie {
} __packed;

/**
+ * struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE
+ *
+ * This structure represents the "Mesh Channel Switch Paramters element"
+ */
+struct ieee80211_mesh_chansw_params_ie {
+ u8 mesh_ttl;
+ u8 mesh_flags;
+ __le16 mesh_reason;
+ __le16 mesh_pre_value;
+} __packed;
+
+/**
* struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE
*/
struct ieee80211_wide_bw_chansw_ie {
@@ -750,6 +762,14 @@ enum mesh_config_capab_flags {
};

/**
+ * mesh channel switch parameters element's flag indicator
+ *
+ */
+#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0)
+#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1)
+#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2)
+
+/**
* struct ieee80211_rann_ie
*
* This structure refers to "Root Announcement information element"
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 62535fe..bf1871e 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -258,6 +258,17 @@ config MAC80211_MESH_SYNC_DEBUG

Do not select this option.

+config MAC80211_MESH_CSA_DEBUG
+ bool "Verbose mesh channel switch debugging"
+ depends on MAC80211_DEBUG_MENU
+ depends on MAC80211_MESH
+ ---help---
+ Selecting this option causes mac80211 to print out very verbose mesh
+ channel switch debugging messages (when mac80211 is taking part in a
+ mesh network).
+
+ Do not select this option.
+
config MAC80211_MESH_PS_DEBUG
bool "Verbose mesh powersave debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 4ccc5ed..493d680 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -44,6 +44,12 @@
#define MAC80211_MESH_SYNC_DEBUG 0
#endif

+#ifdef CONFIG_MAC80211_MESH_CSA_DEBUG
+#define MAC80211_MESH_CSA_DEBUG 1
+#else
+#define MAC80211_MESH_CSA_DEBUG 0
+#endif
+
#ifdef CONFIG_MAC80211_MESH_PS_DEBUG
#define MAC80211_MESH_PS_DEBUG 1
#else
@@ -157,6 +163,10 @@ do { \
_sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \
sdata, fmt, ##__VA_ARGS__)

+#define mcsa_dbg(sdata, fmt, ...) \
+ _sdata_dbg(MAC80211_MESH_CSA_DEBUG, \
+ sdata, fmt, ##__VA_ARGS__)
+
#define mps_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_MESH_PS_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3a87c89..7f13b65 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -598,6 +598,9 @@ struct ieee80211_if_mesh {
int ps_peers_light_sleep;
int ps_peers_deep_sleep;
struct ps_data ps;
+ /* Channel Switching Support */
+ bool chsw_init;
+ u16 pre_value;
};

#ifdef CONFIG_MAC80211_MESH
@@ -1239,6 +1242,7 @@ struct ieee802_11_elems {
const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
+ const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;

/* length of them, respectively */
u8 ssid_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 707ac61..308ef98 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -920,6 +920,82 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
stype, mgmt, &elems, rx_status);
}

+static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee80211_mgmt *mgmt_fwd;
+ struct sk_buff *skb;
+ struct ieee80211_local *local = sdata->local;
+ u8 *pos = mgmt->u.action.u.chan_switch.variable;
+ size_t offset_ttl;
+
+ skb = dev_alloc_skb(local->tx_headroom + len);
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->tx_headroom);
+ mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
+
+ /* offset_ttl is based on whether the secondary channel
+ * offset is available or not. Substract 1 from the mesh TTL
+ * and disable the initiator flag before forwarding.
+ */
+ offset_ttl = (len < 42) ? 7 : 10;
+ *(pos + offset_ttl) -= 1;
+ *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+
+ memcpy(mgmt_fwd, mgmt, len);
+ eth_broadcast_addr(mgmt_fwd->da);
+ memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
+ memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
+
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+}
+
+static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee802_11_elems elems;
+ u16 pre_value;
+ bool block_tx, fwd_csa = true;
+ size_t baselen;
+ u8 *pos, ttl;
+
+ if (mgmt->u.action.u.measurement.action_code !=
+ WLAN_ACTION_SPCT_CHL_SWITCH)
+ return;
+
+ pos = mgmt->u.action.u.chan_switch.variable;
+ baselen = offsetof(struct ieee80211_mgmt,
+ u.action.u.chan_switch.variable);
+ ieee802_11_parse_elems(pos, len - baselen, false, &elems);
+
+ ttl = elems.mesh_chansw_params_ie->mesh_ttl;
+ if (!--ttl)
+ fwd_csa = false;
+
+ pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
+ if (ifmsh->pre_value >= pre_value)
+ return;
+
+ ifmsh->pre_value = pre_value;
+
+ /* forward or re-broadcast the CSA frame */
+ if (fwd_csa) {
+ if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
+ mcsa_dbg(sdata, "Failed to forward the CSA frame");
+ }
+
+ /* block the Tx only after fowarding the CSA frame if required */
+ block_tx = !!(elems.mesh_chansw_params_ie->mesh_flags
+ & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT);
+ if (block_tx)
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+}
+
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
@@ -939,6 +1015,9 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
if (mesh_action_is_path_sel(mgmt))
mesh_rx_path_sel_frame(sdata, mgmt, len);
break;
+ case WLAN_CATEGORY_SPECTRUM_MGMT:
+ mesh_rx_csa_frame(sdata, mgmt, len);
+ break;
}
}

@@ -1056,13 +1135,11 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);

ifmsh->accepting_plinks = true;
- ifmsh->preq_id = 0;
- ifmsh->sn = 0;
- ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
ifmsh->next_perr = jiffies;
+ ifmsh->chsw_init = false;
/* Allocate all mesh structures when creating the first mesh interface. */
if (!mesh_allocated)
ieee80211s_init();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3c8283b..133667c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -743,6 +743,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case WLAN_EID_TIMEOUT_INTERVAL:
case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
+ case WLAN_EID_CHAN_SWITCH_PARAM:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
@@ -908,6 +909,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems->sec_chan_offs = (void *)pos;
break;
+ case WLAN_EID_CHAN_SWITCH_PARAM:
+ if (elen !=
+ sizeof(*elems->mesh_chansw_params_ie)) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->mesh_chansw_params_ie = (void *)pos;
+ break;
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
if (!action ||
elen != sizeof(*elems->wide_bw_chansw_ie)) {
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-09-13 23:36:10 UTC
Permalink
Support the adding of CSA and MCSP elements while building the beacon
for mesh if necessary. This is defined in the IEEE Std 802.11-2012
section 10.9.8.4.3 that both CSA and MCSP elements must be included
in beacon and probe response frames until the intended channel
switch time.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow-W/***@public.gmane.org>
---
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mesh.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 829ff7e..f10907f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -599,7 +599,9 @@ struct ieee80211_if_mesh {
int ps_peers_deep_sleep;
struct ps_data ps;
/* Channel Switching Support */
+ struct cfg80211_csa_settings *csa_settings;
bool chsw_init;
+ u8 chsw_ttl;
u16 pre_value;
};

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 308ef98..a839ab9 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -624,6 +624,10 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)

head_len = hdr_len +
2 + /* NULL SSID */
+ /* Channel Switch Announcement */
+ 2 + sizeof(struct ieee80211_channel_sw_ie) +
+ /* Mesh Channel Swith Parameters */
+ 2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
2 + 8 + /* supported rates */
2 + 3; /* DS params */
tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -665,6 +669,36 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;

+ if (ifmsh->csa_settings) {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ __le16 pre_value;
+
+ pos = skb_put(skb, 13);
+ memset(pos, 0, 13);
+ *pos++ = WLAN_EID_CHANNEL_SWITCH;
+ *pos++ = 3;
+ *pos++ = 0x0;
+ *pos++ = ieee80211_frequency_to_channel(
+ ifmsh->csa_settings->chandef.chan->center_freq);
+ sdata->csa_counter_offset_beacon = hdr_len + 6;
+ *pos++ = ifmsh->csa_settings->count;
+ *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
+ *pos++ = 6;
+ if (ifmsh->chsw_init) {
+ *pos++ = ifmsh->mshcfg.dot11MeshTTL;
+ *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+ } else {
+ *pos++ = ifmsh->chsw_ttl;
+ }
+ *pos++ |= ifmsh->csa_settings->block_tx ?
+ WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+ put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
+ pos += 2;
+ pre_value = cpu_to_le16(ifmsh->pre_value);
+ memcpy(pos, &pre_value, 2);
+ pos += 2;
+ }
+
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(sdata, skb))
goto out_free;
@@ -942,6 +976,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
offset_ttl = (len < 42) ? 7 : 10;
*(pos + offset_ttl) -= 1;
*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+ sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);

memcpy(mgmt_fwd, mgmt, len);
eth_broadcast_addr(mgmt_fwd->da);
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
2013-10-01 11:25:31 UTC
Permalink
Subject should probably just say "add", not "adding".

Should this patch be before the other one so userspace can't trigger an
invalid CSA thing inbetween the two patches?


> + if (ifmsh->csa_settings) {

> + *pos++ = ieee80211_frequency_to_channel(
> + ifmsh->csa_settings->chandef.chan->center_freq);

Why is that csa_settings access not racy?

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-10-01 22:39:01 UTC
Permalink
> Should this patch be before the other one so userspace can't trigger an
> invalid CSA thing inbetween the two patches?
Nope, this is related to add the new CSA IE elements to beacon. With
the first two patches, the userspace is already able to generate a
valid CSA action frame to trigger channel switch attempt on the mesh
network.

> Why is that csa_settings access not racy?
I will take a look on this.

--- Chun-Yeow
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-09-13 23:36:09 UTC
Permalink
Allow the triggering of CSA frame using mesh interface. The
rules are more or less same with IBSS, such as not allowed to
change between the band and channel width has to be same from
the previous mode. Also, move the ieee80211_send_action_csa
to a common space so that it can be re-used by mesh interface.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow-W/***@public.gmane.org>
---
net/mac80211/cfg.c | 19 ++++++++++
net/mac80211/ibss.c | 54 ---------------------------
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/util.c | 88 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.c | 1 +
5 files changed, 110 insertions(+), 54 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b455e72..438c689 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2907,6 +2907,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
+ struct ieee80211_if_mesh *ifmsh;
int err, num_chanctx;

if (!list_empty(&local->roc_list) || local->scanning)
@@ -2990,6 +2991,24 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if (err < 0)
return err;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ ifmsh = &sdata->u.mesh;
+
+ if (!ifmsh->mesh_id)
+ return -EINVAL;
+
+ if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
+ return -EINVAL;
+
+ /* changes into another band are not supported */
+ if (sdata->vif.bss_conf.chandef.chan->band !=
+ params->chandef.chan->band)
+ return -EINVAL;
+
+ err = ieee80211_send_action_csa(sdata, params);
+ if (err < 0)
+ return err;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 5ea9b3a..017e206 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -428,60 +428,6 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
tsf, false);
}

-static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings)
-{
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_local *local = sdata->local;
- int freq;
- int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
- sizeof(mgmt->u.action.u.chan_switch);
- u8 *pos;
-
- skb = dev_alloc_skb(local->tx_headroom + hdr_len +
- 5 + /* channel switch announcement element */
- 3); /* secondary channel offset element */
- if (!skb)
- return -1;
-
- skb_reserve(skb, local->tx_headroom);
- mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
- memset(mgmt, 0, hdr_len);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- eth_broadcast_addr(mgmt->da);
- memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
- memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
- mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
- mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
- pos = skb_put(skb, 5);
- *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
- *pos++ = 3; /* IE length */
- *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
- freq = csa_settings->chandef.chan->center_freq;
- *pos++ = ieee80211_frequency_to_channel(freq); /* channel */
- *pos++ = csa_settings->count; /* count */
-
- if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
- enum nl80211_channel_type ch_type;
-
- skb_put(skb, 3);
- *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
- *pos++ = 1; /* IE length */
- ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
- if (ch_type == NL80211_CHAN_HT40PLUS)
- *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- else
- *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- }
-
- ieee80211_tx_skb(sdata, skb);
- return 0;
-}
-
int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *csa_settings)
{
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7f13b65..829ff7e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1714,6 +1714,8 @@ void ieee80211_dfs_cac_timer(unsigned long data);
void ieee80211_dfs_cac_timer_work(struct work_struct *work);
void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
void ieee80211_dfs_radar_detected_work(struct work_struct *work);
+int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings);

#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 133667c..c013cc4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2361,3 +2361,91 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)

return ret;
}
+
+int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings)
+{
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_local *local = sdata->local;
+ int freq;
+ int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
+ sizeof(mgmt->u.action.u.chan_switch);
+ u8 *pos;
+
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
+
+ skb = dev_alloc_skb(local->tx_headroom + hdr_len +
+ 5 + /* channel switch announcement element */
+ 3 + /* secondary channel offset element */
+ 8); /* mesh channel switch parameters element */
+ if (!skb)
+ return -1;
+
+ skb_reserve(skb, local->tx_headroom);
+ mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
+ memset(mgmt, 0, hdr_len);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ eth_broadcast_addr(mgmt->da);
+ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+ } else {
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
+ }
+ mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+ mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
+ pos = skb_put(skb, 5);
+ *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
+ *pos++ = 3; /* IE length */
+ *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
+ freq = csa_settings->chandef.chan->center_freq;
+ *pos++ = ieee80211_frequency_to_channel(freq); /* channel */
+ *pos++ = csa_settings->count; /* count */
+
+ if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
+ enum nl80211_channel_type ch_type;
+
+ skb_put(skb, 3);
+ *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
+ *pos++ = 1; /* IE length */
+ ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
+ if (ch_type == NL80211_CHAN_HT40PLUS)
+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ else
+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ }
+
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ __le16 pre_value;
+
+ skb_put(skb, 8);
+ *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
+ *pos++ = 6; /* IE length */
+ *pos++ = sdata->u.mesh.mshcfg.dot11MeshTTL; /* Mesh TTL */
+ *pos = 0x00; /* Mesh Flag: Tx Restrict, Initiator, Reason */
+ *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+ *pos++ |= csa_settings->block_tx ?
+ WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+ put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
+ pos += 2;
+ if (!ifmsh->pre_value)
+ ifmsh->pre_value = 1;
+ else
+ ifmsh->pre_value++;
+ pre_value = cpu_to_le16(ifmsh->pre_value);
+ memcpy(pos, &pre_value, 2); /* Precedence Value */
+ pos += 2;
+ ifmsh->chsw_init = true;
+ }
+
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+}
+
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index da8de5b..7bb5aca 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5650,6 +5650,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
break;
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
break;
default:
return -EOPNOTSUPP;
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
2013-10-01 11:24:04 UTC
Permalink
On Fri, 2013-09-13 at 16:36 -0700, Chun-Yeow Yeoh wrote:
> + skb = dev_alloc_skb(local->tx_headroom + hdr_len +
> + 5 + /* channel switch announcement element */
> + 3 + /* secondary channel offset element */
> + 8); /* mesh channel switch parameters element */
> + if (!skb)
> + return -1;

please fix that to -ENOMEM while at it

> +}
> +

Please no blank line at EOF

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-09-13 23:36:11 UTC
Permalink
Finalizing the requried procedures for channel switching completion and
also adding the function for updating the beacon and probe response frames
with CSA and MCSP elements. Once the channel switching is completed, the
CSA and MCSP elements are removed from the beacon or probe response frames
as defined in the IEEE Std 802.11-2012 section 10.9.8.4.3.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow-W/***@public.gmane.org>
---
net/mac80211/cfg.c | 7 +++++-
net/mac80211/ieee80211_i.h | 4 ++++
net/mac80211/mesh.c | 54 ++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/rx.c | 5 +++-
net/mac80211/tx.c | 16 +++++++++++++
net/wireless/nl80211.c | 3 ++-
6 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 438c689..a0b41d7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2887,6 +2887,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_finish_csa(sdata);
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ err = ieee80211_mesh_finish_csa(sdata);
+ if (err < 0)
+ return;
+ break;
default:
WARN_ON(1);
return;
@@ -3005,7 +3010,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
params->chandef.chan->band)
return -EINVAL;

- err = ieee80211_send_action_csa(sdata, params);
+ err = ieee80211_mesh_csa_beacon(sdata, params, true);
if (err < 0)
return err;
break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f10907f..48da719 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1345,6 +1345,10 @@ void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings,
+ bool csa_action);
+int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);

/* scan/BSS handling */
void ieee80211_scan_work(struct work_struct *work);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index a839ab9..2f756dd 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,6 +12,7 @@
#include <asm/unaligned.h>
#include "ieee80211_i.h"
#include "mesh.h"
+#include "driver-ops.h"

static int mesh_allocated;
static struct kmem_cache *rm_cache;
@@ -954,6 +955,59 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
stype, mgmt, &elems, rx_status);
}

+int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ int ret = 0;
+
+ /* Remove the CSA and MCSP elements from the beacon */
+ kfree(ifmsh->csa_settings);
+ ifmsh->csa_settings = NULL;
+ ret = ieee80211_mesh_rebuild_beacon(sdata);
+ if (ret)
+ return -EINVAL;
+
+ /* Reset the TTL value and Initiator flag */
+ ifmsh->chsw_init = false;
+ ifmsh->chsw_ttl = 0;
+
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+
+ mcsa_dbg(sdata, "complete switching to center freq %d MHz",
+ sdata->vif.bss_conf.chandef.chan->center_freq);
+ return ret;
+}
+
+int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *csa_settings,
+ bool csa_action)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct cfg80211_csa_settings *tmp_csa_settings;
+ int ret = 0;
+
+ if (csa_action)
+ ieee80211_send_action_csa(sdata, csa_settings);
+
+ tmp_csa_settings = kmalloc(sizeof(struct cfg80211_csa_settings),
+ GFP_ATOMIC);
+ if (!tmp_csa_settings) {
+ mcsa_dbg(sdata, "could not allocate memory for csa beaconing");
+ return -ENOMEM;
+ }
+
+ ifmsh->csa_settings = tmp_csa_settings;
+ memcpy(ifmsh->csa_settings, csa_settings,
+ sizeof(struct cfg80211_csa_settings));
+
+ ret = ieee80211_mesh_rebuild_beacon(sdata);
+ if (ret)
+ return -EINVAL;
+
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ return ret;
+}
+
static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
{
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8e908e1..0ba1fad 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2592,13 +2592,16 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;

if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
break;

if (sdata->vif.type == NL80211_IFTYPE_STATION)
bssid = sdata->u.mgd.bssid;
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
bssid = sdata->u.ibss.bssid;
+ else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+ bssid = mgmt->sa;
else
break;

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4fcbf63..80b9a57 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2369,6 +2369,10 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
beacon_data = beacon->head;
beacon_data_len = beacon->head_len;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
+ break;
default:
return;
}
@@ -2425,6 +2429,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)

beacon_data = beacon->head;
beacon_data_len = beacon->head_len;
+ } else if (vif->type == NL80211_IFTYPE_MESH_POINT) {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ beacon = rcu_dereference(ifmsh->beacon);
+ if (!beacon)
+ goto out;
+
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
} else {
WARN_ON(1);
goto out;
@@ -2530,6 +2543,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!bcn)
goto out;

+ if (sdata->vif.csa_active)
+ ieee80211_update_csa(sdata, bcn);
+
if (ifmsh->sync_ops)
ifmsh->sync_ops->adjust_tbtt(
sdata);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7bb5aca..be844d4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10760,7 +10760,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,

if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
- wdev->iftype != NL80211_IFTYPE_ADHOC))
+ wdev->iftype != NL80211_IFTYPE_ADHOC &&
+ wdev->iftype != NL80211_IFTYPE_MESH_POINT))
goto out;

wdev->channel = chandef->chan;
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
2013-10-01 11:27:44 UTC
Permalink
On Fri, 2013-09-13 at 16:36 -0700, Chun-Yeow Yeoh wrote:
> Finalizing the requried procedures for channel switching completion and

typo: required

> also adding the function for updating the beacon and probe response frames
> with CSA and MCSP elements. Once the channel switching is completed, the
> CSA and MCSP elements are removed from the beacon or probe response frames
> as defined in the IEEE Std 802.11-2012 section 10.9.8.4.3.

I'd prefer you rewrote this to be more active ... this seems rather
observer style :)

> +int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
> +{
> + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
> + int ret = 0;
> +
> + /* Remove the CSA and MCSP elements from the beacon */
> + kfree(ifmsh->csa_settings);
> + ifmsh->csa_settings = NULL;
> + ret = ieee80211_mesh_rebuild_beacon(sdata);
> + if (ret)
> + return -EINVAL;

This seems totally racy with what I pointed out in the other patch ...

> + /* Reset the TTL value and Initiator flag */
> + ifmsh->chsw_init = false;
> + ifmsh->chsw_ttl = 0;
> +
> + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
> +
> + mcsa_dbg(sdata, "complete switching to center freq %d MHz",
> + sdata->vif.bss_conf.chandef.chan->center_freq);
> + return ret;

return 0

> + tmp_csa_settings = kmalloc(sizeof(struct cfg80211_csa_settings),
> + GFP_ATOMIC);
> + if (!tmp_csa_settings) {
> + mcsa_dbg(sdata, "could not allocate memory for csa beaconing");

You should never print a message for memory allocation failures, they
already give very verbose output.

> + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
> + return ret;

return 0

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-10-01 22:39:20 UTC
Permalink
> I'd prefer you rewrote this to be more active ... this seems rather
> observer style :)
Alright.

>
> This seems totally racy with what I pointed out in the other patch ...
>
Definitely take a look on this.

> You should never print a message for memory allocation failures, they
> already give very verbose output.
Ok.

>> + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
>> + return ret;
>
> return 0
Ok

--- Chun-Yeow
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-09-13 23:36:12 UTC
Permalink
Trigger the mesh channel switching procedure if the mesh STA
happens to miss the CSA action frame but able to receive the
beacon containing the CSA and MCSP elements from its peer
mesh STAs.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow-W/***@public.gmane.org>
---
net/mac80211/ibss.c | 4 +-
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/mesh.c | 129 +++++++++++++++++++++++++++++++++++++++++---
net/mac80211/mlme.c | 4 +-
net/mac80211/spectmgmt.c | 8 ++-
5 files changed, 134 insertions(+), 13 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 017e206..a29f969 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -736,7 +736,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type ch_type;
int err, num_chanctx;
u32 sta_flags;
- u8 mode;
+ u8 mode, ttl;

if (sdata->vif.csa_active)
return true;
@@ -762,7 +762,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
ifibss->chandef.chan->band,
sta_flags, ifibss->bssid,
- &params.count, &mode,
+ &params.count, &mode, &ttl,
&params.chandef);

/* can't switch to destination channel, fail */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 48da719..fb24ad9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1510,6 +1510,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
* @count: to be filled with the counter until the switch (on success only)
* @bssid: the currently connected bssid (for reporting)
* @mode: to be filled with CSA mode (on success only)
+ * @ttl: to be filled with mesh TTL related to channel switch
* @new_chandef: to be filled with destination chandef (on success only)
* Return: 0 on success, <0 on error and >0 if there is nothing to parse.
*/
@@ -1517,6 +1518,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems, bool beacon,
enum ieee80211_band current_band,
u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
+ u8 *ttl,
struct cfg80211_chan_def *new_chandef);

/* Suspend/resume and hw reconfiguration */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2f756dd..180c898 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -847,6 +847,121 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_configure_filter(local);
}

+static bool
+ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems, bool beacon)
+{
+ struct cfg80211_csa_settings params;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_chanctx *chanctx;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
+ int err, num_chanctx;
+ u32 sta_flags;
+ u8 mode, ttl;
+
+ if (sdata->vif.csa_active)
+ return true;
+
+ if (!ifmsh->mesh_id)
+ return false;
+
+ sta_flags = IEEE80211_STA_DISABLE_VHT;
+ switch (sdata->vif.bss_conf.chandef.width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ sta_flags |= IEEE80211_STA_DISABLE_HT;
+ case NL80211_CHAN_WIDTH_20:
+ sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+ break;
+ default:
+ break;
+ }
+
+ memset(&params, 0, sizeof(params));
+ err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
+ sta_flags, sdata->vif.addr,
+ &params.count, &mode, &ttl,
+ &params.chandef);
+
+ if (err < 0)
+ return false;
+ if (err)
+ return false;
+
+ if (sdata->vif.bss_conf.chandef.chan->band !=
+ params.chandef.chan->band)
+ return false;
+
+ if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
+ IEEE80211_CHAN_DISABLED)) {
+ sdata_info(sdata,
+ "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
+ sdata->vif.addr,
+ params.chandef.chan->center_freq,
+ params.chandef.width,
+ params.chandef.center_freq1,
+ params.chandef.center_freq2);
+ }
+
+ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+ &params.chandef);
+ if (err < 0)
+ return false;
+ if (err) {
+ params.radar_required = true;
+ /* TODO: DFS not (yet) supported */
+ return false;
+ }
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (!chanctx_conf)
+ goto failed_chswitch;
+
+ /* don't handle for multi-VIF cases */
+ chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+ if (chanctx->refcount > 1)
+ goto failed_chswitch;
+
+ num_chanctx = 0;
+ list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
+ num_chanctx++;
+
+ if (num_chanctx > 1)
+ goto failed_chswitch;
+
+ rcu_read_unlock();
+
+ mcsa_dbg(sdata,
+ "received channel switch announcement to go to channel %d MHz\n",
+ params.chandef.chan->center_freq);
+
+ params.block_tx = !!(mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT);
+ if (beacon)
+ ifmsh->chsw_ttl = ttl - 1;
+
+ if (ifmsh->chsw_ttl > 0)
+ ieee80211_mesh_csa_beacon(sdata, &params, false);
+
+ sdata->csa_radar_required = params.radar_required;
+
+ if (params.block_tx)
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+
+ sdata->local->csa_chandef = params.chandef;
+ sdata->vif.csa_active = true;
+
+ ieee80211_bss_info_change_notify(sdata, err);
+ drv_channel_switch_beacon(sdata, &params.chandef);
+
+ return true;
+failed_chswitch:
+ rcu_read_unlock();
+ return false;
+}
+
static void
ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
@@ -953,6 +1068,9 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (ifmsh->sync_ops)
ifmsh->sync_ops->rx_bcn_presp(sdata,
stype, mgmt, &elems, rx_status);
+
+ if (!ifmsh->chsw_init)
+ ieee80211_mesh_process_chnswitch(sdata, &elems, true);
}

int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
@@ -1047,7 +1165,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee802_11_elems elems;
u16 pre_value;
- bool block_tx, fwd_csa = true;
+ bool fwd_csa = true;
size_t baselen;
u8 *pos, ttl;

@@ -1076,13 +1194,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
mcsa_dbg(sdata, "Failed to forward the CSA frame");
}

- /* block the Tx only after fowarding the CSA frame if required */
- block_tx = !!(elems.mesh_chansw_params_ie->mesh_flags
- & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT);
- if (block_tx)
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_MAX_QUEUE_MAP,
- IEEE80211_QUEUE_STOP_REASON_CSA);
+ if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false))
+ mcsa_dbg(sdata, "Failed to process CSA action frame");
}

static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9fce0f4..83e6609 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -942,7 +942,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *chanctx;
enum ieee80211_band current_band;
u8 count;
- u8 mode;
+ u8 mode, ttl;
struct cfg80211_chan_def new_chandef = {};
int res;

@@ -962,7 +962,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
ifmgd->flags,
ifmgd->associated->bssid, &count,
- &mode, &new_chandef);
+ &mode, &ttl, &new_chandef);
if (res < 0)
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 921597e..0762676 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -25,7 +25,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems, bool beacon,
enum ieee80211_band current_band,
u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
- struct cfg80211_chan_def *new_chandef)
+ u8 *ttl, struct cfg80211_chan_def *new_chandef)
{
enum ieee80211_band new_band;
int new_freq;
@@ -74,6 +74,12 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
return 1;
}

+ /* Mesh Channel Switch Parameters Element */
+ if (elems->mesh_chansw_params_ie) {
+ *ttl = elems->mesh_chansw_params_ie->mesh_ttl;
+ *mode = elems->mesh_chansw_params_ie->mesh_flags;
+ }
+
new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
2013-10-01 11:30:23 UTC
Permalink
On Fri, 2013-09-13 at 16:36 -0700, Chun-Yeow Yeoh wrote:

> err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
> ifibss->chandef.chan->band,
> sta_flags, ifibss->bssid,
> - &params.count, &mode,
> + &params.count, &mode, &ttl,
> &params.chandef);

I think it'd be worth doing some refactoring here to have an output
struct ... the parameters to this function are getting unreal. :)

> + if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
> + IEEE80211_CHAN_DISABLED)) {
> + sdata_info(sdata,
> + "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
> + sdata->vif.addr,
> + params.chandef.chan->center_freq,
> + params.chandef.width,
> + params.chandef.center_freq1,
> + params.chandef.center_freq2);
> + }

Seems like you should *do* something here, like return false?

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-10-01 22:39:36 UTC
Permalink
> I think it'd be worth doing some refactoring here to have an output
> struct ... the parameters to this function are getting unreal. :)
Yes. Bob commented this before. I will take a look on this.

> Seems like you should *do* something here, like return false?
Yes. You are right.

-- Chun-Yeow
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
2013-10-01 11:21:54 UTC
Permalink
On Fri, 2013-09-13 at 16:36 -0700, Chun-Yeow Yeoh wrote:

> + skb = dev_alloc_skb(local->tx_headroom + len);
> + if (!skb)
> + return -1;

-ENOMEM ?

> + skb_reserve(skb, local->tx_headroom);
> + mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
> +
> + /* offset_ttl is based on whether the secondary channel
> + * offset is available or not. Substract 1 from the mesh TTL
> + * and disable the initiator flag before forwarding.
> + */
> + offset_ttl = (len < 42) ? 7 : 10;
> + *(pos + offset_ttl) -= 1;
> + *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;

That's somewhat ugly, is there no better way to express that? Maybe with
different structs or something? I guess I can live with it, just asking
though.


> + /* forward or re-broadcast the CSA frame */
> + if (fwd_csa) {
> + if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
> + mcsa_dbg(sdata, "Failed to forward the CSA frame");
> + }
> +
> + /* block the Tx only after fowarding the CSA frame if required */

typo: forwarding

> + block_tx = !!(elems.mesh_chansw_params_ie->mesh_flags
> + & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT);

No need for !! with bool variables

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-10-01 22:38:26 UTC
Permalink
> -ENOMEM ?
Yes.

> That's somewhat ugly, is there no better way to express that? Maybe with
> different structs or something? I guess I can live with it, just asking
> though.
It's uglier before Bob commenting on this. Hope that this works fine.

> No need for !! with bool variables
Noted.

Chun-Yeow
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Johannes Berg
2013-10-01 11:31:01 UTC
Permalink
On Fri, 2013-09-13 at 16:36 -0700, Chun-Yeow Yeoh wrote:

> These patches are reviewed and commented by Bob Copeland and Thomas
> Pedersen. Any further comments are welcomed.

Sorry for the long delay, I posted some more comments. Can't really
comment on how good this is etc. since I'm not familiar with mesh :)

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Chun-Yeow Yeoh
2013-10-01 22:39:42 UTC
Permalink
> Sorry for the long delay, I posted some more comments. Can't really
> comment on how good this is etc. since I'm not familiar with mesh :)

Thanks for your comment. Gute Besserung!

-- Chun-Yeow
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Loading...