2020-09-22 05:38:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 00/17] add support for S1G association

These are the remaining (v4) patches in the S1G association series.

Changes in v4:
- stop fudging the channel width in cfg80211_chandef_create() (we don't
actually need it).
- use NLA_POLICY_EXACT_LEN() in nl80211 policy
- protect against eg. DS param IE in S1G
- remove bss->s1g tracking
- clean up ugly check for S1G BSS
- fix ieee80211_encode_usf() return type (thanks kbot)

Thomas Pedersen (17):
{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: fix TSF timestamp write to S1G beacon
mac80211_hwsim: indicate support for S1G

drivers/net/wireless/mac80211_hwsim.c | 98 +++++++++++--
include/linux/ieee80211.h | 67 +++++++++
include/net/cfg80211.h | 3 +
include/net/mac80211.h | 4 +
include/uapi/linux/nl80211.h | 11 ++
net/mac80211/cfg.c | 2 +
net/mac80211/chan.c | 9 +-
net/mac80211/ibss.c | 3 +-
net/mac80211/ieee80211_i.h | 16 +++
net/mac80211/iface.c | 5 +
net/mac80211/mlme.c | 180 ++++++++++++++++++-----
net/mac80211/rate.c | 39 ++++-
net/mac80211/rx.c | 87 +++++-------
net/mac80211/scan.c | 34 ++++-
net/mac80211/tx.c | 4 +
net/mac80211/util.c | 196 ++++++++++++++++++++++++++
net/wireless/mlme.c | 14 +-
net/wireless/nl80211.c | 22 +++
net/wireless/scan.c | 85 +++++++++--
19 files changed, 756 insertions(+), 123 deletions(-)

--
2.20.1


2020-09-22 05:38:41

by Thomas Pedersen

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

When deleting a channel context, mac80211 would assing
NL80211_CHAN_WIDTH_20_NOHT as the default channel width.
This is wrong in S1G however, so instead get the allowed
channel width for a given channel.

Fixes eg. configuring strange (20Mhz) width during a scan
on the S1G band.

Signed-off-by: Thomas Pedersen <[email protected]>

---

v4:
- drop S1G channel width calculation in
cfg80211_chandef_create as it is not needed (Johannes)
---
net/mac80211/chan.c | 9 ++++++++-
1 file changed, 8 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;
--
2.20.1

2020-09-22 05:38:58

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 03/17] 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]>

---

v4:
- nit + use NLA_POLICY_EXACT_LEN() (Johannes)
- move NL80211_S1G_CAPABILITY_LEN -> ieee80211.h (Johannes)
---
include/linux/ieee80211.h | 2 ++
include/net/cfg80211.h | 3 +++
include/uapi/linux/nl80211.h | 9 +++++++++
net/wireless/nl80211.c | 17 +++++++++++++++++
4 files changed, 31 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 53fba39d4ba6..f71cffa18176 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2330,6 +2330,8 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
}

/* S1G Capabilities Information field */
+#define IEEE80211_S1G_CAPABILITY_LEN 15
+
#define S1G_CAP0_S1G_LONG BIT(0)
#define S1G_CAP0_SGI_1MHZ BIT(1)
#define S1G_CAP0_SGI_2MHZ BIT(2)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 10c2cc8f0efc..6d242ce8c520 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2528,6 +2528,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;
@@ -2542,6 +2544,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 bdc90b8dfd24..84b37932f80f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2521,6 +2521,12 @@ enum nl80211_commands {
* unsolicited broadcast probe response. It is a nested attribute, see
* &enum nl80211_unsol_bcast_probe_resp_attributes.
*
+ * @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
@@ -3007,6 +3013,9 @@ enum nl80211_attrs {

NL80211_ATTR_UNSOL_BCAST_PROBE_RESP,

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

__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a212db7a300..fe25ac23d7e9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -704,6 +704,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
NLA_POLICY_NESTED(nl80211_fils_discovery_policy),
[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP] =
NLA_POLICY_NESTED(nl80211_unsol_bcast_probe_resp_policy),
+ [NL80211_ATTR_S1G_CAPABILITY] =
+ NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
+ [NL80211_ATTR_S1G_CAPABILITY_MASK] =
+ NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
};

/* policy for the key attributes */
@@ -9792,6 +9796,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-09-22 05:39:00

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 04/17] 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 ecd9229012bf..27b73891aa4c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -544,6 +544,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);
@@ -2204,6 +2206,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 50a9b9025725..5afc009aabac 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;
@@ -5455,6 +5459,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 c8504ffc71a1..27b2f1ceca69 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4276,6 +4276,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-09-22 05:39:11

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 08/17] 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]>

