AIDL: STA: Indicate EHT connection and bandwidth capabilities
Indicate EHT capability of the current connection determined from
association request and response frames to framework. Also, parse EHT
capabilities and operation IEs of association request and response
frames to get bandwidth capability of the current connection and
indicate the same to framework.
Bug: 254955620
Test: Manual - STA connect to AP
Change-Id: I8c4a6925867a3125e971ebace76f0be4f5b3449a
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 52dc8df..d6fd792 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -312,10 +312,14 @@
elems->pasn_params_len = elen;
break;
case WLAN_EID_EXT_EHT_CAPABILITIES:
+ if (elen < EHT_CAPABILITIES_IE_MIN_LEN)
+ break;
elems->eht_capabilities = pos;
elems->eht_capabilities_len = elen;
break;
case WLAN_EID_EXT_EHT_OPERATION:
+ if (elen < EHT_OPERATION_IE_MIN_LEN)
+ break;
elems->eht_operation = pos;
elems->eht_operation_len = elen;
break;
@@ -2851,6 +2855,7 @@
struct supported_chan_width supported_width;
supported_width.is_160_supported = 0;
supported_width.is_80p80_supported = 0;
+ supported_width.is_320_supported = 0;
if (elems == NULL)
return supported_width;
@@ -2858,6 +2863,8 @@
(struct ieee80211_vht_capabilities *) elems->vht_capabilities;
struct ieee80211_he_capabilities *hecaps =
(struct ieee80211_he_capabilities *) elems->he_capabilities;
+ struct ieee80211_eht_capabilities *ehtcaps =
+ (struct ieee80211_eht_capabilities *) elems->eht_capabilities;
if (vhtcaps) {
le32 vht_capabilities_info =
@@ -2875,8 +2882,16 @@
if (channel_width_set & HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
supported_width.is_80p80_supported = 1;
}
- wpa_printf(MSG_DEBUG, " IE indicate 160 supported: %u, 80+80 supported: %u",
- supported_width.is_160_supported, supported_width.is_80p80_supported);
+ if (ehtcaps) {
+ if (ehtcaps->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+ supported_width.is_320_supported = 1;
+ }
+ wpa_printf(MSG_DEBUG,
+ " IE indicates 320 supported: %u, 160 supported: %u, 80+80 supported: %u",
+ supported_width.is_320_supported,
+ supported_width.is_160_supported,
+ supported_width.is_80p80_supported);
return supported_width;
}
@@ -2986,6 +3001,39 @@
return channel_width;
}
+/* Parse EHT operation IE to get EHT operation channel width */
+static enum chan_width get_eht_operation_channel_width(
+ struct ieee80211_eht_operation *eht_oper,
+ int eht_oper_len)
+{
+ enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+ if (!(eht_oper->oper_params & EHT_OPER_INFO_PRESENT) ||
+ eht_oper_len < (EHT_OPERATION_IE_MIN_LEN + EHT_OPER_INFO_MIN_LEN))
+ return channel_width;
+
+ switch (eht_oper->oper_info.control & EHT_OPER_CHANNEL_WIDTH_MASK) {
+ case EHT_OPER_CHANNEL_WIDTH_20MHZ:
+ channel_width = CHAN_WIDTH_20;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_40MHZ:
+ channel_width = CHAN_WIDTH_40;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_80MHZ:
+ channel_width = CHAN_WIDTH_80;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_160MHZ:
+ channel_width = CHAN_WIDTH_160;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_320MHZ:
+ channel_width = CHAN_WIDTH_320;
+ break;
+ default:
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " EHT operation CBW: %u", channel_width);
+ return channel_width;
+}
+
/* Parse HT/VHT/HE operation IEs to get operation channel width */
enum chan_width get_operation_channel_width(struct ieee802_11_elems *elems)
{
@@ -2999,7 +3047,14 @@
(struct ieee80211_vht_operation_info *) elems->vht_operation;
struct ieee80211_he_operation *he_oper =
(struct ieee80211_he_operation *) elems->he_operation;
- if (he_oper)
+ struct ieee80211_eht_operation *eht_oper =
+ (struct ieee80211_eht_operation *) elems->eht_operation;
+
+ if (eht_oper)
+ channel_width = get_eht_operation_channel_width(
+ eht_oper, elems->eht_operation_len);
+
+ if (channel_width == CHAN_WIDTH_UNKNOWN && he_oper)
channel_width = get_he_operation_channel_width(
he_oper, elems->he_operation_len);
@@ -3023,7 +3078,11 @@
enum chan_width ap_operation_chan_width,
struct supported_chan_width sta_supported_chan_width)
{
- if (ap_operation_chan_width == CHAN_WIDTH_160)
+ if (ap_operation_chan_width == CHAN_WIDTH_320 &&
+ sta_supported_chan_width.is_320_supported)
+ return CHAN_WIDTH_320;
+ if (ap_operation_chan_width == CHAN_WIDTH_160 ||
+ ap_operation_chan_width == CHAN_WIDTH_320)
return (sta_supported_chan_width.is_160_supported)
? CHAN_WIDTH_160 : CHAN_WIDTH_80;
if (ap_operation_chan_width == CHAN_WIDTH_80P80)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2e81751..ff31e8d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -351,6 +351,7 @@
struct supported_chan_width {
u8 is_160_supported;
u8 is_80p80_supported;
+ u8 is_320_supported;
};
struct supported_chan_width get_supported_channel_width(struct ieee802_11_elems *elems);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 4345488..ec3b42b 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2446,11 +2446,14 @@
/* IEEE P802.11be/D1.5, 9.4.2.311 - EHT Operation element */
+#define EHT_OPERATION_IE_MIN_LEN 1
+
/* Figure 9-1002b: EHT Operation Parameters field subfields */
#define EHT_OPER_INFO_PRESENT BIT(0)
#define EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
/* Control subfield: Channel Width subfield; see Table 9-401b */
+#define EHT_OPER_CHANNEL_WIDTH_MASK 0x7
#define EHT_OPER_CHANNEL_WIDTH_20MHZ 0
#define EHT_OPER_CHANNEL_WIDTH_40MHZ 1
#define EHT_OPER_CHANNEL_WIDTH_80MHZ 2
@@ -2458,6 +2461,8 @@
#define EHT_OPER_CHANNEL_WIDTH_320MHZ 4
/* Figure 9-1002c: EHT Operation Information field format */
+#define EHT_OPER_INFO_MIN_LEN 3
+
struct ieee80211_eht_oper_info {
u8 control; /* B0..B2: Channel Width */
u8 ccfs0;
@@ -2473,6 +2478,8 @@
/* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */
+#define EHT_CAPABILITIES_IE_MIN_LEN 11
+
/* Figure 9-1002af: EHT MAC Capabilities Information field */
#define EHT_MACCAP_EPCS_PRIO BIT(0)
#define EHT_MACCAP_OM_CONTROL BIT(1)
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index 7a07cc1..6cb310d 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -50,6 +50,7 @@
WIDTH_80P80 = 4,
WIDTH_5 = 5,
WIDTH_10 = 6,
+ WIDTH_320 = 7,
WIDTH_INVALID = -1
};
@@ -1747,7 +1748,9 @@
if (wpa_s->connection_set) {
capa.legacyMode = LegacyMode::UNKNOWN;
- if (wpa_s->connection_he) {
+ if (wpa_s->connection_eht) {
+ capa.technology = WifiTechnology::EHT;
+ } else if (wpa_s->connection_he) {
capa.technology = WifiTechnology::HE;
} else if (wpa_s->connection_vht) {
capa.technology = WifiTechnology::VHT;
@@ -1778,6 +1781,9 @@
case CHAN_WIDTH_80P80:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
break;
+ case CHAN_WIDTH_320:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_320;
+ break;
default:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
break;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 43c9344..aa01245 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3076,7 +3076,8 @@
get_supported_channel_width(&req_elems);
enum chan_width ap_operation_chan_width =
get_operation_channel_width(&resp_elems);
- if (wpa_s->connection_vht || wpa_s->connection_he) {
+ if (wpa_s->connection_vht || wpa_s->connection_he ||
+ wpa_s->connection_eht) {
wpa_s->connection_channel_bandwidth =
get_sta_operation_chan_width(ap_operation_chan_width,
sta_supported_chan_width);