]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: cfg80211/mac80211: implement dot11ExtendedRegInfoSupport
authorSomashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
Mon, 9 Jun 2025 18:35:26 +0000 (21:35 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 9 Jul 2025 09:56:37 +0000 (11:56 +0200)
Implement dot11ExtendedRegInfoSupport to advertise non-AP station
regulatory power capability as part of regulatory connectivity
element in (Re)Association request frames so that AP can achieve
maximum client connectivity. Control field which was interpreted
using value of 3-bits B5 to B3, now uses value of 4-bits B6 to B3 to
interpret the type of AP. Hence update IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO
to parse 4-bits control field. If older AP still updates only 3-bits
value of control field, station can still interpret the value as per
section E.2.7 of IEEE 802.11 REVme D7.0 and support the appropriate
AP type.

Also update IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP as the value of
standard power AP is changed to 8 instead of 4 so that AP can support both
LPI AP and SP AP to maximize the connectivity with stations. For backward
compatibility, keeping value 4 as old AP by limiting it to SP AP only.

Signed-off-by: Somashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250609213232.90cdef116aad.I85da390fbee59355e3855691933e6a5e55c47ac4@changeid
[fix kernel-doc]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/linux/ieee80211.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/util.c
net/wireless/scan.c

index e05219a912f99659dc0b39d7eff6e974d5ae985d..ea95c4a60fa6e606f4145019a33413005106cb22 100644 (file)
@@ -2837,11 +2837,12 @@ static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len)
 #define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR               0x40000000
 #define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED              0x80000000
 
-#define IEEE80211_6GHZ_CTRL_REG_LPI_AP         0
-#define IEEE80211_6GHZ_CTRL_REG_SP_AP          1
-#define IEEE80211_6GHZ_CTRL_REG_VLP_AP         2
-#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP  3
-#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP   4
+#define IEEE80211_6GHZ_CTRL_REG_LPI_AP                 0
+#define IEEE80211_6GHZ_CTRL_REG_SP_AP                  1
+#define IEEE80211_6GHZ_CTRL_REG_VLP_AP                 2
+#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP          3
+#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD       4
+#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP           8
 
 /**
  * struct ieee80211_he_6ghz_oper - HE 6 GHz operation Information field
@@ -2859,13 +2860,31 @@ struct ieee80211_he_6ghz_oper {
 #define                IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ     2
 #define                IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ    3
 #define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4
-#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO   0x38
+#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO   0x78
        u8 control;
        u8 ccfs0;
        u8 ccfs1;
        u8 minrate;
 } __packed;
 
+/**
+ * enum ieee80211_reg_conn_bits - represents Regulatory connectivity field bits.
+ *
+ * This enumeration defines bit flags used to represent regulatory connectivity
+ * field bits.
+ *
+ * @IEEE80211_REG_CONN_LPI_VALID: Indicates whether the LPI bit is valid.
+ * @IEEE80211_REG_CONN_LPI_VALUE: Represents the value of the LPI bit.
+ * @IEEE80211_REG_CONN_SP_VALID: Indicates whether the SP bit is valid.
+ * @IEEE80211_REG_CONN_SP_VALUE: Represents the value of the SP bit.
+ */
+enum ieee80211_reg_conn_bits {
+       IEEE80211_REG_CONN_LPI_VALID = BIT(0),
+       IEEE80211_REG_CONN_LPI_VALUE = BIT(1),
+       IEEE80211_REG_CONN_SP_VALID = BIT(2),
+       IEEE80211_REG_CONN_SP_VALUE = BIT(3),
+};
+
 /* transmit power interpretation type of transmit power envelope element */
 enum ieee80211_tx_power_intrpt_type {
        IEEE80211_TPE_LOCAL_EIRP,
@@ -3847,6 +3866,7 @@ enum ieee80211_eid_ext {
        WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
        WLAN_EID_EXT_FILS_NONCE = 13,
        WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
+       WLAN_EID_EXT_DH_PARAMETER = 32,
        WLAN_EID_EXT_HE_CAPABILITY = 35,
        WLAN_EID_EXT_HE_OPERATION = 36,
        WLAN_EID_EXT_UORA = 37,
@@ -3870,6 +3890,8 @@ enum ieee80211_eid_ext {
        WLAN_EID_EXT_EHT_CAPABILITY = 108,
        WLAN_EID_EXT_TID_TO_LINK_MAPPING = 109,
        WLAN_EID_EXT_BANDWIDTH_INDICATION = 135,
+       WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION = 136,
+       WLAN_EID_EXT_NON_AP_STA_REG_CON = 137,
 };
 
 /* Action category code */
index 4ef7b3656aca80872e95d114b90ee5abccff5bfa..ec68204fddc9722eba9b33d914eae05d35e866e7 100644 (file)
@@ -2642,6 +2642,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
                          struct ieee80211_sub_if_data *sdata,
                          const struct ieee80211_supported_band *sband,
                          const struct ieee80211_conn_settings *conn);
+int ieee80211_put_reg_conn(struct sk_buff *skb,
+                          enum ieee80211_channel_flags flags);
 
 /* channel management */
 bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
index 1bedd8d6e891039f19d266bbcf3f97cf49a16c57..aaff7e9c3eb7177a50460e7836a0b2d16e028df4 100644 (file)
@@ -1641,6 +1641,30 @@ static size_t ieee80211_add_before_he_elems(struct sk_buff *skb,
        return noffset;
 }
 
+static size_t ieee80211_add_before_reg_conn(struct sk_buff *skb,
+                                           const u8 *elems, size_t elems_len,
+                                           size_t offset)
+{
+       static const u8 before_reg_conn[] = {
+               /*
+                * no need to list the ones split off before HE
+                * or generated here
+                */
+               WLAN_EID_EXTENSION, WLAN_EID_EXT_DH_PARAMETER,
+               WLAN_EID_EXTENSION, WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION,
+       };
+       size_t noffset;
+
+       if (!elems_len)
+               return offset;
+
+       noffset = ieee80211_ie_split(elems, elems_len, before_reg_conn,
+                                    ARRAY_SIZE(before_reg_conn), offset);
+       skb_put_data(skb, elems + offset, noffset - offset);
+
+       return noffset;
+}
+
 #define PRESENT_ELEMS_MAX      8
 #define PRESENT_ELEM_EXT_OFFS  0x100
 
@@ -1801,6 +1825,22 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,
                ieee80211_put_he_6ghz_cap(skb, sdata, smps_mode);
        }
 