---

v4:
- clean up ugly check for S1G BSS (Johannes)
---
include/linux/ieee80211.h | 5 +++++
net/wireless/mlme.c | 14 +++++++++++---
2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 1ce0b37441b9..d0fda8424118 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 db7333e20dd7..0ac820780437 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -30,6 +30,15 @@ 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 u8 *resp_ie = mgmt->u.assoc_resp.variable;
+ size_t resp_ie_len = len - offsetof(struct ieee80211_mgmt,
+ u.assoc_resp.variable);
+
+ if (bss->channel->band == NL80211_BAND_S1GHZ) {
+ resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
+ resp_ie_len = len - offsetof(struct ieee80211_mgmt,
+ u.s1g_assoc_resp.variable);
+ }

memset(&cr, 0, sizeof(cr));
cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -37,9 +46,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
cr.bss = bss;
cr.req_ie = req_ies;
cr.req_ie_len = req_ies_len;
- cr.resp_ie = mgmt->u.assoc_resp.variable;
- cr.resp_ie_len =
- len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+ cr.resp_ie = resp_ie;
+ cr.resp_ie_len = resp_ie_len;
cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;

trace_cfg80211_send_rx_assoc(dev, bss);
--
2.20.1

2020-09-22 05:39:22

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 11/17] 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 e90089d104b0..de22524e9270 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -833,6 +833,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-09-22 05:39:37

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 14/17] 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 | 21 ++++++++++
include/net/mac80211.h | 2 +
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 | 55 ++++++++++++++++++++++++++
7 files changed, 154 insertions(+), 13 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 7b6af47dd279..f2f56b287aed 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
@@ -2854,6 +2873,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 de22524e9270..72bc877d2c22 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -627,6 +627,7 @@ struct ieee80211_fils_discovery {
* @fils_discovery: FILS discovery configuration
* @unsol_bcast_probe_resp_interval: Unsolicited broadcast probe response
* interval.
+ * @s1g: BSS is S1G BSS (affects Association Request format).
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -696,6 +697,7 @@ struct ieee80211_bss_conf {
struct cfg80211_he_bss_color he_bss_color;
struct ieee80211_fils_discovery fils_discovery;
u32 unsol_bcast_probe_resp_interval;
+ bool s1g;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8d75a4045d6e..da70f174d629 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1124,6 +1124,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 c0963969a465..1f552f374e97 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 4c95f9a75a98..8fef3ae8dc33 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1539,6 +1539,7 @@ struct ieee802_11_elems {
const struct ieee80211_s1g_cap *s1g_capab;
const struct ieee80211_s1g_oper_ie *s1g_oper;
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;
@@ -2213,6 +2214,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,
@@ -2224,6 +2226,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 75893ebd5c13..d5428f8e5ec4 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
@@ -811,6 +822,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 (sband->band == NL80211_BAND_S1GHZ)
+ goto skip_rates;
+
/* add all rates which were marked to be used above */
supp_rates_len = rates_len;
if (supp_rates_len > 8)
@@ -846,6 +860,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);
@@ -1020,9 +1035,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) {
@@ -3251,14 +3268,26 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_bss_ies *bss_ies = NULL;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
+ bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
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 (is_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
@@ -3275,7 +3304,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ifmgd->broken_ap = true;
}

- if (!elems->supp_rates) {
+ if (!is_s1g && !elems->supp_rates) {
sdata_info(sdata, "no SuppRates element in AssocResp\n");
return false;
}
@@ -3517,7 +3546,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))
@@ -3612,7 +3642,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,
@@ -3622,9 +3653,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.
@@ -3636,7 +3671,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 (cbss->channel->band == NL80211_BAND_S1GHZ) {
+ 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",
@@ -3647,7 +3687,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);

@@ -3667,8 +3706,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);
@@ -3677,10 +3714,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;
@@ -3701,7 +3738,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);
}

