]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Enhance throughput estimation for punctured EHT APs
authorAbishek Ganapathy <quic_abishekg@quicinc.com>
Thu, 17 Apr 2025 11:16:06 +0000 (16:46 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 23 May 2025 12:15:19 +0000 (15:15 +0300)
When an EHT AP is advertising punctured channel widths, the throughput
estimation algorithm did not take it into account. This may lead to
picking a punctured AP with less effective bandwidth over an unpunctured
AP with more effective bandwidth.

For example, an EHT320 AP provides more resources for transmission than
an EHT320 AP with 120 MHz punctured (as it effectively has only 200
MHz).

Enhance the algorithm to compute appropriate throughput by considering
punctured bitmap as well so that the selected AP will have more
effective bandwidth.

Signed-off-by: Abishek Ganapathy <quic_abishekg@quicinc.com>
Co-developed-by: Rohan Dutta <quic_drohan@quicinc.com>
Signed-off-by: Rohan Dutta <quic_drohan@quicinc.com>
Co-developed-by: Basamma Yakkanahalli <quic_ybasamma@quicinc.com>
Signed-off-by: Basamma Yakkanahalli <quic_ybasamma@quicinc.com>
Signed-off-by: Pooventhiran G <quic_pooventh@quicinc.com>
src/common/ieee802_11_defs.h
wpa_supplicant/scan.c

index c5341d3b0450dfa91ac1629d7720987d8ff815e0..4dcdcbcb158f3197f4c0a5e21fefd591a087a314 100644 (file)
@@ -2681,6 +2681,8 @@ struct ieee80211_eht_operation {
        struct ieee80211_eht_oper_info oper_info; /* 0 or 3 or 5 octets */
 } STRUCT_PACKED;
 
+#define IEEE80211_EHT_OP_MIN_LEN (1 + 4)
+
 /* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */
 
 /* Figure 9-1002af: EHT MAC Capabilities Information field */
index ccedcc9542c26d05109530a1405bc0e2a4caecea..a4824678df35244e791b53d20e9731533fba5ba4 100644 (file)
@@ -2802,6 +2802,138 @@ static const struct minsnr_bitrate_entry he160_table[] = {
        { -1, 1441200 }  /* SNR > 51 */
 };
 
+/* See IEEE P802.11be/D7.0, Table 36-78 - EHT-MCSs for 484+242-tone MRU,
+ * NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht60_table[] = {
+       { 0, 0 },
+       { 8, 25800 },   /* EHT80 with 20 MHz punctured MCS0 */
+       { 11, 51600 },  /* EHT80 with 20 MHz punctured MCS1 */
+       { 15, 77400 },  /* EHT80 with 20 MHz punctured MCS2 */
+       { 17, 103200 }, /* EHT80 with 20 MHz punctured MCS3 */
+       { 21, 154900 }, /* EHT80 with 20 MHz punctured MCS4 */
+       { 24, 206500 }, /* EHT80 with 20 MHz punctured MCS5 */
+       { 26, 232300 }, /* EHT80 with 20 MHz punctured MCS6 */
+       { 31, 258100 }, /* EHT80 with 20 MHz punctured MCS7 */
+       { 35, 309700 }, /* EHT80 with 20 MHz punctured MCS8 */
+       { 37, 344100 }, /* EHT80 with 20 MHz punctured MCS9 */
+       { 40, 387100 }, /* EHT80 with 20 MHz punctured MCS10 */
+       { 42, 430100 }, /* EHT80 with 20 MHz punctured MCS11 */
+       { 45, 464600 }, /* EHT80 with 20 MHz punctured MCS12 */
+       { 48, 516200 }, /* EHT80 with 20 MHz punctured MCS13 */
+       { -1, 516200 }  /* SNR > 48 */
+};
+
+/* See IEEE P802.11be/D7.0, Table 36-80 - EHT-MCSs for 996+484-tone MRU,
+ * NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht120_table[] = {
+       { 0, 0 },
+       { 11, 53200 },   /* EHT160 with 40 MHz punctured MCS0 */
+       { 14, 106500 },  /* EHT160 with 40 MHz punctured MCS1 */
+       { 18, 159700 },  /* EHT160 with 40 MHz punctured MCS2 */
+       { 20, 212900 },  /* EHT160 with 40 MHz punctured MCS3 */
+       { 24, 319400 },  /* EHT160 with 40 MHz punctured MCS4 */
+       { 27, 425900 },  /* EHT160 with 40 MHz punctured MCS5 */
+       { 29, 479100 },  /* EHT160 with 40 MHz punctured MCS6 */
+       { 34, 532400 },  /* EHT160 with 40 MHz punctured MCS7 */
+       { 38, 638800 },  /* EHT160 with 40 MHz punctured MCS8 */
+       { 40, 709800 },  /* EHT160 with 40 MHz punctured MCS9 */
+       { 43, 798500 },  /* EHT160 with 40 MHz punctured MCS10 */
+       { 45, 887200 },  /* EHT160 with 40 MHz punctured MCS11 */
+       { 48, 958200 },  /* EHT160 with 40 MHz punctured MCS12 */
+       { 51, 1064700 }, /* EHT160 with 40 MHz punctured MCS13 */
+       { -1, 1064700 }  /* SNR > 51 */
+};
+
+/* See IEEE P802.11be/D7.0, Table 36-81 - EHT-MCSs for 996+484+242-tone MRU,
+ * NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht140_table[] = {
+       { 0, 0 },
+       { 11, 61800 },   /* EHT160 with 20 MHz punctured MCS0 */
+       { 14, 123700 },  /* EHT160 with 20 MHz punctured MCS1 */
+       { 18, 185500 },  /* EHT160 with 20 MHz punctured MCS2 */
+       { 20, 247400 },  /* EHT160 with 20 MHz punctured MCS3 */
+       { 24, 371000 },  /* EHT160 with 20 MHz punctured MCS4 */
+       { 27, 494700 },  /* EHT160 with 20 MHz punctured MCS5 */
+       { 29, 556500 },  /* EHT160 with 20 MHz punctured MCS6 */
+       { 34, 618400 },  /* EHT160 with 20 MHz punctured MCS7 */
+       { 38, 742100 },  /* EHT160 with 20 MHz punctured MCS8 */
+       { 40, 824500 },  /* EHT160 with 20 MHz punctured MCS9 */
+       { 43, 927600 },  /* EHT160 with 20 MHz punctured MCS10 */
+       { 45, 1030600 }, /* EHT160 with 20 MHz punctured MCS11 */
+       { 48, 1113100 }, /* EHT160 with 20 MHz punctured MCS12 */
+       { 51, 1236800 }, /* EHT160 with 20 MHz punctured MCS13 */
+       { -1, 1236800 }  /* SNR > 51 */
+};
+
+/* See IEEE P802.11be/D7.0, Table 36-83 - EHT-MCSs for 2x996+484-tone NRU,
+ * NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht200_table[] = {
+       { 0, 0 },
+       { 14, 89300 },    /* EHT320 with 120 MHz punctured MCS0 */
+       { 17, 178500 },   /* EHT320 with 120 MHz punctured MCS1 */
+       { 21, 267800 },   /* EHT320 with 120 MHz punctured MCS2 */
+       { 23, 357100 },   /* EHT320 with 120 MHz punctured MCS3 */
+       { 27, 535600 },   /* EHT320 with 120 MHz punctured MCS4 */
+       { 30, 714100 },   /* EHT320 with 120 MHz punctured MCS5 */
+       { 32, 803400 },   /* EHT320 with 120 MHz punctured MCS6 */
+       { 37, 892600 },   /* EHT320 with 120 MHz punctured MCS7 */
+       { 41, 1071200 },  /* EHT320 with 120 MHz punctured MCS8 */
+       { 43, 1190100 },  /* EHT320 with 120 MHz punctured MCS9 */
+       { 46, 1339000 },  /* EHT320 with 120 MHz punctured MCS10 */
+       { 48, 1487700 },  /* EHT320 with 120 MHz punctured MCS11 */
+       { 51, 1606800 },  /* EHT320 with 120 MHz punctured MCS12 */
+       { 54, 1785300 },  /* EHT320 with 120 MHz punctured MCS13 */
+       { -1, 1785300 }   /* SNR > 54 */
+};
+
+/* See IEEE P802.11be/D7.0, Table 36-84 - EHT-MCSs for 3x996-tone MRU,
+ * NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht240_table[] = {
+       { 0, 0 },
+       { 14, 108100 },   /* EHT320 with 80 MHz punctured MCS0 */
+       { 17, 216200 },   /* EHT320 with 80 MHz punctured MCS1 */
+       { 21, 324300 },   /* EHT320 with 80 MHz punctured MCS2 */
+       { 23, 432400 },   /* EHT320 with 80 MHz punctured MCS3 */
+       { 27, 648500 },   /* EHT320 with 80 MHz punctured MCS4 */
+       { 30, 864700 },   /* EHT320 with 80 MHz punctured MCS5 */
+       { 32, 972800 },   /* EHT320 with 80 MHz punctured MCS6 */
+       { 37, 1080900 },  /* EHT320 with 80 MHz punctured MCS7 */
+       { 41, 1297100 },  /* EHT320 with 80 MHz punctured MCS8 */
+       { 43, 1441200 },  /* EHT320 with 80 MHz punctured MCS9 */
+       { 46, 1621300 },  /* EHT320 with 80 MHz punctured MCS10 */
+       { 48, 1801500 },  /* EHT320 with 80 MHz punctured MCS11 */
+       { 51, 1945600 },  /* EHT320 with 80 MHz punctured MCS12 */
+       { 54, 2161800 },  /* EHT320 with 80 MHz punctured MCS13 */
+       { -1, 2161800 }   /* SNR > 54 */
+};
+
+/* See IEEE P802.11be/D7.0, Table 36-85: EHT-MCSs for 3x996+484-tone MRU,
+ * NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht280_table[] = {
+       { 0, 0 },
+       { 14, 125300 },   /* EHT320 with 40 MHz punctured MCS0 */
+       { 17, 250600 },   /* EHT320 with 40 MHz punctured MCS1 */
+       { 21, 375900 },   /* EHT320 with 40 MHz punctured MCS2 */
+       { 23, 501200 },   /* EHT320 with 40 MHz punctured MCS3 */
+       { 27, 751800 },   /* EHT320 with 40 MHz punctured MCS4 */
+       { 30, 1002400 },  /* EHT320 with 40 MHz punctured MCS5 */
+       { 32, 1127600 },  /* EHT320 with 40 MHz punctured MCS6 */
+       { 37, 1252900 },  /* EHT320 with 40 MHz punctured MCS7 */
+       { 41, 1503500 },  /* EHT320 with 40 MHz punctured MCS8 */
+       { 43, 1670600 },  /* EHT320 with 40 MHz punctured MCS9 */
+       { 46, 1879400 },  /* EHT320 with 40 MHz punctured MCS10 */
+       { 48, 2088200 },  /* EHT320 with 40 MHz punctured MCS11 */
+       { 51, 2255300 },  /* EHT320 with 40 MHz punctured MCS12 */
+       { 54, 2505900 },  /* EHT320 with 40 MHz punctured MCS13 */
+       { -1, 2505900 }   /* SNR > 54 */
+};
+
 /* See IEEE P802.11be/D2.0, Table 36-86: EHT-MCSs for 4x996-tone RU, NSS,u = 1
  */
 static const struct minsnr_bitrate_entry eht320_table[] = {
@@ -2891,6 +3023,96 @@ static unsigned int max_he_eht_rate(const struct minsnr_bitrate_entry table[],
 }
 
 
+static unsigned int get_eht_punctured_rate(enum chan_width cw,
+                                          u8 num_punct_bits, int adjusted_snr,
+                                          u8 boost)
+{
+       const struct minsnr_bitrate_entry *eht_table;
+
+       switch (cw) {
+       case CHAN_WIDTH_80:
+               switch (num_punct_bits) {
+               case 1:
+                       /* EHT80 with 20 MHz punctured */
+                       eht_table = eht60_table;
+                       break;
+               default:
+                       eht_table = he80_table;
+                       break;
+               }
+               break;
+       case CHAN_WIDTH_160:
+               switch (num_punct_bits) {
+               case 2:
+                       /* EHT160 with 40 MHz punctured */
+                       eht_table = eht120_table;
+                       break;
+               case 1:
+                       /* EHT160 with 20 MHz punctured */
+                       eht_table = eht140_table;
+                       break;
+               default:
+                       eht_table = he160_table;
+                       break;
+               }
+               break;
+       case CHAN_WIDTH_320:
+               switch (num_punct_bits) {
+               case 6:
+                       /* EHT320 with 120 MHz punctured */
+                       eht_table = eht200_table;
+                       break;
+               case 4:
+                       /* EHT320 with 80 MHz punctured */
+                       eht_table = eht240_table;
+                       break;
+               case 2:
+                       /* EHT320 with 40 MHz punctured */
+                       eht_table = eht280_table;
+                       break;
+               default:
+                       eht_table = eht320_table;
+                       break;
+               }
+               break;
+       default:
+               /* Puncturing is not supported for the channel width */
+               return 0;
+       }
+
+       return max_he_eht_rate(eht_table, adjusted_snr, true) + boost;
+}
+
+
+static u8 get_eht_num_punct_bits(const u8 *ies, size_t ies_len)
+{
+       const u8 *eht_ie;
+
+       eht_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_EHT_OPERATION);
+       if (eht_ie && eht_ie[1] >= 1 + IEEE80211_EHT_OP_MIN_LEN) {
+               struct ieee80211_eht_operation *eht_op;
+
+               eht_op = (struct ieee80211_eht_operation *) &eht_ie[3];
+
+               if (eht_op->oper_params &
+                   EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT) {
+                       u16 punct_bitmap;
+                       u8 count = 0;
+
+                       punct_bitmap = le_to_host16(
+                               eht_op->oper_info.disabled_chan_bitmap);
+                       while (punct_bitmap) {
+                               count += punct_bitmap & 1;
+                               punct_bitmap >>= 1;
+                       }
+                       return count;
+               }
+       }
+
+       return 0;
+}
+
+
 unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
                              const u8 *ies, size_t ies_len, int rate,
                              int snr, int freq, enum chan_width *max_cw)
