2020-08-27 22:33:53

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 00/22] add initial S1G support

This is the initial 802.11ah (S1G) patchset which adds support for:

- defining the S1G 900MHz bands in a custom regulatory database
- setting and receiving S1G beacons (sending short beacons will be
supported in a future patch)
- configuring S1G capabilities in Association Request (setting
capabilities along with NL80211_CMD_SET_STATION will be added later).
- scanning on S1G bands
- handling S1G Association Response format
- correctly encoding Listen Interval for S1G
- associating in mac80211
- S1G in mac80211_hwsim

Rate control is still TBD, this patchset simply lops off the rate
control hooks for S1G so eg. missing sband->bitrates and S1G Basic Rate
set can't do too much damage.

Note the mac80211_hwsim S1G support introduces a regression in a few
hostap hwsim tests. This is because when processing the reported bands,
hostap assumes freq < 4000 is 11b, and the actual 11b/g band is
overwritten by the S1G band info. Though it does count as a userspace
regression, I'm not sure there is much to do about it besides apply a
small patch to hostapd which treats freq < 2000 as an unknown band.

After the hostap workaround (https://p.ibsgaard.io/raw/xaweyacunu),
these patches continue to pass the hwsim tests as well as HEAD.

Thomas Pedersen (22):
nl80211: advertise supported channel width in S1G
cfg80211: regulatory: pass min. bandwidth to regulatory rule extractor
cfg80211: regulatory: handle S1G channels
nl80211: correctly validate S1G beacon head
nl80211: support setting S1G channels
{cfg,mac}80211: get correct default channel width for S1G
mac80211: s1g: choose scanning width based on frequency
nl80211: support S1G capabilities
mac80211: support S1G STA capabilities
cfg80211: convert S1G beacon to scan results
cfg80211: parse S1G Operation element for BSS channel
mac80211: convert S1G beacon to scan results
cfg80211: handle Association Response from S1G STA
mac80211: encode listen interval for S1G
mac80211: don't calculate duration for S1G
mac80211: handle S1G low rates
mac80211: avoid rate init for S1G band
mac80211: receive and process S1G beacons
mac80211: support S1G association
nl80211: include frequency offset in survey info
mac80211_hwsim: indicate support for S1G
mac80211_hwsim: fix TSF timestamp write to S1G beacon

drivers/net/wireless/ath/regd.c | 2 +-
.../broadcom/brcm80211/brcmsmac/channel.c | 3 +-
drivers/net/wireless/mac80211_hwsim.c | 93 +++++++-
drivers/net/wireless/realtek/rtlwifi/regd.c | 7 +-
include/linux/ieee80211.h | 82 ++++++-
include/net/cfg80211.h | 31 ++-
include/net/mac80211.h | 3 +
include/uapi/linux/nl80211.h | 26 +++
net/mac80211/cfg.c | 2 +
net/mac80211/chan.c | 9 +-
net/mac80211/ibss.c | 3 +-
net/mac80211/ieee80211_i.h | 20 ++
net/mac80211/iface.c | 5 +
net/mac80211/mlme.c | 184 +++++++++++++---
net/mac80211/rate.c | 39 +++-
net/mac80211/rx.c | 87 ++++----
net/mac80211/scan.c | 37 +++-
net/mac80211/tx.c | 4 +
net/mac80211/util.c | 207 +++++++++++++++++-
net/wireless/chan.c | 140 +++++++-----
net/wireless/mlme.c | 20 ++
net/wireless/nl80211.c | 56 ++++-
net/wireless/reg.c | 74 +++++--
net/wireless/scan.c | 80 +++++--
net/wireless/util.c | 32 +++
25 files changed, 1046 insertions(+), 200 deletions(-)

--
2.20.1


2020-08-27 22:33:55

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 02/22] cfg80211: regulatory: pass min. bandwidth to regulatory rule extractor

The regulatory code assumed 20Mhz is the minimum channel
bandwidth supported. Make this a parameter so S1G code can
pass smaller bandwidths.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/ath/regd.c | 2 +-
drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c | 3 ++-
drivers/net/wireless/realtek/rtlwifi/regd.c | 7 ++++---
include/net/cfg80211.h | 3 ++-
net/mac80211/util.c | 2 +-
net/wireless/nl80211.c | 3 ++-
net/wireless/reg.c | 7 ++++---
7 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index bee9110b91f3..f9c9ac16d2da 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -268,7 +268,7 @@ static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
{
const struct ieee80211_reg_rule *reg_rule;

- reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
+ reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq), 20);
if (IS_ERR(reg_rule))
return;

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
index 5a6d9c86552a..d85b2707e2fa 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
@@ -677,7 +677,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,

if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
rule = freq_reg_info(wiphy,
- MHZ_TO_KHZ(ch->center_freq));
+ MHZ_TO_KHZ(ch->center_freq),
+ 20);
if (IS_ERR(rule))
continue;

diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c
index 8be31e0ad878..3f9dd4941bb1 100644
--- a/drivers/net/wireless/realtek/rtlwifi/regd.c
+++ b/drivers/net/wireless/realtek/rtlwifi/regd.c
@@ -151,7 +151,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
reg_rule = freq_reg_info(wiphy,
- ch->center_freq);
+ ch->center_freq,
+ 20);
if (IS_ERR(reg_rule))
continue;
/*
@@ -213,7 +214,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/

ch = &sband->channels[11]; /* CH 12 */
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq, 20);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
@@ -221,7 +222,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
}

ch = &sband->channels[12]; /* CH 13 */
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq, 20);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3db0444086e2..2c737d6be9a1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5862,6 +5862,7 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
* freq_reg_info - get regulatory information for the given frequency
* @wiphy: the wiphy for which we want to process this rule for
* @center_freq: Frequency in KHz for which we want regulatory information for
+ * @min_bw: Minimum channel bandwidth in MHz for which we want regulatory information for
*
* Use this function to get the regulatory rule for a specific frequency on
* a given wireless device. If the device has a specific regulatory domain
@@ -5877,7 +5878,7 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
* purely subjective and right now it's 802.11 specific.
*/
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
- u32 center_freq);
+ u32 center_freq, u32 min_bw);

/**
* reg_initiator_name - map regulatory request initiator enum to name
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index c8504ffc71a1..9ba1afe4ba1f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1453,7 +1453,7 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
return;
}

- rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq));
+ rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq), 20);

if (IS_ERR_OR_NULL(rrule) || !rrule->has_wmm) {
rcu_read_unlock();
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5aded5de35cd..dd0f62e942ed 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1013,7 +1013,8 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,

if (large) {
const struct ieee80211_reg_rule *rule =
- freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
+ freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
+ 20);

if (!IS_ERR_OR_NULL(rule) && rule->has_wmm) {
if (nl80211_msg_put_wmm_rules(msg, rule))
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 35b8847a2f6d..6c130cec22c3 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1629,9 +1629,10 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
}

const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
- u32 center_freq)
+ u32 center_freq,
+ u32 min_bw)
{
- return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20));
+ return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(min_bw));
}
EXPORT_SYMBOL(freq_reg_info);

@@ -1711,7 +1712,7 @@ static void handle_channel(struct wiphy *wiphy,

flags = chan->orig_flags;

- reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan));
+ reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan), 20);
if (IS_ERR(reg_rule)) {
/*
* We will disable all channels that do not match our
--
2.20.1

2020-08-27 22:34:07

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 05/22] nl80211: support setting S1G channels

S1G channels have a single width defined per frequency, so
derive it from the channel flags with
ieee80211_s1g_channel_width().

Also support setting an S1G channel where control frequency may
differ from operating, and add some basic validation to
ensure the control channel is with the operating.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/cfg80211.h | 10 ++++
net/wireless/chan.c | 130 ++++++++++++++++++++++++-----------------
net/wireless/util.c | 27 +++++++++
3 files changed, 115 insertions(+), 52 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2c737d6be9a1..f44839823d1e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5290,6 +5290,16 @@ ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
}

+/**
+ * ieee80211_s1g_channel_width - get allowed channel width from @chan
+ *
+ * Only allowed for band NL80211_BAND_S1GHZ
+ * @chan: channel
+ * Return: The allowed channel width for this center_freq
+ */
+enum nl80211_chan_width
+ieee80211_s1g_channel_width(const struct ieee80211_channel *chan);
+
/**
* ieee80211_channel_to_freq_khz - convert channel number to frequency
* @chan: channel number
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 90f0f82cd9ca..0a4b8d3eaed9 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -140,9 +140,62 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
return true;
}

+static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
+{
+ int mhz;
+
+ switch (chan_width) {
+ case NL80211_CHAN_WIDTH_1:
+ mhz = 1;
+ break;
+ case NL80211_CHAN_WIDTH_2:
+ mhz = 2;
+ break;
+ case NL80211_CHAN_WIDTH_4:
+ mhz = 4;
+ break;
+ case NL80211_CHAN_WIDTH_8:
+ mhz = 8;
+ break;
+ case NL80211_CHAN_WIDTH_16:
+ mhz = 16;
+ break;
+ case NL80211_CHAN_WIDTH_5:
+ mhz = 5;
+ break;
+ case NL80211_CHAN_WIDTH_10:
+ mhz = 10;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ mhz = 20;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ mhz = 40;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_80:
+ mhz = 80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ mhz = 160;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -1;
+ }
+ return mhz;
+}
+
+static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
+{
+ return nl80211_chan_width_to_mhz(c->width);
+}
+
bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
{
- u32 control_freq;
+ u32 control_freq, oper_freq;
+ int oper_width, control_width;

if (!chandef->chan)
return false;
@@ -154,10 +207,6 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)

switch (chandef->width) {
case NL80211_CHAN_WIDTH_1:
- case NL80211_CHAN_WIDTH_2:
- case NL80211_CHAN_WIDTH_4:
- case NL80211_CHAN_WIDTH_8:
- case NL80211_CHAN_WIDTH_16:
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
@@ -168,6 +217,30 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
if (chandef->center_freq2)
return false;
break;
+ case NL80211_CHAN_WIDTH_2:
+ case NL80211_CHAN_WIDTH_4:
+ case NL80211_CHAN_WIDTH_8:
+ case NL80211_CHAN_WIDTH_16:
+ control_freq = ieee80211_channel_to_khz(chandef->chan);
+ oper_freq = ieee80211_chandef_to_khz(chandef);
+ control_width = nl80211_chan_width_to_mhz(
+ ieee80211_s1g_channel_width(
+ chandef->chan));
+ oper_width = cfg80211_chandef_get_width(chandef);
+
+ if (oper_width < 0 || control_width < 0)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+
+ if (control_freq + MHZ_TO_KHZ(control_width) / 2 >
+ oper_freq + MHZ_TO_KHZ(oper_width) / 2)
+ return false;
+
+ if (control_freq - MHZ_TO_KHZ(control_width) / 2 <
+ oper_freq - MHZ_TO_KHZ(oper_width) / 2)
+ return false;
+ break;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 != control_freq + 10 &&
chandef->center_freq1 != control_freq - 10)
@@ -263,53 +336,6 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
}
}

-static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
-{
- int width;
-
- switch (c->width) {
- case NL80211_CHAN_WIDTH_1:
- width = 1;
- break;
- case NL80211_CHAN_WIDTH_2:
- width = 2;
- break;
- case NL80211_CHAN_WIDTH_4:
- width = 4;
- break;
- case NL80211_CHAN_WIDTH_8:
- width = 8;
- break;
- case NL80211_CHAN_WIDTH_16:
- width = 16;
- break;
- case NL80211_CHAN_WIDTH_5:
- width = 5;
- break;
- case NL80211_CHAN_WIDTH_10:
- width = 10;
- break;
- case NL80211_CHAN_WIDTH_20:
- case NL80211_CHAN_WIDTH_20_NOHT:
- width = 20;
- break;
- case NL80211_CHAN_WIDTH_40:
- width = 40;
- break;
- case NL80211_CHAN_WIDTH_80P80:
- case NL80211_CHAN_WIDTH_80:
- width = 80;
- break;
- case NL80211_CHAN_WIDTH_160:
- width = 160;
- break;
- default:
- WARN_ON_ONCE(1);
- return -1;
- }
- return width;
-}
-
const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
const struct cfg80211_chan_def *c2)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 383278c05a75..91ffb5132501 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -111,6 +111,33 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
}
EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);

+enum nl80211_chan_width
+ieee80211_s1g_channel_width(const struct ieee80211_channel *chan)
+{
+ if (WARN_ON(!chan || chan->band != NL80211_BAND_S1GHZ))
+ return NL80211_CHAN_WIDTH_20_NOHT;
+
+ /*S1G defines a single allowed channel width per channel.
+ * Extract that width here.
+ */
+ if (chan->flags & IEEE80211_CHAN_1MHZ)
+ return NL80211_CHAN_WIDTH_1;
+ else if (chan->flags & IEEE80211_CHAN_2MHZ)
+ return NL80211_CHAN_WIDTH_2;
+ else if (chan->flags & IEEE80211_CHAN_4MHZ)
+ return NL80211_CHAN_WIDTH_4;
+ else if (chan->flags & IEEE80211_CHAN_8MHZ)
+ return NL80211_CHAN_WIDTH_8;
+ else if (chan->flags & IEEE80211_CHAN_16MHZ)
+ return NL80211_CHAN_WIDTH_16;
+
+ pr_err("unknown channel width for channel at %dKHz?\n",
+ ieee80211_channel_to_khz(chan));
+
+ return NL80211_CHAN_WIDTH_1;
+}
+EXPORT_SYMBOL(ieee80211_s1g_channel_width);
+
int ieee80211_freq_khz_to_channel(u32 freq)
{
/* TODO: just handle MHz for now */
--
2.20.1

2020-08-27 22:34:09

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 04/22] nl80211: correctly validate S1G beacon head