@@ -4151,7 +4188,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",
@@ -4904,6 +4941,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;
@@ -5006,10 +5044,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),
@@ -5136,6 +5187,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,
@@ -5180,6 +5235,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 cf6488292066..267d6250deba 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1060,6 +1060,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
@@ -1364,6 +1365,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;
}
@@ -3446,6 +3453,42 @@ 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 (FIELD_GET(S1G_OPER_CH_WIDTH_OPER, oper->ch_width)) {
+ 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;
}

@@ -4352,6 +4395,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-09-22 05:39:56

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 15/17] 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 84b37932f80f..31f99ba6210c 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4097,6 +4097,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 {
@@ -4112,6 +4113,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 fe25ac23d7e9..619c763ad83d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9319,6 +9319,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-09-22 05:39:57

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 16/17] 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]>

---
v3:
- fix this before claiming S1G support
Reported-by: kernel test robot <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index dce3bc9c9f84..3daf5b399ebf 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1687,9 +1687,19 @@ 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 / txrate->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 /
+ txrate->bitrate);
+ } else {
+ mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
+ data->tsf_offset +
+ 24 * 8 * 10 /
+ txrate->bitrate);
+ }

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

2020-09-22 05:40:07

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 05/17] 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 f71cffa18176..1ce0b37441b9 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 84fc8ab16dd2..b4c85e8f2107 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-09-22 05:40:46

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 17/17] 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]>

---
v2:
- split out changes to ieee80211.h in a separate commit
and use GENMASK + FIELD_GET (Kalle)

v4:
- handle new channel widths in debug statements
---
drivers/net/wireless/mac80211_hwsim.c | 86 ++++++++++++++++++++++++---
1 file changed, 78 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 3daf5b399ebf..a50de395727e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -377,6 +377,49 @@ 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_CAP0_SGI_1MHZ | S1G_CAP0_SGI_2MHZ,
+ 0,
+ 0,
+ S1G_CAP3_MAX_MPDU_LEN,
+ 0,
+ S1G_CAP5_AMPDU,
+ 0,
+ S1G_CAP7_DUP_1MHZ,
+ S1G_CAP8_TWT_RESPOND | S1G_CAP8_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 +548,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 +944,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 +970,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 +1387,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 +1569,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 +1715,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,6 +1736,8 @@ 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 */
@@ -1693,12 +1748,12 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
ext->u.s1g_beacon.timestamp = cpu_to_le32(data->abs_bcn_ts +
data->tsf_offset +
10 * 8 * 10 /
- txrate->bitrate);
+ bitrate);
} else {
mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
data->tsf_offset +
24 * 8 * 10 /
- txrate->bitrate);
+ bitrate);
}

mac80211_hwsim_tx_frame(hw, skb,
@@ -1747,6 +1802,11 @@ static const char * const hwsim_chanwidths[] = {
[NL80211_CHAN_WIDTH_80] = "vht80",
[NL80211_CHAN_WIDTH_80P80] = "vht80p80",
[NL80211_CHAN_WIDTH_160] = "vht160",
+ [NL80211_CHAN_WIDTH_1] = "1MHz",
+ [NL80211_CHAN_WIDTH_2] = "2MHz",
+ [NL80211_CHAN_WIDTH_4] = "4MHz",
+ [NL80211_CHAN_WIDTH_8] = "8MHz",
+ [NL80211_CHAN_WIDTH_16] = "16MHz",
};

static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
@@ -3089,6 +3149,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++) {
@@ -3131,6 +3193,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;
}
@@ -4328,6 +4396,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 };

--
2.20.1

2020-09-22 05:41:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 12/17] 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-09-22 05:41:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 10/17] 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 adc83d830691..713b432e3d8b 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;

+ /* device is expected to do this */
+ if (sband->band == NL80211_BAND_S1GHZ)
+ return 0;
+
/*
* data and mgmt (except PS Poll):
* - during CFP: 32768
--
2.20.1

2020-09-22 05:41:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 02/17] 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]>

---

v4:
- double space after goto (Johannes)
---
net/mac80211/scan.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 5ac2785cdc7b..d2d6ff37a77b 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-09-22 05:41:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 06/17] 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]>

---

v4:
- add protection against strange IEs in S1G (Johannes)
---
net/wireless/scan.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index b4c85e8f2107..38dabe33a4c5 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1315,18 +1315,34 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
int channel_number = -1;
struct ieee80211_channel *alt_channel;

+
+ if (channel->band == NL80211_BAND_S1GHZ) {
+ 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;
+ }
+
+ /* even if we didn't try to use the one frame came in on */
+ goto found_channel;
+ }
+
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;
}

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

