2022-07-11 01:10:11

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 00/12] Additional support for 802.11ah (S1G)

This patchset builds on the work down by Thomas Pedersen to add further
support for 802.11ah in cfg80211 and mac80211. The ultimate goal is
to enable the successful starting of an AP on 802.11ah using 802.11ah
terms by implementing the various features that are required by the
AP. The features are split into their own commits, please see those
patches for more details.

The patchset has been tested on both real hardware (Morse Micro MM610x)
and mac80211_hwsim, in AP and STA modes. Basic regression testing was
performed on 802.11n with mac80211_hwsim by starting an AP and having a
STA interface connect to it.

802.11ah features/support missing:
- Rate control integration
- Regulatory database updates (only US regulatory information exists)
- Optional 802.11ah (S1G) features such as RAW, TWT and AID grouping

Kieran Frewen (12):
cfg80211: regulatory: extend regulatory support for S1G
mac80211: update TIM for S1G specification changes
mac80211: S1G beacon/short beacon support
nl80211: support setting S1G short beacon period
nl80211: support advertising S1G capabilities
mac80211: support ieee80211_ext format
mac80211: S1G capabilities information element in probe request
cfg80211: S1G rate flags
nl80211: support advertising S1G rate information
mac80211: support S1G rate encoding.
cfg80211: support for calculating S1G bitrates
mac80211_hwsim: support for S1G rate information

drivers/net/wireless/mac80211_hwsim.c | 40 +++-
include/net/cfg80211.h | 16 +-
include/net/mac80211.h | 33 ++-
include/uapi/linux/nl80211.h | 27 +++
net/mac80211/cfg.c | 43 +++-
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/rx.c | 32 ++-
net/mac80211/sta_info.c | 7 +
net/mac80211/sta_info.h | 7 +
net/mac80211/tx.c | 27 ++-
net/mac80211/util.c | 67 +++++-
net/wireless/nl80211.c | 37 ++++
net/wireless/reg.c | 50 +++--
net/wireless/reg_s1g.h | 281 ++++++++++++++++++++++++++
net/wireless/util.c | 144 ++++++++++++-
15 files changed, 758 insertions(+), 54 deletions(-)
create mode 100644 net/wireless/reg_s1g.h

--
2.25.1


2022-07-11 01:10:12

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 08/12] cfg80211: S1G rate flags

Increase the size of S1G rate_info flags to support S1G. Add flags for new
S1G bandwidths and S1G MCS.

