wifi: ieee80211: add definitions for multi-link element
authorJohannes Berg <johannes.berg@intel.com>
Tue, 31 May 2022 12:03:38 +0000 (14:03 +0200)
committerChristian Lamparter <chunkeey@gmail.com>
Sun, 21 May 2023 21:03:28 +0000 (23:03 +0200)
Add the definitions necessary to build and parse some of the
multi-link element, the per-STA profile isn't fully included.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
include/linux/ieee80211.h

index 690441b17f477753ebf59e0c689271e7d170cddc..3ec463ba9eda4226127a7ce943d7f9017ee0d78d 100644 (file)
@@ -4308,4 +4308,225 @@ enum ieee80211_range_params_max_total_ltf {
 /* multi-link device */
 #define IEEE80211_MLD_MAX_NUM_LINKS    15
 
+#define IEEE80211_ML_CONTROL_TYPE                      0x0007
+#define IEEE80211_ML_CONTROL_TYPE_BASIC                        0
+#define IEEE80211_ML_CONTROL_TYPE_PREQ                 1
+#define IEEE80211_ML_CONTROL_TYPE_RECONF               2
+#define IEEE80211_ML_CONTROL_TYPE_TDLS                 3
+#define IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS          4
+#define IEEE80211_ML_CONTROL_PRESENCE_MASK             0xfff0
+
+struct ieee80211_multi_link_elem {
+       __le16 control;
+       u8 variable[];
+} __packed;
+
+#define IEEE80211_MLC_BASIC_PRES_LINK_ID               0x0010
+#define IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT      0x0020
+#define IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY                0x0040
+#define IEEE80211_MLC_BASIC_PRES_EML_CAPA              0x0080
+#define IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP           0x0100
+#define IEEE80211_MLC_BASIC_PRES_MLD_ID                        0x0200
+
+#define IEEE80211_MED_SYNC_DELAY_DURATION              0x00ff
+#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH   0x0f00
+#define IEEE80211_MED_SYNC_DELAY_SYNC_MAX_NUM_TXOPS    0xf000
+
+#define IEEE80211_EML_CAP_EMLSR_SUPP                   0x0001
+#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY          0x000e
+#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_0US             0
+#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US            1
+#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_64US            2
+#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_128US           3
+#define  IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US           4
+#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY       0x0070
+#define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_0US          0
+#define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_16US         1
+#define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US         2
+#define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US         3
+#define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_128US                4
+#define  IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US                5
+#define IEEE80211_EML_CAP_EMLMR_SUPPORT                        0x0080
+#define IEEE80211_EML_CAP_EMLMR_DELAY                  0x0700
+#define  IEEE80211_EML_CAP_EMLMR_DELAY_0US                     0
+#define  IEEE80211_EML_CAP_EMLMR_DELAY_32US                    1
+#define  IEEE80211_EML_CAP_EMLMR_DELAY_64US                    2
+#define  IEEE80211_EML_CAP_EMLMR_DELAY_128US                   3
+#define  IEEE80211_EML_CAP_EMLMR_DELAY_256US                   4
+#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT           0x7800
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_0                        0
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128US            1
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_256US            2
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_512US            3
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_1TU              4
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_2TU              5
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_4TU              6
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_8TU              7
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_16TU             8
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_32TU             9
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_64TU             10
+#define  IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU            11
+
+#define IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS           0x000f
+#define IEEE80211_MLD_CAP_OP_SRS_SUPPORT               0x0010
+#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP  0x0060
+#define IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND         0x0f80
+#define IEEE80211_MLD_CAP_OP_AAR_SUPPORT               0x1000
+
+struct ieee80211_mle_basic_common_info {
+       u8 len;
+       u8 mld_mac_addr[6];
+       u8 variable[];
+} __packed;
+
+#define IEEE80211_MLC_PREQ_PRES_MLD_ID                 0x0010
+
+struct ieee80211_mle_preq_common_info {
+       u8 len;
+       u8 variable[];
+} __packed;
+
+#define IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR         0x0010
+
+/* no fixed fields in RECONF */
+
+struct ieee80211_mle_tdls_common_info {
+       u8 len;
+       u8 ap_mld_mac_addr[6];
+} __packed;
+
+#define IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR 0x0010
+
+/* no fixed fields in PRIO_ACCESS */
+
+/**
+ * ieee80211_mle_common_size - check multi-link element common size
+ * @data: multi-link element, must already be checked for size using
+ *     ieee80211_mle_size_ok()
+ */
+static inline u8 ieee80211_mle_common_size(const u8 *data)
+{
+       const struct ieee80211_multi_link_elem *mle = (const void *)data;
+       u16 control = le16_to_cpu(mle->control);
+       u8 common = 0;
+
+       switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) {
+       case IEEE80211_ML_CONTROL_TYPE_BASIC:
+               common += sizeof(struct ieee80211_mle_basic_common_info);
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_PREQ:
+               common += sizeof(struct ieee80211_mle_preq_common_info);
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_RECONF:
+               if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR)
+                       common += 6;
+               return common;
+       case IEEE80211_ML_CONTROL_TYPE_TDLS:
+               common += sizeof(struct ieee80211_mle_tdls_common_info);
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
+               if (control & IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR)
+                       common += 6;
+               return common;
+       default:
+               return 0;
+       }
+
+       return common + mle->variable[0];
+}
+
+/**
+ * ieee80211_mle_size_ok - validate multi-link element size
+ * @data: pointer to the element data
+ * @len: length of the containing element
+ */
+static inline bool ieee80211_mle_size_ok(const u8 *data, u8 len)
+{
+       const struct ieee80211_multi_link_elem *mle = (const void *)data;
+       u8 fixed = sizeof(*mle);
+       u8 common = 0;
+       bool check_common_len = false;
+       u16 control;
+
+       if (len < fixed)
+               return false;
+
+       control = le16_to_cpu(mle->control);
+
+       switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) {
+       case IEEE80211_ML_CONTROL_TYPE_BASIC:
+               common += sizeof(struct ieee80211_mle_basic_common_info);
+               check_common_len = true;
+               if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
+                       common += 1;
+               if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
+                       common += 1;
+               if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)
+                       common += 2;
+               if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)
+                       common += 2;
+               if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)
+                       common += 2;
+               if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID)
+                       common += 1;
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_PREQ:
+               common += sizeof(struct ieee80211_mle_preq_common_info);
+               if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID)
+                       common += 1;
+               check_common_len = true;
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_RECONF:
+               if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR)
+                       common += 6;
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_TDLS:
+               common += sizeof(struct ieee80211_mle_tdls_common_info);
+               check_common_len = true;
+               break;
+       case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
+               if (control & IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR)
+                       common += 6;
+               break;
+       default:
+               /* we don't know this type */
+               return true;
+       }
+
+       if (len < fixed + common)
+               return false;
+
+       if (!check_common_len)
+               return true;
+
+       /* if present, common length is the first octet there */
+       return mle->variable[0] >= common;
+}
+
+enum ieee80211_mle_subelems {
+       IEEE80211_MLE_SUBELEM_PER_STA_PROFILE           = 0,
+};
+
+#define IEEE80211_MLE_STA_CONTROL_LINK_ID                      0x000f
+#define IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE             0x0010
+#define IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT         0x0020
+#define IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT           0x0040
+#define IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT             0x0080
+#define IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT            0x0100
+#define IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT       0x0200
+#define IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE             0x0400
+#define IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT 0x0800
+
+struct ieee80211_mle_per_sta_profile {
+       __le16 control;
+       u8 sta_info_len;
+       u8 variable[];
+} __packed;
+
+#define for_each_mle_subelement(_elem, _data, _len)                    \
+       if (ieee80211_mle_size_ok(_data, _len))                         \
+               for_each_element(_elem,                                 \
+                                _data + ieee80211_mle_common_size(_data),\
+                                _len - ieee80211_mle_common_size(_data))
+
 #endif /* __LINUX_IEEE80211_H */