wifi: mac80211: store BSS param change count from assoc response
authorJohannes Berg <johannes.berg@intel.com>
Mon, 19 Jun 2023 13:26:48 +0000 (16:26 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 21 Jun 2023 12:01:28 +0000 (14:01 +0200)
When receiving a multi-link association response, make sure to
track the BSS parameter change count for each link, including
the assoc link.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230619161906.1799c164e7e9.I8e2c1f5eec6eec3fab525ae2dead9f6f099a2427@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/linux/ieee80211.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c

index fa67961..15c4e12 100644 (file)
@@ -4690,6 +4690,34 @@ static inline u8 ieee80211_mle_common_size(const u8 *data)
 }
 
 /**
+ * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count
+ * @mle: the basic multi link element
+ *
+ * The element is assumed to be of the correct type (BASIC) and big enough,
+ * this must be checked using ieee80211_mle_type_ok().
+ *
+ * If the BSS parameter change count value can't be found (the presence bit
+ * for it is clear), 0 will be returned.
+ */
+static inline u8
+ieee80211_mle_get_bss_param_ch_cnt(const struct ieee80211_multi_link_elem *mle)
+{
+       u16 control = le16_to_cpu(mle->control);
+       const u8 *common = mle->variable;
+
+       /* common points now at the beginning of ieee80211_mle_basic_common_info */
+       common += sizeof(struct ieee80211_mle_basic_common_info);
+
+       if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT))
+               return 0;
+
+       if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
+               common += 1;
+
+       return *common;
+}
+
+/**
  * ieee80211_mle_get_eml_sync_delay - returns the medium sync delay
  * @data: pointer to the multi link EHT IE
  *
@@ -4902,6 +4930,42 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data,
               fixed + prof->sta_info_len <= len;
 }
 
+/**
+ * ieee80211_mle_basic_sta_prof_bss_param_ch_cnt - get per-STA profile BSS
+ *     parameter change count
+ * @prof: the per-STA profile, having been checked with
+ *     ieee80211_mle_basic_sta_prof_size_ok() for the correct length
+ *
+ * Return: The BSS parameter change count value if present, 0 otherwise.
+ */
+static inline u8
+ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(const struct ieee80211_mle_per_sta_profile *prof)
+{
+       u16 control = le16_to_cpu(prof->control);
+       const u8 *pos = prof->variable;
+
+       if (!(control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT))
+               return 0;
+
+       if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT)
+               pos += 6;
+       if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT)
+               pos += 2;
+       if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT)
+               pos += 8;
+       if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT)
+               pos += 2;
+       if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE &&
+           control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) {
+               if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE)
+                       pos += 2;
+               else
+                       pos += 1;
+       }
+
+       return *pos;
+}
+
 #define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID                       0x000f
 #define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE              0x0010
 #define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT          0x0020
index 2f76659..91633a0 100644 (file)
@@ -951,6 +951,8 @@ struct ieee80211_link_data_managed {
        int wmm_last_param_set;
        int mu_edca_last_param_set;
 
+       u8 bss_param_ch_cnt;
+
        struct cfg80211_bss *bss;
 };
 
index cf15089..f93eb38 100644 (file)
@@ -4018,6 +4018,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
        const struct cfg80211_bss_ies *bss_ies = NULL;
        struct ieee80211_supported_band *sband;
        struct ieee802_11_elems *elems;
+       const __le16 prof_bss_param_ch_present =
+               cpu_to_le16(IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT);
        u16 capab_info;
        bool ret;
 
@@ -4033,7 +4035,17 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
                 * successful, so set the status directly to success
                 */
                assoc_data->link[link_id].status = WLAN_STATUS_SUCCESS;
-       } else if (!elems->prof) {
+               if (elems->ml_basic) {
+                       if (!(elems->ml_basic->control &
+                                       cpu_to_le16(IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT))) {
+                               ret = false;
+                               goto out;
+                       }
+                       link->u.mgd.bss_param_ch_cnt =
+                               ieee80211_mle_get_bss_param_ch_cnt(elems->ml_basic);
+               }
+       } else if (!elems->prof ||
+                  !(elems->prof->control & prof_bss_param_ch_present)) {
                ret = false;
                goto out;
        } else {
@@ -4046,6 +4058,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
                 */
                capab_info = get_unaligned_le16(ptr);
                assoc_data->link[link_id].status = get_unaligned_le16(ptr + 2);
+               link->u.mgd.bss_param_ch_cnt =
+                       ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(elems->prof);
 
                if (assoc_data->link[link_id].status != WLAN_STATUS_SUCCESS) {
                        link_info(link, "association response status code=%u\n",