The S1G beacon has a different header size than regular
beacons, so adjust the beacon head validator.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/wireless/nl80211.c | 16 +++++++++++++---
net/wireless/util.c | 5 +++++
2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a57872708108..c5950d154d66 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -209,14 +209,24 @@ static int validate_beacon_head(const struct nlattr *attr,
unsigned int len = nla_len(attr);
const struct element *elem;
const struct ieee80211_mgmt *mgmt = (void *)data;
- unsigned int fixedlen = offsetof(struct ieee80211_mgmt,
- u.beacon.variable);
+ bool s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
+ unsigned int fixedlen, hdrlen;
+
+ if (s1g_bcn) {
+ fixedlen = offsetof(struct ieee80211_ext,
+ u.s1g_beacon.variable);
+ hdrlen = offsetof(struct ieee80211_ext, u.s1g_beacon);
+ } else {
+ fixedlen = offsetof(struct ieee80211_mgmt,
+ u.beacon.variable);
+ hdrlen = offsetof(struct ieee80211_mgmt, u.beacon);
+ }

if (len < fixedlen)
goto err;

if (ieee80211_hdrlen(mgmt->frame_control) !=
- offsetof(struct ieee80211_mgmt, u.beacon))
+ hdrlen)
goto err;

data += fixedlen;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index dfad1c0f57ad..383278c05a75 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -397,6 +397,11 @@ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
{
unsigned int hdrlen = 24;

+ if (ieee80211_is_ext(fc)) {
+ hdrlen = 4;
+ goto out;
+ }
+
if (ieee80211_is_data(fc)) {
if (ieee80211_has_a4(fc))
hdrlen = 30;
--
2.20.1

2020-08-27 22:34:10

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 08/22] nl80211: support S1G capabilities

Declare the structures needed to define S1G capabilities.

NL80211_ATTR_S1G_CAPABILITY can be passed along with
NL80211_ATTR_S1G_CAPABILITY_MASK to NL80211_CMD_ASSOCIATE
to indicate S1G capabilities which should override the
hardware capabilities in eg. the association request.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/cfg80211.h | 3 +++
include/uapi/linux/nl80211.h | 9 +++++++++
net/wireless/nl80211.c | 16 ++++++++++++++++
3 files changed, 28 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f44839823d1e..b7e1a9dcf22c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2486,6 +2486,8 @@ enum cfg80211_assoc_req_flags {
* @fils_nonces: FILS nonces (part of AAD) for protecting (Re)Association
* Request/Response frame or %NULL if FILS is not used. This field starts
* with 16 octets of STA Nonce followed by 16 octets of AP Nonce.
+ * @s1g_capa: S1G capability override
+ * @s1g_capa_mask: S1G capability override mask
*/
struct cfg80211_assoc_request {
struct cfg80211_bss *bss;
@@ -2500,6 +2502,7 @@ struct cfg80211_assoc_request {
const u8 *fils_kek;
size_t fils_kek_len;
const u8 *fils_nonces;
+ struct ieee80211_s1g_cap s1g_capa, s1g_capa_mask;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 00ac24f2e293..03f4d83da473 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2515,6 +2515,12 @@ enum nl80211_commands {
* @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
* association request when used with NL80211_CMD_NEW_STATION).
*
+ * @NL80211_ATTR_S1G_CAPABILITY: S1G Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ * @NL80211_ATTR_S1G_CAPABILITY_MASK: S1G Capability Information element
+ * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
+ * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2997,6 +3003,8 @@ enum nl80211_attrs {

NL80211_ATTR_HE_6GHZ_CAPABILITY,

+ NL80211_ATTR_S1G_CAPABILITY,
+ NL80211_ATTR_S1G_CAPABILITY_MASK,
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -3046,6 +3054,7 @@ enum nl80211_attrs {
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
+#define NL80211_S1G_CAPABILITY_LEN 15
#define NL80211_HE_MIN_CAPABILITY_LEN 16
#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c5950d154d66..5672abb34b86 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -666,6 +666,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_SCAN_FREQ_KHZ] = { .type = NLA_NESTED },
[NL80211_ATTR_HE_6GHZ_CAPABILITY] =
NLA_POLICY_EXACT_LEN(sizeof(struct ieee80211_he_6ghz_capa)),
+ [NL80211_ATTR_S1G_CAPABILITY] = { .len = NL80211_S1G_CAPABILITY_LEN },
+ [NL80211_ATTR_S1G_CAPABILITY_MASK] = {
+ .len = NL80211_S1G_CAPABILITY_LEN },
};

/* policy for the key attributes */
@@ -9594,6 +9597,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
}

+ if (info->attrs[NL80211_ATTR_S1G_CAPABILITY_MASK])
+ memcpy(&req.s1g_capa_mask,
+ nla_data(info->attrs[NL80211_ATTR_S1G_CAPABILITY_MASK]),
+ sizeof(req.s1g_capa_mask));
+
+ if (info->attrs[NL80211_ATTR_S1G_CAPABILITY]) {
+ if (!info->attrs[NL80211_ATTR_S1G_CAPABILITY_MASK])
+ return -EINVAL;
+ memcpy(&req.s1g_capa,
+ nla_data(info->attrs[NL80211_ATTR_S1G_CAPABILITY]),
+ sizeof(req.s1g_capa));
+ }
+
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
if (!err) {
wdev_lock(dev->ieee80211_ptr);
--
2.20.1

2020-08-27 22:34:11

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 07/22] mac80211: s1g: choose scanning width based on frequency

An S1G BSS can beacon at either 1 or 2 MHz and the channel
width is unique to a given frequency. Ignore scan channel
width for now and use the allowed channel width.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/scan.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 5ac2785cdc7b..5002791fe165 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -905,6 +905,17 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
local->scan_chandef.center_freq1 = chan->center_freq;
local->scan_chandef.freq1_offset = chan->freq_offset;
local->scan_chandef.center_freq2 = 0;
+
+ /* For scanning on the S1G band, ignore scan_width (which is constant
+ * across all channels) for now since channel width is specific to each
+ * channel. Detect the required channel width here and likely revisit
+ * later. Maybe scan_width could be used to build the channel scan list?
+ */
+ if (chan->band == NL80211_BAND_S1GHZ) {
+ local->scan_chandef.width = ieee80211_s1g_channel_width(chan);
+ goto set_channel;
+ }
+
switch (scan_req->scan_width) {
case NL80211_BSS_CHAN_WIDTH_5:
local->scan_chandef.width = NL80211_CHAN_WIDTH_5;
@@ -925,8 +936,14 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
else
local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
break;
+ case NL80211_BSS_CHAN_WIDTH_1:
+ case NL80211_BSS_CHAN_WIDTH_2:
+ /* shouldn't get here, S1G handled above */
+ WARN_ON(1);
+ break;
}

+set_channel:
if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
skip = 1;

--
2.20.1

2020-08-27 22:34:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 10/22] cfg80211: convert S1G beacon to scan results

The S1G beacon is an extension frame as opposed to
management frame for the regular beacon. This means we may
have to occasionally cast the frame buffer to a different
header type. Luckily this isn't too bad as scan results
mostly only care about the IEs.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/linux/ieee80211.h | 32 ++++++++++++++++++++++
net/wireless/scan.c | 57 ++++++++++++++++++++++++++++++++-------
2 files changed, 80 insertions(+), 9 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index c47f43e65a2f..fe70cd99dec7 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -151,6 +151,9 @@

#define IEEE80211_ANO_NETTYPE_WILD 15

+/* bits unique to S1G beacon */
+#define IEEE80211_S1G_BCN_NEXT_TBTT 0x100
+
/* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */
#define IEEE80211_CTL_EXT_POLL 0x2000
#define IEEE80211_CTL_EXT_SPR 0x3000
@@ -553,6 +556,28 @@ static inline bool ieee80211_is_s1g_beacon(__le16 fc)
cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON);
}

+/**
+ * ieee80211_next_tbtt_present - check if IEEE80211_FTYPE_EXT &&
+ * IEEE80211_STYPE_S1G_BEACON && IEEE80211_S1G_BCN_NEXT_TBTT
+ * @fc: frame control bytes in little-endian byteorder
+ */
+static inline bool ieee80211_next_tbtt_present(__le16 fc)
+{
+ return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
+ cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON) &&
+ fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT);
+}
+
+/**
+ * ieee80211_is_s1g_short_beacon - check if next tbtt present bit is set. Only
+ * true for S1G beacons when they're short.
+ * @fc: frame control bytes in little-endian byteorder
+ */
+static inline bool ieee80211_is_s1g_short_beacon(__le16 fc)
+{
+ return ieee80211_is_s1g_beacon(fc) && ieee80211_next_tbtt_present(fc);
+}
+
/**
* ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM
* @fc: frame control bytes in little-endian byteorder
@@ -1034,6 +1059,13 @@ struct ieee80211_ext {
u8 change_seq;
u8 variable[0];
} __packed s1g_beacon;
+ struct {
+ u8 sa[ETH_ALEN];
+ __le32 timestamp;
+ u8 change_seq;
+ u8 next_tbtt[3];
+ u8 variable[0];
+ } __packed s1g_short_beacon;
} u;
} __packed __aligned(2);

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e67a74488bbe..bf72a13dd2aa 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1807,8 +1807,11 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
struct cfg80211_bss_ies *ies;
struct ieee80211_channel *channel;
bool signal_valid;
- size_t ielen = len - offsetof(struct ieee80211_mgmt,
- u.probe_resp.variable);
+ struct ieee80211_ext *ext = NULL;
+ u8 *bssid, *variable;
+ u16 capability, beacon_int;
+ size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable);
int bss_type;

BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
@@ -1826,21 +1829,57 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
(data->signal < 0 || data->signal > 100)))
return NULL;

- if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
+ ext = (void *) mgmt;
+ min_hdr_len = offsetof(struct ieee80211_ext, u.s1g_beacon);
+ if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
+ min_hdr_len = offsetof(struct ieee80211_ext,
+ u.s1g_short_beacon.variable);
+ }
+
+ if (WARN_ON(len < min_hdr_len))
return NULL;

- channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
+ ielen = len - min_hdr_len;
+ variable = mgmt->u.probe_resp.variable;
+ if (ext) {
+ if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
+ variable = ext->u.s1g_short_beacon.variable;
+ else
+ variable = ext->u.s1g_beacon.variable;
+ }
+
+ channel = cfg80211_get_bss_channel(wiphy, variable,
ielen, data->chan, data->scan_width);
if (!channel)
return NULL;

+ if (ext) {
+ struct ieee80211_s1g_bcn_compat_ie *compat;
+ u8 *ie;
+
+ ie = (void *)cfg80211_find_ie(WLAN_EID_S1G_BCN_COMPAT,
+ variable, ielen);
+ if (!ie)
+ return NULL;
+ compat = (void *)(ie + 2);
+ bssid = ext->u.s1g_beacon.sa;
+ capability = le16_to_cpu(compat->compat_info);
+ beacon_int = le16_to_cpu(compat->beacon_int);
+ } else {
+ bssid = mgmt->bssid;
+ beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
+ capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
+ }
+
ies = kzalloc(sizeof(*ies) + ielen, gfp);
if (!ies)
return NULL;
ies->len = ielen;
ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
- ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
- memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
+ ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) ||
+ ieee80211_is_s1g_beacon(mgmt->frame_control);
+ memcpy(ies->data, variable, ielen);

if (ieee80211_is_probe_resp(mgmt->frame_control))
rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
@@ -1848,12 +1887,12 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
rcu_assign_pointer(tmp.pub.ies, ies);

- memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
+ memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
+ tmp.pub.beacon_interval = beacon_int;
+ tmp.pub.capability = capability;
tmp.pub.channel = channel;
tmp.pub.scan_width = data->scan_width;
tmp.pub.signal = data->signal;
- tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
- tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
tmp.ts_boottime = data->boottime_ns;
tmp.parent_tsf = data->parent_tsf;
tmp.pub.chains = data->chains;
--
2.20.1

2020-08-27 22:34:18

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 13/22] cfg80211: handle Association Response from S1G STA

The sending STA type is implicit based on beacon or probe
response content. If sending STA was an S1G STA, adjust
the Information Element location accordingly.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/linux/ieee80211.h | 5 +++++
net/wireless/mlme.c | 20 ++++++++++++++++++++
2 files changed, 25 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index fe70cd99dec7..9307b60cef97 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1100,6 +1100,11 @@ struct ieee80211_mgmt {
/* followed by Supported rates */
u8 variable[0];
} __packed assoc_resp, reassoc_resp;
+ struct {
+ __le16 capab_info;
+ __le16 status_code;
+ u8 variable[0];
+ } __packed s1g_assoc_resp, s1g_reassoc_resp;
struct {
__le16 capab_info;
__le16 listen_interval;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index a6c61a2e6569..b5275fe93531 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -30,6 +30,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
struct cfg80211_connect_resp_params cr;
+ const struct cfg80211_bss_ies *ies;
+ const u8 *s1g;

memset(&cr, 0, sizeof(cr));
cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -42,6 +44,24 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;

+ /* Detect whether this was an S1G Association Response and adjust IE
+ * location accordingly.
+ */
+ rcu_read_lock();
+ ies = rcu_dereference(bss->ies);
+ if (WARN_ON(!ies)) {
+ rcu_read_unlock();
+ return;
+ }
+ s1g = cfg80211_find_ie(WLAN_EID_S1G_CAPABILITIES, ies->data, ies->len);
+ if (s1g) {
+ cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
+ cr.resp_ie_len =
+ len - offsetof(struct ieee80211_mgmt,
+ u.s1g_assoc_resp.variable);
+ }
+ rcu_read_unlock();
+
trace_cfg80211_send_rx_assoc(dev, bss);

/*
--
2.20.1

2020-08-27 22:34:20

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 09/22] mac80211: support S1G STA capabilities

Include the S1G Capabilities element in an association
request, and support the cfg80211 capability overrides.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/ieee80211_i.h | 4 ++++
net/mac80211/mlme.c | 8 +++++++
net/mac80211/util.c | 45 ++++++++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0b1eaec6649f..5da2713af500 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -530,6 +530,8 @@ struct ieee80211_if_managed {
struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */
struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */
+ struct ieee80211_s1g_cap s1g_capa; /* configured S1G overrides */
+ struct ieee80211_s1g_cap s1g_capa_mask; /* valid s1g_capa bits */

/* TDLS support */
u8 tdls_peer[ETH_ALEN] __aligned(2);
@@ -2193,6 +2195,8 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic,
enum nl80211_band band);
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
+u8 *ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_s1g_cap *caps, u8 *buf);

/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ac870309b911..b69889563457 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1018,6 +1018,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info);
}

