[RFC 7/8] nl80211: add S1G support
Lachlan Hodges
lachlan.hodges at morsemicro.com
Wed May 27 23:38:56 PDT 2026
Introduce the ability to configure an S1G interface via nl80211.
Signed-off-by: Lachlan Hodges <lachlan.hodges at morsemicro.com>
---
src/drivers/driver_nl80211.c | 51 ++++++++++++++++++++++++++++--
src/drivers/driver_nl80211_capa.c | 36 +++++++++++++++++++--
src/drivers/driver_nl80211_event.c | 10 ++++--
3 files changed, 88 insertions(+), 9 deletions(-)
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index df82c1b670e3..0cdeb9bd5668 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5666,6 +5666,7 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
+ wpa_printf(MSG_DEBUG, " * s1g_enabled=%d", freq->s1g_enabled);
wpa_printf(MSG_DEBUG, " * radar_background=%d",
freq->radar_background);
@@ -5673,7 +5674,43 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
hw_mode == HOSTAPD_MODE_IEEE80211B;
- if (freq->vht_enabled ||
+ if (freq->s1g_enabled) {
+ enum nl80211_chan_width cw;
+
+ wpa_printf(MSG_DEBUG, " * channel_width=%d", freq->bandwidth);
+ wpa_printf(MSG_DEBUG, " * center_freq1=%d", freq->center_freq1);
+ wpa_printf(MSG_DEBUG, " * center_freq1_offset=%d", freq->center_freq1_offset);
+ wpa_printf(MSG_DEBUG, " * s1g_primary_2mhz=%d", freq->s1g_primary_2mhz);
+
+ switch (freq->bandwidth) {
+ case 1:
+ cw = NL80211_CHAN_WIDTH_1;
+ break;
+ case 2:
+ cw = NL80211_CHAN_WIDTH_2;
+ break;
+ case 4:
+ cw = NL80211_CHAN_WIDTH_4;
+ break;
+ case 8:
+ cw = NL80211_CHAN_WIDTH_8;
+ break;
+ case 16:
+ cw = NL80211_CHAN_WIDTH_16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw))
+ return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1))
+ return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1_OFFSET, freq->center_freq1_offset))
+ return -ENOBUFS;
+ if (freq->s1g_primary_2mhz && nla_put_flag(msg, NL80211_ATTR_S1G_PRIMARY_2MHZ))
+ return -ENOBUFS;
+ } else if (freq->vht_enabled ||
((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) {
enum nl80211_chan_width cw;
@@ -6193,9 +6230,9 @@ static int nl80211_set_channel(struct i802_bss *bss,
int ret;
wpa_printf(MSG_DEBUG,
- "nl80211: Set freq %d offset %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, , bandwidth=%d MHz, cf1=%d MHz, cf1_offset=%d KHz cf2=%d MHz)",
+ "nl80211: Set freq %d offset %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, s1g_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf1_offset=%d KHz cf2=%d MHz)",
freq->freq, freq->freq_offset, freq->ht_enabled, freq->vht_enabled,
- freq->he_enabled, freq->eht_enabled, freq->bandwidth,
+ freq->he_enabled, freq->eht_enabled, freq->s1g_enabled, freq->bandwidth,
freq->center_freq1, freq->center_freq1_offset, freq->center_freq2);
msg = nl80211_bss_msg(bss, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
@@ -6381,6 +6418,14 @@ static int wpa_driver_nl80211_sta_add(void *priv,
goto fail;
}
+ if (params->s1g_capab) {
+ wpa_hexdump(MSG_DEBUG, " * s1g_capab",
+ params->s1g_capab, sizeof(*params->s1g_capab));
+ if (nla_put(msg, NL80211_ATTR_S1G_CAPABILITY,
+ sizeof(*params->s1g_capab), params->s1g_capab))
+ goto fail;
+ }
+
if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
params->ext_capab, params->ext_capab_len);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index e423eeeb4528..2b96721c8d49 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -2132,6 +2132,24 @@ static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
}
+static void phy_info_s1g_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *capability,
+ struct nlattr *mcs_nss_set)
+{
+ if (capability && nla_len(capability) >= 10) {
+ u8 *capa;
+ capa = nla_data(capability);
+ os_memcpy(&mode->s1g_capab.capab_info, capa, 10);
+ }
+
+ if (mcs_nss_set && nla_len(mcs_nss_set) >= 5) {
+ u8 *mcs_nss;
+ mcs_nss = nla_data(mcs_nss_set);
+ os_memcpy(&mode->s1g_capab.supp_mcs_nss, mcs_nss, 5);
+ }
+}
+
+
static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
struct nlattr *bw_config,
struct nlattr *channels)
@@ -2208,6 +2226,13 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
if (tb_freq[NL80211_FREQUENCY_ATTR_NO_320MHZ])
chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_320;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_4MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_4;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_8MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_8;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_16MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_16;
+
if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
enum nl80211_dfs_state state =
nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -2589,6 +2614,8 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+ phy_info_s1g_capa(mode, tb_band[NL80211_BAND_ATTR_S1G_CAPA],
+ tb_band[NL80211_BAND_ATTR_S1G_MCS_NSS_SET]);
ret = phy_info_edmg_capa(mode,
tb_band[NL80211_BAND_ATTR_EDMG_BW_CONFIG],
tb_band[NL80211_BAND_ATTR_EDMG_CHANNELS]);
@@ -2658,8 +2685,9 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
continue;
modes[m].is_6ghz = false;
-
- if (modes[m].channels[0].freq < 2000) {
+ if (is_s1ghz_freq(modes[m].channels[0].freq)) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211AH;
+ } else if (modes[m].channels[0].freq < 2000) {
modes[m].num_channels = 0;
continue;
} else if (modes[m].channels[0].freq < 4000) {
@@ -3124,6 +3152,8 @@ static const char * modestr(enum hostapd_hw_mode mode)
return "802.11a";
case HOSTAPD_MODE_IEEE80211AD:
return "802.11ad";
+ case HOSTAPD_MODE_IEEE80211AH:
+ return "802.11ah";
default:
return "?";
}
@@ -3151,7 +3181,7 @@ static void nl80211_dump_chan_list(struct wpa_driver_nl80211_data *drv,
if (is_6ghz_freq(chan->freq))
drv->uses_6ghz = true;
- if (chan->freq >= 900 && chan->freq < 1000)
+ if (is_s1ghz_freq(chan->freq))
drv->uses_s1g = true;
if (drv->uses_s1g) {
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 28e8a7123af6..14c6f27fbebf 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -327,9 +327,13 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
event.assoc_info.resp_frame = frame;
event.assoc_info.resp_frame_len = len;
if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
- event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
- event.assoc_info.resp_ies_len =
- len - 24 - sizeof(mgmt->u.assoc_resp);
+ if (is_s1ghz_freq(drv->assoc_freq)) {
+ event.assoc_info.resp_ies = (u8 *) mgmt->u.s1g_assoc_resp.variable;
+ event.assoc_info.resp_ies_len = len - 24 - sizeof(mgmt->u.s1g_assoc_resp);
+ } else {
+ event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_info.resp_ies_len = len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
}
if (req_ie) {
--
2.43.0
More information about the Hostap
mailing list