From patchwork Wed Nov 8 03:58:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kaidong Wang X-Patchwork-Id: 1861390 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=S1Kij0ER; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=Yh+6Cy+/; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SQBDL1G9xz1yQl for ; Wed, 8 Nov 2023 14:59:30 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=Qk0FT9qD4cnXy0sZoy13oIi4G9Kzavkb+lTe6QevNxM=; b=S1Kij0ERRi7CZm ySUbLkCHxeOhA8L3+tQdgBtOA6KQQo6PnWK9s5j2Dq4+Sjg79lcYlD5Rc4sa53btD2Gg4lMDqT4U3 aBlD4lQcPXR6hftVIa4FDvKOgciiEatCWnC14MknyigWP7vNTYx7rbotrylJsk9yKo4XBSDfHTKre yr/zBYT9y0USA/APkpoRfI2PRuobukMlQXPVLjWH2mWyi0hloxA9dAUX+oB75zVjy4Ad68k8rkNs9 DAfnC1J3C8lMSsE0YTbLBSHHL6wmJqDuRn12nltuiEnhiQzQIEp1i5ebiw2vh0lmZieTHdHtKBR6V 0+fHAOMfSKubXeHSP+NA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1r0Zhu-002tjW-2R; Wed, 08 Nov 2023 03:58:22 +0000 Received: from mail-pg1-x531.google.com ([2607:f8b0:4864:20::531]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1r0Zhq-002ti0-0b for hostap@lists.infradead.org; Wed, 08 Nov 2023 03:58:20 +0000 Received: by mail-pg1-x531.google.com with SMTP id 41be03b00d2f7-5aa7172bafdso4359014a12.1 for ; Tue, 07 Nov 2023 19:58:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1699415892; x=1700020692; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=Gd0jOt73FAOCpoFBvjnIPC7+c2xZm6PrcW6fqGnSi4o=; b=Yh+6Cy+/cGXKmBksgz99eAXtxqJagsyyVBVV4phpKVx80Tri3DOsqYlS78mskumqqc 5dZrXqKMaIctYCcOfb6K6eU7Lf1KMi9VKFaPvKQzYP1E/o6tPJzQYv1j/+T3+ks4jk0y FX+kEJsYXZMc5fbWFponeRLXaB63Foc9apbDQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699415892; x=1700020692; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Gd0jOt73FAOCpoFBvjnIPC7+c2xZm6PrcW6fqGnSi4o=; b=IAS4u5uxr2ARjyDndAsUhgngwkHwxK5f2RuxvbLYAb5UXDXVLEPUB6FrdEtAcgFu9k pHwewm+PuT7SAqPJABkWe0PP/OjWC9lbAYNCaktGyTVylESX8xYLa6z7RIJ5ClKq7RZ+ KWSE6tnln0/y/xpA2nYk9vwnxRRI2FoyMwz/LYuszGBG1GsB2kFzg9Jg6NL9bbZq1WNz 12CVQtd89nmBopw4uxyjljyy/bh+5FNGGoevCdVO8VR0/99gJUUU6RE3Xwiz6JgGX7AE /j68vyQvzJn7TxeI/RZj29Dq2dFaCbKtZ62vWgTExmRgfhzR4nHYA7pcWEq8iQ6xrqog bzuw== X-Gm-Message-State: AOJu0YysR9VLQaVJv8FWVIM1zZXxMByjFmUd2cLXFOpzye/eySyiV8NG JVnxGzPSoF+g2Fd5kcmXPZabLdeo6AmrgoVxaZg= X-Google-Smtp-Source: AGHT+IGu09zRH51X5oqSk7Z8+Exqf+aiclKznrw6bYaiUpd1lOPRLcIlJhPjzoEorff+WgIyb2Aq2g== X-Received: by 2002:a17:90b:384c:b0:280:8544:42fb with SMTP id nl12-20020a17090b384c00b00280854442fbmr715254pjb.17.1699415891917; Tue, 07 Nov 2023 19:58:11 -0800 (PST) Received: from kaidong.c.googlers.com.com (240.111.247.35.bc.googleusercontent.com. [35.247.111.240]) by smtp.gmail.com with ESMTPSA id lr16-20020a17090b4b9000b0027d219d3ac6sm549707pjb.47.2023.11.07.19.58.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Nov 2023 19:58:11 -0800 (PST) From: Kaidong Wang To: hostap@lists.infradead.org Cc: Kaidong Wang Subject: [PATCH v2 1/2] Adjust the SNR when comparing BSSes based on Tx power config Date: Wed, 8 Nov 2023 03:58:05 +0000 Message-ID: <983686ffd91cf958eae0229e24065ea507d67043.1699415021.git.kaidong@chromium.org> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231107_195818_257827_B28B2111 X-CRM114-Status: GOOD ( 26.30 ) X-Spam-Score: -0.4 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The max transmit power of Standard Power (SP) Access Points (AP) on 6 GHz band and APs on 2.4 GHz and 5 GHz bands is limited by effective isotropic radiated power (EIRP), while the max transmit power [...] Content analysis details: (-0.4 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:531 listed in] [list.dnswl.org] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.2 DKIMWL_WL_HIGH DKIMwl.org - High trust sender X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The max transmit power of Standard Power (SP) Access Points (AP) on 6 GHz band and APs on 2.4 GHz and 5 GHz bands is limited by effective isotropic radiated power (EIRP), while the max transmit power of Low Power Indoor (LPI) APs on 6 GHz Band is limited by power spectral density (PSD). Therefore the max transmit power of LPI APs grows as the channel width increases, similar to the noise power which has constant PSD. Adjust the SNR of BSSes based on the transmit power config and max channel width. EIRP limited APs usually have constant max transmit power on different channel widths, their SNR decreases on larger channel width because the noise power is higher, while PSD limited APs have constant SNR over all channel widths. Signed-off-by: Kaidong Wang --- src/drivers/driver.h | 3 + wpa_supplicant/bss.c | 1 + wpa_supplicant/bss.h | 2 + wpa_supplicant/events.c | 4 +- wpa_supplicant/scan.c | 188 +++++++++++++++++++++++++++++++++++++--- wpa_supplicant/scan.h | 14 ++- 6 files changed, 200 insertions(+), 12 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 24016b344..b56512796 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -334,6 +334,8 @@ struct hostapd_hw_modes { * @flags: information flags about the BSS/IBSS (WPA_SCAN_*) * @bssid: BSSID * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) + * @max_cw: the max channel width of the connection (calculated during scan + * result processing) * @beacon_int: beacon interval in TUs (host byte order) * @caps: capability information field in host byte order * @qual: signal quality @@ -370,6 +372,7 @@ struct wpa_scan_res { unsigned int flags; u8 bssid[ETH_ALEN]; int freq; + enum chan_width max_cw; u16 beacon_int; u16 caps; int qual; diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 2ad74f3a4..cdc86c23f 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -296,6 +296,7 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); dst->freq = src->freq; + dst->max_cw = src->max_cw; dst->beacon_int = src->beacon_int; dst->caps = src->caps; dst->qual = src->qual; diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 39dad868e..ef4a20c44 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -96,6 +96,8 @@ struct wpa_bss { size_t ssid_len; /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */ int freq; + /** the max channel width supported by both the AP and the STA */ + enum chan_width max_cw; /** Beacon interval in TUs (host byte order) */ u16 beacon_int; /** Capability information field in host byte order */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 1f186eb67..273f73d41 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2092,8 +2092,10 @@ wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s, int rate = wpa_bss_get_max_rate(bss); const u8 *ies = wpa_bss_ie_ptr(bss); size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + enum chan_width max_cw = CHAN_WIDTH_UNKNOWN; - return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, bss->freq); + return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, bss->freq, + &max_cw); } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 5c5c399e9..9b8d1111c 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -2212,6 +2212,140 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, return buf; } +int wpas_channel_width_offset(enum chan_width cw) +{ + switch (cw) { + case CHAN_WIDTH_40: + return 1; + case CHAN_WIDTH_80: + return 2; + case CHAN_WIDTH_80P80: + case CHAN_WIDTH_160: + return 3; + case CHAN_WIDTH_320: + return 4; + default: + return 0; + } +} + +/** + * wpas_channel_width_tx_pwr - Calculate the max transmit power at the channel + * width + * @ies: Information elements + * @ies_len: Length of IEs + * @cw: the channel width + * Returns: the max transmit power at the channel width, TX_POWER_NO_CONSTRAINT + * if it is not constrained. + * + * This function is only used to estimate the actual signal RSSI when associated + * based on the beacon RSSI at the STA. Beacons are transmitted on 20 MHz + * channels, while the data frames usually use higher channel width. Therefore + * their RSSIs may be different. Assuming there is a fixed gap between the tx + * power limit of the STA defined by the transmit power envelope IE and the tx + * power of the AP, the difference in the tx power of X MHz and Y MHz at the STA + * equals to the difference at the AP, and the difference in the signal RSSI at + * the STA. tx_pwr is a floating point number in the spec, but the error of + * casting to int is trivial in comparing two BSSes. + */ +static int wpas_channel_width_tx_pwr(const u8 *ies, + size_t ies_len, + enum chan_width cw) +{ +#define MIN(a, b) (a < b ? a : b) + int offset = wpas_channel_width_offset(cw); + const struct element *elem; + int max_tx_power = TX_POWER_NO_CONSTRAINT, tx_pwr = 0; + + for_each_element_id(elem, WLAN_EID_TRANSMIT_POWER_ENVELOPE, ies, + ies_len) { + /* + * 80211ax-2021 9.4.2.161 Transmit Power Envelope element + * defines Maximum Transmit Power Count (B0-B2), Maximum + * Transmit Power Interpretation (B3-B5) and Maximum Transmit + * Power Category (B6-B7). + */ + int max_tx_pwr_count = elem->data[0] & 0x07; + enum max_tx_pwr_interpretation tx_pwr_intrpn = + (elem->data[0] >> 3) & 0x07; + enum reg_6g_client_type client_type = + (elem->data[0] >> 6) & 0x03; + if (client_type != REG_DEFAULT_CLIENT) + continue; + if (tx_pwr_intrpn == LOCAL_EIRP || + tx_pwr_intrpn == REGULATORY_CLIENT_EIRP) { + max_tx_pwr_count = MIN(max_tx_pwr_count, 3); + tx_pwr = (signed char)elem->data[MIN(offset, + max_tx_pwr_count) + 1]; + /* + * Maximum Transmit Power subfield is encoded as an + * 8-bit 2s complement signed integer in the range -64 + * dBm to 63 dBm with a 0.5 dB step. 63.5 dBm means no + * local maximum transmit power constraint. + */ + if (tx_pwr == 127) + continue; + tx_pwr /= 2; + max_tx_power = MIN(max_tx_power, tx_pwr); + } else if (tx_pwr_intrpn == LOCAL_EIRP_PSD || + tx_pwr_intrpn == REGULATORY_CLIENT_EIRP_PSD) { + tx_pwr = (signed char)elem->data[1]; + /* + * Maximum Transmit PSD subfield is encoded as an 8-bit + * 2s complement signed integer. -128 indicates that the + * corresponding 20 MHz channel cannot be used for + * transmission. +127 indicates that no maximum PSD + * limit is specified for the corresponding 20 MHz + * channel. + */ + if (tx_pwr == 127 || tx_pwr == -128) + continue; + /* + * The Maximum Transmit PSD subfield indicates the + * maximum transmit PSD for the 20 MHz channel. Suppose + * the PSD value is X dBm/MHz, the tx power of N MHz is + * X + 10*log10(N) = X + 10*log10(20) + 10*log10(N/20) = + * X + 13 + 3*log2(N/20) + */ + tx_pwr = tx_pwr / 2 + 13 + offset * 3; + max_tx_power = MIN(max_tx_power, tx_pwr); + } + } + return max_tx_power; +#undef MIN +} + +/** + * Estimate the RSSI bump of channel width |cw| with respect to 20 MHz channel. + * If the tx power has no constraint, it is unable to estimate the RSSI bump. + */ +int wpas_channel_width_rssi_bump(const u8 *ies, size_t ies_len, + enum chan_width cw) +{ + int max_20mhz_tx_pwr = wpas_channel_width_tx_pwr(ies, ies_len, + CHAN_WIDTH_20); + int max_cw_tx_pwr = wpas_channel_width_tx_pwr(ies, ies_len, cw); + + return (max_20mhz_tx_pwr == TX_POWER_NO_CONSTRAINT || + max_cw_tx_pwr == TX_POWER_NO_CONSTRAINT) + ? 0 : (max_cw_tx_pwr - max_20mhz_tx_pwr); +} + +int wpas_adjust_snr_by_chanwidth(const u8 *ies, size_t ies_len, + enum chan_width max_cw, int snr) +{ + int rssi_bump = wpas_channel_width_rssi_bump(ies, ies_len, max_cw); + /* + * The noise has uniform power spectral density (PSD) across the + * frequency band, its power is proportional to the channel width. + * Suppose the PSD of noise is X dBm/MHz, the noise power of N MHz is + * X + 10*log10(N), and the noise power bump with respect to 20 MHz is + * 10*log10(N) - 10*log10(20) = 10*log10(N/20) = 3*log2(N/20) + */ + int noise_bump = 3 * wpas_channel_width_offset(max_cw); + + return snr + rssi_bump - noise_bump; +} /* Compare function for sorting scan results. Return >0 if @b is considered * better. */ @@ -2224,6 +2358,7 @@ static int wpa_scan_result_compar(const void *a, const void *b) struct wpa_scan_res *wb = *_wb; int wpa_a, wpa_b; int snr_a, snr_b, snr_a_full, snr_b_full; + size_t ies_len; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || @@ -2245,10 +2380,21 @@ static int wpa_scan_result_compar(const void *a, const void *b) return -1; if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) { - snr_a_full = wa->snr; - snr_a = MIN(wa->snr, GREAT_SNR); - snr_b_full = wb->snr; - snr_b = MIN(wb->snr, GREAT_SNR); + /* + * The scan result estimates SNR over 20 MHz, while data frames + * usually use wider channel width. The tx power and noise power + * are both affected by the channel width. + */ + ies_len = wa->ie_len ? wa->ie_len : wa->beacon_ie_len; + snr_a_full = wpas_adjust_snr_by_chanwidth((const u8 *)(wa + 1), + ies_len, wa->max_cw, + wa->snr); + snr_a = MIN(snr_a_full, GREAT_SNR); + ies_len = wb->ie_len ? wb->ie_len : wb->beacon_ie_len; + snr_b_full = wpas_adjust_snr_by_chanwidth((const u8 *)(wb + 1), + ies_len, wb->max_cw, + wb->snr); + snr_b = MIN(snr_b_full, GREAT_SNR); } else { /* Level is not in dBm, so we can't calculate * SNR. Just use raw level (units unknown). */ @@ -2698,10 +2844,9 @@ static unsigned int max_he_eht_rate(const struct minsnr_bitrate_entry table[], prev->bitrate, entry->bitrate); } - 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) + int snr, int freq, enum chan_width *max_cw) { struct hostapd_hw_modes *hw_mode; unsigned int est, tmp; @@ -2754,6 +2899,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (hw_mode && hw_mode->ht_capab) { ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP); if (ie) { + *max_cw = CHAN_WIDTH_20; tmp = max_ht20_rate(snr, false); if (tmp > est) est = tmp; @@ -2765,6 +2911,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); if (ie && ie[1] >= 2 && (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { + *max_cw = CHAN_WIDTH_40; tmp = max_ht40_rate(snr, false); if (tmp > est) est = tmp; @@ -2776,7 +2923,8 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP); if (ie) { bool vht80 = false, vht160 = false; - + if (*max_cw == CHAN_WIDTH_UNKNOWN) + *max_cw = CHAN_WIDTH_20; tmp = max_ht20_rate(snr, true) + 1; if (tmp > est) est = tmp; @@ -2785,6 +2933,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (ie && ie[1] >= 2 && (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { + *max_cw = CHAN_WIDTH_40; tmp = max_ht40_rate(snr, true) + 1; if (tmp > est) est = tmp; @@ -2811,6 +2960,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, } if (vht80) { + *max_cw = CHAN_WIDTH_80; tmp = max_vht80_rate(snr) + 1; if (tmp > est) est = tmp; @@ -2820,6 +2970,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, (hw_mode->vht_capab & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { + *max_cw = CHAN_WIDTH_160; tmp = max_vht160_rate(snr) + 1; if (tmp > est) est = tmp; @@ -2852,7 +3003,8 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, boost = 3; } } - + if (*max_cw == CHAN_WIDTH_UNKNOWN) + *max_cw = CHAN_WIDTH_20; tmp = max_he_eht_rate(he20_table, snr, is_eht) + boost; if (tmp > est) est = tmp; @@ -2862,6 +3014,10 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (cw & (IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G : HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_40) { + *max_cw = CHAN_WIDTH_40; + } tmp = max_he_eht_rate(he40_table, snr, is_eht) + boost; if (tmp > est) est = tmp; @@ -2869,6 +3025,10 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (!IS_2P4GHZ(freq) && (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_80) { + *max_cw = CHAN_WIDTH_80; + } tmp = max_he_eht_rate(he80_table, snr, is_eht) + boost; if (tmp > est) est = tmp; @@ -2877,6 +3037,10 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (!IS_2P4GHZ(freq) && (cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_160) { + *max_cw = CHAN_WIDTH_160; + } tmp = max_he_eht_rate(he160_table, snr, is_eht) + boost; if (tmp > est) est = tmp; @@ -2890,6 +3054,10 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (is_6ghz_freq(freq) && (eht->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_320) { + *max_cw = CHAN_WIDTH_320; + } tmp = max_he_eht_rate(eht320_table, snr, true); if (tmp > est) est = tmp; @@ -2916,8 +3084,8 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, if (!ie_len) ie_len = res->beacon_ie_len; - res->est_throughput = - wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, res->freq); + res->est_throughput = wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, + res->freq, &res->max_cw); /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ } diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index b5ed7842f..a5e33740c 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -30,6 +30,13 @@ */ #define GREAT_SNR 25 +/* + * IEEE 80211ax-2021 9.4.2.161 Transmit Power Envelope element indicates no max + * tx power limit if Maximum Transmit Power field is 63.5 dBm. + * The default tx power if it is not constrained by Transmit Power Envelope IE + */ +#define TX_POWER_NO_CONSTRAINT 64 + #define IS_2P4GHZ(n) (n >= 2412 && n <= 2484) #define IS_5GHZ(n) (n > 4000 && n < 5895) @@ -88,12 +95,17 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res); 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); + int snr, int freq, enum chan_width *max_cw); void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s); int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s, enum hostapd_hw_mode band, struct wpa_driver_scan_params *params, bool is_6ghz, bool only_6ghz_psc, bool exclude_radar); +int wpas_channel_width_offset(enum chan_width cw); +int wpas_channel_width_rssi_bump(const u8 *ies, size_t ies_len, + enum chan_width cw); +int wpas_adjust_snr_by_chanwidth(const u8 *ies, size_t ies_len, + enum chan_width max_cw, int snr); #endif /* SCAN_H */