+ if (sband->band == NL80211_BAND_S1GHZ)
+ pos = ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap,
+ skb_put(skb, 17));
+
/* add any remaining custom (i.e. vendor specific here) IEs */
if (assoc_data->ie_len) {
noffset = assoc_data->ie_len;
@@ -5461,6 +5465,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask,
sizeof(ifmgd->vht_capa_mask));

+ memcpy(&ifmgd->s1g_capa, &req->s1g_capa, sizeof(ifmgd->s1g_capa));
+ memcpy(&ifmgd->s1g_capa_mask, &req->s1g_capa_mask,
+ sizeof(ifmgd->s1g_capa_mask));
+
if (req->ie && req->ie_len) {
memcpy(assoc_data->ie, req->ie, req->ie_len);
assoc_data->ie_len = req->ie_len;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 35798997e521..c7ab7ab057f9 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4278,6 +4278,51 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
return max_num_different_channels;
}

+u8 *ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_s1g_cap *own_cap, u8 *buf)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_s1g_cap s1g_capab;
+ u8 *pos = buf;
+ int i;
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return pos;
+
+ if (!own_cap->s1g)
+ return pos;
+
+ memcpy(s1g_capab.capab_info, own_cap->cap, sizeof(own_cap->cap));
+ memcpy(s1g_capab.supp_mcs_nss, own_cap->nss_mcs,
+ sizeof(own_cap->nss_mcs));
+
+ /* override the capability info */
+ for (i = 0; i < sizeof(ifmgd->s1g_capa.capab_info); i++) {
+ u8 mask = ifmgd->s1g_capa_mask.capab_info[i];
+
+ s1g_capab.capab_info[i] &= ~mask;
+ s1g_capab.capab_info[i] |= (ifmgd->s1g_capa.capab_info[i] &
+ mask);
+ }
+
+ /* then MCS and NSS set */
+ for (i = 0; i < sizeof(ifmgd->s1g_capa.supp_mcs_nss); i++) {
+ u8 mask = ifmgd->s1g_capa_mask.supp_mcs_nss[i];
+
+ s1g_capab.supp_mcs_nss[i] &= ~mask;
+ s1g_capab.supp_mcs_nss[i] |= (ifmgd->s1g_capa.supp_mcs_nss[i] &
+ mask);
+ }
+
+ *pos++ = WLAN_EID_S1G_CAPABILITIES;
+ *pos++ = sizeof(s1g_capab);
+
+ memcpy(pos, &s1g_capab, sizeof(s1g_capab));
+ pos += sizeof(s1g_capab);
+
+ return pos;
+}
+
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo)
{
*buf++ = WLAN_EID_VENDOR_SPECIFIC;
--
2.20.1

2020-08-27 22:34:24

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 11/22] cfg80211: parse S1G Operation element for BSS channel

Extract the BSS primary channel from the S1G Operation
element.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/wireless/scan.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index bf72a13dd2aa..169b6904e011 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1318,15 +1318,26 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
if (tmp && tmp[1] == 1) {
channel_number = tmp[2];
- } else {
- tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
- if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
- struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
+ goto found_channel;
+ }

- channel_number = htop->primary_chan;
- }
+ tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
+ if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
+ struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
+
+ channel_number = htop->primary_chan;
+ goto found_channel;
+ }
+
+ tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
+ if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
+ struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
+
+ channel_number = s1gop->primary_ch;
+ goto found_channel;
}

+found_channel:
if (channel_number < 0) {
/* No channel information in frame payload */
return channel;
--
2.20.1

2020-08-27 22:34:28

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 15/22] mac80211: don't calculate duration for S1G

For now just skip the duration calculation for frames
transmitted on the S1G band and avoid a warning.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/tx.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index dca01d7e6e3e..424fd9b2aeda 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -82,6 +82,10 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,

erp = txrate->flags & IEEE80211_RATE_ERP_G;

+ /* TODO */
+ if (sband->band == NL80211_BAND_S1GHZ)
+ return 0;
+
/*
* data and mgmt (except PS Poll):
* - during CFP: 32768
--
2.20.1

2020-08-27 22:34:36

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 12/22] mac80211: convert S1G beacon to scan results

This commit finds the correct offset for Information
Elements in S1G beacon frames so they can be reported in
scan results, and track whether a given BSS is S1G.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/ieee80211_i.h | 7 +++++++
net/mac80211/rx.c | 3 ++-
net/mac80211/scan.c | 20 ++++++++++++++++----
net/mac80211/util.c | 28 ++++++++++++++++++++++++++++
4 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5da2713af500..378945b0f3a0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -127,6 +127,9 @@ struct ieee80211_bss {

/* Keep track of what bits of information we have valid info for. */
u8 valid_data;
+
+ /* BSS info was transmitted by an S1G STA */
+ u8 s1g;
};

/**
@@ -1524,6 +1527,10 @@ struct ieee802_11_elems {
u8 dtim_count;
u8 dtim_period;
const struct ieee80211_addba_ext_ie *addba_ext_ie;
+ const struct ieee80211_s1g_cap *s1g_capab;
+ const struct ieee80211_s1g_oper_ie *s1g_oper;
+ const u8 *s1g_tsbtt;
+ const struct ieee80211_s1g_bcn_compat_ie *s1g_bcn_compat;

/* length of them, respectively */
u8 ext_capab_len;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 836cde516a18..5b92f56682e2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4586,7 +4586,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_verify_alignment(&rx);

if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
- ieee80211_is_beacon(hdr->frame_control)))
+ ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_s1g_beacon(hdr->frame_control)))
ieee80211_scan_rx(local, skb);

if (ieee80211_is_data(fc)) {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 5002791fe165..3dd65b7c839b 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -124,6 +124,9 @@ ieee80211_update_bss_from_elems(struct ieee80211_local *local,
bss->valid_data |= IEEE80211_BSS_VALID_WMM;
}

+ if (!elems->parse_error && elems->s1g_capab)
+ bss->s1g = true;
+
if (beacon) {
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[rx_status->band];
@@ -146,7 +149,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_channel *channel)
{
- bool beacon = ieee80211_is_beacon(mgmt->frame_control);
+ bool beacon = ieee80211_is_beacon(mgmt->frame_control) ||
+ ieee80211_is_s1g_beacon(mgmt->frame_control);
struct cfg80211_bss *cbss, *non_tx_cbss;
struct ieee80211_bss *bss, *non_tx_bss;
struct cfg80211_inform_bss bss_meta = {
@@ -195,6 +199,11 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
elements = mgmt->u.probe_resp.variable;
baselen = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
+ } else if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
+ struct ieee80211_ext *ext = (void *) mgmt;
+
+ baselen = offsetof(struct ieee80211_ext, u.s1g_beacon.variable);
+ elements = ext->u.s1g_beacon.variable;
} else {
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
elements = mgmt->u.beacon.variable;
@@ -246,9 +255,12 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
struct ieee80211_bss *bss;
struct ieee80211_channel *channel;

- if (skb->len < 24 ||
- (!ieee80211_is_probe_resp(mgmt->frame_control) &&
- !ieee80211_is_beacon(mgmt->frame_control)))
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
+ if (skb->len < 15)
+ return;
+ } else if (skb->len < 24 ||
+ (!ieee80211_is_probe_resp(mgmt->frame_control) &&
+ !ieee80211_is_beacon(mgmt->frame_control)))
return;

sdata1 = rcu_dereference(local->scan_sdata);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index c7ab7ab057f9..0fa57349c4e5 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1003,6 +1003,10 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case WLAN_EID_LINK_ID:
case WLAN_EID_BSS_MAX_IDLE_PERIOD:
case WLAN_EID_RSNX:
+ case WLAN_EID_S1G_BCN_COMPAT:
+ case WLAN_EID_S1G_CAPABILITIES:
+ case WLAN_EID_S1G_OPERATION:
+ case WLAN_EID_S1G_SHORT_BCN_INTERVAL:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
@@ -1288,6 +1292,30 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
&crc : NULL,
elem, elems);
break;
+ case WLAN_EID_S1G_CAPABILITIES:
+ if (elen == 15)
+ elems->s1g_capab = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
+ case WLAN_EID_S1G_OPERATION:
+ if (elen == 6)
+ elems->s1g_oper = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
+ case WLAN_EID_S1G_SHORT_BCN_INTERVAL:
+ if (elen == 2)
+ elems->s1g_tsbtt = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
+ case WLAN_EID_S1G_BCN_COMPAT:
+ if (elen == sizeof(struct ieee80211_s1g_bcn_compat_ie))
+ elems->s1g_bcn_compat = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
default:
break;
}
--
2.20.1

2020-08-27 22:34:55

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 16/22] mac80211: handle S1G low rates

S1G doesn't have legacy (sband->bitrates) rates, only MCS.
For now, just send a frame at MCS 0 if a low rate is
requested. Note we also redefine (since we're out of TX
flags) TX_RC_VHT_MCS as TX_RC_S1G_MCS to indicate an S1G
MCS. This is probably OK as VHT MCS is not valid on S1G
band and vice versa.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/mac80211.h | 2 ++
net/mac80211/rate.c | 33 ++++++++++++++++++++++++++-------
2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 66e2bfd165e8..a9340e673610 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -812,6 +812,8 @@ enum mac80211_tx_info_flags {

#define IEEE80211_TX_CTL_STBC_SHIFT 23

+#define IEEE80211_TX_RC_S1G_MCS IEEE80211_TX_RC_VHT_MCS
+
/**
* enum mac80211_tx_control_flags - flags to describe transmit control
*
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index b051f125d3af..63266d73c252 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -266,10 +266,15 @@ void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata)
if (WARN_ON(!sdata->vif.bss_conf.chandef.chan))
return;

+ band = sdata->vif.bss_conf.chandef.chan->band;
+ if (band == NL80211_BAND_S1GHZ) {
+ /* TODO */
+ return;
+ }
+
if (WARN_ON_ONCE(!basic_rates))
return;

- band = sdata->vif.bss_conf.chandef.chan->band;
user_mask = sdata->rc_rateidx_mask[band];
sband = local->hw.wiphy->bands[band];

@@ -296,21 +301,29 @@ static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
!ieee80211_is_data(fc);
}

-static void rc_send_low_basicrate(s8 *idx, u32 basic_rates,
+static void rc_send_low_basicrate(struct ieee80211_tx_rate *rate,
+ u32 basic_rates,
struct ieee80211_supported_band *sband)
{
u8 i;

+ if (sband->band == NL80211_BAND_S1GHZ) {
+ /* TODO */
+ rate->flags |= IEEE80211_TX_RC_S1G_MCS;
+ rate->idx = 0;
+ return;
+ }
+
if (basic_rates == 0)
return; /* assume basic rates unknown and accept rate */
- if (*idx < 0)
+ if (rate->idx < 0)
return;
- if (basic_rates & (1 << *idx))
+ if (basic_rates & (1 << rate->idx))
return; /* selected rate is a basic rate */

- for (i = *idx + 1; i <= sband->n_bitrates; i++) {
+ for (i = rate->idx + 1; i <= sband->n_bitrates; i++) {
if (basic_rates & (1 << i)) {
- *idx = i;
+ rate->idx = i;
return;
}
}
@@ -328,6 +341,12 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
u32 rate_flags =
ieee80211_chandef_rate_flags(&hw->conf.chandef);

+ if (sband->band == NL80211_BAND_S1GHZ) {
+ info->control.rates[0].flags |= IEEE80211_TX_RC_S1G_MCS;
+ info->control.rates[0].idx = 0;
+ return;
+ }
+
if ((sband->band == NL80211_BAND_2GHZ) &&
(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
rate_flags |= IEEE80211_RATE_ERP_G;
@@ -388,7 +407,7 @@ static bool rate_control_send_low(struct ieee80211_sta *pubsta,
}

if (use_basicrate)
- rc_send_low_basicrate(&info->control.rates[0].idx,
+ rc_send_low_basicrate(&info->control.rates[0],
txrc->bss_conf->basic_rates,
sband);

--
2.20.1

2020-08-27 22:34:59

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 14/22] mac80211: encode listen interval for S1G

S1G allows listen interval up to 2^14 * 10000 beacon
intervals. In order to do this listen interval needs a
scaling factor applied to the lower 14 bits. Calculate
this and properly encode the listen interval for S1G STAs.

See IEEE802.11ah-2016 Table 9-44a for reference.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/linux/ieee80211.h | 8 ++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 11 +++++++----
net/mac80211/util.c | 20 ++++++++++++++++++++
4 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 9307b60cef97..93c1496af8f2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2446,6 +2446,14 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)

#define S1G_CAPAB_B9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0)

+#define LISTEN_INT_USF_MASK (BIT(14) | BIT(15))
+#define LISTEN_INT_USF_SHIFT 14
+
+#define IEEE80211_MAX_USF 3
+#define IEEE80211_MAX_UI ((1 << 14) - 1)
+
+static const int listen_int_usf[] = { 1, 10, 1000, 10000 };
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 378945b0f3a0..8b779ad363c5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2293,6 +2293,7 @@ void ieee80211_tdls_chsw_work(struct work_struct *wk);
void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata,
const u8 *peer, u16 reason);
const char *ieee80211_get_reason_code_string(u16 reason_code);
+__le16 ieee80211_encode_usf(int val);

extern const struct ethtool_ops ieee80211_ethtool_ops;

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b69889563457..6a62a221b89e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -686,6 +686,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
+ struct ieee80211_bss *bss = (void *)assoc_data->bss->priv;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, qos_info, *ie_start;
@@ -696,6 +697,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
u32 rates = 0;
+ __le16 listen_int;
struct element *ext_capa = NULL;

/* we know it's writable, cast away the const */
@@ -784,13 +786,15 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN);

+ listen_int = cpu_to_le16(bss->s1g ?
+ ieee80211_encode_usf(local->hw.conf.listen_interval) :
+ local->hw.conf.listen_interval);
if (!is_zero_ether_addr(assoc_data->prev_bssid)) {
skb_put(skb, 10);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_REASSOC_REQ);
mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
- mgmt->u.reassoc_req.listen_interval =
- cpu_to_le16(local->hw.conf.listen_interval);
+ mgmt->u.reassoc_req.listen_interval = listen_int;
memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid,
ETH_ALEN);
} else {
@@ -798,8 +802,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ASSOC_REQ);
mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
- mgmt->u.assoc_req.listen_interval =
- cpu_to_le16(local->hw.conf.listen_interval);
+ mgmt->u.assoc_req.listen_interval = listen_int;
}