@@ -3048,8 +3270,9 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
                struct ieee80211_eht_capabilities *eht;
                struct he_capabilities *own_he;
                u8 cw, boost = 2;
-               const u8 *eht_ie;
+               const u8 *eht_ie = NULL;
                bool is_eht = false;
+               u8 num_punct_bits;
 
                ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES);
                if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN))
@@ -3099,8 +3322,17 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
                                *max_cw = CHAN_WIDTH_80;
                        adjusted_snr = snr + wpas_channel_width_rssi_bump(
                                ies, ies_len, CHAN_WIDTH_80);
-                       tmp = max_he_eht_rate(he80_table, adjusted_snr,
-                                             is_eht) + boost;
+
+                       num_punct_bits = get_eht_num_punct_bits(ies, ies_len);
+                       if (is_eht && num_punct_bits)
+                               tmp = get_eht_punctured_rate(CHAN_WIDTH_80,
+                                                            num_punct_bits,
+                                                            adjusted_snr,
+                                                            boost);
+                       else
+                               tmp = max_he_eht_rate(he80_table, adjusted_snr,
+                                                     is_eht) + boost;
+
                        if (tmp > est)
                                est = tmp;
                }
@@ -3114,13 +3346,21 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
                                *max_cw = CHAN_WIDTH_160;
                        adjusted_snr = snr + wpas_channel_width_rssi_bump(
                                ies, ies_len, CHAN_WIDTH_160);