2020-09-22 05:41:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 07/17] 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.

Signed-off-by: Thomas Pedersen <[email protected]>

---

v4:
- remove bss->s1g (Johannes)
- use sizeof() when checking IE lengths and don't parse
short beacon element (yet) (Johannes)
---
net/mac80211/ieee80211_i.h | 3 +++
net/mac80211/rx.c | 3 ++-
net/mac80211/scan.c | 17 +++++++++++++----
net/mac80211/util.c | 22 ++++++++++++++++++++++
4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 27b73891aa4c..32b9631a458e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1536,6 +1536,9 @@ 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 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 b04d6e01a346..7cc423bd38bb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4577,7 +4577,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 d2d6ff37a77b..d5fa627c5acc 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -146,7 +146,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 +196,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 +252,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 27b2f1ceca69..ba2810a6fae8 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,24 @@ _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 == sizeof(*elems->s1g_capab))
+ elems->s1g_capab = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
+ case WLAN_EID_S1G_OPERATION:
+ if (elen == sizeof(*elems->s1g_oper))
+ elems->s1g_oper = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
+ case WLAN_EID_S1G_BCN_COMPAT:
+ if (elen == sizeof(*elems->s1g_bcn_compat))
+ elems->s1g_bcn_compat = (void *)pos;
+ else
+ elem_parse_failed = true;
+ break;
default:
break;
}
--
2.20.1

2020-09-22 05:41:17

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 09/17] 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]>
Reported-by: kernel test robot <[email protected]>

---

v4:
- move listen_int_usf[] into util.c (Johannes)
- fix __le16 return type (kernel test robot)
---
include/linux/ieee80211.h | 7 +++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 10 ++++++----
net/mac80211/util.c | 22 ++++++++++++++++++++++
4 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index d0fda8424118..7b6af47dd279 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2448,6 +2448,13 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
#define S1G_OPER_CH_WIDTH_PRIMARY_1MHZ BIT(0)
#define S1G_OPER_CH_WIDTH_OPER GENMASK(4, 1)

+
+#define LISTEN_INT_USF GENMASK(15, 14)
+#define LISTEN_INT_UI GENMASK(13, 0)
+
+#define IEEE80211_MAX_USF FIELD_MAX(LISTEN_INT_USF)
+#define IEEE80211_MAX_UI FIELD_MAX(LISTEN_INT_UI)
+
/* 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 32b9631a458e..e65b29ec68a7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2300,6 +2300,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);
+u16 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 5afc009aabac..7b3397050b23 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -696,6 +696,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 +785,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(sband->band == NL80211_BAND_S1GHZ ?
+ 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 +801,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 ba2810a6fae8..326f2147bdf2 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -33,6 +33,8 @@
#include "led.h"
#include "wep.h"

+static const int listen_int_usf[] = { 1, 10, 1000, 10000 };
+
/* privid for wiphys to determine whether they belong to us or not */
const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid;

@@ -4385,3 +4387,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
};
+
+u16 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 */
+ WARN_ON_ONCE(ui > IEEE80211_MAX_UI);
+ listen_interval = FIELD_PREP(LISTEN_INT_USF, usf) |
+ FIELD_PREP(LISTEN_INT_UI, ui);
+
+ return (u16) listen_interval;
+}
--
2.20.1

2020-09-22 05:41:18

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v4 13/17] 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 | 84 +++++++++++++++++++++++++++++---------
net/mac80211/rx.c | 84 ++++++++++++++++----------------------
net/mac80211/util.c | 52 +++++++++++++++++++++++
5 files changed, 162 insertions(+), 67 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e65b29ec68a7..4c95f9a75a98 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1657,6 +1657,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);
@@ -2301,6 +2303,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);
u16 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 7ac9af66f545..240862a74a0f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1433,6 +1433,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 7b3397050b23..75893ebd5c13 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1603,6 +1603,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))) {
@@ -3896,12 +3899,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;
@@ -3911,14 +3915,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;

@@ -3938,10 +3952,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);
@@ -3974,7 +3988,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;