Signed-off-by: Kieran Frewen <[email protected]>
Signed-off-by: Bassem Dawood <[email protected]>
---
include/net/cfg80211.h | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7859b8b11968..47f71fb5d07a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1608,6 +1608,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
* @RATE_INFO_FLAGS_EDMG: 60GHz MCS in EDMG mode
* @RATE_INFO_FLAGS_EXTENDED_SC_DMG: 60GHz extended SC MCS
* @RATE_INFO_FLAGS_EHT_MCS: EHT MCS information
+ * @RATE_INFO_FLAGS_S1G_MCS: mcs field filled with S1G MCS
*/
enum rate_info_flags {
RATE_INFO_FLAGS_MCS = BIT(0),
@@ -1618,6 +1619,7 @@ enum rate_info_flags {
RATE_INFO_FLAGS_EDMG = BIT(5),
RATE_INFO_FLAGS_EXTENDED_SC_DMG = BIT(6),
RATE_INFO_FLAGS_EHT_MCS = BIT(7),
+ RATE_INFO_FLAGS_S1G_MCS = BIT(8),
};

/**
@@ -1634,6 +1636,11 @@ enum rate_info_flags {
* @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation
* @RATE_INFO_BW_320: 320 MHz bandwidth
* @RATE_INFO_BW_EHT_RU: bandwidth determined by EHT RU allocation
+ * @RATE_INFO_BW_1: 1 MHz bandwidth
+ * @RATE_INFO_BW_2: 2 MHz bandwidth
+ * @RATE_INFO_BW_4: 4 MHz bandwidth
+ * @RATE_INFO_BW_8: 8 MHz bandwidth
+ * @RATE_INFO_BW_16: 16 MHz bandwidth
*/
enum rate_info_bw {
RATE_INFO_BW_20 = 0,
@@ -1645,6 +1652,11 @@ enum rate_info_bw {
RATE_INFO_BW_HE_RU,
RATE_INFO_BW_320,
RATE_INFO_BW_EHT_RU,
+ RATE_INFO_BW_1,
+ RATE_INFO_BW_2,
+ RATE_INFO_BW_4,
+ RATE_INFO_BW_8,
+ RATE_INFO_BW_16,
};

/**
@@ -1667,7 +1679,7 @@ enum rate_info_bw {
* only valid if bw is %RATE_INFO_BW_EHT_RU)
*/
struct rate_info {
- u8 flags;
+ u16 flags;
u8 mcs;
u16 legacy;
u8 nss;
--
2.25.1

2022-07-11 01:10:24

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 09/12] nl80211: support advertising S1G rate information

Add S1G rate information to netlink STA rate message.

Signed-off-by: Kieran Frewen <[email protected]>
Signed-off-by: Bassem Dawood <[email protected]>
---
include/uapi/linux/nl80211.h | 14 ++++++++++++++
net/wireless/nl80211.c | 23 +++++++++++++++++++++++
2 files changed, 37 insertions(+)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 71074332ccc5..19cf030004e9 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3539,6 +3539,13 @@ enum nl80211_eht_ru_alloc {
* (u8, see &enum nl80211_eht_gi)
* @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then
* non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc)
+ * @NL80211_RATE_INFO_S1G_MCS: S1G MCS index (u8, 0-10)
+ * @NL80211_RATE_INFO_S1G_nss: S1G NSS value (u8, 1-4)
+ * @NL80211_RATE_INFO_1_MHZ_WIDTH: 1 MHz S1G rate
+ * @NL80211_RATE_INFO_2_MHZ_WIDTH: 2 MHz S1G rate
+ * @NL80211_RATE_INFO_4_MHZ_WIDTH: 4 MHz S1G rate
+ * @NL80211_RATE_INFO_8_MHZ_WIDTH: 8 MHz S1G rate
+ * @NL80211_RATE_INFO_16_MHZ_WIDTH: 16 MHz S1G rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -3565,6 +3572,13 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_EHT_NSS,
NL80211_RATE_INFO_EHT_GI,
NL80211_RATE_INFO_EHT_RU_ALLOC,
+ NL80211_RATE_INFO_S1G_MCS,
+ NL80211_RATE_INFO_S1G_NSS,
+ NL80211_RATE_INFO_1_MHZ_WIDTH,
+ NL80211_RATE_INFO_2_MHZ_WIDTH,
+ NL80211_RATE_INFO_4_MHZ_WIDTH,
+ NL80211_RATE_INFO_8_MHZ_WIDTH,
+ NL80211_RATE_INFO_16_MHZ_WIDTH,

/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 077dc2938551..70efed2b5899 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6073,6 +6073,21 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
return false;

switch (info->bw) {
+ case RATE_INFO_BW_1:
+ rate_flg = NL80211_RATE_INFO_1_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_2:
+ rate_flg = NL80211_RATE_INFO_2_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_4:
+ rate_flg = NL80211_RATE_INFO_4_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_8:
+ rate_flg = NL80211_RATE_INFO_8_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_16:
+ rate_flg = NL80211_RATE_INFO_16_MHZ_WIDTH;
+ break;
case RATE_INFO_BW_5:
rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
break;
@@ -6137,6 +6152,14 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
info->he_ru_alloc))
return false;
+ } else if (info->flags & RATE_INFO_FLAGS_S1G_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_S1G_MCS, info->mcs))
+ return false;
+ if (nla_put_u8(msg, NL80211_RATE_INFO_S1G_NSS, info->nss))
+ return false;
+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+ nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+ return false;
} else if (info->flags & RATE_INFO_FLAGS_EHT_MCS) {
if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_MCS, info->mcs))
return false;
--
2.25.1

2022-07-11 01:10:24

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 10/12] mac80211: support S1G rate encoding.

Add support for receiving and transmitting S1G frames.

