diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 6cbaed4d7a6b..d9650ae2b4f7 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2475,6 +2475,7 @@ enum ieee80211_eid_ext { WLAN_EID_EXT_HE_OPERATION = 36, WLAN_EID_EXT_UORA = 37, WLAN_EID_EXT_HE_MU_EDCA = 38, + WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME = 52, WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55, }; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 97aed7b1ba5d..3fb38d2bdb4f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1519,6 +1519,9 @@ struct ieee80211_conf { * scheduled channel switch, as indicated by the AP. * @chandef: the new channel to switch to * @count: the number of TBTT's until the channel switch event + * @delay: maximum delay between the time the AP transmitted the last beacon in + * current channel and the expected time of the first beacon in the new + * channel, expressed in TU. */ struct ieee80211_channel_switch { u64 timestamp; @@ -1526,6 +1529,7 @@ struct ieee80211_channel_switch { bool block_tx; struct cfg80211_chan_def chandef; u8 count; + u32 delay; }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index afce50da6fd6..e170f986d226 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1453,6 +1453,7 @@ struct ieee80211_csa_ie { u8 ttl; u16 pre_value; u16 reason_code; + u32 max_switch_time; }; /* Parsed Information Elements */ @@ -1493,6 +1494,7 @@ struct ieee802_11_elems { const struct ieee80211_channel_sw_ie *ch_switch_ie; const struct ieee80211_ext_chansw_ie *ext_chansw_ie; const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; + const u8 *max_channel_switch_time; const u8 *country_elem; const u8 *pwr_constr_elem; const u8 *cisco_dtpc_elem; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index df5d4b90616d..1b4938d100d5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1352,6 +1352,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ch_switch.block_tx = csa_ie.mode; ch_switch.chandef = csa_ie.chandef; ch_switch.count = csa_ie.count; + ch_switch.delay = csa_ie.max_switch_time; if (drv_pre_channel_switch(sdata, &ch_switch)) { sdata_info(sdata, diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 4e4902bdbef8..3c644f14dd59 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -177,6 +177,12 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, csa_ie->chandef = new_vht_chandef; } + if (elems->max_channel_switch_time) + csa_ie->max_switch_time = + (elems->max_channel_switch_time[0] << 0) | + (elems->max_channel_switch_time[1] << 8) | + (elems->max_channel_switch_time[2] << 16); + return 0; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8349c91250ef..3f5a704d1ab0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1274,6 +1274,10 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, elems->he_operation = (void *)&pos[1]; } else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) { elems->uora_element = (void *)&pos[1]; + } else if (pos[0] == + WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME && + elen == 4) { + elems->max_channel_switch_time = pos + 1; } else if (pos[0] == WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION && elen == 3) {