-                       tmp = max_he_eht_rate(he160_table, adjusted_snr,
-                                             is_eht) + boost;
+
+                       num_punct_bits = get_eht_num_punct_bits(ies, ies_len);
+                       if (is_eht && num_punct_bits)
+                               tmp = get_eht_punctured_rate(CHAN_WIDTH_160,
+                                                            num_punct_bits,
+                                                            adjusted_snr,
+                                                            boost);
+                       else
+                               tmp = max_he_eht_rate(he160_table, adjusted_snr,
+                                                     is_eht) + boost;
                        if (tmp > est)
                                est = tmp;
                }
 
-               if (!is_eht)
+               if (!is_eht || !eht_ie)
                        return est;
 
                eht = (struct ieee80211_eht_capabilities *) &eht_ie[3];
@@ -3133,7 +3373,16 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
                                *max_cw = CHAN_WIDTH_320;
                        adjusted_snr = snr + wpas_channel_width_rssi_bump(
                                ies, ies_len, CHAN_WIDTH_320);
-                       tmp = max_he_eht_rate(eht320_table, adjusted_snr, true);
+
+                       num_punct_bits = get_eht_num_punct_bits(ies, ies_len);
+                       if (num_punct_bits)
+                               tmp = get_eht_punctured_rate(CHAN_WIDTH_320,
+                                                            num_punct_bits,
+                                                            adjusted_snr,
+                                                            0);
+                       else
+                               tmp = max_he_eht_rate(eht320_table, adjusted_snr,
+                                                     true);
                        if (tmp > est)
                                est = tmp;
                }