/* SSID */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0fa57349c4e5..caf4098deeda 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4393,3 +4393,23 @@ const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS] = {
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE,
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK
};
+
+__le16 ieee80211_encode_usf(int listen_interval)
+{
+ u16 ui, usf = 0;
+
+ /* find greatest USF */
+ while (usf < IEEE80211_MAX_USF) {
+ if (listen_interval % listen_int_usf[usf + 1])
+ break;
+ usf += 1;
+ }
+ ui = listen_interval / listen_int_usf[usf];
+
+ /* error if there is a remainder. Should've been checked by user */
+ if (WARN_ON_ONCE(ui > IEEE80211_MAX_UI))
+ ui &= (1 << LISTEN_INT_USF_SHIFT) - 1;
+ listen_interval = usf << LISTEN_INT_USF_SHIFT | ui;
+
+ return listen_interval;
+}
--
2.20.1

2020-08-27 22:34:59

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 17/22] mac80211: avoid rate init for S1G band

minstrel_ht is confused by the lack of sband->bitrates,
and S1G will likely require a unique RC algorithm, so
avoid rate init for now if STA is on the S1G band.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/rate.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 63266d73c252..0cba7fed28cf 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -51,6 +51,12 @@ void rate_control_rate_init(struct sta_info *sta)

sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];

+ /* TODO: check for minstrel_s1g ? */
+ if (sband->band == NL80211_BAND_S1GHZ) {
+ rcu_read_unlock();
+ return;
+ }
+
spin_lock_bh(&sta->rate_ctrl_lock);
ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
priv_sta);
--
2.20.1

2020-08-27 22:34:59

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 18/22] mac80211: receive and process S1G beacons

S1G beacons are 802.11 Extension Frames, so the fixed
header part differs from regular beacons.

Add a handler to process S1G beacons and abstract out the
fetching of BSSID and element start locations in the
beacon body handler.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/ieee80211_i.h | 4 ++
net/mac80211/iface.c | 5 +++
net/mac80211/mlme.c | 87 +++++++++++++++++++++++++++++---------
net/mac80211/rx.c | 84 ++++++++++++++++--------------------
net/mac80211/util.c | 52 +++++++++++++++++++++++
5 files changed, 164 insertions(+), 68 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8b779ad363c5..5d0157065db6 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1649,6 +1649,8 @@ int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata);
@@ -2294,6 +2296,8 @@ void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata,
const u8 *peer, u16 reason);
const char *ieee80211_get_reason_code_string(u16 reason_code);
__le16 ieee80211_encode_usf(int val);
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+ enum nl80211_iftype type);

extern const struct ethtool_ops ieee80211_ethtool_ops;

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 9740ae8fa697..1369f6e575d7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1379,6 +1379,11 @@ static void ieee80211_iface_work(struct work_struct *work)
WARN_ON(1);
break;
}
+ } else if (ieee80211_is_ext(mgmt->frame_control)) {
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_sta_rx_queued_ext(sdata, skb);
+ else
+ WARN_ON(1);
} else if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *)mgmt;
/*
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6a62a221b89e..9a26ef99cef9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1604,6 +1604,9 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
int new_ap_level;
__le16 capab = mgmt->u.probe_resp.capab_info;

+ if (ieee80211_is_s1g_beacon(mgmt->frame_control))
+ return 0; /* TODO */
+
if (country_ie &&
(capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) ||
capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) {
@@ -2450,7 +2453,8 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
* data idle periods for sending the periodic probe request to the
* AP we're connected to.
*/
- if (is_multicast_ether_addr(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1) ||
+ ieee80211_is_s1g_beacon(hdr->frame_control))
return;

ieee80211_sta_reset_conn_monitor(sdata);
@@ -3919,12 +3923,13 @@ static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
}

-static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len,
- struct ieee80211_rx_status *rx_status)
+static void ieee80211_rx_beacon(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr, size_t len,
+ struct ieee80211_rx_status *rx_status)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+ struct ieee80211_mgmt *mgmt = (void *) hdr;
size_t baselen;
struct ieee802_11_elems elems;
struct ieee80211_local *local = sdata->local;
@@ -3934,14 +3939,24 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
u32 changed = 0;
bool erp_valid;
u8 erp_value = 0;
- u32 ncrc;
- u8 *bssid;
+ u32 ncrc = 0;
+ u8 *bssid, *variable = mgmt->u.beacon.variable;
u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];

sdata_assert_lock(sdata);

/* Process beacon from the current BSS */
- baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type);
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
+ struct ieee80211_ext *ext = (void *) mgmt;
+
+ if (ieee80211_is_s1g_short_beacon(ext->frame_control))
+ variable = ext->u.s1g_short_beacon.variable;
+ else
+ variable = ext->u.s1g_beacon.variable;
+ }
+
+ baselen = (u8 *) variable - (u8 *) mgmt;
if (baselen > len)
return;

@@ -3961,10 +3976,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();

if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
- ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) {
- ieee802_11_parse_elems(mgmt->u.beacon.variable,
+ ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) {
+ ieee802_11_parse_elems(variable,
len - baselen, false, &elems,
- mgmt->bssid,
+ bssid,
ifmgd->assoc_data->bss->bssid);

ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
@@ -3997,7 +4012,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}

if (!ifmgd->associated ||
- !ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->associated))
+ !ieee80211_rx_our_beacon(bssid, ifmgd->associated))
return;
bssid = ifmgd->associated->bssid;

@@ -4017,8 +4032,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
*/
ieee80211_sta_reset_beacon_monitor(sdata);

- ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
- ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
+ /* TODO: CRC urrently not calculated on S1G Beacon Compatibility
+ * element (which carries the beacon interval). Don't forget to add a
+ * bit to care_about_ies[] above if mac80211 is interested in a
+ * changing S1G element.
+ */
+ if (!ieee80211_is_s1g_beacon(hdr->frame_control))
+ ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
+ ncrc = ieee802_11_parse_elems_crc(variable,
len - baselen, false, &elems,
care_about_ies, ncrc,
mgmt->bssid, bssid);
@@ -4052,7 +4073,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
struct ieee80211_p2p_noa_attr noa = {};
int ret;

- ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable,
+ ret = cfg80211_get_p2p_attr(variable,
len - baselen,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
(u8 *) &noa, sizeof(noa));
@@ -4088,7 +4109,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
* the driver will use them. The synchronized view is currently
* guaranteed only in certain callbacks.
*/
- if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
+ if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) &&
+ !ieee80211_is_s1g_beacon(hdr->frame_control)) {
sdata->vif.bss_conf.sync_tsf =
le64_to_cpu(mgmt->u.beacon.timestamp);
sdata->vif.bss_conf.sync_device_ts =
@@ -4096,7 +4118,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
}

- if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
+ if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) ||
+ ieee80211_is_s1g_short_beacon(mgmt->frame_control))
return;
ifmgd->beacon_crc = ncrc;
ifmgd->beacon_crc_valid = true;
@@ -4137,9 +4160,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
} else {
erp_valid = false;
}
- changed |= ieee80211_handle_bss_capability(sdata,
- le16_to_cpu(mgmt->u.beacon.capab_info),
- erp_valid, erp_value);
+
+ if (!ieee80211_is_s1g_beacon(hdr->frame_control)) {
+ changed |= ieee80211_handle_bss_capability(sdata,
+ le16_to_cpu(mgmt->u.beacon.capab_info),
+ erp_valid, erp_value);
+ }

mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, bssid);
@@ -4177,6 +4203,26 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, changed);
}

+void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ rx_status = (struct ieee80211_rx_status *) skb->cb;
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ sdata_lock(sdata);
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_S1G_BEACON:
+ ieee80211_rx_beacon(sdata, hdr, skb->len, rx_status);
+ break;
+ }
+ sdata_unlock(sdata);
+}
+
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
@@ -4194,7 +4240,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,

switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_BEACON:
- ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
+ ieee80211_rx_beacon(sdata, (struct ieee80211_hdr *) mgmt,
+ skb->len, rx_status);
break;
case IEEE80211_STYPE_PROBE_RESP:
ieee80211_rx_mgmt_probe_resp(sdata, skb);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5b92f56682e2..e1291898bde8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -42,51 +42,6 @@ static inline void ieee80211_rx_stats(struct net_device *dev, u32 len)
u64_stats_update_end(&tstats->syncp);
}

-static u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
- enum nl80211_iftype type)
-{
- __le16 fc = hdr->frame_control;
-
- if (ieee80211_is_data(fc)) {
- if (len < 24) /* drop incorrect hdr len (data) */
- return NULL;
-
- if (ieee80211_has_a4(fc))
- return NULL;
- if (ieee80211_has_tods(fc))
- return hdr->addr1;
- if (ieee80211_has_fromds(fc))
- return hdr->addr2;
-
- return hdr->addr3;
- }
-
- if (ieee80211_is_mgmt(fc)) {
- if (len < 24) /* drop incorrect hdr len (mgmt) */
- return NULL;
- return hdr->addr3;
- }
-
- if (ieee80211_is_ctl(fc)) {
- if (ieee80211_is_pspoll(fc))
- return hdr->addr1;
-
- if (ieee80211_is_back_req(fc)) {
- switch (type) {
- case NL80211_IFTYPE_STATION:
- return hdr->addr2;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_AP_VLAN:
- return hdr->addr1;
- default:
- break; /* fall through to the return */
- }
- }
- }
-
- return NULL;
-}
-
/*
* monitor mode reception
*
@@ -1801,7 +1756,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
}
} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
sta->rx_stats.last_rx = jiffies;
- } else if (!is_multicast_ether_addr(hdr->addr1)) {
+ } else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1)) {
/*
* Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed.
@@ -1839,6 +1795,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
}
}

+ if (ieee80211_is_s1g_beacon(hdr->frame_control))
+ return RX_CONTINUE;
+
/*
* Change STA power saving mode only at the end of a frame
* exchange sequence, and only for a data or management
@@ -1949,6 +1908,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
__le16 fc;
const struct ieee80211_cipher_scheme *cs = NULL;

+ if (ieee80211_is_ext(hdr->frame_control))
+ return RX_CONTINUE;
+
/*
* Key selection 101
*
@@ -2257,7 +2219,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
hdr = (struct ieee80211_hdr *)rx->skb->data;
fc = hdr->frame_control;

- if (ieee80211_is_ctl(fc))
+ if (ieee80211_is_ctl(fc) || ieee80211_is_ext(fc))
return RX_CONTINUE;

sc = le16_to_cpu(hdr->seq_ctrl);
@@ -3131,6 +3093,9 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);

+ if (ieee80211_is_s1g_beacon(mgmt->frame_control))
+ return RX_CONTINUE;
+
/*
* From here on, look only at management frames.
* Data and control frames are already handled,
@@ -3597,6 +3562,27 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
return RX_QUEUED;
}

+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_ext(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_hdr *hdr = (void *)rx->skb->data;
+
+ if (!ieee80211_is_ext(hdr->frame_control))
+ return RX_CONTINUE;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return RX_DROP_MONITOR;
+
+ /* for now only beacons are ext, so queue them */
+ skb_queue_tail(&sdata->skb_queue, rx->skb);
+ ieee80211_queue_work(&rx->local->hw, &sdata->work);
+ if (rx->sta)
+ rx->sta->rx_stats.packets++;
+
+ return RX_QUEUED;
+}
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
@@ -3816,6 +3802,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
CALL_RXH(ieee80211_rx_h_userspace_mgmt);
CALL_RXH(ieee80211_rx_h_action_post_userspace);
CALL_RXH(ieee80211_rx_h_action_return);
+ CALL_RXH(ieee80211_rx_h_ext);
CALL_RXH(ieee80211_rx_h_mgmt);

rxh_next:
@@ -3982,7 +3969,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
- bool multicast = is_multicast_ether_addr(hdr->addr1);
+ bool multicast = is_multicast_ether_addr(hdr->addr1) ||
+ ieee80211_is_s1g_beacon(hdr->frame_control);

switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index caf4098deeda..0d304c328f7e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -45,6 +45,58 @@ struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
}
EXPORT_SYMBOL(wiphy_to_ieee80211_hw);

+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+ enum nl80211_iftype type)
+{
+ __le16 fc = hdr->frame_control;
+
+ if (ieee80211_is_data(fc)) {
+ if (len < 24) /* drop incorrect hdr len (data) */
+ return NULL;
+
+ if (ieee80211_has_a4(fc))
+ return NULL;
+ if (ieee80211_has_tods(fc))
+ return hdr->addr1;
+ if (ieee80211_has_fromds(fc))
+ return hdr->addr2;
+
+ return hdr->addr3;
+ }
+
+ if (ieee80211_is_s1g_beacon(fc)) {
+ struct ieee80211_ext *ext = (void *) hdr;
+
+ return ext->u.s1g_beacon.sa;
+ }
+
+ if (ieee80211_is_mgmt(fc)) {
+ if (len < 24) /* drop incorrect hdr len (mgmt) */
+ return NULL;
+ return hdr->addr3;
+ }
+
+ if (ieee80211_is_ctl(fc)) {
+ if (ieee80211_is_pspoll(fc))
+ return hdr->addr1;
+
+ if (ieee80211_is_back_req(fc)) {
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ return hdr->addr2;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ return hdr->addr1;
+ default:
+ break; /* fall through to the return */
+ }
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(ieee80211_get_bssid);
+
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb;
--
2.20.1

2020-08-27 22:35:05

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 19/22] mac80211: support S1G association

The changes required for associating in S1G are:

- apply S1G BSS channel info before assoc
- mark all S1G STAs as QoS STAs
- include and parse AID request element
- handle new Association Response format
- don't fail assoc if supported rates element is missing

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/linux/ieee80211.h | 25 ++++++++++++
include/net/mac80211.h | 1 +
net/mac80211/cfg.c | 2 +
net/mac80211/ibss.c | 3 +-
net/mac80211/ieee80211_i.h | 4 ++
net/mac80211/mlme.c | 80 ++++++++++++++++++++++++++++++++------
net/mac80211/util.c | 56 ++++++++++++++++++++++++++
7 files changed, 158 insertions(+), 13 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 93c1496af8f2..5cff6a373158 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -987,6 +987,25 @@ enum ieee80211_vht_opmode_bits {
IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80,
};

+/**
+ * enum ieee80211_s1g_chanwidth
+ * These are defined in IEEE802.11-2016ah Table 10-20
+ * as BSS Channel Width
+ *
+ * @IEEE80211_S1G_CHANWIDTH_1MHZ: 1MHz operating channel
+ * @IEEE80211_S1G_CHANWIDTH_2MHZ: 2MHz operating channel
+ * @IEEE80211_S1G_CHANWIDTH_4MHZ: 4MHz operating channel
+ * @IEEE80211_S1G_CHANWIDTH_8MHZ: 8MHz operating channel
+ * @IEEE80211_S1G_CHANWIDTH_16MHZ: 16MHz operating channel
+ */
+enum ieee80211_s1g_chanwidth {
+ IEEE80211_S1G_CHANWIDTH_1MHZ = 0,
+ IEEE80211_S1G_CHANWIDTH_2MHZ = 1,
+ IEEE80211_S1G_CHANWIDTH_4MHZ = 3,
+ IEEE80211_S1G_CHANWIDTH_8MHZ = 7,
+ IEEE80211_S1G_CHANWIDTH_16MHZ = 15,
+};
+
#define WLAN_SA_QUERY_TR_ID_LEN 2
#define WLAN_MEMBERSHIP_LEN 8
#define WLAN_USER_POSITION_LEN 16
@@ -2446,6 +2465,10 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)

