This patchset adds DFS and CSA functionality:
* Mesh CSA is handled similary to IBSS, that means CSA will mark
channels as unusable, and require userspace to handle actual
radar signals
* Add VHT processing for CSA in mesh mode, and some small cleanups
We have been working on this feature set for quite some time internally,
and I believe it is time to propose it for inclusion. I'll handle
any change requests to this patchset. :)
Cheers,
Simon
Benjamin Berg (4):
mac80211: Mark channel as unusable if a regulatory MESH CSA is
received
wireless: Only join DFS channels in mesh mode if userspace flags
support
wireless: Require HANDLE_DFS flag to switch channel for non-AP mode
mac80211: Allow following CSA to DFS channels if userspace handles it
Simon Wunderlich (3):
mac80211: add wide bandwidth channel switch announcement to CSA action
frames and mesh beacons
mac80211: enable VHT for mesh channel processing
mac80211: mark as action frame when parsing IEs of CSA action frames
include/net/cfg80211.h | 4 +++
net/mac80211/cfg.c | 1 +
net/mac80211/ieee80211_i.h | 5 +++
net/mac80211/mesh.c | 89 ++++++++++++++++++++++++++++++++++++++++++----
net/mac80211/spectmgmt.c | 5 +++
net/mac80211/util.c | 40 +++++++++++++++++++++
net/wireless/mesh.c | 8 +++++
net/wireless/nl80211.c | 17 ++++++++-
8 files changed, 161 insertions(+), 8 deletions(-)
--
2.11.0
Hi Basti,
On Tuesday, May 16, 2017 11:44:04 AM CEST Bastian Bittorf wrote:
> * Simon Wunderlich <[email protected]> [16.05.2017 11:35]:
> > This patchset adds DFS and CSA functionality:
> thanks a lot. can you give a brief 'iw event' output when applied:
> for a two-node mesh, where station A detects CSA and station B
> should emit an event...
The idea would be:
* station A detects a Radar, and informs userspace
* userspace of station A will initiate a CSA, kernel will execute it (action
frame, beacons)
* station B picks up the CSA, and executes it as well
* station B also marks the channel as unavailable
* both station A and station B will send an event to userspace once the
channel switch is complete
>
> question: there is no userspace part for now, or maybe planned?
I've got some patches for wpa_supplicant here, but they are still quite dirty
...
>
> bye, bastian - now it's time for battlemesh.org 8-)
See you at battlemesh :)
Cheers,
Simon
Signed-off-by: Simon Wunderlich <[email protected]>
---
net/mac80211/mesh.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index a57af5df7ee4..ab07974cdcf4 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1308,7 +1308,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
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);
+ ieee802_11_parse_elems(pos, len - baselen, true, &elems);
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
if (!--ifmsh->chsw_ttl)
--
2.11.0
I've applied patches 1-4 now.
The subject is a bit long - I was going to change it to
mac80211: mesh: support sending wide bandwidth CSA
To support HT and VHT channel switch announcements, both beacons
and action frames must include the corresponding IEs.
but:
> + 2 + 2 + sizeof(struct
> ieee80211_wide_bw_chansw_ie) +
> + 2 + sizeof(struct ieee80211_sec_chan_offs_ie) +
The "2 + 2" should have a comment - no that I'm even really sure that
you need the wrapper?
> - pos = skb_put(skb, 13);
> - memset(pos, 0, 13);
Removing that is nice - but why do you do this:
> + bool have_secondary_chan_offset = false;
> + bool have_wide_bandwidth_cs = false;
> + int ie_len = 2 + sizeof(struct
> ieee80211_channel_sw_ie) +
> + 2 + sizeof(struct
> ieee80211_mesh_chansw_params_ie);
> +
> + switch (csa->settings.chandef.width) {
> + case NL80211_CHAN_WIDTH_80:
> + case NL80211_CHAN_WIDTH_80P80:
> + case NL80211_CHAN_WIDTH_160:
> + have_wide_bandwidth_cs = true;
> + ie_len += 2 + 2 +
> + sizeof(struct
> ieee80211_wide_bw_chansw_ie);
> + break;
> + case NL80211_CHAN_WIDTH_40:
> + have_secondary_chan_offset = true;
> + ie_len += 2 + sizeof(struct
> ieee80211_sec_chan_offs_ie);
> + default:
> + break;
> + }
> + pos = skb_put(skb, ie_len);
> + memset(pos, 0, ie_len);
I think having multiple calls to skb_put() would be better.
> *pos++ = WLAN_EID_CHANNEL_SWITCH;
> *pos++ = 3;
> *pos++ = 0x0;
> @@ -760,6 +781,28 @@ ieee80211_mesh_build_beacon(struct
> ieee80211_if_mesh *ifmsh)
> pos += 2;
> put_unaligned_le16(ifmsh->pre_value, pos);
> pos += 2;
> +
> + if (have_secondary_chan_offset) {
> + enum nl80211_channel_type ct;
You can have one here, and re-initialize pos.
> + *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
> /* EID */
> + *pos++ = 1;
> /* len */
> + ct = cfg80211_get_chandef_type(&csa-
> >settings.chandef);
> + if (ct == NL80211_CHAN_HT40PLUS)
> + *pos++ =
> IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
> + else
> + *pos++ =
> IEEE80211_HT_PARAM_CHA_SEC_BELOW;
> + }
> +
> + if (have_wide_bandwidth_cs) {
> + struct cfg80211_chan_def *chandef;
and likewise here.
That'd also be safer in a way.
johannes
* Simon Wunderlich <[email protected]> [16.05.2017 12:24]:
> * station A detects a Radar, and informs userspace
> * userspace of station A will initiate a CSA, kernel will execute it (action
> frame, beacons)
> * station B picks up the CSA, and executes it as well
> * station B also marks the channel as unavailable
> * both station A and station B will send an event to userspace once the
> channel switch is complete
ah, I remember the slides from last battlemesh.
The "problems" in userspace are: we must maintain a global list
(so each node) which channel is the next best and we must time
the final channel switch. IMHO the specs are saying, that we must
switch within 30 secs after detecting the first radar-pattern.
Also we must mark/show the new channel somehow for new/crashed/upcoming nodes.
quite hard...
bye, bastian
Applied this as well, I assume you don't want patch 6 in before 5.
johannes
Hi,
> The spec says I need it, and if I understood the parsing function
> correctly it will only search for the wide bw IE when it finds the
> wrapper.
Yeah, I think there's some difference between action frames and beacons
though. You're only building the beacon here, so I think this is right.
johannes
From: Benjamin Berg <[email protected]>
If userspace has flagged support for DFS earlier, then we can follow CSA
to DFS channels. So instead of rejecting the switch, allow it to happen
if the flag has been set during mesh setup.
Signed-off-by: Benjamin Berg <[email protected]>
Signed-off-by: Simon Wunderlich <[email protected]>
---
net/mac80211/cfg.c | 1 +
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mesh.c | 15 ++++++++++++---
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 6c2e6060cd54..6980a936a437 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1874,6 +1874,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
ifmsh->user_mpm = setup->user_mpm;
ifmsh->mesh_auth_id = setup->auth_id;
ifmsh->security = IEEE80211_MESH_SEC_NONE;
+ ifmsh->userspace_handles_dfs = setup->userspace_handles_dfs;
if (setup->is_authenticated)
ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
if (setup->is_secure)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 60bed6c69801..c960e4999380 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -643,6 +643,8 @@ struct ieee80211_if_mesh {
unsigned long wrkq_flags;
unsigned long mbss_changed;
+ bool userspace_handles_dfs;
+
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
size_t mesh_id_len;
/* Active Path Selection Protocol Identifier */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 3702e3d9141d..4807a5d77572 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -979,7 +979,9 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
params.count = csa_ie.count;
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef,
- IEEE80211_CHAN_DISABLED)) {
+ IEEE80211_CHAN_DISABLED) ||
+ !cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef,
+ NL80211_IFTYPE_MESH_POINT)) {
sdata_info(sdata,
"mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
sdata->vif.addr,
@@ -995,9 +997,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
NL80211_IFTYPE_MESH_POINT);
if (err < 0)
return false;
- if (err > 0)
- /* TODO: DFS not (yet) supported */
+ if (err > 0 && !ifmsh->userspace_handles_dfs) {
+ sdata_info(sdata,
+ "mesh STA %pM switches to channel requiring DFS (%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);
return false;
+ }
params.radar_required = err;
--
2.11.0
On Tuesday, May 16, 2017 1:55:46 PM CEST Bastian Bittorf wrote:
> * Simon Wunderlich <[email protected]> [16.05.2017 12:24]:
> > * station A detects a Radar, and informs userspace
> > * userspace of station A will initiate a CSA, kernel will execute it
> > (action>
> > frame, beacons)
> >
> > * station B picks up the CSA, and executes it as well
> > * station B also marks the channel as unavailable
> > * both station A and station B will send an event to userspace once the
> >
> > channel switch is complete
>
> ah, I remember the slides from last battlemesh.
>
> The "problems" in userspace are: we must maintain a global list
> (so each node) which channel is the next best and we must time
> the final channel switch. IMHO the specs are saying, that we must
> switch within 30 secs after detecting the first radar-pattern.
> Also we must mark/show the new channel somehow for new/crashed/upcoming
> nodes. quite hard...
The timing is not a big problem, since the switch does not happen immediately
but is performed after a "countdown" which is part of the channel switch
announcement IEs. The specific rules for the countdown depend on the regulatory
domain, but it's usually something between 1 and 5 seconds where payload traffic
must not be transmitted (at least for the DFS case).
The bigger problem appears when a node is missing the CSA for whatever reason,
or is joining the network - worst case, the mesh network can split into clouds
on different channels. This is where we need the global list, or showing the
next channel, etc. :)
Cheers,
Simon
Hi Johannes,
On Friday, May 19, 2017 1:33:37 PM CEST Johannes Berg wrote:
> I've applied patches 1-4 now.
>
> The subject is a bit long - I was going to change it to
>
> mac80211: mesh: support sending wide bandwidth CSA
>
> To support HT and VHT channel switch announcements, both beacons
> and action frames must include the corresponding IEs.
>
> but:
> > + 2 + 2 + sizeof(struct
> > ieee80211_wide_bw_chansw_ie) +
> > + 2 + sizeof(struct ieee80211_sec_chan_offs_ie) +
>
> The "2 + 2" should have a comment - no that I'm even really sure that
> you need the wrapper?
>
right, I'll add a comment. The spec says I need it, and if I understood the
parsing function correctly it will only search for the wide bw IE when it finds
the wrapper.
> > - pos = skb_put(skb, 13);
> > - memset(pos, 0, 13);
>
> Removing that is nice - but why do you do this:
> > + bool have_secondary_chan_offset = false;
> > + bool have_wide_bandwidth_cs = false;
> > + int ie_len = 2 + sizeof(struct
> > ieee80211_channel_sw_ie) +
> > + 2 + sizeof(struct
> > ieee80211_mesh_chansw_params_ie);
> > +
> > + switch (csa->settings.chandef.width) {
> > + case NL80211_CHAN_WIDTH_80:
> > + case NL80211_CHAN_WIDTH_80P80:
> > + case NL80211_CHAN_WIDTH_160:
> > + have_wide_bandwidth_cs = true;
> > + ie_len += 2 + 2 +
> > + sizeof(struct
> > ieee80211_wide_bw_chansw_ie);
> > + break;
> > + case NL80211_CHAN_WIDTH_40:
> > + have_secondary_chan_offset = true;
> > + ie_len += 2 + sizeof(struct
> > ieee80211_sec_chan_offs_ie);
> > + default:
> > + break;
> > + }
> > + pos = skb_put(skb, ie_len);
> > + memset(pos, 0, ie_len);
>
> I think having multiple calls to skb_put() would be better.
>
OK.
>[...]
>
> and likewise here.
>
> That'd also be safer in a way.
Understood, I can change it this way.
Thanks a lot for the feedback!
Simon
From: Benjamin Berg <[email protected]>
When joining a mesh network it is not guaranteed that userspace has a
daemon listening for radar events. This is however required for channels
requiring DFS. To flag that userspace will handle radar events, it needs
to set NL80211_ATTR_HANDLE_DFS.
This matches the current mechanism used for IBSS mode.
Signed-off-by: Benjamin Berg <[email protected]>
Signed-off-by: Simon Wunderlich <[email protected]>
---
include/net/cfg80211.h | 4 ++++
net/wireless/mesh.c | 8 ++++++++
net/wireless/nl80211.c | 3 +++
3 files changed, 15 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b083e6cbae8c..fa25fbb67cb6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1441,6 +1441,9 @@ struct mesh_config {
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
* @basic_rates: basic rates to use when creating the mesh
* @beacon_rate: bitrate to be used for beacons
+ * @userspace_handles_dfs: whether user space controls DFS operation, i.e.
+ * changes the channel when a radar is detected. This is required
+ * to operate on DFS channels.
*
* These parameters are fixed when the mesh is created.
*/
@@ -1462,6 +1465,7 @@ struct mesh_setup {
int mcast_rate[NUM_NL80211_BANDS];
u32 basic_rates;
struct cfg80211_bitrate_mask beacon_rate;
+ bool userspace_handles_dfs;
};
/**
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index ec0b1c20ac99..421a6b80ec62 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -174,6 +174,14 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
scan_width);
}
+ err = cfg80211_chandef_dfs_required(&rdev->wiphy,
+ &setup->chandef,
+ NL80211_IFTYPE_MESH_POINT);
+ if (err < 0)
+ return err;
+ if (err > 0 && !setup->userspace_handles_dfs)
+ return -EINVAL;
+
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
NL80211_IFTYPE_MESH_POINT))
return -EINVAL;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c3bc9da30cff..d47e55e3f445 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9962,6 +9962,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
return err;
}
+ setup.userspace_handles_dfs =
+ nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
+
return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
}
--
2.11.0
From: Benjamin Berg <[email protected]>
In the case the channel should be switched to one requiring DFS we need
to make sure that userspace will handle radar events when they happen.
For AP mode this is assumed to be the case, as a manager like hostapd
is required. However IBSS and MESH modes can work without further
userspace assistance, so refuse to use DFS channels unless userspace
vouches that it handles DFS.
NOTE: Userspace should have already flagged support earlier during mesh
or IBSS setup. However, this information is not readily accessible
currently.
Signed-off-by: Benjamin Berg <[email protected]>
[sw: style cleanups]
Signed-off-by: Simon Wunderlich <[email protected]>
---
net/wireless/nl80211.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d47e55e3f445..9eb59196a378 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7501,6 +7501,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
int err;
bool need_new_beacon = false;
+ bool need_handle_dfs_flag = true;
int len, i;
u32 cs_count;
@@ -7512,6 +7513,12 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
need_new_beacon = true;
+ /* For all modes except AP the handle_dfs flag needs to be
+ * supplied to tell the kernel that userspace will handle radar
+ * events when they happen. Otherwise a switch to a channel
+ * requiring DFS will be rejected.
+ */
+ need_handle_dfs_flag = false;
/* useless if AP is not running */
if (!wdev->beacon_interval)
@@ -7634,8 +7641,13 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if (err < 0)
return err;
- if (err > 0)
+ if (err > 0) {
params.radar_required = true;
+ if (need_handle_dfs_flag &&
+ !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
+ return -EINVAL;
+ }
+ }
if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
params.block_tx = true;
--
2.11.0
Signed-off-by: Simon Wunderlich <[email protected]>
---
net/mac80211/mesh.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 7c6593c0d453..a57af5df7ee4 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -991,12 +991,14 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
if (!sband)
return false;
- sta_flags = IEEE80211_STA_DISABLE_VHT;
+ sta_flags = 0;
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;
+ case NL80211_CHAN_WIDTH_40:
+ sta_flags |= IEEE80211_STA_DISABLE_VHT;
break;
default:
break;
--
2.11.0
To support HT and VHT CSA, beacons and action frames must include the
corresponding IEs.
Signed-off-by: Simon Wunderlich <[email protected]>
---
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mesh.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/util.c | 40 +++++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c960e4999380..e3a0b295c5ce 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2066,6 +2066,8 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
const struct cfg80211_chan_def *chandef,
u16 prot_mode, bool rifs_mode);
+u8 *ieee80211_ie_build_wide_bw_cs(u8 *pos,
+ const struct cfg80211_chan_def *chandef);
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u32 cap);
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 4807a5d77572..7c6593c0d453 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -690,6 +690,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
2 + sizeof(struct ieee80211_channel_sw_ie) +
/* Mesh Channel Switch Parameters */
2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
+ 2 + 2 + sizeof(struct ieee80211_wide_bw_chansw_ie) +
+ 2 + sizeof(struct ieee80211_sec_chan_offs_ie) +
2 + 8 + /* supported rates */
2 + 3; /* DS params */
tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -736,8 +738,27 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
rcu_read_lock();
csa = rcu_dereference(ifmsh->csa);
if (csa) {
- pos = skb_put(skb, 13);
- memset(pos, 0, 13);
+ bool have_secondary_chan_offset = false;
+ bool have_wide_bandwidth_cs = false;
+ int ie_len = 2 + sizeof(struct ieee80211_channel_sw_ie) +
+ 2 + sizeof(struct ieee80211_mesh_chansw_params_ie);
+
+ switch (csa->settings.chandef.width) {
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ have_wide_bandwidth_cs = true;
+ ie_len += 2 + 2 +
+ sizeof(struct ieee80211_wide_bw_chansw_ie);
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ have_secondary_chan_offset = true;
+ ie_len += 2 + sizeof(struct ieee80211_sec_chan_offs_ie);
+ default:
+ break;
+ }
+ pos = skb_put(skb, ie_len);
+ memset(pos, 0, ie_len);
*pos++ = WLAN_EID_CHANNEL_SWITCH;
*pos++ = 3;
*pos++ = 0x0;
@@ -760,6 +781,28 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
pos += 2;
put_unaligned_le16(ifmsh->pre_value, pos);
pos += 2;
+
+ if (have_secondary_chan_offset) {
+ enum nl80211_channel_type ct;
+
+ *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
+ *pos++ = 1; /* len */
+ ct = cfg80211_get_chandef_type(&csa->settings.chandef);
+ if (ct == NL80211_CHAN_HT40PLUS)
+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ else
+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ }
+
+ if (have_wide_bandwidth_cs) {
+ struct cfg80211_chan_def *chandef;
+
+ *pos++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; /* EID */
+ *pos++ = 5; /* len */
+ /* put sub IE */
+ chandef = &csa->settings.chandef;
+ pos = ieee80211_ie_build_wide_bw_cs(pos, chandef);
+ }
}
rcu_read_unlock();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ac9ac6c35594..d2e885cbfdf8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2414,6 +2414,37 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
return pos + sizeof(struct ieee80211_ht_operation);
}
+u8 *ieee80211_ie_build_wide_bw_cs(u8 *pos,
+ const struct cfg80211_chan_def *chandef)
+{
+ *pos++ = WLAN_EID_WIDE_BW_CHANNEL_SWITCH; /* EID */
+ *pos++ = 3; /* IE length */
+ /* New channel width */
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_80:
+ *pos++ = IEEE80211_VHT_CHANWIDTH_80MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ *pos++ = IEEE80211_VHT_CHANWIDTH_160MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ *pos++ = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+ break;
+ default:
+ *pos++ = IEEE80211_VHT_CHANWIDTH_USE_HT;
+ }
+
+ /* new center frequency segment 0 */
+ *pos++ = ieee80211_frequency_to_channel(chandef->center_freq1);
+ /* new center frequency segment 1 */
+ if (chandef->center_freq2)
+ *pos++ = ieee80211_frequency_to_channel(chandef->center_freq2);
+ else
+ *pos++ = 0;
+
+ return pos;
+}
+
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
const struct cfg80211_chan_def *chandef)
{
@@ -2964,6 +2995,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
skb = dev_alloc_skb(local->tx_headroom + hdr_len +
5 + /* channel switch announcement element */
3 + /* secondary channel offset element */
+ 5 + /* wide bandwidth channel switch announcement */
8); /* mesh channel switch parameters element */
if (!skb)
return -ENOMEM;
@@ -3022,6 +3054,14 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
pos += 2;
}
+ if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_80 ||
+ csa_settings->chandef.width == NL80211_CHAN_WIDTH_80P80 ||
+ csa_settings->chandef.width == NL80211_CHAN_WIDTH_160) {
+ skb_put(skb, 5);
+ pos = ieee80211_ie_build_wide_bw_cs(pos,
+ &csa_settings->chandef);
+ }
+
ieee80211_tx_skb(sdata, skb);
return 0;
}
--
2.11.0
* Simon Wunderlich <[email protected]> [16.05.2017 11:35]:
> This patchset adds DFS and CSA functionality:
thanks a lot. can you give a brief 'iw event' output when applied:
for a two-node mesh, where station A detects CSA and station B
should emit an event...
question: there is no userspace part for now, or maybe planned?
bye, bastian - now it's time for battlemesh.org 8-)
From: Benjamin Berg <[email protected]>
In the Mesh Channel Switch Parameters (8.4.2.105) the reason is specified
to WLAN_REASON_MESH_CHAN_REGULATORY in the case that a regulatory
limitation was the cause for the switch. This means another station
detected a radar event.
Mark the channel as unusable if this happens.
Signed-off-by: Benjamin Berg <[email protected]>
[sw: style cleanup, rebase]
Signed-off-by: Simon Wunderlich <[email protected]>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 21 +++++++++++++++++++++
net/mac80211/spectmgmt.c | 5 +++++
3 files changed, 27 insertions(+)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f8f6c148f554..60bed6c69801 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1440,6 +1440,7 @@ struct ieee80211_csa_ie {
u8 count;
u8 ttl;
u16 pre_value;
+ u16 reason_code;
};
/* Parsed Information Elements */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 737e1f082b0d..3702e3d9141d 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -916,6 +916,21 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_configure_filter(local);
}
+static void ieee80211_mesh_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
+{
+ int err;
+
+ /* if the current channel is a DFS channel, mark the channel as
+ * unavailable.
+ */
+ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+ &sdata->vif.bss_conf.chandef,
+ NL80211_IFTYPE_MESH_POINT);
+ if (err > 0)
+ cfg80211_radar_event(sdata->local->hw.wiphy,
+ &sdata->vif.bss_conf.chandef, GFP_ATOMIC);
+}
+
static bool
ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems, bool beacon)
@@ -954,6 +969,12 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
if (err)
return false;
+ /* Mark the channel unavailable if the reason for the switch is
+ * regulatory.
+ */
+ if (csa_ie.reason_code == WLAN_REASON_MESH_CHAN_REGULATORY)
+ ieee80211_mesh_csa_mark_radar(sdata);
+
params.chandef = csa_ie.chandef;
params.count = csa_ie.count;
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 0782e486fe89..d2ea0017c79d 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -76,6 +76,11 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
csa_ie->pre_value = le16_to_cpu(
elems->mesh_chansw_params_ie->mesh_pre_value);
+
+ if (elems->mesh_chansw_params_ie->mesh_flags &
+ WLAN_EID_CHAN_SWITCH_PARAM_REASON)
+ csa_ie->reason_code = le16_to_cpu(
+ elems->mesh_chansw_params_ie->mesh_reason);
}
new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
--
2.11.0