Signed-off-by: Kieran Frewen <[email protected]>
Signed-off-by: Bassem Dawood <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 2 +-
include/net/mac80211.h | 32 ++++++++++++++++----
net/mac80211/cfg.c | 42 ++++++++++++++++++++-------
net/mac80211/rx.c | 8 +++++
net/mac80211/sta_info.c | 7 +++++
net/mac80211/sta_info.h | 7 +++++
net/mac80211/util.c | 30 ++++++++++++++++++-
7 files changed, 110 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index c5bb97b381cf..304249038ac6 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1547,7 +1547,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.freq_offset = chan->freq_offset;
rx_status.band = chan->band;
if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
rx_status.rate_idx =
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1fd461ed746d..93fe4b98017c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -848,6 +848,10 @@ enum mac80211_tx_info_flags {
#define IEEE80211_TX_CTL_STBC_SHIFT 23

#define IEEE80211_TX_RC_S1G_MCS IEEE80211_TX_RC_VHT_MCS
+#define IEEE80211_TX_RC_2_MHZ_WIDTH IEEE80211_TX_RC_MCS
+#define IEEE80211_TX_RC_4_MHZ_WIDTH IEEE80211_TX_RC_40_MHZ_WIDTH
+#define IEEE80211_TX_RC_8_MHZ_WIDTH IEEE80211_TX_RC_80_MHZ_WIDTH
+#define IEEE80211_TX_RC_16_MHZ_WIDTH IEEE80211_TX_RC_160_MHZ_WIDTH

/**
* enum mac80211_tx_control_flags - flags to describe transmit control
@@ -1028,6 +1032,20 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
return (rate->idx >> 4) + 1;
}

+static inline u8
+ieee80211_rate_get_s1g_mcs(const struct ieee80211_tx_rate *rate)
+{
+ /* S1G uses the same MCS encoding as VHT */
+ return ieee80211_rate_get_vht_mcs(rate);
+}
+
+static inline u8
+ieee80211_rate_get_s1g_nss(const struct ieee80211_tx_rate *rate)
+{
+ /* S1G uses the same NSS encoding as VHT */
+ return ieee80211_rate_get_vht_nss(rate);
+}
+
/**
* struct ieee80211_tx_info - skb transmit information
*
@@ -1408,6 +1426,7 @@ enum mac80211_rx_encoding {
RX_ENC_HT,
RX_ENC_VHT,
RX_ENC_HE,
+ RX_ENC_S1G,
};

/**
@@ -1458,10 +1477,11 @@ struct ieee80211_rx_status {
u32 device_timestamp;
u32 ampdu_reference;
u32 flag;
- u16 freq: 13, freq_offset: 1;
+ u16 freq;
+ u16 freq_offset;
u8 enc_flags;
- u8 encoding:2, bw:3, he_ru:3;
- u8 he_gi:2, he_dcm:1;
+ u8 encoding:3, bw:5;
+ u8 he_ru:3, he_gi:2, he_dcm:1;
u8 rate_idx;
u8 nss;
u8 rx_flags;
@@ -1477,8 +1497,7 @@ struct ieee80211_rx_status {
static inline u32
ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
{
- return MHZ_TO_KHZ(rx_status->freq) +
- (rx_status->freq_offset ? 500 : 0);
+ return MHZ_TO_KHZ(rx_status->freq) + rx_status->freq_offset;
}

/**
@@ -6506,6 +6525,9 @@ bool rate_usable_index_exists(struct ieee80211_supported_band *sband,
{
unsigned int i;

+ if (sband->band == NL80211_BAND_S1GHZ)
+ return true;
+
for (i = 0; i < sband->n_bitrates; i++)
if (rate_supported(sta, sband->band, i))
return true;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b4c2f4e9083e..a5511eb56dd9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -743,8 +743,16 @@ void sta_set_rate_info_tx(struct sta_info *sta,
const struct ieee80211_tx_rate *rate,
struct rate_info *rinfo)
{
+ struct ieee80211_supported_band *sband;
+
+ sband = ieee80211_get_sband(sta->sdata);
rinfo->flags = 0;
- if (rate->flags & IEEE80211_TX_RC_MCS) {
+ if (rate->flags & IEEE80211_TX_RC_S1G_MCS &&
+ sband->band == NL80211_BAND_S1GHZ) {
+ rinfo->flags |= RATE_INFO_FLAGS_S1G_MCS;
+ rinfo->mcs = ieee80211_rate_get_s1g_mcs(rate);
+ rinfo->nss = ieee80211_rate_get_s1g_nss(rate);
+ } else if (rate->flags & IEEE80211_TX_RC_MCS) {
rinfo->flags |= RATE_INFO_FLAGS_MCS;
rinfo->mcs = rate->idx;
} else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
@@ -752,25 +760,37 @@ void sta_set_rate_info_tx(struct sta_info *sta,
rinfo->mcs = ieee80211_rate_get_vht_mcs(rate);
rinfo->nss = ieee80211_rate_get_vht_nss(rate);
} else {
- struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;

- sband = ieee80211_get_sband(sta->sdata);
WARN_ON_ONCE(sband && !sband->bitrates);
if (sband && sband->bitrates) {
brate = sband->bitrates[rate->idx].bitrate;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
}
- if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- rinfo->bw = RATE_INFO_BW_40;
- else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- rinfo->bw = RATE_INFO_BW_80;
- else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
- rinfo->bw = RATE_INFO_BW_160;
- else
- rinfo->bw = RATE_INFO_BW_20;
+ if (sband->band == NL80211_BAND_S1GHZ) {
+ if (rate->flags & IEEE80211_TX_RC_2_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_2;
+ else if (rate->flags & IEEE80211_TX_RC_4_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_4;
+ else if (rate->flags & IEEE80211_TX_RC_8_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_8;
+ else if (rate->flags & IEEE80211_TX_RC_16_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_16;
+ else
+ rinfo->bw = RATE_INFO_BW_1;
+ } else {
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_40;
+ else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_80;
+ else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_160;
+ else
+ rinfo->bw = RATE_INFO_BW_20;
+ }
+
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index feab1d58e932..e0a2975d0959 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4982,6 +4982,14 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
status->rate_idx, status->nss))
goto drop;
break;
+ case RX_ENC_S1G:
+ if (WARN_ONCE(status->rate_idx > 10 ||
+ !status->nss ||
+ status->nss > 8,
+ "Rate marked as a S1G rate but data is invalid: MCS: %d, NSS: %d\n",
+ status->rate_idx, status->nss))
+ goto drop;
+ break;
default:
WARN_ON_ONCE(1);
fallthrough;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 014032369994..da03d4eef321 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2297,6 +2297,13 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate);
rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate);
break;
+ case STA_STATS_RATE_TYPE_S1G:
+ rinfo->flags = RATE_INFO_FLAGS_S1G_MCS;
+ rinfo->mcs = STA_STATS_GET(S1G_MCS, rate);
+ rinfo->nss = STA_STATS_GET(S1G_NSS, rate);
+ if (STA_STATS_GET(SGI, rate))
+ rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
}
}

diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 218430790660..d2173a191da4 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -931,6 +931,8 @@ enum sta_stats_type {
#define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4)
#define STA_STATS_FIELD_HE_MCS GENMASK( 3, 0)
#define STA_STATS_FIELD_HE_NSS GENMASK( 7, 4)
+#define STA_STATS_FIELD_S1G_MCS GENMASK( 3, 0)
+#define STA_STATS_FIELD_S1G_NSS GENMASK( 7, 4)
#define STA_STATS_FIELD_BW GENMASK(11, 8)
#define STA_STATS_FIELD_SGI GENMASK(12, 12)
#define STA_STATS_FIELD_TYPE GENMASK(15, 13)
@@ -975,6 +977,11 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
r |= STA_STATS_FIELD(HE_RU, s->he_ru);
r |= STA_STATS_FIELD(HE_DCM, s->he_dcm);
break;
+ case RX_ENC_S1G:
+ r |= STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G);
+ r |= STA_STATS_FIELD(S1G_NSS, s->nss);
+ r |= STA_STATS_FIELD(S1G_MCS, s->rate_idx);
+ break;
default:
WARN_ON(1);
return STA_STATS_RATE_INVALID;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 51a2c1dee360..8b896aec5f8c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3861,7 +3861,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
u64 ts = status->mactime;
struct rate_info ri;
u16 rate;
- u8 n_ltf;
+ u8 n_ltf, guard_factor;

if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
return 0;
@@ -3948,6 +3948,34 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ts += 4 * n_ltf;
}

+ break;
+ case RX_ENC_S1G:
+ /* Set to duration of S1G OFDM symbol with normal GI */
+ guard_factor = 40;
+ ri.flags |= RATE_INFO_FLAGS_S1G_MCS;
+ ri.mcs = status->rate_idx;
+ ri.nss = status->nss;
+ if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) {
+ ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ guard_factor = 36;
+ }
+
+ /*
+ * See 80211-2020, section 23.3.2 for S1G PPDU
+ * format and 23.3.6 for timing-related parameters.
+ * Here using the general structure for S1G_1M as
+ * in figure 23-3.
+ */
+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+ mpdu_offset += 2;
+ ts += (14 * guard_factor);
+
+ /* Add S1G-LTFs per streams */
+ n_ltf = (ri.nss != 1) && (ri.nss % 2) ?
+ ri.nss + 1 : ri.nss;
+ ts += (guard_factor * n_ltf);
+ }
+
break;
default:
WARN_ON(1);
--
2.25.1