#define S1G_CAPAB_B9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0)

+#define S1G_OPER_CH_WIDTH_PRIMARY_1MHZ BIT(0)
+#define S1G_OPER_CH_WIDTH_OPER (BIT(1) | BIT(2) | BIT(3) | BIT(4))
+#define S1G_OPER_CH_WIDTH_OPER_SHIFT 1
+
#define LISTEN_INT_USF_MASK (BIT(14) | BIT(15))
#define LISTEN_INT_USF_SHIFT 14

@@ -2853,6 +2876,8 @@ enum ieee80211_eid {

WLAN_EID_REDUCED_NEIGHBOR_REPORT = 201,

+ WLAN_EID_AID_REQUEST = 210,
+ WLAN_EID_AID_RESPONSE = 211,
WLAN_EID_S1G_BCN_COMPAT = 213,
WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214,
WLAN_EID_S1G_CAPABILITIES = 217,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a9340e673610..c5760a912ec5 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -674,6 +674,7 @@ struct ieee80211_bss_conf {
} he_oper;
struct ieee80211_he_obss_pd he_obss_pd;
struct cfg80211_he_bss_color he_bss_color;
+ bool s1g;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 87fddd84c621..bbd9577788fb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1071,6 +1071,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sizeof(struct ieee80211_he_obss_pd));
memcpy(&sdata->vif.bss_conf.he_bss_color, &params->he_bss_color,
sizeof(struct ieee80211_he_bss_color));
+ sdata->vif.bss_conf.s1g = params->chandef.chan->band ==
+ NL80211_BAND_S1GHZ;

sdata->vif.bss_conf.ssid_len = params->ssid_len;
if (params->ssid_len)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 53632c2f5217..a8a87ce2d9da 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1037,7 +1037,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
}

if (sta && !sta->sta.wme &&
- elems->wmm_info && local->hw.queues >= IEEE80211_NUM_ACS) {
+ (elems->wmm_info || elems->s1g_capab) &&
+ local->hw.queues >= IEEE80211_NUM_ACS) {
sta->sta.wme = true;
ieee80211_check_fast_xmit(sta);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5d0157065db6..c218e2294869 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1531,6 +1531,7 @@ struct ieee802_11_elems {
const struct ieee80211_s1g_oper_ie *s1g_oper;
const u8 *s1g_tsbtt;
const struct ieee80211_s1g_bcn_compat_ie *s1g_bcn_compat;
+ const struct ieee80211_aid_response_ie *aid_resp;

/* length of them, respectively */
u8 ext_capab_len;
@@ -2206,6 +2207,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
u8 *ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_s1g_cap *caps, u8 *buf);
+u8 *ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata, u8 *buf);

/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
@@ -2217,6 +2219,8 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_he_operation *he_oper,
struct cfg80211_chan_def *chandef);
+bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
+ struct cfg80211_chan_def *chandef);
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);

int __must_check
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9a26ef99cef9..2476d4a9596c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -149,6 +149,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_ht_operation *ht_oper,
const struct ieee80211_vht_operation *vht_oper,
const struct ieee80211_he_operation *he_oper,
+ const struct ieee80211_s1g_oper_ie *s1g_oper,
struct cfg80211_chan_def *chandef, bool tracking)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -176,6 +177,15 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);

+ if (s1g_oper && sband->band == NL80211_BAND_S1GHZ) {
+ ieee80211_chandef_s1g_oper(s1g_oper, chandef);
+ ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_40MHZ |
+ IEEE80211_STA_DISABLE_VHT |
+ IEEE80211_STA_DISABLE_80P80MHZ |
+ IEEE80211_STA_DISABLE_160MHZ;
+ goto out;
+ }
+
if (!ht_oper || !sta_ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
@@ -347,6 +357,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_ht_operation *ht_oper,
const struct ieee80211_vht_operation *vht_oper,
const struct ieee80211_he_operation *he_oper,
+ const struct ieee80211_s1g_oper_ie *s1g_oper,
const u8 *bssid, u32 *changed)
{
struct ieee80211_local *local = sdata->local;
@@ -393,7 +404,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
/* calculate new channel (type) based on HT/VHT/HE operation IEs */
flags = ieee80211_determine_chantype(sdata, sband, chan, vht_cap_info,
ht_oper, vht_oper, he_oper,
- &chandef, true);
+ s1g_oper, &chandef, true);

/*
* Downgrade the new channel if we associated with restricted
@@ -812,6 +823,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*pos++ = assoc_data->ssid_len;
memcpy(pos, assoc_data->ssid, assoc_data->ssid_len);

+ if (bss->s1g)
+ goto skip_rates;
+
/* add all rates which were marked to be used above */
supp_rates_len = rates_len;
if (supp_rates_len > 8)
@@ -847,6 +861,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
}

+skip_rates:
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT ||
capab & WLAN_CAPABILITY_RADIO_MEASURE) {
pos = skb_put(skb, 4);
@@ -1021,9 +1036,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info);
}

- if (sband->band == NL80211_BAND_S1GHZ)
+ if (sband->band == NL80211_BAND_S1GHZ) {
+ pos = ieee80211_add_aid_request_ie(sdata, skb_put(skb, 3));
pos = ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap,
skb_put(skb, 17));
+ }

/* add any remaining custom (i.e. vendor specific here) IEs */
if (assoc_data->ie_len) {
@@ -3270,6 +3287,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_bss *bss = (void *)cbss->priv;
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
struct sta_info *sta;
@@ -3279,13 +3297,24 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
u32 changed = 0;
+ u8 *pos;
int err;
bool ret;

/* AssocResp and ReassocResp have identical structure */

+ pos = mgmt->u.assoc_resp.variable;
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+ if (bss->s1g) {
+ pos = (u8 *) mgmt->u.s1g_assoc_resp.variable;
+ aid = 0; /* TODO */
+ }
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems,
+ mgmt->bssid, assoc_data->bss->bssid);
+
+ if (elems->aid_resp)
+ aid = le16_to_cpu(elems->aid_resp->aid);

/*
* The 5 MSB of the AID field are reserved
@@ -3302,7 +3331,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ifmgd->broken_ap = true;
}

- if (!elems->supp_rates) {
+ if (!bss->s1g && !elems->supp_rates) {
sdata_info(sdata, "no SuppRates element in AssocResp\n");
return false;
}
@@ -3544,7 +3573,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
sta->sta.mfp = false;
}

- sta->sta.wme = elems->wmm_param && local->hw.queues >= IEEE80211_NUM_ACS;
+ sta->sta.wme = (elems->wmm_param || elems->s1g_capab) &&
+ local->hw.queues >= IEEE80211_NUM_ACS;

err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -3636,7 +3666,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
int ac, uapsd_queues = -1;
u8 *pos;
bool reassoc;
- struct cfg80211_bss *bss;
+ struct cfg80211_bss *cbss;
+ struct ieee80211_bss *bss;
struct ieee80211_event event = {
.type = MLME_EVENT,
.u.mlme.data = ASSOC_EVENT,
@@ -3646,9 +3677,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,

if (!assoc_data)
return;
+
if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid))
return;

+ cbss = assoc_data->bss;
+ bss = (void *) cbss->priv;
+
/*
* AssocResp and ReassocResp have identical structure, so process both
* of them in this function.
@@ -3660,7 +3695,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control);
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ pos = mgmt->u.assoc_resp.variable;
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+ if (bss->s1g) {
+ pos = (u8 *) mgmt->u.s1g_assoc_resp.variable;
+ aid = 0; /* TODO */
+ }

sdata_info(sdata,
"RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
@@ -3671,7 +3711,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
return;

- pos = mgmt->u.assoc_resp.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
mgmt->bssid, assoc_data->bss->bssid);

@@ -3691,8 +3730,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
return;
}

- bss = assoc_data->bss;
-
if (status_code != WLAN_STATUS_SUCCESS) {
sdata_info(sdata, "%pM denied association (code=%d)\n",
mgmt->sa, status_code);
@@ -3701,10 +3738,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
event.u.mlme.reason = status_code;
drv_event_callback(sdata->local, sdata, &event);
} else {
- if (!ieee80211_assoc_success(sdata, bss, mgmt, len, &elems)) {
+ if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) {
/* oops -- internal error -- send timeout for now */
ieee80211_destroy_assoc_data(sdata, false, false);
- cfg80211_assoc_timeout(sdata->dev, bss);
+ cfg80211_assoc_timeout(sdata->dev, cbss);
return;
}
event.u.mlme.status = MLME_SUCCESS;
@@ -3725,7 +3762,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
uapsd_queues |= ieee80211_ac_to_qos_mask[ac];
}

- cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues,
+ cfg80211_rx_assoc_resp(sdata->dev, cbss, (u8 *)mgmt, len, uapsd_queues,
ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
}

@@ -4175,7 +4212,7 @@ static void ieee80211_rx_beacon(struct ieee80211_sub_if_data *sdata,
if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem,
elems.vht_cap_elem, elems.ht_operation,
elems.vht_operation, elems.he_operation,
- bssid, &changed)) {
+ elems.s1g_oper, bssid, &changed)) {
mutex_unlock(&local->sta_mtx);
sdata_info(sdata,
"failed to follow AP %pM bandwidth change, disconnect\n",
@@ -4912,6 +4949,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_ht_operation *ht_oper = NULL;
const struct ieee80211_vht_operation *vht_oper = NULL;
const struct ieee80211_he_operation *he_oper = NULL;
+ const struct ieee80211_s1g_oper_ie *s1g_oper = NULL;
struct ieee80211_supported_band *sband;
struct cfg80211_chan_def chandef;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
@@ -5014,10 +5052,23 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
if (!have_80mhz)
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;

+ if (sband->band == NL80211_BAND_S1GHZ) {
+ const u8 *s1g_oper_ie;
+
+ s1g_oper_ie = ieee80211_bss_get_ie(cbss,
+ WLAN_EID_S1G_OPERATION);
+ if (s1g_oper_ie && s1g_oper_ie[1] >= sizeof(*s1g_oper))
+ s1g_oper = (void *)(s1g_oper_ie + 2);
+ else
+ sdata_info(sdata,
+ "AP missing S1G operation element?\n");
+ }
+
ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
cbss->channel,
bss->vht_cap_info,
ht_oper, vht_oper, he_oper,
+ s1g_oper,
&chandef, false);

sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
@@ -5144,6 +5195,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_bss_ies *ies;
int shift = ieee80211_vif_get_shift(&sdata->vif);

+ /* TODO: S1G Basic Rate Set is expressed elsewhere */
+ if (cbss->channel->band == NL80211_BAND_S1GHZ)
+ goto skip_rates;
+
ieee80211_get_rates(sband, bss->supp_rates,
bss->supp_rates_len,
&rates, &basic_rates,
@@ -5188,6 +5243,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;

+skip_rates:
memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN);

/* set timing information */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0d304c328f7e..2153b65297c4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1058,6 +1058,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case WLAN_EID_S1G_BCN_COMPAT:
case WLAN_EID_S1G_CAPABILITIES:
case WLAN_EID_S1G_OPERATION:
+ case WLAN_EID_AID_RESPONSE:
case WLAN_EID_S1G_SHORT_BCN_INTERVAL:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
@@ -1368,6 +1369,12 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
else
elem_parse_failed = true;
break;
+ case WLAN_EID_AID_RESPONSE:
+ if (elen == sizeof(struct ieee80211_aid_response_ie))
+ elems->aid_resp = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
default:
break;
}
@@ -3452,6 +3459,43 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,

*chandef = he_chandef;

+ return false;
+}
+
+bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
+ struct cfg80211_chan_def *chandef)
+{
+ u32 oper_freq;
+
+ if (!oper)
+ return false;
+
+ switch ((oper->ch_width & S1G_OPER_CH_WIDTH_OPER) >>
+ S1G_OPER_CH_WIDTH_OPER_SHIFT) {
+ case IEEE80211_S1G_CHANWIDTH_1MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_1;
+ break;
+ case IEEE80211_S1G_CHANWIDTH_2MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_2;
+ break;
+ case IEEE80211_S1G_CHANWIDTH_4MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_4;
+ break;
+ case IEEE80211_S1G_CHANWIDTH_8MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_8;
+ break;
+ case IEEE80211_S1G_CHANWIDTH_16MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_16;
+ break;
+ default:
+ return false;
+ }
+
+ oper_freq = ieee80211_channel_to_freq_khz(oper->oper_ch,
+ NL80211_BAND_S1GHZ);
+ chandef->center_freq1 = KHZ_TO_MHZ(oper_freq);
+ chandef->freq1_offset = oper_freq % 1000;
+
return true;
}

@@ -4358,6 +4402,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
return max_num_different_channels;
}

+u8 *ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata, u8 *buf)
+{
+ u8 *pos = buf;
+
+ *pos++ = WLAN_EID_AID_REQUEST;
+ *pos++ = 1;
+
+ *pos++ = 0;
+
+ return pos;
+}
+
u8 *ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_s1g_cap *own_cap, u8 *buf)
{
--
2.20.1

2020-08-27 22:35:08

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 21/22] mac80211_hwsim: indicate support for S1G