@@ -3994,8 +4008,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);
@@ -4029,7 +4049,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));
@@ -4065,7 +4085,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 =
@@ -4073,7 +4094,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;
@@ -4114,9 +4136,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);
@@ -4154,6 +4179,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)
{
@@ -4171,7 +4216,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 7cc423bd38bb..5696abaac171 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.
@@ -1836,6 +1792,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
@@ -1946,6 +1905,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
*
@@ -2254,7 +2216,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);
@@ -3128,6 +3090,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,
@@ -3594,6 +3559,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)
{
@@ -3813,6 +3799,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:
@@ -3979,7 +3966,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 326f2147bdf2..cf6488292066 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -47,6 +47,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-09-28 12:19:31

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association


> @@ -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;
> + }

I've applied this now (and made some changes in a few patches, please
check), but this particular thing seems a bit odd, in that it looks for
HT/VHT elements even on an S1G channel if the s1g oper element isn't
present? That seems like it shouldn't be the case, can you take a look?

johannes

2020-09-29 17:08:19

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association

On 2020-09-28 05:17, Johannes Berg wrote:
>> @@ -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;
>> + }
>
> I've applied this now (and made some changes in a few patches, please
> check), but this particular thing seems a bit odd, in that it looks for
> HT/VHT elements even on an S1G channel if the s1g oper element isn't
> present? That seems like it shouldn't be the case, can you take a look?

Thanks for the (numerous) fixups.

I don't think applying a (NULL) HT cap is a big deal since the same code
path
is already executed for eg. non HT, but it does look strange and I'll
send a
fixup.

--
thomas

2020-11-23 08:56:35

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association

On 2020-09-22 10:28, Thomas Pedersen wrote:
...
> @@ -3446,6 +3453,42 @@ bool ieee80211_chandef_he_6ghz_oper(struct
> ieee80211_sub_if_data *sdata,
>
> *chandef = he_chandef;
>
> + return false;
> +}
This change the "return true" to "return false" by default of
ieee80211_chandef_he_6ghz_oper.
It should be typo mistake.
> +
> +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 (FIELD_GET(S1G_OPER_CH_WIDTH_OPER, oper->ch_width)) {
> + 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;
> }
>
....

2020-11-23 08:58:03

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association

add more to know it.
On 2020-11-23 16:38, Wen Gong wrote:
> On 2020-09-22 10:28, Thomas Pedersen wrote:
> ...
>> @@ -3446,6 +3453,42 @@ bool ieee80211_chandef_he_6ghz_oper(struct
>> ieee80211_sub_if_data *sdata,
>>
>> *chandef = he_chandef;
>>
>> + return false;
>> +}
> This change the "return true" to "return false" by default of
> ieee80211_chandef_he_6ghz_oper.
> It should be typo mistake.
>> +
>> +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 (FIELD_GET(S1G_OPER_CH_WIDTH_OPER, oper->ch_width)) {
>> + 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;
>> }
>>
> ....

2020-11-23 18:50:12

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association

On 2020-11-23 00:38, Wen Gong wrote:
> On 2020-09-22 10:28, Thomas Pedersen wrote:
> ...
>> @@ -3446,6 +3453,42 @@ bool ieee80211_chandef_he_6ghz_oper(struct
>> ieee80211_sub_if_data *sdata,
>>
>> *chandef = he_chandef;
>>
>> + return false;
>> +}
> This change the "return true" to "return false" by default of
> ieee80211_chandef_he_6ghz_oper.
> It should be typo mistake.

Thanks Wen. This was maybe rebase damage? Will send a fixup.

--
thomas

2020-11-24 04:03:59

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association

On 2020-11-24 02:40, Thomas Pedersen wrote:
> On 2020-11-23 00:38, Wen Gong wrote:
>> On 2020-09-22 10:28, Thomas Pedersen wrote:
>> ...
>>> @@ -3446,6 +3453,42 @@ bool ieee80211_chandef_he_6ghz_oper(struct
>>> ieee80211_sub_if_data *sdata,
>>>
>>> *chandef = he_chandef;
>>>
>>> + return false;
>>> +}
>> This change the "return true" to "return false" by default of
>> ieee80211_chandef_he_6ghz_oper.
>> It should be typo mistake.
>
> Thanks Wen. This was maybe rebase damage? Will send a fixup.
yes, I have sent a patch, 6G connect success with this patch, otherwise
fail for 6G connect.
https://lore.kernel.org/linux-wireless/[email protected]/

