Merge "MLD STA(aidl): Implement getConnectionMloLinksInfo()"
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 3110f43..ec9efff 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);