Advertise S1G Capabilities and channels to mac80211.

Requires a few fixups to account for missing
sband->bitrates, and a custom regulatory db to actually
enable the S1G channels.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 80 ++++++++++++++++++++++++---
include/linux/ieee80211.h | 12 +++-
2 files changed, 84 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 9dd9d73f4484..ee2f3a008e01 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -377,6 +377,50 @@ static const struct ieee80211_channel hwsim_channels_5ghz[] = {
CHAN5G(5925), /* Channel 185 */
};

+#define NUM_S1G_CHANS_US 51
+static struct ieee80211_channel hwsim_channels_s1g[NUM_S1G_CHANS_US];
+
+static const struct ieee80211_sta_s1g_cap hwsim_s1g_cap = {
+ .s1g = true,
+ .cap = { S1G_CAPAB_B0_SGI_1MHZ | S1G_CAPAB_B0_SGI_2MHZ |
+ SM(S1G_CAPAB_B0_SUPP_CH_WIDTH, S1G_SUPP_CH_WIDTH_2),
+ 0,
+ 0,
+ S1G_CAPAB_B3_MAX_MPDU_LEN,
+ 0,
+ S1G_CAPAB_B5_AMPDU,
+ 0,
+ S1G_CAPAB_B7_DUP_1MHZ,
+ S1G_CAPAB_B8_TWT_RESPOND | S1G_CAPAB_B8_TWT_REQUEST,
+ 0},
+ .nss_mcs = { 0xfc | 1, /* MCS 7 for 1 SS */
+ /* RX Highest Supported Long GI Data Rate 0:7 */
+ 0,
+ /* RX Highest Supported Long GI Data Rate 0:7 */
+ /* TX S1G MCS Map 0:6 */
+ 0xfa,
+ /* TX S1G MCS Map :7 */
+ /* TX Highest Supported Long GI Data Rate 0:6 */
+ 0x80,
+ /* TX Highest Supported Long GI Data Rate 7:8 */
+ /* Rx Single spatial stream and S1G-MCS Map for 1MHz */
+ /* Tx Single spatial stream and S1G-MCS Map for 1MHz */
+ 0 },
+};
+
+static void hwsim_init_s1g_channels(struct ieee80211_channel *channels)
+{
+ int ch, freq;
+
+ for (ch = 0; ch < NUM_S1G_CHANS_US; ch++) {
+ freq = 902000 + (ch + 1) * 500;
+ channels[ch].band = NL80211_BAND_S1GHZ;
+ channels[ch].center_freq = KHZ_TO_MHZ(freq);
+ channels[ch].freq_offset = freq % 1000;
+ channels[ch].hw_value = ch + 1;
+ }
+}
+
static const struct ieee80211_rate hwsim_rates[] = {
{ .bitrate = 10 },
{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
@@ -505,6 +549,7 @@ struct mac80211_hwsim_data {
struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)];
struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
+ struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)];
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
struct ieee80211_iface_combination if_combination;
struct ieee80211_iface_limit if_limits[3];
@@ -900,12 +945,14 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
struct mac80211_hwsim_data *data = hw->priv;
struct sk_buff *skb;
struct hwsim_radiotap_hdr *hdr;
- u16 flags;
+ u16 flags, bitrate;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);

- if (WARN_ON(!txrate))
- return;
+ if (!txrate)
+ bitrate = 0;
+ else
+ bitrate = txrate->bitrate;

if (!netif_running(hwsim_mon))
return;
@@ -924,10 +971,10 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
(1 << IEEE80211_RADIOTAP_CHANNEL));
hdr->rt_tsft = __mac80211_hwsim_get_tsf(data);
hdr->rt_flags = 0;
- hdr->rt_rate = txrate->bitrate / 5;
+ hdr->rt_rate = bitrate / 5;
hdr->rt_channel = cpu_to_le16(chan->center_freq);
flags = IEEE80211_CHAN_2GHZ;
- if (txrate->flags & IEEE80211_RATE_ERP_G)
+ if (txrate && txrate->flags & IEEE80211_RATE_ERP_G)
flags |= IEEE80211_CHAN_OFDM;
else
flags |= IEEE80211_CHAN_CCK;
@@ -1341,6 +1388,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
memset(&rx_status, 0, sizeof(rx_status));
rx_status.flag |= RX_FLAG_MACTIME_START;
rx_status.freq = chan->center_freq;
+ rx_status.freq_offset = chan->freq_offset ? 1 : 0;
rx_status.band = chan->band;
if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
rx_status.rate_idx =
@@ -1522,14 +1570,18 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
/* fake header transmission time */
struct ieee80211_mgmt *mgmt;
struct ieee80211_rate *txrate;
+ /* TODO: get MCS */
+ int bitrate = 100;
u64 ts;

mgmt = (struct ieee80211_mgmt *)skb->data;
txrate = ieee80211_get_tx_rate(hw, txi);
+ if (txrate)
+ bitrate = txrate->bitrate;
ts = mac80211_hwsim_get_tsf_raw();
mgmt->u.probe_resp.timestamp =
cpu_to_le64(ts + data->tsf_offset +
- 24 * 8 * 10 / txrate->bitrate);
+ 24 * 8 * 10 / bitrate);
}

mac80211_hwsim_monitor_rx(hw, skb, channel);
@@ -1664,6 +1716,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
struct ieee80211_rate *txrate;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
+ /* TODO: get MCS */
+ int bitrate = 100;

hwsim_check_magic(vif);

@@ -1683,13 +1737,15 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
ARRAY_SIZE(info->control.rates));

txrate = ieee80211_get_tx_rate(hw, info);
+ if (txrate)
+ bitrate = txrate->bitrate;

mgmt = (struct ieee80211_mgmt *) skb->data;
/* fake header transmission time */
data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
data->tsf_offset +
- 24 * 8 * 10 / txrate->bitrate);
+ 24 * 8 * 10 / bitrate);

mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
@@ -3079,6 +3135,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
sizeof(hwsim_channels_2ghz));
memcpy(data->channels_5ghz, hwsim_channels_5ghz,
sizeof(hwsim_channels_5ghz));
+ memcpy(data->channels_s1g, hwsim_channels_s1g,
+ sizeof(hwsim_channels_s1g));
memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));

for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
@@ -3121,6 +3179,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
sband->vht_cap.vht_mcs.tx_mcs_map =
sband->vht_cap.vht_mcs.rx_mcs_map;
break;
+ case NL80211_BAND_S1GHZ:
+ memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
+ sizeof(sband->s1g_cap));
+ sband->channels = data->channels_s1g;
+ sband->n_channels = ARRAY_SIZE(hwsim_channels_s1g);
+ break;
default:
continue;
}
@@ -4318,6 +4382,8 @@ static int __init init_mac80211_hwsim(void)
goto out_exit_virtio;
}

+ hwsim_init_s1g_channels(hwsim_channels_s1g);
+
for (i = 0; i < radios; i++) {
struct hwsim_new_radio_params param = { 0 };

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 5cff6a373158..e2198453ecb6 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2385,6 +2385,9 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
return spr_len;
}

+#define SM(f, v) (((v) << f##_SHIFT) & f)
+#define MS(f, v) (((v) & f) >> f##_SHIFT)
+
/* S1G Capabilities Information field */
#define S1G_CAPAB_B0_S1G_LONG BIT(0)
#define S1G_CAPAB_B0_SGI_1MHZ BIT(1)
@@ -2392,9 +2395,16 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
#define S1G_CAPAB_B0_SGI_4MHZ BIT(3)
#define S1G_CAPAB_B0_SGI_8MHZ BIT(4)
#define S1G_CAPAB_B0_SGI_16MHZ BIT(5)
-#define S1G_CAPAB_B0_SUPP_CH_WIDTH_MASK (BIT(6) | BIT(7))
+#define S1G_CAPAB_B0_SUPP_CH_WIDTH (BIT(6) | BIT(7))
#define S1G_CAPAB_B0_SUPP_CH_WIDTH_SHIFT 6

+#define S1G_SUPP_CH_WIDTH_2 0
+#define S1G_SUPP_CH_WIDTH_4 1
+#define S1G_SUPP_CH_WIDTH_8 2
+#define S1G_SUPP_CH_WIDTH_16 3
+#define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 << MS(S1G_CAPAB_B0_SUPP_CH_WIDTH, \
+ cap[0])) << 1)
+
#define S1G_CAPAB_B1_RX_LDPC BIT(0)
#define S1G_CAPAB_B1_TX_STBC BIT(1)
#define S1G_CAPAB_B1_RX_STBC BIT(2)
--
2.20.1

2020-08-27 22:35:49

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 03/22] cfg80211: regulatory: handle S1G channels

S1G channels have a minimum bandwidth of 1Mhz, and there
is a 1:1 mapping of allowed bandwidth to channel number.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/util.c | 6 ++--
net/wireless/nl80211.c | 3 +-
net/wireless/reg.c | 69 ++++++++++++++++++++++++++++++++++--------
3 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9ba1afe4ba1f..35798997e521 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1437,7 +1437,7 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx_conf *chanctx_conf;
const struct ieee80211_reg_rule *rrule;
const struct ieee80211_wmm_ac *wmm_ac;
- u16 center_freq = 0;
+ u16 min_bw, center_freq = 0;

if (sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_STATION)
@@ -1453,7 +1453,9 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
return;
}

- rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq), 20);
+ min_bw = chanctx_conf->def.chan->band == NL80211_BAND_S1GHZ ? 1 : 20;
+ rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq),
+ min_bw);

if (IS_ERR_OR_NULL(rrule) || !rrule->has_wmm) {
rcu_read_unlock();
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index dd0f62e942ed..a57872708108 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1012,9 +1012,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
goto nla_put_failure;

if (large) {
+ u32 min_bw = chan->band == NL80211_BAND_S1GHZ ? 1 : 20;
const struct ieee80211_reg_rule *rule =
freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
- 20);
+ min_bw);

if (!IS_ERR_OR_NULL(rule) && rule->has_wmm) {
if (nl80211_msg_put_wmm_rules(msg, rule))
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6c130cec22c3..f23ca3103558 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1617,9 +1617,11 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{
const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
const struct ieee80211_reg_rule *reg_rule = NULL;
+ const u32 bws[] = {1, 2, 4, 5, 8, 10, 16, 20};
+ int i = sizeof(bws) / sizeof(u32) - 1;
u32 bw;

- for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
+ for (bw = MHZ_TO_KHZ(bws[i]); bw >= min_bw; bw = MHZ_TO_KHZ(bws[i--])) {
reg_rule = freq_reg_info_regd(center_freq, regd, bw);
if (!IS_ERR(reg_rule))
return reg_rule;
@@ -1660,6 +1662,7 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
{
const struct ieee80211_freq_range *freq_range = NULL;
u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
+ bool is_s1g = chan->band == NL80211_BAND_S1GHZ;

freq_range = &reg_rule->freq_range;

@@ -1679,16 +1682,57 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;

- if (max_bandwidth_khz < MHZ_TO_KHZ(10))
- bw_flags |= IEEE80211_CHAN_NO_10MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(20))
- bw_flags |= IEEE80211_CHAN_NO_20MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(40))
- bw_flags |= IEEE80211_CHAN_NO_HT40;
- if (max_bandwidth_khz < MHZ_TO_KHZ(80))
- bw_flags |= IEEE80211_CHAN_NO_80MHZ;
- if (max_bandwidth_khz < MHZ_TO_KHZ(160))
- bw_flags |= IEEE80211_CHAN_NO_160MHZ;
+ if (is_s1g) {
+ /* S1G is strict about non overlapping channels. We can
+ * calculate which bandwidth is allowed per channel by finding
+ * the largest bandwidth which cleanly divides the freq_range.
+ */
+ int edge_offset;
+ int ch_bw = max_bandwidth_khz;
+
+ while (ch_bw) {
+ edge_offset = (center_freq_khz - ch_bw / 2) -
+ freq_range->start_freq_khz;
+ if (edge_offset % ch_bw == 0) {
+ switch (KHZ_TO_MHZ(ch_bw)) {
+ case 1:
+ bw_flags |= IEEE80211_CHAN_1MHZ;
+ break;
+ case 2:
+ bw_flags |= IEEE80211_CHAN_2MHZ;
+ break;
+ case 4:
+ bw_flags |= IEEE80211_CHAN_4MHZ;
+ break;
+ case 8:
+ bw_flags |= IEEE80211_CHAN_8MHZ;
+ break;
+ case 16:
+ bw_flags |= IEEE80211_CHAN_16MHZ;
+ break;
+ default:
+ /* If we got here, no bandwidths fit on
+ * this frequency, ie. band edge.
+ */
+ bw_flags |= IEEE80211_CHAN_DISABLED;
+ break;
+ }
+ break;
+ }
+ ch_bw /= 2;
+ }
+ } else {
+ if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+ bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+ bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(40))
+ bw_flags |= IEEE80211_CHAN_NO_HT40;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(80))
+ bw_flags |= IEEE80211_CHAN_NO_80MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(160))
+ bw_flags |= IEEE80211_CHAN_NO_160MHZ;
+ }
return bw_flags;
}

@@ -1707,12 +1751,13 @@ static void handle_channel(struct wiphy *wiphy,
struct wiphy *request_wiphy = NULL;
struct regulatory_request *lr = get_last_request();
const struct ieee80211_regdomain *regd;
+ u32 min_bw = chan->band == NL80211_BAND_S1GHZ ? 1 : 20;

request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);

flags = chan->orig_flags;

- reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan), 20);
+ reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan), min_bw);
if (IS_ERR(reg_rule)) {
/*
* We will disable all channels that do not match our
--
2.20.1

2020-08-27 22:35:58

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 22/22] mac80211_hwsim: fix TSF timestamp write to S1G beacon

mac80211_hwsim was corrupting the S1G beacon because the
timestamp location (and size) does not match the
management beacon.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ee2f3a008e01..f53b144c431b 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1743,9 +1743,18 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
mgmt = (struct ieee80211_mgmt *) skb->data;
/* fake header transmission time */
data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
- mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
- data->tsf_offset +
- 24 * 8 * 10 / bitrate);
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
+ struct ieee80211_ext *ext = (void *) mgmt;
+
+ ext->u.s1g_beacon.timestamp = cpu_to_le32(data->abs_bcn_ts +
+ data->tsf_offset +
+ 10 * 8 * 10 /
+ bitrate);
+ } else {
+ mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
+ data->tsf_offset +
+ 24 * 8 * 10 / bitrate);
+ }

mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
--
2.20.1

2020-08-27 22:36:44

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 06/22] {cfg,mac}80211: get correct default channel width for S1G

Until now, the wifi default channels were assumed to be
NL80211_CHAN_NO_HT, or NL80211_CHAN_WIDTH_20_NOHT. S1G
devices however do not support these channel types/width.
When a default channel width is requested (during default
chandef init, or chanctx removal when not using channel
context), for S1G calculate the correct width. Fixes eg.
configuring strange (20Mhz) width during a scan on the S1G
band.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/chan.c | 9 ++++++++-
net/wireless/chan.c | 10 ++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index bdc0f29dc6cd..8f48aff74c7b 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -536,7 +536,14 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,

if (!local->use_chanctx) {
struct cfg80211_chan_def *chandef = &local->_oper_chandef;
- chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ /* S1G doesn't have 20MHz, so get the correct width for the
+ * current channel.
+ */
+ if (chandef->chan->band == NL80211_BAND_S1GHZ)
+ chandef->width =
+ ieee80211_s1g_channel_width(chandef->chan);
+ else
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = chandef->chan->center_freq;
chandef->freq1_offset = chandef->chan->freq_offset;
chandef->center_freq2 = 0;
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 0a4b8d3eaed9..3bff52d51b05 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -32,6 +32,16 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
chandef->edmg.bw_config = 0;
chandef->edmg.channels = 0;

+ /* S1G allows a single width per channel, and since chan_type seems to
+ * be for backwards compatibility only, ignore it and return the per
+ * frequency width.
+ */
+ if (chan->band == NL80211_BAND_S1GHZ) {
+ chandef->width = ieee80211_s1g_channel_width(chan);
+ chandef->center_freq1 = chan->center_freq;
+ return;
+ }
+
switch (chan_type) {
case NL80211_CHAN_NO_HT:
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
--
2.20.1

2020-08-27 22:37:15

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 20/22] nl80211: include frequency offset in survey info

Recently channels gained a potential frequency offset, so
include this in the per-channel survey info.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/uapi/linux/nl80211.h | 2 ++
net/wireless/nl80211.c | 5 +++++
2 files changed, 7 insertions(+)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 03f4d83da473..973b56c2226f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4073,6 +4073,7 @@ enum nl80211_user_reg_hint_type {
* receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
+ * @NL80211_SURVEY_INFO_FREQUENCY_OFFSET: center frequency offset in KHz
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
*/
enum nl80211_survey_info {
@@ -4088,6 +4089,7 @@ enum nl80211_survey_info {
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
NL80211_SURVEY_INFO_TIME_BSS_RX,
+ NL80211_SURVEY_INFO_FREQUENCY_OFFSET,

/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5672abb34b86..750bef58b319 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9119,6 +9119,11 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
survey->channel->center_freq))
goto nla_put_failure;

+ if (survey->channel &&
+ nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY_OFFSET,
+ survey->channel->freq_offset))
+ goto nla_put_failure;
+
if ((survey->filled & SURVEY_INFO_NOISE_DBM) &&
nla_put_u8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise))
goto nla_put_failure;
--
2.20.1

2020-08-28 01:41:21

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 02/22] cfg80211: regulatory: pass min. bandwidth to regulatory rule extractor

Hi Thomas,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on next-20200827]
[also build test ERROR on v5.9-rc2]
[cannot apply to mac80211-next/master mac80211/master wireless-drivers-next/master wireless-drivers/master v5.9-rc2 v5.9-rc1 v5.8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Thomas-Pedersen/add-initial-S1G-support/20200828-063630
base: 88abac0b753dfdd85362a26d2da8277cb1e0842b
config: riscv-allyesconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=riscv

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

drivers/net/wireless/realtek/rtw88/regd.c: In function 'rtw_regd_apply_beaconing_flags':
>> drivers/net/wireless/realtek/rtw88/regd.c:279:15: error: too few arguments to function 'freq_reg_info'
279 | reg_rule = freq_reg_info(wiphy,
| ^~~~~~~~~~~~~
In file included from include/net/mac80211.h:21,
from drivers/net/wireless/realtek/rtw88/main.h:8,
from drivers/net/wireless/realtek/rtw88/regd.c:5:
include/net/cfg80211.h:5880:34: note: declared here
5880 | const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
| ^~~~~~~~~~~~~
In file included from include/linux/energy_model.h:10,
from include/linux/device.h:16,
from include/linux/dma-mapping.h:7,
from include/linux/skbuff.h:31,
from include/linux/if_ether.h:19,
from include/net/mac80211.h:18,
from drivers/net/wireless/realtek/rtw88/main.h:8,
from drivers/net/wireless/realtek/rtw88/regd.c:5:
At top level:
include/linux/sched/topology.h:40:3: warning: 'sd_flag_debug' defined but not used [-Wunused-const-variable=]
40 | } sd_flag_debug[] = {
| ^~~~~~~~~~~~~
In file included from include/linux/energy_model.h:10,
from include/linux/device.h:16,
from include/linux/dma-mapping.h:7,
from include/linux/skbuff.h:31,
from include/linux/if_ether.h:19,
from include/net/mac80211.h:18,
from drivers/net/wireless/realtek/rtw88/main.h:8,
from drivers/net/wireless/realtek/rtw88/regd.c:5:
include/linux/sched/topology.h:30:27: warning: 'SD_DEGENERATE_GROUPS_MASK' defined but not used [-Wunused-const-variable=]
30 | static const unsigned int SD_DEGENERATE_GROUPS_MASK =
| ^~~~~~~~~~~~~~~~~~~~~~~~~

# https://github.com/0day-ci/linux/commit/cc241e6d10cc9d9bef4ab40d2989677df2623bd9
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Thomas-Pedersen/add-initial-S1G-support/20200828-063630
git checkout cc241e6d10cc9d9bef4ab40d2989677df2623bd9
vim +/freq_reg_info +279 drivers/net/wireless/realtek/rtw88/regd.c

e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 261
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 262 static void rtw_regd_apply_beaconing_flags(struct wiphy *wiphy,
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 263 enum nl80211_reg_initiator initiator)
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 264 {
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 265 enum nl80211_band band;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 266 struct ieee80211_supported_band *sband;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 267 const struct ieee80211_reg_rule *reg_rule;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 268 struct ieee80211_channel *ch;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 269 unsigned int i;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 270
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 271 for (band = 0; band < NUM_NL80211_BANDS; band++) {
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 272 if (!wiphy->bands[band])
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 273 continue;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 274
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 275 sband = wiphy->bands[band];
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 276 for (i = 0; i < sband->n_channels; i++) {
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 277 ch = &sband->channels[i];
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 278
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 @279 reg_rule = freq_reg_info(wiphy,
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 280 MHZ_TO_KHZ(ch->center_freq));
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 281 if (IS_ERR(reg_rule))
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 282 continue;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 283
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 284 ch->flags &= ~IEEE80211_CHAN_DISABLED;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 285
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 286 if (!(reg_rule->flags & NL80211_RRF_NO_IR))
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 287 ch->flags &= ~IEEE80211_CHAN_NO_IR;
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 288 }
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 289 }
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 290 }
e3037485c68ec1a Yan-Hsuan Chuang 2019-04-26 291

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (5.90 kB)
.config.gz (65.22 kB)
Download all attachments

2020-08-28 06:24:39

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 02/22] cfg80211: regulatory: pass min. bandwidth to regulatory rule extractor

On 2020-08-27 15:32, Thomas Pedersen wrote:

> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 35b8847a2f6d..6c130cec22c3 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -1629,9 +1629,10 @@ __freq_reg_info(struct wiphy *wiphy, u32
> center_freq, u32 min_bw)
> }
>
> const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
> - u32 center_freq)
> + u32 center_freq,
> + u32 min_bw)
> {
> - return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20));
> + return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(min_bw));
> }
> EXPORT_SYMBOL(freq_reg_info);

Actually, it would be cleaner to keep the freq_reg_info() interface
intact,
then set min_bw = 1 if center_freq is in the S1G band. The call to
freq_reg_info() for successively smaller bandwidths in the next patch
could
just call __freq_reg_info() directly. Will fix in v2.

--
thomas

2020-08-28 07:18:26

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 21/22] mac80211_hwsim: indicate support for S1G

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on next-20200827]
[cannot apply to mac80211-next/master mac80211/master wireless-drivers-next/master wireless-drivers/master v5.9-rc2 v5.9-rc1 v5.8 v5.9-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Thomas-Pedersen/add-initial-S1G-support/20200828-063630
base: 88abac0b753dfdd85362a26d2da8277cb1e0842b
config: riscv-allyesconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=riscv

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

In file included from drivers/net/wireless/ath/ath10k/sdio.c:17:
>> drivers/net/wireless/ath/ath10k/core.h:31: warning: "MS" redefined
31 | #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
|
In file included from include/net/mac80211.h:20,
from drivers/net/wireless/ath/ath10k/htt.h:16,
from drivers/net/wireless/ath/ath10k/core.h:18,
from drivers/net/wireless/ath/ath10k/sdio.c:17:
include/linux/ieee80211.h:2389: note: this is the location of the previous definition
2389 | #define MS(f, v) (((v) & f) >> f##_SHIFT)
|
In file included from drivers/net/wireless/ath/ath10k/sdio.c:17:
>> drivers/net/wireless/ath/ath10k/core.h:32: warning: "SM" redefined
32 | #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
In file included from include/net/mac80211.h:20,
from drivers/net/wireless/ath/ath10k/htt.h:16,
from drivers/net/wireless/ath/ath10k/core.h:18,
from drivers/net/wireless/ath/ath10k/sdio.c:17:
include/linux/ieee80211.h:2388: note: this is the location of the previous definition
2388 | #define SM(f, v) (((v) << f##_SHIFT) & f)
|
include/linux/ieee80211.h:2488:18: warning: 'listen_int_usf' defined but not used [-Wunused-const-variable=]
2488 | static const int listen_int_usf[] = { 1, 10, 1000, 10000 };
| ^~~~~~~~~~~~~~
In file included from include/linux/energy_model.h:10,
from include/linux/device.h:16,
from include/linux/mmc/card.h:10,
from drivers/net/wireless/ath/ath10k/sdio.c:9:
include/linux/sched/topology.h:40:3: warning: 'sd_flag_debug' defined but not used [-Wunused-const-variable=]
40 | } sd_flag_debug[] = {
| ^~~~~~~~~~~~~
In file included from include/linux/energy_model.h:10,
from include/linux/device.h:16,
from include/linux/mmc/card.h:10,
from drivers/net/wireless/ath/ath10k/sdio.c:9:
include/linux/sched/topology.h:30:27: warning: 'SD_DEGENERATE_GROUPS_MASK' defined but not used [-Wunused-const-variable=]
30 | static const unsigned int SD_DEGENERATE_GROUPS_MASK =
| ^~~~~~~~~~~~~~~~~~~~~~~~~
--
In file included from drivers/net/wireless/ath/ath10k/trace.h:10,
from drivers/net/wireless/ath/ath10k/trace.c:9:
>> drivers/net/wireless/ath/ath10k/core.h:31: warning: "MS" redefined
31 | #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
|
In file included from include/net/mac80211.h:20,
from drivers/net/wireless/ath/ath10k/htt.h:16,
from drivers/net/wireless/ath/ath10k/core.h:18,
from drivers/net/wireless/ath/ath10k/trace.h:10,
from drivers/net/wireless/ath/ath10k/trace.c:9:
include/linux/ieee80211.h:2389: note: this is the location of the previous definition
2389 | #define MS(f, v) (((v) & f) >> f##_SHIFT)
|
In file included from drivers/net/wireless/ath/ath10k/trace.h:10,
from drivers/net/wireless/ath/ath10k/trace.c:9:
>> drivers/net/wireless/ath/ath10k/core.h:32: warning: "SM" redefined
32 | #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
In file included from include/net/mac80211.h:20,
from drivers/net/wireless/ath/ath10k/htt.h:16,
from drivers/net/wireless/ath/ath10k/core.h:18,
from drivers/net/wireless/ath/ath10k/trace.h:10,
from drivers/net/wireless/ath/ath10k/trace.c:9:
include/linux/ieee80211.h:2388: note: this is the location of the previous definition
2388 | #define SM(f, v) (((v) << f##_SHIFT) & f)
|
--
In file included from drivers/net/wireless/ath/ath11k/mhi.c:7:
>> drivers/net/wireless/ath/ath11k/core.h:27: warning: "SM" redefined
27 | #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
In file included from include/net/mac80211.h:20,
from drivers/net/wireless/ath/ath11k/wmi.h:9,
from drivers/net/wireless/ath/ath11k/core.h:15,
from drivers/net/wireless/ath/ath11k/mhi.c:7:
include/linux/ieee80211.h:2388: note: this is the location of the previous definition
2388 | #define SM(f, v) (((v) << f##_SHIFT) & f)
|
include/linux/ieee80211.h:2488:18: warning: 'listen_int_usf' defined but not used [-Wunused-const-variable=]
2488 | static const int listen_int_usf[] = { 1, 10, 1000, 10000 };
| ^~~~~~~~~~~~~~
In file included from include/linux/energy_model.h:10,
from include/linux/device.h:16,
from include/linux/pci.h:37,
from drivers/net/wireless/ath/ath11k/mhi.c:5:
include/linux/sched/topology.h:40:3: warning: 'sd_flag_debug' defined but not used [-Wunused-const-variable=]
40 | } sd_flag_debug[] = {
| ^~~~~~~~~~~~~
In file included from include/linux/energy_model.h:10,
from include/linux/device.h:16,
from include/linux/pci.h:37,
from drivers/net/wireless/ath/ath11k/mhi.c:5:
include/linux/sched/topology.h:30:27: warning: 'SD_DEGENERATE_GROUPS_MASK' defined but not used [-Wunused-const-variable=]
30 | static const unsigned int SD_DEGENERATE_GROUPS_MASK =
| ^~~~~~~~~~~~~~~~~~~~~~~~~
--
In file included from drivers/net/wireless/ath/ath11k/core.c:10:
>> drivers/net/wireless/ath/ath11k/core.h:27: warning: "SM" redefined
27 | #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
In file included from include/net/mac80211.h:20,
from drivers/net/wireless/ath/ath11k/wmi.h:9,
from drivers/net/wireless/ath/ath11k/core.h:15,
from drivers/net/wireless/ath/ath11k/core.c:10:
include/linux/ieee80211.h:2388: note: this is the location of the previous definition
2388 | #define SM(f, v) (((v) << f##_SHIFT) & f)
|

# https://github.com/0day-ci/linux/commit/dc5ef7078b77772b5e2ff5a57cd87144c4c9a583
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Thomas-Pedersen/add-initial-S1G-support/20200828-063630
git checkout dc5ef7078b77772b5e2ff5a57cd87144c4c9a583
vim +/MS +31 drivers/net/wireless/ath/ath10k/core.h

5e3dd157d7e70f0 Kalle Valo 2013-06-12 30
5e3dd157d7e70f0 Kalle Valo 2013-06-12 @31 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
5e3dd157d7e70f0 Kalle Valo 2013-06-12 @32 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
5e3dd157d7e70f0 Kalle Valo 2013-06-12 33 #define WO(_f) ((_f##_OFFSET) >> 2)
5e3dd157d7e70f0 Kalle Valo 2013-06-12 34

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (8.14 kB)
.config.gz (65.22 kB)
Download all attachments

2020-08-28 07:52:54

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 21/22] mac80211_hwsim: indicate support for S1G