2022-07-11 01:10:33

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 11/12] cfg80211: support for calculating S1G bitrates

Support for reporting and calculating S1G MCS bitrates.

Signed-off-by: Kieran Frewen <[email protected]>
Signed-off-by: Bassem Dawood <[email protected]>
---
net/wireless/util.c | 113 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)

diff --git a/net/wireless/util.c b/net/wireless/util.c
index 412403d29c22..1bc604ec66dc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1380,6 +1380,117 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
return 0;
}

+static u32 cfg80211_calculate_bitrate_s1g(struct rate_info *rate)
+{
+ /* For 1, 2, 4, 8 and 16 MHz channels */
+ static const u32 base[5][12] = {
+ { 300000,
+ 600000,
+ 900000,
+ 1200000,
+ 1800000,
+ 2400000,
+ 2700000,
+ 3000000,
+ 3600000,
+ 4000000,
+ /* MCS 10 supported in 1 MHz only */
+ 150000,
+ },
+ { 650000,
+ 1300000,
+ 1950000,
+ 2600000,
+ 3900000,
+ 5200000,
+ 5850000,
+ 6500000,
+ 7800000,
+ /* MCS 9 not valid */
+ },
+ { 1350000,
+ 2700000,
+ 4050000,
+ 5400000,
+ 8100000,
+ 10800000,
+ 12150000,
+ 13500000,
+ 16200000,
+ 18000000,
+ },
+ { 2925000,
+ 5850000,
+ 8775000,
+ 11700000,
+ 17550000,
+ 23400000,
+ 26325000,
+ 29250000,
+ 35100000,
+ 39000000,
+ },
+ { 8580000,
+ 11700000,
+ 17550000,
+ 23400000,
+ 35100000,
+ 46800000,
+ 52650000,
+ 58500000,
+ 70200000,
+ 78000000,
+ },
+ };
+ u32 bitrate;
+ /* default is 1 MHz index */
+ int idx = 0;
+
+ if (rate->mcs > 11)
+ goto warn;
+
+ switch (rate->bw) {
+ case RATE_INFO_BW_16:
+ idx = 4;
+ break;
+ case RATE_INFO_BW_8:
+ idx = 3;
+ break;
+ case RATE_INFO_BW_4:
+ idx = 2;
+ break;
+ case RATE_INFO_BW_2:
+ idx = 1;
+ break;
+ case RATE_INFO_BW_1:
+ idx = 0;
+ break;
+ case RATE_INFO_BW_5:
+ case RATE_INFO_BW_10:
+ case RATE_INFO_BW_20:
+ case RATE_INFO_BW_40:
+ case RATE_INFO_BW_80:
+ case RATE_INFO_BW_160:
+ default:
+ goto warn;
+ }
+
+ bitrate = base[idx][rate->mcs];
+ bitrate *= rate->nss;
+
+ if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+ bitrate = (bitrate / 9) * 10;
+ /* do NOT round down here */
+ return (bitrate + 50000) / 100000;
+warn:
+ if (!rate->bw && !rate->mcs && !rate->nss)
+ pr_debug("%s: rx status was not received yet!", __func__);
+ else
+ WARN_ONCE(1, "invalid rate bw=%d, mcs=%d, nss=%d\n",
+ rate->bw, rate->mcs, rate->nss);
+ return 0;
+}
+
static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
{
#define SCALE 6144
@@ -1608,6 +1719,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
return cfg80211_calculate_bitrate_he(rate);
if (rate->flags & RATE_INFO_FLAGS_EHT_MCS)
return cfg80211_calculate_bitrate_eht(rate);
+ if (rate->flags & RATE_INFO_FLAGS_S1G_MCS)
+ return cfg80211_calculate_bitrate_s1g(rate);

return rate->legacy;
}
--
2.25.1