+       /*
+        * if present, add any custom IEs that go before regulatory
+        * connectivity element
+        */
+       offset = ieee80211_add_before_reg_conn(skb, extra_elems,
+                                              extra_elems_len, offset);
+
+       if (sband->band == NL80211_BAND_6GHZ) {
+               /*
+                * as per Section E.2.7 of IEEE 802.11 REVme D7.0, non-AP STA
+                * capable of operating on the 6 GHz band shall transmit
+                * regulatory connectivity element.
+                */
+               ieee80211_put_reg_conn(skb, chan->flags);
+       }
+
        /*
         * careful - need to know about all the present elems before
         * calling ieee80211_assoc_add_ml_elem(), so add this one if
@@ -5931,6 +5971,7 @@ ieee80211_ap_power_type(u8 control)
                return IEEE80211_REG_LPI_AP;
        case IEEE80211_6GHZ_CTRL_REG_SP_AP:
        case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
+       case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
                return IEEE80211_REG_SP_AP;
        case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
                return IEEE80211_REG_VLP_AP;
index ff6c5d5e631d9674db046b5f4c6f19c75f2d4bb0..a1cb63222b6d26a31ead1fd29dea74ef9644d465 100644 (file)
@@ -2556,6 +2556,23 @@ end:
        return 0;
 }
 
+int ieee80211_put_reg_conn(struct sk_buff *skb,
+                          enum ieee80211_channel_flags flags)
+{
+       u8 reg_conn = IEEE80211_REG_CONN_LPI_VALID |
+                     IEEE80211_REG_CONN_LPI_VALUE |
+                     IEEE80211_REG_CONN_SP_VALID;
+
+       if (!(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT))
+               reg_conn |= IEEE80211_REG_CONN_SP_VALUE;
+
+       skb_put_u8(skb, WLAN_EID_EXTENSION);
+       skb_put_u8(skb, 1 + sizeof(reg_conn));
+       skb_put_u8(skb, WLAN_EID_EXT_NON_AP_STA_REG_CON);
+       skb_put_u8(skb, reg_conn);
+       return 0;
+}
+
 int ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
                              struct ieee80211_sub_if_data *sdata,
                              enum ieee80211_smps_mode smps_mode)
index b963ca5c606eb4dc560b141a112494807eb2bbdb..a8339ed52404c6ba10fff58e6e4c59538ce5a480 100644 (file)
@@ -2231,6 +2231,7 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len)
                return IEEE80211_REG_LPI_AP;
        case IEEE80211_6GHZ_CTRL_REG_SP_AP:
        case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
+       case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
                return IEEE80211_REG_SP_AP;
        case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
                return IEEE80211_REG_VLP_AP;