diff mbox series

[v4,14/17] mac80211: support S1G association

Message ID 20200922022818.15855-15-thomas@adapt-ip.com (mailing list archive)
State Accepted
Delegated to: Johannes Berg
Headers show
Series add support for S1G association | expand

Commit Message

Thomas Pedersen Sept. 22, 2020, 2:28 a.m. UTC
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 <thomas@adapt-ip.com>
---
 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(-)

Comments

Johannes Berg Sept. 28, 2020, 12:17 p.m. UTC | #1
> @@ -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
Thomas Pedersen Sept. 29, 2020, 5:07 p.m. UTC | #2
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.
Wen Gong Nov. 23, 2020, 8:38 a.m. UTC | #3
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;
>  }
> 
....
Wen Gong Nov. 23, 2020, 8:39 a.m. UTC | #4
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;
>>  }
>> 
> ....
Thomas Pedersen Nov. 23, 2020, 6:40 p.m. UTC | #5
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.
Wen Gong Nov. 24, 2020, 3:59 a.m. UTC | #6
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/1606121152-3452-1-git-send-email-wgong@codeaurora.org/
Thomas Pedersen Nov. 24, 2020, 7:04 a.m. UTC | #7
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/1606121152-3452-1-git-send-email-wgong@codeaurora.org/

Excellent, thank you.
diff mbox series

Patch

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)
 {