2022-07-11 01:10:40

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 12/12] mac80211_hwsim: support for S1G rate information

Include S1G rate information in S1G frames.

Signed-off-by: Kieran Frewen<[email protected]>
Signed-off-by: Bassem Dawood <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 38 ++++++++++++++++++++-------
1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 304249038ac6..c4c0796a610d 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1549,7 +1549,14 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
rx_status.freq = chan->center_freq;
rx_status.freq_offset = chan->freq_offset;
rx_status.band = chan->band;
- if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_S1G_MCS &&
+ rx_status.band == NL80211_BAND_S1GHZ) {
+ rx_status.rate_idx =
+ ieee80211_rate_get_s1g_mcs(&info->control.rates[0]);
+ rx_status.nss =
+ ieee80211_rate_get_s1g_nss(&info->control.rates[0]);
+ rx_status.encoding = RX_ENC_S1G;
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
rx_status.rate_idx =
ieee80211_rate_get_vht_mcs(&info->control.rates[0]);
rx_status.nss =
@@ -1560,14 +1567,27 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
rx_status.encoding = RX_ENC_HT;
}
- if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- rx_status.bw = RATE_INFO_BW_40;
- else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- rx_status.bw = RATE_INFO_BW_80;
- else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
- rx_status.bw = RATE_INFO_BW_160;
- else
- rx_status.bw = RATE_INFO_BW_20;
+ if (rx_status.band == NL80211_BAND_S1GHZ) {
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_2_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_2;
+ else if (info->control.rates[0].flags & IEEE80211_TX_RC_4_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_4;
+ else if (info->control.rates[0].flags & IEEE80211_TX_RC_8_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_8;
+ else if (info->control.rates[0].flags & IEEE80211_TX_RC_16_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_16;
+ else
+ rx_status.bw = RATE_INFO_BW_1;
+ } else {
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_40;
+ else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_80;
+ else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ rx_status.bw = RATE_INFO_BW_160;
+ else
+ rx_status.bw = RATE_INFO_BW_20;
+ }
if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI;
/* TODO: simulate optional packet loss */
--
2.25.1

2022-07-11 01:12:05

by Kieran Frewen

[permalink] [raw]
Subject: [PATCH 03/12] mac80211: S1G beacon/short beacon support

If configured, use the S1G short beacon format. The S1G short beacon
format includes a limited set of information elements.

Signed-off-by: Kieran Frewen <[email protected]>
Signed-off-by: Bassem Dawood <[email protected]>
---
include/net/cfg80211.h | 2 +-
include/net/mac80211.h | 1 +
net/mac80211/cfg.c | 1 +
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/tx.c | 14 +++++++++++++-
5 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 996782c44838..7859b8b11968 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1310,7 +1310,7 @@ struct cfg80211_ap_settings {

struct cfg80211_beacon_data beacon;

- int beacon_interval, dtim_period;
+ int beacon_interval, dtim_period, short_beacon_period;
const u8 *ssid;
size_t ssid_len;
enum nl80211_hidden_ssid hidden_ssid;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 27f24ac0426d..1fd461ed746d 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -656,6 +656,7 @@ struct ieee80211_bss_conf {
bool enable_beacon;
u8 dtim_period;
u16 beacon_int;
+ u8 short_beacon_period;
u16 assoc_capability;
u64 sync_tsf;
u32 sync_device_ts;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b387f5f4fef0..b4c2f4e9083e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1227,6 +1227,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
}

link_conf->dtim_period = params->dtim_period;
+ link_conf->short_beacon_period = params->short_beacon_period;
link_conf->enable_beacon = true;
link_conf->allow_p2p_go_ps = sdata->vif.p2p;
link_conf->twt_responder = params->twt_responder;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2190d08f4e34..19fa3f830abc 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -257,6 +257,7 @@ struct beacon_data {
struct ieee80211_meshconf_ie *meshconf;
u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM];
u8 cntdwn_current_counter;
+ u8 long_beacon_count;
struct cfg80211_mbssid_elems *mbssid_ies;
struct rcu_head rcu_head;
};
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3d83f838d728..632df040f07f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -5065,6 +5065,18 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
struct sk_buff *skb = NULL;
u16 csa_off_base = 0;
int mbssid_len;
+ bool is_short = false;
+
+ if (vif->cfg.s1g) {
+ if (beacon->long_beacon_count == 0) {
+ is_short = false;
+ beacon->long_beacon_count =
+ vif->bss_conf.short_beacon_period - 1;
+ } else {
+ is_short = true;
+ beacon->long_beacon_count--;
+ }
+ }

if (beacon->cntdwn_counter_offsets[0]) {
if (!is_template)
@@ -5102,7 +5114,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
csa_off_base = skb->len;
}

- if (beacon->tail)
+ if (beacon->tail && !is_short)
skb_put_data(skb, beacon->tail, beacon->tail_len);

if (ieee80211_beacon_protect(skb, local, sdata, link_id) < 0)
--
2.25.1

2022-07-12 22:51:08

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH 08/12] cfg80211: S1G rate flags

On 7/10/2022 6:08 PM, Kieran Frewen wrote:
> Increase the size of S1G rate_info flags to support S1G. Add flags for new
> S1G bandwidths and S1G MCS.
>
> Signed-off-by: Kieran Frewen <[email protected]>
> Signed-off-by: Bassem Dawood <[email protected]>
> ---
> include/net/cfg80211.h | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 7859b8b11968..47f71fb5d07a 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -1608,6 +1608,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
> * @RATE_INFO_FLAGS_EDMG: 60GHz MCS in EDMG mode
> * @RATE_INFO_FLAGS_EXTENDED_SC_DMG: 60GHz extended SC MCS
> * @RATE_INFO_FLAGS_EHT_MCS: EHT MCS information
> + * @RATE_INFO_FLAGS_S1G_MCS: mcs field filled with S1G MCS

nit: s/mcs/MCS/

> */
> enum rate_info_flags {
> RATE_INFO_FLAGS_MCS = BIT(0),
> @@ -1618,6 +1619,7 @@ enum rate_info_flags {
> RATE_INFO_FLAGS_EDMG = BIT(5),
> RATE_INFO_FLAGS_EXTENDED_SC_DMG = BIT(6),
> RATE_INFO_FLAGS_EHT_MCS = BIT(7),
> + RATE_INFO_FLAGS_S1G_MCS = BIT(8),
> };
>
> /**
> @@ -1634,6 +1636,11 @@ enum rate_info_flags {
> * @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation
> * @RATE_INFO_BW_320: 320 MHz bandwidth
> * @RATE_INFO_BW_EHT_RU: bandwidth determined by EHT RU allocation
> + * @RATE_INFO_BW_1: 1 MHz bandwidth
> + * @RATE_INFO_BW_2: 2 MHz bandwidth
> + * @RATE_INFO_BW_4: 4 MHz bandwidth
> + * @RATE_INFO_BW_8: 8 MHz bandwidth
> + * @RATE_INFO_BW_16: 16 MHz bandwidth
> */
> enum rate_info_bw {
> RATE_INFO_BW_20 = 0,
> @@ -1645,6 +1652,11 @@ enum rate_info_bw {
> RATE_INFO_BW_HE_RU,
> RATE_INFO_BW_320,
> RATE_INFO_BW_EHT_RU,
> + RATE_INFO_BW_1,
> + RATE_INFO_BW_2,
> + RATE_INFO_BW_4,
> + RATE_INFO_BW_8,
> + RATE_INFO_BW_16,
> };
>
> /**
> @@ -1667,7 +1679,7 @@ enum rate_info_bw {
> * only valid if bw is %RATE_INFO_BW_EHT_RU)
> */
> struct rate_info {
> - u8 flags;
> + u16 flags;
> u8 mcs;
> u16 legacy;
> u8 nss;

should we group legacy with flags so that the two u16s are adjacent?
note unfortunately we can't avoid padding

2022-07-13 00:56:35

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH 09/12] nl80211: support advertising S1G rate information

On 7/10/2022 6:08 PM, Kieran Frewen wrote:
> Add S1G rate information to netlink STA rate message.
>
> Signed-off-by: Kieran Frewen <[email protected]>
> Signed-off-by: Bassem Dawood <[email protected]>
> ---
> include/uapi/linux/nl80211.h | 14 ++++++++++++++
> net/wireless/nl80211.c | 23 +++++++++++++++++++++++
> 2 files changed, 37 insertions(+)
>
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index 71074332ccc5..19cf030004e9 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -3539,6 +3539,13 @@ enum nl80211_eht_ru_alloc {
> * (u8, see &enum nl80211_eht_gi)
> * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then
> * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc)
> + * @NL80211_RATE_INFO_S1G_MCS: S1G MCS index (u8, 0-10)
> + * @NL80211_RATE_INFO_S1G_nss: S1G NSS value (u8, 1-4)

nit: s/nss/NSS/

> + * @NL80211_RATE_INFO_1_MHZ_WIDTH: 1 MHz S1G rate
> + * @NL80211_RATE_INFO_2_MHZ_WIDTH: 2 MHz S1G rate
> + * @NL80211_RATE_INFO_4_MHZ_WIDTH: 4 MHz S1G rate
> + * @NL80211_RATE_INFO_8_MHZ_WIDTH: 8 MHz S1G rate
> + * @NL80211_RATE_INFO_16_MHZ_WIDTH: 16 MHz S1G rate
> * @__NL80211_RATE_INFO_AFTER_LAST: internal use
> */
> enum nl80211_rate_info {
> @@ -3565,6 +3572,13 @@ enum nl80211_rate_info {
> NL80211_RATE_INFO_EHT_NSS,
> NL80211_RATE_INFO_EHT_GI,
> NL80211_RATE_INFO_EHT_RU_ALLOC,
> + NL80211_RATE_INFO_S1G_MCS,
> + NL80211_RATE_INFO_S1G_NSS,
> + NL80211_RATE_INFO_1_MHZ_WIDTH,
> + NL80211_RATE_INFO_2_MHZ_WIDTH,
> + NL80211_RATE_INFO_4_MHZ_WIDTH,
> + NL80211_RATE_INFO_8_MHZ_WIDTH,
> + NL80211_RATE_INFO_16_MHZ_WIDTH,
>
> /* keep last */
> __NL80211_RATE_INFO_AFTER_LAST,
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index 077dc2938551..70efed2b5899 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -6073,6 +6073,21 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
> return false;
>
> switch (info->bw) {
> + case RATE_INFO_BW_1:
> + rate_flg = NL80211_RATE_INFO_1_MHZ_WIDTH;
> + break;
> + case RATE_INFO_BW_2:
> + rate_flg = NL80211_RATE_INFO_2_MHZ_WIDTH;
> + break;
> + case RATE_INFO_BW_4:
> + rate_flg = NL80211_RATE_INFO_4_MHZ_WIDTH;
> + break;
> + case RATE_INFO_BW_8:
> + rate_flg = NL80211_RATE_INFO_8_MHZ_WIDTH;
> + break;
> + case RATE_INFO_BW_16:
> + rate_flg = NL80211_RATE_INFO_16_MHZ_WIDTH;
> + break;

does it make sense to order these 1 2 4 5 8 10 16 20...

> case RATE_INFO_BW_5:
> rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
> break;
> @@ -6137,6 +6152,14 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
> nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
> info->he_ru_alloc))
> return false;
> + } else if (info->flags & RATE_INFO_FLAGS_S1G_MCS) {
> + if (nla_put_u8(msg, NL80211_RATE_INFO_S1G_MCS, info->mcs))
> + return false;
> + if (nla_put_u8(msg, NL80211_RATE_INFO_S1G_NSS, info->nss))
> + return false;
> + if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
> + nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
> + return false;
> } else if (info->flags & RATE_INFO_FLAGS_EHT_MCS) {
> if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_MCS, info->mcs))
> return false;