2020-11-24 07:07:14

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH v4 14/17] mac80211: support S1G association

On 2020-11-23 19:59, Wen Gong wrote:
> On 2020-11-24 02:40, Thomas Pedersen wrote:
>> On 2020-11-23 00:38, Wen Gong wrote:
>>> On 2020-09-22 10:28, Thomas Pedersen wrote:
>>> ...
>>>> @@ -3446,6 +3453,42 @@ bool ieee80211_chandef_he_6ghz_oper(struct
>>>> ieee80211_sub_if_data *sdata,
>>>>
>>>> *chandef = he_chandef;
>>>>
>>>> + return false;
>>>> +}
>>> This change the "return true" to "return false" by default of
>>> ieee80211_chandef_he_6ghz_oper.
>>> It should be typo mistake.
>>
>> Thanks Wen. This was maybe rebase damage? Will send a fixup.
> yes, I have sent a patch, 6G connect success with this patch,
> otherwise fail for 6G connect.
> https://lore.kernel.org/linux-wireless/[email protected]/

Excellent, thank you.

--
thomas

2020-12-08 07:45:53

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH v4 13/17] mac80211: receive and process S1G beacons

On 2020-09-22 10:28, Thomas Pedersen wrote:
> 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 | 84 +++++++++++++++++++++++++++++---------
> net/mac80211/rx.c | 84 ++++++++++++++++----------------------
> net/mac80211/util.c | 52 +++++++++++++++++++++++
> 5 files changed, 162 insertions(+), 67 deletions(-)
>
...
> @@ -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)) {
is this a typo mistake?
it removed ! for is_multicast_ether_addr(!is_multicast_ether_addr ==>
is_multicast_ether_addr)
> /*
> * Mesh beacons will update last_rx when if they are found to
> * match the current local configuration when processed.
...

2020-12-08 18:25:15

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH v4 13/17] mac80211: receive and process S1G beacons

Hi Wen,

On 2020-12-07 23:44, Wen Gong wrote:
> On 2020-09-22 10:28, Thomas Pedersen wrote:
>> 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 | 84
>> +++++++++++++++++++++++++++++---------
>> net/mac80211/rx.c | 84
>> ++++++++++++++++----------------------
>> net/mac80211/util.c | 52 +++++++++++++++++++++++
>> 5 files changed, 162 insertions(+), 67 deletions(-)
>>
> ...
>> @@ -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)) {
> is this a typo mistake?
> it removed ! for is_multicast_ether_addr(!is_multicast_ether_addr ==>
> is_multicast_ether_addr)

Yes that does look like a typo, it should be:

} else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
!is_multicast_ether_addr(hdr->addr1)) {

(because is_multicast_ether_addr() evaluates to true for s1g beacons).

Do you have a patch or would you like me to send a fixup?

Thanks,

--
thomas

2020-12-09 02:54:13

by Wen Gong

[permalink] [raw]
Subject: Re: [PATCH v4 13/17] mac80211: receive and process S1G beacons

On 2020-12-09 02:19, Thomas Pedersen wrote:
> Hi Wen,
>
> On 2020-12-07 23:44, Wen Gong wrote:
>> On 2020-09-22 10:28, Thomas Pedersen wrote:
>>> 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 | 84
>>> +++++++++++++++++++++++++++++---------
>>> net/mac80211/rx.c | 84
>>> ++++++++++++++++----------------------
>>> net/mac80211/util.c | 52 +++++++++++++++++++++++
>>> 5 files changed, 162 insertions(+), 67 deletions(-)
>>>
>> ...
>>> @@ -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)) {
>> is this a typo mistake?
>> it removed ! for is_multicast_ether_addr(!is_multicast_ether_addr ==>
>> is_multicast_ether_addr)
>
> Yes that does look like a typo, it should be:
>
> } else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
> !is_multicast_ether_addr(hdr->addr1)) {
>
> (because is_multicast_ether_addr() evaluates to true for s1g beacons).
>
> Do you have a patch or would you like me to send a fixup?
Yes, I have a patch for it.
I will send it.
>
> Thanks,