Thomas Pedersen <[email protected]> writes:

> Advertise S1G Capabilities and channels to mac80211.
>
> Requires a few fixups to account for missing
> sband->bitrates, and a custom regulatory db to actually
> enable the S1G channels.
>
> Signed-off-by: Thomas Pedersen <[email protected]>
> ---
> drivers/net/wireless/mac80211_hwsim.c | 80 ++++++++++++++++++++++++---
> include/linux/ieee80211.h | 12 +++-

IMHO a mac80211_hwsim patch should not touch ieee80211.h.

> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -2385,6 +2385,9 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
> return spr_len;
> }
>
> +#define SM(f, v) (((v) << f##_SHIFT) & f)
> +#define MS(f, v) (((v) & f) >> f##_SHIFT)
> +
> /* S1G Capabilities Information field */
> #define S1G_CAPAB_B0_S1G_LONG BIT(0)
> #define S1G_CAPAB_B0_SGI_1MHZ BIT(1)
> @@ -2392,9 +2395,16 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
> #define S1G_CAPAB_B0_SGI_4MHZ BIT(3)
> #define S1G_CAPAB_B0_SGI_8MHZ BIT(4)
> #define S1G_CAPAB_B0_SGI_16MHZ BIT(5)
> -#define S1G_CAPAB_B0_SUPP_CH_WIDTH_MASK (BIT(6) | BIT(7))
> +#define S1G_CAPAB_B0_SUPP_CH_WIDTH (BIT(6) | BIT(7))
> #define S1G_CAPAB_B0_SUPP_CH_WIDTH_SHIFT 6
>
> +#define S1G_SUPP_CH_WIDTH_2 0
> +#define S1G_SUPP_CH_WIDTH_4 1
> +#define S1G_SUPP_CH_WIDTH_8 2
> +#define S1G_SUPP_CH_WIDTH_16 3
> +#define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 << MS(S1G_CAPAB_B0_SUPP_CH_WIDTH, \
> + cap[0])) << 1)

We have GENMASK(), FIELD_GET() & co nowadays so no need for custom
macros.

--
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2020-08-30 03:57:17

by kernel test robot

[permalink] [raw]
Subject: [mac80211_hwsim] dc5ef7078b: BUG:KASAN:stack-out-of-bounds_in__freq_reg_info

Greeting,

FYI, we noticed the following commit (built with gcc-9):

commit: dc5ef7078b77772b5e2ff5a57cd87144c4c9a583 ("mac80211_hwsim: indicate support for S1G")
url: https://github.com/0day-ci/linux/commits/Thomas-Pedersen/add-initial-S1G-support/20200828-063630


in testcase: boot

on test machine: qemu-system-x86_64 -enable-kvm -cpu SandyBridge -smp 2 -m 8G

caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):


+-------------------------------------------------+------------+------------+
| | d86026ca9a | dc5ef7078b |
+-------------------------------------------------+------------+------------+
| boot_successes | 8 | 0 |
| boot_failures | 0 | 8 |
| BUG:KASAN:stack-out-of-bounds_in__freq_reg_info | 0 | 8 |
+-------------------------------------------------+------------+------------+


If you fix the issue, kindly add following tag
Reported-by: kernel test robot <[email protected]>


[ 16.018498] BUG: KASAN: stack-out-of-bounds in __freq_reg_info+0x14b/0x170
[ 16.019402] Read of size 4 at addr ffffc9000001f8e4 by task swapper/0/1
[ 16.020281]
[ 16.020387] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.9.0-rc2-next-20200827-00021-gdc5ef7078b7777 #1
[ 16.020387] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
[ 16.020387] Call Trace:
[ 16.020387] dump_stack+0xbf/0x110
[ 16.020387] print_address_description.cold+0x5/0x4b3
[ 16.020387] ? log_store.cold+0x11/0x11
[ 16.020387] ? trace_hardirqs_off+0x29/0x110
[ 16.020387] ? _raw_spin_lock_irqsave+0x8c/0xd0
[ 16.020387] ? _raw_read_lock_irq+0x50/0x50
[ 16.020387] ? trace_hardirqs_on+0x2e/0x120
[ 16.020387] ? __freq_reg_info+0x14b/0x170
[ 16.020387] kasan_report.cold+0x1f/0x38
[ 16.020387] ? __freq_reg_info+0x14b/0x170
[ 16.020387] __freq_reg_info+0x14b/0x170
[ 16.020387] ? freq_reg_info_regd+0x110/0x110
[ 16.020387] ? mutex_is_locked+0x1b/0x30
[ 16.020387] wiphy_update_regulatory+0x338/0x6b0
[ 16.020387] wiphy_regulatory_register+0x3b/0xa0
[ 16.020387] wiphy_register+0xcf3/0x1020
[ 16.020387] ? wiphy_unregister+0x570/0x570
[ 16.020387] ? register_netdev+0x40/0x40
[ 16.020387] ? minstrel_ht_alloc+0x1a7/0x230
[ 16.020387] ieee80211_register_hw+0xf05/0x1460
[ 16.020387] ? ieee80211_ifa6_changed+0x230/0x230
[ 16.020387] ? memset+0x20/0x40
[ 16.020387] ? __hrtimer_init+0xbb/0xf0
[ 16.020387] mac80211_hwsim_new_radio+0xd89/0x1830
[ 16.020387] ? hwsim_virtio_rx_work+0x1f0/0x1f0
[ 16.020387] init_mac80211_hwsim+0x315/0x42c
[ 16.020387] ? printk+0x96/0xb2
[ 16.020387] ? rndis_wlan_driver_init+0x1a/0x1a
[ 16.020387] do_one_initcall+0x75/0x294
[ 16.020387] ? perf_trace_initcall_level+0x1f0/0x1f0
[ 16.020387] ? parameqn+0x80/0x90
[ 16.020387] ? kasan_unpoison_shadow+0x33/0x40
[ 16.020387] kernel_init_freeable+0x2b8/0x313
[ 16.020387] ? rest_init+0xd6/0xd6
[ 16.020387] kernel_init+0xd/0x11a
[ 16.020387] ret_from_fork+0x22/0x30
[ 16.020387]
[ 16.020387] addr ffffc9000001f8e4 is located in stack of task swapper/0/1 at offset 28 in frame:
[ 16.020387] __freq_reg_info+0x0/0x170
[ 16.020387]
[ 16.020387] this frame has 1 object:
[ 16.020387] [32, 64) 'bws'
[ 16.020387]
[ 16.020387] Memory state around the buggy address:
[ 16.020387] ffffc9000001f780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 16.020387] ffffc9000001f800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 16.020387] >ffffc9000001f880: 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 00
[ 16.020387] ^
[ 16.020387] ffffc9000001f900: 00 f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00
[ 16.020387] ffffc9000001f980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 16.020387] ==================================================================
[ 16.020387] Disabling lock debugging due to kernel taint
[ 16.065939] ieee80211 phy1: Selected rate control algorithm 'minstrel_ht'
[ 16.073468] usbcore: registered new interface driver catc
[ 16.074373] usbcore: registered new interface driver kaweth
[ 16.075147] pegasus: v0.9.3 (2013/04/25), Pegasus/Pegasus II USB Ethernet driver
[ 16.076356] usbcore: registered new interface driver pegasus
[ 16.077286] usbcore: registered new interface driver rtl8150
[ 16.078066] hso: drivers/net/usb/hso.c: Option Wireless
[ 16.079118] usbcore: registered new interface driver hso
[ 16.080014] usbcore: registered new interface driver lan78xx
[ 16.080941] usbcore: registered new interface driver cdc_ether
[ 16.081861] usbcore: registered new interface driver cdc_eem
[ 16.082776] usbcore: registered new interface driver dm9601
[ 16.083759] usbcore: registered new interface driver CoreChips
[ 16.084773] usbcore: registered new interface driver smsc95xx
[ 16.085703] usbcore: registered new interface driver gl620a
[ 16.086632] usbcore: registered new interface driver net1080
[ 16.087543] usbcore: registered new interface driver rndis_host
[ 16.088503] usbcore: registered new interface driver cdc_subset
[ 16.089446] usbcore: registered new interface driver kalmia
[ 16.090365] usbcore: registered new interface driver ipheth
[ 16.091315] usbcore: registered new interface driver sierra_net
[ 16.092269] usbcore: registered new interface driver cx82310_eth
[ 16.093306] usbcore: registered new interface driver cdc_ncm
[ 16.094224] usbcore: registered new interface driver huawei_cdc_ncm
[ 16.095202] usbcore: registered new interface driver lg-vl600
[ 16.096151] usbcore: registered new interface driver qmi_wwan
[ 16.097078] usbcore: registered new interface driver cdc_mbim
[ 16.100599] usbcore: registered new interface driver ch9200
[ 16.102062] parport0: cannot grant exclusive access for device ks0108
[ 16.102925] ks0108: ERROR: parport didn't register new device
[ 16.247986] panel: panel driver registered on parport0 (io=0x378).
[ 16.252248] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 16.253129] ehci-pci: EHCI PCI platform driver
[ 16.253917] ehci-platform: EHCI generic platform driver
[ 16.254894] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[ 16.255875] ohci-pci: OHCI PCI platform driver
[ 16.256689] ohci-platform: OHCI generic platform driver
[ 16.257770] driver u132_hcd
[ 16.258888] fotg210_hcd: FOTG210 Host Controller (EHCI) Driver
[ 16.259689] Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after
[ 16.261402] usbcore: registered new interface driver cdc_acm
[ 16.262181] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[ 16.263434] usbcore: registered new interface driver cdc_wdm


To reproduce:

# build kernel
cd linux
cp config-5.9.0-rc2-next-20200827-00021-gdc5ef7078b7777 .config
make HOSTCC=gcc-9 CC=gcc-9 ARCH=x86_64 olddefconfig prepare modules_prepare bzImage

git clone https://github.com/intel/lkp-tests.git
cd lkp-tests
bin/lkp qemu -k <bzImage> job-script # job-script is attached in this email



Thanks,
lkp


Attachments:
(No filename) (7.27 kB)
config-5.9.0-rc2-next-20200827-00021-gdc5ef7078b7777 (162.21 kB)
job-script (4.83 kB)
dmesg.xz (17.89 kB)
Download all attachments

2020-08-31 16:47:16

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 21/22] mac80211_hwsim: indicate support for S1G

On 2020-08-28 00:52, Kalle Valo wrote:
> Thomas Pedersen <[email protected]> writes:
>
>> Advertise S1G Capabilities and channels to mac80211.
>>
>> Requires a few fixups to account for missing
>> sband->bitrates, and a custom regulatory db to actually
>> enable the S1G channels.
>>
>> Signed-off-by: Thomas Pedersen <[email protected]>
>> ---
>> drivers/net/wireless/mac80211_hwsim.c | 80
>> ++++++++++++++++++++++++---
>> include/linux/ieee80211.h | 12 +++-
>
> IMHO a mac80211_hwsim patch should not touch ieee80211.h.

Fair enough, I'll split it out.

>> --- a/include/linux/ieee80211.h
>> +++ b/include/linux/ieee80211.h
>> @@ -2385,6 +2385,9 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
>> return spr_len;
>> }
>>
>> +#define SM(f, v) (((v) << f##_SHIFT) & f)
>> +#define MS(f, v) (((v) & f) >> f##_SHIFT)
>> +
>> /* S1G Capabilities Information field */
>> #define S1G_CAPAB_B0_S1G_LONG BIT(0)
>> #define S1G_CAPAB_B0_SGI_1MHZ BIT(1)
>> @@ -2392,9 +2395,16 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
>> #define S1G_CAPAB_B0_SGI_4MHZ BIT(3)
>> #define S1G_CAPAB_B0_SGI_8MHZ BIT(4)
>> #define S1G_CAPAB_B0_SGI_16MHZ BIT(5)
>> -#define S1G_CAPAB_B0_SUPP_CH_WIDTH_MASK (BIT(6) | BIT(7))
>> +#define S1G_CAPAB_B0_SUPP_CH_WIDTH (BIT(6) | BIT(7))
>> #define S1G_CAPAB_B0_SUPP_CH_WIDTH_SHIFT 6
>>
>> +#define S1G_SUPP_CH_WIDTH_2 0
>> +#define S1G_SUPP_CH_WIDTH_4 1
>> +#define S1G_SUPP_CH_WIDTH_8 2
>> +#define S1G_SUPP_CH_WIDTH_16 3
>> +#define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 <<
>> MS(S1G_CAPAB_B0_SUPP_CH_WIDTH, \
>> + cap[0])) << 1)
>
> We have GENMASK(), FIELD_GET() & co nowadays so no need for custom
> macros.

Nice. Thanks for the heads up.

--
thomas