Index: hostapd-2022-07-29-b704dc72/hostapd/Makefile
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/hostapd/Makefile
+++ hostapd-2022-07-29-b704dc72/hostapd/Makefile
@@ -324,6 +324,10 @@ NEED_HMAC_SHA512_KDF=y
 NEED_SHA384=y
 NEED_SHA512=y
 endif
+CFLAGS += -DCONFIG_MTK_IEEE80211BE
+OBJS += ../src/ml/ml_common.o
+OBJS += ../src/drivers/mediatek_driver_cmd_nl80211.o
+CFLAGS += -DHOSTAPD_PMKID_IN_DRIVER_SUPPORT
 
 ifdef CONFIG_AIRTIME_POLICY
 CFLAGS += -DCONFIG_AIRTIME_POLICY
Index: hostapd-2022-07-29-b704dc72/hostapd/ctrl_iface.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/hostapd/ctrl_iface.c
+++ hostapd-2022-07-29-b704dc72/hostapd/ctrl_iface.c
@@ -69,6 +69,10 @@
 #include "ctrl_iface.h"
 #include "config_file.h"
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "ap/wpa_auth_i.h"
+#endif
 
 #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
 
@@ -2396,7 +2400,7 @@ static int hostapd_ctrl_rekey_ptk(struct
 
 	return wpa_auth_rekey_ptk(hapd->wpa_auth, sta->wpa_sm);
 }
-
+#endif
 
 static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
 				      char *buf, size_t buflen)
@@ -2419,9 +2423,52 @@ static int hostapd_ctrl_get_pmk(struct h
 	const u8 *pmk;
 	int pmk_len;
 
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_MTK_IEEE80211BE
+	struct wpa_ml_group *ml_group = hapd->ml_group;
+#endif
+#endif
+
 	if (hwaddr_aton(cmd, addr))
 		return -1;
 
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_MTK_IEEE80211BE
+	/* check the input sta addr is sta mld addr? */
+	if (ml_group) {
+		u8 i = 0;
+		u8 find_mld_sta = 0;
+		struct wpa_ml_link *link;
+		struct sta_info *sta = NULL;
+
+		for (i = 0; i < ml_group->ml_link_num; i++) {
+			link = &ml_group->links[i];
+			if (link) {
+				for (sta = ((struct hostapd_data *)link->ctx)->sta_list; sta; sta = sta->next) {
+					if (sta->wpa_sm)
+						if (sta->wpa_sm->sta_ml_ie) { /*find mld STA, so it is the assoc link */
+							wpa_printf(MSG_DEBUG, "ML: find mld sta ");
+							if (os_memcmp(addr, sta->wpa_sm->sta_ml_ie->ml_addr, ETH_ALEN) == 0) {
+								find_mld_sta = 1;
+								wpa_printf(MSG_DEBUG, "ML: the input sta addr is sta mld addr ");
+								goto GET_MLD_PMK;
+							}
+							wpa_printf(MSG_DEBUG, "ML: it is the set up link ");
+						}
+				}
+			}
+		}
+GET_MLD_PMK:
+		if (find_mld_sta) {
+			hapd = (struct hostapd_data *)link->ctx; /*it is set up link*/
+			os_memcpy(addr, sta->wpa_sm->addr, ETH_ALEN);
+			wpa_printf(MSG_DEBUG, "ML:the infact set up link addr " MACSTR,
+			   MAC2STR(addr));
+		}
+	}
+#endif
+#endif
+
 	sta = ap_get_sta(hapd, addr);
 	if (!sta || !sta->wpa_sm) {
 		wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
@@ -2438,7 +2485,7 @@ static int hostapd_ctrl_get_pmk(struct h
 	return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
 }
 
-
+#ifdef CONFIG_TESTING_OPTIONS
 static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
 				       const char *cmd)
 {
Index: hostapd-2022-07-29-b704dc72/src/ap/drv_callbacks.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/drv_callbacks.c
+++ hostapd-2022-07-29-b704dc72/src/ap/drv_callbacks.c
@@ -43,6 +43,11 @@
 #include "fils_hlp.h"
 #include "neighbor_db.h"
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "wpa_auth_i.h"
+#include "ml/ml_common.h"
+#endif
+
 
 #ifdef CONFIG_FILS
 void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
@@ -543,7 +548,11 @@ skip_wpa_check:
 #ifdef CONFIG_IEEE80211R_AP
 	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
 					sta->auth_alg, req_ies, req_ies_len,
-					!elems.rsnxe);
+					!elems.rsnxe
+#ifdef CONFIG_MTK_IEEE80211BE
+					, hapd
+#endif
+					);
 	if (!p) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -720,6 +729,10 @@ skip_wpa_check:
 	else
 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	ml_new_assoc_sta(sta->wpa_sm, elems.ml, elems.ml_len);
+#endif
+
 	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
 
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
@@ -1314,7 +1327,11 @@ static void hostapd_notif_auth(struct ho
 		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
 				    rx_auth->auth_transaction, rx_auth->ies,
 				    rx_auth->ies_len,
-				    hostapd_notify_auth_ft_finish, hapd);
+				    hostapd_notify_auth_ft_finish, hapd
+#ifdef CONFIG_MTK_IEEE80211BE
+					, hapd->ml_group->ml_addr
+#endif
+					);
 		return;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
@@ -1881,6 +1898,12 @@ err:
 }
 #endif /* CONFIG_OWE */
 
+static int hostapd_event_bss_ml_info(struct hostapd_data *hapd,
+		u8 mld_grp_idx, u8 link_id, u8 *mld_addr)
+{
+	wpa_printf(MSG_DEBUG, "hostapd_event_bss_mlo_info, mld_grp_idx=%d, link_id=%d\n", mld_grp_idx, link_id);
+	ml_group_init(hapd, mld_grp_idx, link_id, mld_addr);
+}
 
 void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
 		       union wpa_event_data *data)
@@ -2122,6 +2145,11 @@ void hostapd_wpa_event(void *ctx, enum w
 			data->wds_sta_interface.ifname,
 			data->wds_sta_interface.sta_addr);
 		break;
+	case EVENT_UPDATE_BSS_ML_INFO:
+		hostapd_event_bss_ml_info(hapd,
+			data->ml_info_event.mld_grp_idx,
+			data->ml_info_event.link_id, data->ml_info_event.addr);
+		break;
 #ifdef CONFIG_IEEE80211AX
 	case EVENT_BSS_COLOR_COLLISION:
 		/* The BSS color is shared amongst all BBSs on a specific phy.
Index: hostapd-2022-07-29-b704dc72/src/ap/hostapd.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/hostapd.c
+++ hostapd-2022-07-29-b704dc72/src/ap/hostapd.c
@@ -56,6 +56,9 @@
 #include "airtime_policy.h"
 #include "wpa_auth_kay.h"
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#endif
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
 #ifdef CONFIG_WEP
@@ -472,6 +475,9 @@ void hostapd_free_hapd_data(struct hosta
 	hostapd_ubus_free_bss(hapd);
 	accounting_deinit(hapd);
 	hostapd_deinit_wpa(hapd);
+#ifdef CONFIG_MTK_IEEE80211BE
+	ml_group_deinit(hapd);
+#endif
 	vlan_deinit(hapd);
 	hostapd_acl_deinit(hapd);
 #ifndef CONFIG_NO_RADIUS
@@ -2959,7 +2965,7 @@ int hostapd_disable_iface(struct hostapd
 }
 
 
-static struct hostapd_iface *
+struct hostapd_iface *
 hostapd_iface_alloc(struct hapd_interfaces *interfaces)
 {
 	struct hostapd_iface **iface, *hapd_iface;
Index: hostapd-2022-07-29-b704dc72/src/ap/hostapd.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/hostapd.h
+++ hostapd-2022-07-29-b704dc72/src/ap/hostapd.h
@@ -256,6 +256,10 @@ struct hostapd_data {
 
 	struct l2_packet_data *l2;
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	struct wpa_ml_group *ml_group;
+#endif
+
 #ifdef CONFIG_IEEE80211R_AP
 	struct dl_list l2_queue;
 	struct dl_list l2_oui_queue;
@@ -478,6 +482,8 @@ struct hostapd_data {
 #ifdef CONFIG_CTRL_IFACE_UDP
        unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
 #endif /* CONFIG_CTRL_IFACE_UDP */
+
+		struct per_sta_profile profiles[ML_MAX_LINK_NUM];
 };
 
 
@@ -694,6 +700,7 @@ int hostapd_disable_iface(struct hostapd
 void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
 void hostapd_free_hapd_data(struct hostapd_data *hapd);
 void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
+struct hostapd_iface *hostapd_iface_alloc(struct hapd_interfaces *interfaces);
 int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
 int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
 void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
Index: hostapd-2022-07-29-b704dc72/src/ap/ieee802_11.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/ieee802_11.c
+++ hostapd-2022-07-29-b704dc72/src/ap/ieee802_11.c
@@ -56,6 +56,14 @@
 #include "dpp_hostapd.h"
 #include "gas_query_ap.h"
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "netlink/genl/genl.h"
+#include "mtk_vendor_nl80211.h"
+#include "../drivers/nl80211_copy.h"
+#include "../drivers/driver_nl80211.h"
+#endif
+#include "wpa_auth_i.h"
 
 #ifdef CONFIG_FILS
 static struct wpabuf *
@@ -551,13 +559,24 @@ static struct wpabuf * auth_build_sae_co
 	int use_pt = 0;
 	struct sae_pt *pt = NULL;
 	const struct sae_pk *pk = NULL;
+	const u8 *own_addr = hapd->own_addr;
+	const u8 *peer_addr = sta->addr;
+	u8 ext_len = 0;
+
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sta->sae->dot11MultiLinkActivated && hapd->ml_group) {/*check own ml capability*/
+		own_addr = hapd->ml_group->ml_addr;
+		peer_addr = sta->sae->peer_ml_ie->ml_addr;
+		ext_len = 12;
+	}
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	if (sta->sae->tmp) {
 		rx_id = sta->sae->tmp->pw_id;
 		use_pt = sta->sae->h2e;
 #ifdef CONFIG_SAE_PK
-		os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
-		os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
+		os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN);
+		os_memcpy(sta->sae->tmp->peer_addr, peer_addr, ETH_ALEN);
 #endif /* CONFIG_SAE_PK */
 	}
 
@@ -576,12 +595,12 @@ static struct wpabuf * auth_build_sae_co
 	}
 
 	if (update && use_pt &&
-	    sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+	    sae_prepare_commit_pt(sta->sae, pt, own_addr, peer_addr,
 				  NULL, pk) < 0)
 		return NULL;
 
 	if (update && !use_pt &&
-	    sae_prepare_commit(hapd->own_addr, sta->addr,
+	    sae_prepare_commit(own_addr, peer_addr,
 			       (u8 *) password, os_strlen(password),
 			       sta->sae) < 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
@@ -597,7 +616,7 @@ static struct wpabuf * auth_build_sae_co
 		sta->sae->tmp->vlan_id = pw->vlan_id;
 	}
 
-	buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
+	buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN + ext_len +
 			   (rx_id ? 3 + os_strlen(rx_id) : 0));
 	if (buf &&
 	    sae_write_commit(sta->sae, buf, sta->sae->tmp ?
@@ -607,6 +626,14 @@ static struct wpabuf * auth_build_sae_co
 		buf = NULL;
 	}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (buf &&
+		ml_sae_write_auth(hapd, sta->sae, buf) < 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+#endif
+
 	return buf;
 }
 
@@ -615,8 +642,14 @@ static struct wpabuf * auth_build_sae_co
 					      struct sta_info *sta)
 {
 	struct wpabuf *buf;
+	u8 ext_len = 0;
+
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sta->sae->dot11MultiLinkActivated && hapd->ml_group)
+		ext_len = 16;
+#endif /* CONFIG_MTK_IEEE80211BE */
 
-	buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
+	buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN + ext_len);
 	if (buf == NULL)
 		return NULL;
 
@@ -632,6 +665,14 @@ static struct wpabuf * auth_build_sae_co
 		return NULL;
 	}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (buf &&
+		ml_sae_write_auth(hapd, sta->sae, buf) < 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+#endif
+
 	return buf;
 }
 
@@ -944,6 +985,9 @@ static void sae_sme_send_external_auth_s
 
 void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
+	const u8* spa = sta->addr;
+	const u8* aa = hapd->wpa_auth->addr;
+
 #ifndef CONFIG_NO_VLAN
 	struct vlan_description vlan_desc;
 
@@ -981,10 +1025,24 @@ void sae_accept_sta(struct hostapd_data
 	crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
 	sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
 	sta->sae->peer_commit_scalar = NULL;
-	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (sta->sae->dot11MultiLinkActivated) {
+			wpa_printf(MSG_DEBUG,
+				   "ML: SAE confirmed SPA[" MACSTR "] AA["MACSTR"]",
+				   MAC2STR(sta->sae->peer_ml_addr),
+				   MAC2STR(sta->sae->own_ml_addr));
+			spa = sta->sae->peer_ml_addr;
+			aa = sta->sae->own_ml_addr;
+		}
+#endif /* CONFIG_MTK_IEEE80211BE */
+
+#ifndef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+		/*set PMKID in driver before sending Auth Confirm,else Assoc req rcv before pmkid is set  */
+	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr, aa,
 			       sta->sae->pmk, sta->sae->pmk_len,
 			       sta->sae->pmkid, sta->sae->akmp);
 	sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 }
 
 
@@ -1142,7 +1200,7 @@ static int sae_sm_step(struct hostapd_da
 			wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
 				   ") doing reauthentication",
 				   MAC2STR(sta->addr));
-			wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+			wpa_auth_pmksa_remove(hapd->wpa_auth, ml_auth_spa(sta->wpa_sm, sta->addr));
 			ap_free_sta(hapd, sta);
 			*sta_removed = 1;
 		} else if (auth_transaction == 1) {
@@ -1300,6 +1358,42 @@ static int check_sae_rejected_groups(str
 	return 0;
 }
 
+#ifdef CONFIG_MTK_IEEE80211BE
+static int nl80211_set_mlo_ie(struct wpa_driver_nl80211_data *drv,
+					struct wpa_ml_ie_parse *peer_ml_ie)
+{
+	struct nl_msg *msg = NULL;
+	struct nlattr *attr;
+	int ret;
+
+	wpa_printf(MSG_INFO, "nl80211_set_mlo_ie");
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+			nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
+			nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_SET_MLO_IE))
+			goto fail;
+
+	attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+	if (!attr)
+		goto fail;
+
+	if (nla_put(msg, MTK_NL80211_VENDOR_ATTR_SET_AUTH_MLO_IE, sizeof(struct wpa_mlo_ie_parse),
+				(void *)peer_ml_ie))
+		goto fail;
+
+	nla_nest_end(msg, attr);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: mlo ie vendor command failed err=%d",
+				  ret);
+	return ret;
+
+	fail:
+		nlmsg_free(msg);
+		return ret;
+}
+#endif
 
 static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 			    const struct ieee80211_mgmt *mgmt, size_t len,
@@ -1312,6 +1406,8 @@ static void handle_auth_sae(struct hosta
 	const u8 *pos, *end;
 	int sta_removed = 0;
 	bool success_status;
+	const u8* spa = sta->addr;
+	const u8* aa = hapd->wpa_auth->addr;
 
 	if (!groups)
 		groups = default_groups;
@@ -1353,12 +1449,20 @@ static void handle_auth_sae(struct hosta
 		}
 		sae_set_state(sta, SAE_NOTHING, "Init");
 		sta->sae->sync = 0;
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (hapd->ml_group) {
+			os_memcpy(sta->sae->own_ml_addr,
+				hapd->ml_group->ml_addr, ETH_ALEN);
+			wpa_printf(MSG_DEBUG, "ML: SAE init own ml addr "MACSTR"",
+				   MAC2STR(sta->sae->own_ml_addr));
+		}
+#endif
 	}
 
 	if (sta->mesh_sae_pmksa_caching) {
 		wpa_printf(MSG_DEBUG,
 			   "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
-		wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+		wpa_auth_pmksa_remove(hapd->wpa_auth, ml_auth_spa(sta->wpa_sm, sta->addr));
 		sta->mesh_sae_pmksa_caching = 0;
 	}
 
@@ -1524,6 +1628,18 @@ static void handle_auth_sae(struct hosta
 			goto reply;
 		}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (sta->sae->peer_ml_ie && hapd->ml_group) {
+			struct i802_bss *bss = hapd->drv_priv;
+			struct wpa_driver_nl80211_data *drv = bss->drv;
+
+			nl80211_set_mlo_ie(drv, sta->sae->peer_ml_ie);
+			wpa_printf(MSG_DEBUG,
+				   "SAE: send auth mlo ie to driver "
+				   MACSTR, MAC2STR(sta->addr));
+		}
+#endif
+
 		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
 				   status_code, allow_reuse, &sta_removed);
 	} else if (auth_transaction == 2) {
@@ -1566,6 +1682,24 @@ static void handle_auth_sae(struct hosta
 			}
 			sta->sae->rc = peer_send_confirm;
 		}
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (sta->sae->dot11MultiLinkActivated) {
+			wpa_printf(MSG_DEBUG,
+				   "ML: SAE confirmed SPA[" MACSTR "] AA["MACSTR"]",
+				   MAC2STR(sta->sae->peer_ml_addr),
+				   MAC2STR(sta->sae->own_ml_addr));
+			spa = sta->sae->peer_ml_addr;
+			aa = sta->sae->own_ml_addr;
+		}
+#endif /* CONFIG_MTK_IEEE80211BE */
+		wpa_printf(MSG_DEBUG, "(%s)[%d]ML: SAE SPA[" MACSTR "] AA["MACSTR"]",
+				   __func__, __LINE__, MAC2STR(spa), MAC2STR(aa));
+		/*set PMKID in driver before sending Auth Confirm,else Assoc_Req rcv before pmkid is set  */
+		wpa_auth_pmksa_add_sae(hapd->wpa_auth,
+					spa, aa, sta->sae->pmk, sta->sae->pmk_len,
+					sta->sae->pmkid, sta->sae->akmp);
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
 				   status_code, 0, &sta_removed);
 	} else {
@@ -1588,7 +1722,6 @@ reply:
 		 * rejected it as unsupported group. */
 		if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
 		    !data && end - pos >= 2)
-			data = wpabuf_alloc_copy(pos, 2);
 
 		sae_sme_send_external_auth_status(hapd, sta, resp);
 		send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
@@ -2518,7 +2651,9 @@ static int pasn_wd_handle_sae_confirm(st
 	 * PASN/SAE should only be allowed with future PASN only. For now do not
 	 * restrict this only for PASN.
 	 */
-	wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+	wpa_auth_pmksa_add_sae(hapd->wpa_auth,
+			       ml_auth_spa(sta->wpa_sm, sta->addr),
+			       ml_auth_aa(sta->wpa_sm, hapd->wpa_auth->addr),
 			       pasn->sae.pmk, pasn->sae.pmk_len,
 			       pasn->sae.pmkid, pasn->sae.akmp);
 	return 0;
@@ -3922,7 +4057,11 @@ static void handle_auth(struct hostapd_d
 				    auth_transaction, mgmt->u.auth.variable,
 				    len - IEEE80211_HDRLEN -
 				    sizeof(mgmt->u.auth),
-				    handle_auth_ft_finish, hapd);
+				    handle_auth_ft_finish, hapd
+#ifdef CONFIG_MTK_IEEE80211BE
+					, hapd->ml_group->ml_addr
+#endif
+					);
 		/* handle_auth_ft_finish() callback will complete auth. */
 		return;
 #endif /* CONFIG_IEEE80211R_AP */
@@ -4317,8 +4456,11 @@ static u16 owe_process_assoc_req(struct
 
 	wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
 	wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
-	wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
-			    sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE);
+	wpa_auth_pmksa_add3(hapd->wpa_auth,
+			    ml_auth_spa(sta->wpa_sm, sta->addr),
+			    ml_auth_aa(sta->wpa_sm, hapd->wpa_auth->addr),
+			    sta->owe_pmk, sta->owe_pmk_len,
+			    pmkid, 0, WPA_KEY_MGMT_OWE);
 
 	return WLAN_STATUS_SUCCESS;
 }
@@ -4724,7 +4866,9 @@ static int check_assoc_ies(struct hostap
 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
 		}
 #endif /* CONFIG_SAE */
-
+#ifdef CONFIG_MTK_IEEE80211BE
+	ml_new_assoc_sta(sta->wpa_sm, elems.ml, elems.ml_len); /*for logan owe flow*/
+#endif
 #ifdef CONFIG_OWE
 		if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
 		    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
@@ -4803,6 +4947,7 @@ static int check_assoc_ies(struct hostap
 	} else
 		wpa_auth_sta_no_wpa(sta->wpa_sm);
 
+
 #ifdef CONFIG_P2P
 	p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
 #endif /* CONFIG_P2P */
@@ -5136,7 +5281,11 @@ static u16 send_assoc_resp(struct hostap
 		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
 						buf + buflen - p,
 						sta->auth_alg, ies, ies_len,
-						omit_rsnxe);
+						omit_rsnxe
+#ifdef CONFIG_MTK_IEEE80211BE
+						, hapd
+#endif
+						);
 		if (!p) {
 			wpa_printf(MSG_DEBUG,
 				   "FT: Failed to write AssocResp IEs");
Index: hostapd-2022-07-29-b704dc72/src/ap/pmksa_cache_auth.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/pmksa_cache_auth.c
+++ hostapd-2022-07-29-b704dc72/src/ap/pmksa_cache_auth.c
@@ -16,7 +16,14 @@
 #include "sta_info.h"
 #include "ap_config.h"
 #include "pmksa_cache_auth.h"
-
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+#include "wpa_auth_i.h"
+#include "hostapd.h"
+#include "netlink/genl/genl.h"
+#include "mtk_vendor_nl80211.h"
+#include "../drivers/nl80211_copy.h"
+#include "../drivers/driver_nl80211.h"
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 
 static const int pmksa_cache_max_entries = 1024;
 static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -47,6 +54,50 @@ static void _pmksa_cache_free_entry(stru
 	bin_clear_free(entry, sizeof(*entry));
 }
 
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+static int pmksa_update_sta_pmkid(void *priv,
+					     struct wpa_pmkid_entry *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg = NULL;
+	struct nlattr *attr;
+	int ret = -1;
+	int ParamSize= sizeof(struct wpa_pmkid_entry);
+
+	wpa_printf(MSG_DEBUG,
+			   "nl80211: call testmode command");
+	wpa_printf(MSG_ERROR, "bssid:" MACSTR "sta:" MACSTR
+				"PMKID Add-Remove:%d ParamSize:%d",
+				MAC2STR(params->bssid), MAC2STR(params->sta),
+				params->AddRemove, ParamSize);
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+			nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
+			nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_SET_PMKID))
+			goto fail;
+
+	attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+	if (!attr)
+		goto fail;
+
+	if (nla_put(msg, MTK_NL80211_VENDOR_ATTR_SET_PMKSA_CACHE, sizeof(struct wpa_pmkid_entry),
+				(void *)params))
+		goto fail;
+
+	nla_nest_end(msg, attr);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: pmkid vendor command failed err=%d",
+				  ret);
+	return ret;
+
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 
 void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
 			    struct rsn_pmksa_cache_entry *entry)
@@ -54,6 +105,24 @@ void pmksa_cache_free_entry(struct rsn_p
 	struct rsn_pmksa_cache_entry *pos, *prev;
 	unsigned int hash;
 
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+	struct wpa_authenticator *wpa_auth;
+	struct hostapd_data *hapd;
+	struct wpa_pmkid_entry pmkid_entry;
+
+	wpa_auth = (struct wpa_authenticator *)pmksa->ctx;
+	hapd = (struct hostapd_data *)wpa_auth->cb_ctx;
+	/*wpa_auth = pmksa->ctx;
+	hapd = wpa_auth->cb_ctx;*/
+
+	wpa_printf(MSG_ERROR, "remove PMKID in driver ");
+	pmkid_entry.AddRemove = 0;      /*remove entry*/
+	os_memcpy(pmkid_entry.sta, entry->spa, ETH_ALEN);
+	os_memcpy(pmkid_entry.bssid, wpa_auth->addr, ETH_ALEN);
+	os_memcpy(pmkid_entry.pmkid, entry->pmkid, PMKID_LEN);
+	pmksa_update_sta_pmkid(hapd->drv_priv, &pmkid_entry);
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
+
 	pmksa->pmksa_count--;
 	pmksa->free_cb(entry, pmksa->ctx);
 
@@ -283,6 +352,11 @@ pmksa_cache_auth_add(struct rsn_pmksa_ca
 		     struct eapol_state_machine *eapol, int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry;
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+		struct wpa_authenticator *wpa_auth;
+		struct hostapd_data *hapd;
+		struct wpa_pmkid_entry pmkid_entry;
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 
 	entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len,
 					      aa, spa, session_timeout, eapol,
@@ -290,7 +364,19 @@ pmksa_cache_auth_add(struct rsn_pmksa_ca
 
 	if (pmksa_cache_auth_add_entry(pmksa, entry) < 0)
 		return NULL;
-
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+	wpa_printf(MSG_DEBUG, "add PMKID in driver spa:"MACSTR" aa:"MACSTR"",
+	MAC2STR(spa),MAC2STR(aa));
+	pmkid_entry.AddRemove = 1;	      /*Add PMKID in driver entry*/
+	os_memcpy(pmkid_entry.sta, spa, ETH_ALEN);
+	os_memcpy(pmkid_entry.bssid, aa, ETH_ALEN);
+	if (pmkid) {
+		os_memcpy(pmkid_entry.pmkid, pmkid, PMKID_LEN);
+	}
+	wpa_auth = (struct wpa_authenticator *)(pmksa->ctx);
+	hapd = (struct hostapd_data *)(wpa_auth->cb_ctx);
+	pmksa_update_sta_pmkid(hapd->drv_priv, &pmkid_entry);
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 	return entry;
 }
 
Index: hostapd-2022-07-29-b704dc72/src/ap/preauth_auth.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/preauth_auth.c
+++ hostapd-2022-07-29-b704dc72/src/ap/preauth_auth.c
@@ -22,6 +22,10 @@
 #include "sta_info.h"
 #include "wpa_auth.h"
 #include "preauth_auth.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "wpa_auth_i.h"
+#include "ml/ml_common.h"
+#endif
 
 #ifndef ETH_P_PREAUTH
 #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
@@ -206,7 +210,8 @@ void rsn_preauth_finished(struct hostapd
 		len = PMK_LEN;
 	if (success && key) {
 		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
-					       sta->addr,
+					       ml_auth_spa(sta->wpa_sm, sta->addr),
+					       ml_auth_aa(sta->wpa_sm, hapd->wpa_auth->addr),
 					       dot11RSNAConfigPMKLifetime,
 					       sta->eapol_sm) == 0) {
 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
Index: hostapd-2022-07-29-b704dc72/src/ap/wnm_ap.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/wnm_ap.c
+++ hostapd-2022-07-29-b704dc72/src/ap/wnm_ap.c
@@ -550,7 +550,7 @@ static void ieee802_11_rx_bss_trans_mgmt
 						    target_bssid, pos, end - pos);
 
 	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
-		    pos, end - pos);
+		pos, end - pos);
 }
 
 
@@ -597,6 +597,7 @@ static void ieee802_11_rx_wnm_notificati
 		   MAC2STR(addr), dialog_token, type);
 	wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
 		    buf, len);
+
 	switch (type) {
 	case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
 		wnm_beacon_protection_failure(hapd, addr);
Index: hostapd-2022-07-29-b704dc72/src/ap/wpa_auth.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/wpa_auth.c
+++ hostapd-2022-07-29-b704dc72/src/ap/wpa_auth.c
@@ -33,6 +33,11 @@
 #include "wpa_auth_i.h"
 #include "wpa_auth_ie.h"
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "hostapd.h"
+#include "ml/ml_common.h"
+#endif
+
 #define STATE_MACHINE_DATA struct wpa_state_machine
 #define STATE_MACHINE_DEBUG_PREFIX "WPA"
 #define STATE_MACHINE_ADDR sm->addr
@@ -326,12 +331,92 @@ static void wpa_rekey_gmk(void *eloop_ct
 }
 
 
-static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_authenticator *wpa_auth = eloop_ctx;
 	struct wpa_group *group, *next;
+#ifdef CONFIG_MTK_IEEE80211BE
+	struct wpa_ml_group *ml_group = ((struct hostapd_data *)wpa_auth->cb_ctx)->ml_group;
+#endif
 
 	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (ml_group) { /* ap mlo on */
+			u8 i = 0;
+			struct wpa_authenticator *wpa_auth_tmp;
+			struct wpa_ml_link *link;
+			struct sta_info *sta = NULL;
+
+			if (1) {
+				group = wpa_auth->group;
+				while (group) {
+					wpa_group_get(wpa_auth, group);
+
+					group->GTKReKey = true;
+					do {
+						group->changed = false;
+						wpa_group_sm_step(wpa_auth, group);
+					} while (group->changed);
+
+					next = group->next;
+					wpa_group_put(wpa_auth, group);
+					group = next;
+				}
+			}
+
+			if (1) {
+				for (i = 0; i < ml_group->ml_link_num; i++) {
+					link = &ml_group->links[i];
+					if (link) {
+						for (sta = ((struct hostapd_data *)link->ctx)->sta_list; sta; sta = sta->next) {
+							if (sta->wpa_sm)
+								if (sta->wpa_sm->sta_ml_ie) { /*find mld STA, so it is the assoc link */
+									wpa_printf(MSG_DEBUG, "find mld sta ");
+									if (link->ctx == wpa_auth->cb_ctx) {
+										wpa_printf(MSG_DEBUG, "the rekey happen in assoc link ");
+										break;
+									} else {
+										wpa_printf(MSG_DEBUG, "the rekey happen in not assoc link ");
+										wpa_auth_tmp = ((struct hostapd_data *)link->ctx)->wpa_auth;
+										group = wpa_auth_tmp->group;
+										while (group) {
+											wpa_group_get(wpa_auth_tmp, group);
+
+											group->GTKReKey = true;
+											do {
+												group->changed = false;
+												wpa_group_sm_step(wpa_auth_tmp, group);
+											} while (group->changed);
+
+											next = group->next;
+											wpa_group_put(wpa_auth_tmp, group);
+											group = next;
+										}
+										break;
+									}
+								}
+						}
+					}
+				}
+			}
+		} else { /*ap mlo off, go legacy gtk rekey flow */
+			group = wpa_auth->group;
+			while (group) {
+				wpa_group_get(wpa_auth, group);
+
+				group->GTKReKey = true;
+				do {
+					group->changed = false;
+					wpa_group_sm_step(wpa_auth, group);
+				} while (group->changed);
+
+				next = group->next;
+				wpa_group_put(wpa_auth, group);
+				group = next;
+			}
+		}
+#else
+
 	group = wpa_auth->group;
 	while (group) {
 		wpa_group_get(wpa_auth, group);
@@ -346,6 +431,7 @@ static void wpa_rekey_gtk(void *eloop_ct
 		wpa_group_put(wpa_auth, group);
 		group = next;
 	}
+#endif
 
 	if (wpa_auth->conf.wpa_group_rekey) {
 		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
@@ -755,6 +841,9 @@ static void wpa_free_sta_sm(struct wpa_s
 #ifdef CONFIG_DPP2
 	wpabuf_clear_free(sm->dpp_z);
 #endif /* CONFIG_DPP2 */
+#ifdef CONFIG_MTK_IEEE80211BE
+			os_free(sm->sta_ml_ie);
+#endif
 	bin_clear_free(sm, sizeof(*sm));
 }
 
@@ -1102,6 +1191,9 @@ void wpa_receive(struct wpa_authenticato
 		msg = GROUP_2;
 		msgtxt = "2/2 Group";
 	} else if (key_data_length == 0 ||
+#ifdef CONFIG_MTK_IEEE80211BE
+		key_data_length == 12 /* len of mac addr kde */ ||
+#endif
 		   (mic_len == 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
 		    key_data_length == AES_BLOCK_SIZE)) {
 		msg = PAIRWISE_4;
@@ -1258,6 +1350,13 @@ continue_processing:
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 			return;
 		}
+#ifdef CONFIG_MTK_IEEE80211BE
+			if (ml_process_m2_kde(sm, key_data, key_data_length)) {
+				wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+						 "received invalid ML EAPOL-Key msg 2/4 - dropped");
+				return;
+			}
+#endif
 		break;
 	case PAIRWISE_4:
 		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1267,6 +1366,14 @@ continue_processing:
 					 sm->wpa_ptk_state);
 			return;
 		}
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (ml_process_m4_kde(sm, key_data, key_data_length)) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received invalid ML EAPOL-Key msg 4/4 - dropped");
+			return;
+		}
+#endif
+
 		break;
 	case GROUP_2:
 		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
@@ -1373,6 +1480,10 @@ continue_processing:
 			   wpa_parse_kde_ies(key_data, key_data_length,
 					     &kde) == 0 &&
 			   kde.mac_addr) {
+#ifdef CONFIG_MTK_IEEE80211BE
+				ml_rekey_gtk(sm, &kde);
+#endif /* CONFIG_MTK_IEEE80211BE */
+
 		} else {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for GTK rekeying");
@@ -1698,7 +1809,7 @@ void __wpa_send_eapol(struct wpa_authent
 	}
 
 	wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
-	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
+	wpa_auth_send_eapol(wpa_auth, ml_auth_spa(sm, sm->addr), (u8 *) hdr, len,
 			    sm->pairwise_set);
 	os_free(hdr);
 }
@@ -2008,6 +2119,15 @@ SM_STATE(WPA_PTK, AUTHENTICATION)
 static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
 				  struct wpa_group *group)
 {
+#ifdef CONFIG_MTK_IEEE80211BE
+	struct wpa_ml_group *ml_group = ((struct hostapd_data *)wpa_auth->cb_ctx)->ml_group;
+	if (ml_group) {
+		wpa_printf(MSG_DEBUG,
+		   "ML: it is mlo device, no need to Re-initialize GMK/Counter");
+		return;
+	}
+#endif
+
 	if (group->first_sta_seen)
 		return;
 	/*
@@ -2190,7 +2310,13 @@ SM_STATE(WPA_PTK, INITPSK)
 
 SM_STATE(WPA_PTK, PTKSTART)
 {
-	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN +
+			   2 + RSN_SELECTOR_LEN + ETH_ALEN];
+#else
+	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN];
+#endif
+	u8 *pmkid = NULL;
 	size_t pmkid_len = 0;
 	u16 key_info;
 
@@ -2286,16 +2412,26 @@ SM_STATE(WPA_PTK, PTKSTART)
 			 * Calculate PMKID since no PMKSA cache entry was
 			 * available with pre-calculated PMKID.
 			 */
-			rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
-				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
+			rsn_pmkid(sm->PMK, sm->pmk_len, ml_auth_aa(sm, sm->wpa_auth->addr),
+				  ml_auth_spa(sm, sm->addr), &pmkid[2 + RSN_SELECTOR_LEN],
 				  sm->wpa_key_mgmt);
 			wpa_hexdump(MSG_DEBUG,
 				    "RSN: Message 1/4 PMKID derived from PMK",
 				    &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+			wpa_auth_add_wpa_pmkid(sm, &pmkid[2 + RSN_SELECTOR_LEN]);
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 		}
 	}
 	if (!pmkid)
 		pmkid_len = 0;
+
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (!pmkid)
+		pmkid = buf;
+	pmkid_len = ml_add_m1_kde(sm, pmkid + pmkid_len) - pmkid;
+#endif
+
 	key_info = WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE;
 	if (sm->pairwise_set && sm->wpa != WPA_VERSION_WPA)
 		key_info |= WPA_KEY_INFO_SECURE;
@@ -2348,7 +2484,8 @@ static int wpa_derive_ptk(struct wpa_sta
 	if (force_sha256)
 		akmp |= WPA_KEY_MGMT_PSK_SHA256;
 	return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
-			      sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
+			      ml_auth_aa(sm, sm->wpa_auth->addr),
+			      ml_auth_spa(sm, sm->addr), sm->ANonce, snonce,
 			      ptk, akmp, sm->pairwise, z, z_len, kdk_len);
 }
 
@@ -3545,11 +3682,20 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 		kde_len += 2 + RSN_SELECTOR_LEN + 2;
 #endif /* CONFIG_DPP2 */
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	kde_len += 512; /*For ML link KDE, GTK/IGTK/BIGTK KDE*/
+#endif
+
 	kde = os_malloc(kde_len);
 	if (!kde)
 		goto done;
 
 	pos = kde;
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated)
+		goto skip;
+#endif
+
 	os_memcpy(pos, wpa_ie, wpa_ie_len);
 	pos += wpa_ie_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -3581,6 +3727,14 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 				  gtk, gtk_len);
 	}
 	pos = ieee80211w_kde_add(sm, pos);
+
+#ifdef CONFIG_MTK_IEEE80211BE
+skip:
+		pos = ml_add_m3_kde(sm, pos);
+		if (!pos)
+			goto done;
+#endif
+
 	if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
 		goto done;
 
@@ -3932,16 +4086,29 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING
 	if (sm->wpa == WPA_VERSION_WPA2) {
 		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
 			ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+#ifdef CONFIG_MTK_IEEE80211BE
+		kde_len += 512; /*For ML MAC KDE, GTK/IGTK/BIGTK KDE*/
+#endif
+
 		kde_buf = os_malloc(kde_len);
 		if (!kde_buf)
 			return;
-
 		kde = pos = kde_buf;
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (sm->dot11MultiLinkActivated)
+			goto skip;
+#endif  /* CONFIG_MTK_IEEE80211BE */
+
 		hdr[0] = gsm->GN & 0x03;
 		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gsm->GTK_len);
 		pos = ieee80211w_kde_add(sm, pos);
+#ifdef CONFIG_MTK_IEEE80211BE
+skip:
+		pos = ml_add_rekey_kde(sm, pos);
+#endif /* CONFIG_MTK_IEEE80211BE */
+
 		if (ocv_oci_add(sm, &pos,
 				conf->oci_freq_override_eapol_g1) < 0) {
 			os_free(kde_buf);
@@ -4830,10 +4997,15 @@ int wpa_auth_pmksa_add(struct wpa_state_
 	}
 
 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
-	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
-				 sm->PTK.kck, sm->PTK.kck_len,
-				 sm->wpa_auth->addr, sm->addr, session_timeout,
-				 eapol, sm->wpa_key_mgmt))
+	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len,
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+				sm->pmkid,
+#else
+				NULL,
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
+				sm->PTK.kck, sm->PTK.kck_len,
+				ml_auth_aa(sm, sm->wpa_auth->addr), ml_auth_spa(sm, sm->addr), session_timeout,
+				eapol, sm->wpa_key_mgmt))
 		return 0;
 
 	return -1;
@@ -4842,7 +5014,7 @@ int wpa_auth_pmksa_add(struct wpa_state_
 
 int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
 			       const u8 *pmk, size_t len, const u8 *sta_addr,
-			       int session_timeout,
+			       const u8 *aa, int session_timeout,
 			       struct eapol_state_machine *eapol)
 {
 	if (!wpa_auth)
@@ -4851,7 +5023,7 @@ int wpa_auth_pmksa_add_preauth(struct wp
 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
 	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
 				 NULL, 0,
-				 wpa_auth->addr,
+				 aa,
 				 sta_addr, session_timeout, eapol,
 				 WPA_KEY_MGMT_IEEE8021X))
 		return 0;
@@ -4861,8 +5033,8 @@ int wpa_auth_pmksa_add_preauth(struct wp
 
 
 int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
-			   const u8 *pmk, size_t pmk_len, const u8 *pmkid,
-			   int akmp)
+			   const u8 *aa, const u8 *pmk, size_t pmk_len,
+			   const u8 *pmkid, int akmp)
 {
 	if (wpa_auth->conf.disable_pmksa_caching)
 		return -1;
@@ -4871,7 +5043,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_au
 	if (!akmp)
 		akmp = WPA_KEY_MGMT_SAE;
 	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
-				 NULL, 0, wpa_auth->addr, addr, 0, NULL, akmp))
+				 NULL, 0, aa, addr, 0, NULL, akmp))
 		return 0;
 
 	return -1;
@@ -4885,6 +5057,15 @@ void wpa_auth_add_sae_pmkid(struct wpa_s
 }
 
 
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+void wpa_auth_add_wpa_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
+{
+	os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+	sm->pmkid_set = 1;
+}
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
+
+
 int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
 			int session_timeout, int akmp)
@@ -4898,6 +5079,22 @@ int wpa_auth_pmksa_add2(struct wpa_authe
 				 NULL, akmp))
 		return 0;
 
+	return -1;
+}
+
+int wpa_auth_pmksa_add3(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			const u8 *aa, const u8 *pmk, size_t pmk_len,
+			const u8 *pmkid, int session_timeout, int akmp)
+{
+	if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching)
+		return -1;
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (3)", pmk, PMK_LEN);
+	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
+				 NULL, 0, aa, addr, session_timeout,
+				 NULL, akmp))
+		return 0;
+
 	return -1;
 }
 
Index: hostapd-2022-07-29-b704dc72/src/ap/wpa_auth.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/wpa_auth.h
+++ hostapd-2022-07-29-b704dc72/src/ap/wpa_auth.h
@@ -13,6 +13,9 @@
 #include "common/eapol_common.h"
 #include "common/wpa_common.h"
 #include "common/ieee802_11_defs.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+struct hostapd_data;
+#endif
 
 struct vlan_description;
 
@@ -422,15 +425,22 @@ int wpa_auth_pmksa_add(struct wpa_state_
 		       int session_timeout, struct eapol_state_machine *eapol);
 int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
 			       const u8 *pmk, size_t len, const u8 *sta_addr,
-			       int session_timeout,
+			       const u8 *aa, int session_timeout,
 			       struct eapol_state_machine *eapol);
 int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
-			   const u8 *pmk, size_t pmk_len, const u8 *pmkid,
-			   int akmp);
+			   const u8 *aa, const u8 *pmk, size_t pmk_len,
+			   const u8 *pmkid, int akmp);
 void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+void wpa_auth_add_wpa_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
 			int session_timeout, int akmp);
+int wpa_auth_pmksa_add3(struct wpa_authenticator * wpa_auth,const u8 * addr,
+			const u8 * aa,const u8 * pmk,size_t pmk_len,const u8 * pmkid,
+			int session_timeout,int akmp);
+
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 			   const u8 *sta_addr);
 int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
@@ -462,13 +472,21 @@ void wpa_auth_eapol_key_tx_status(struct
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
 				 const u8 *req_ies, size_t req_ies_len,
-				 int omit_rsnxe);
+				 int omit_rsnxe
+#ifdef CONFIG_MTK_IEEE80211BE
+				, struct hostapd_data *hapd
+#endif
+		);
 void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
 			 u16 auth_transaction, const u8 *ies, size_t ies_len,
 			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
 				    u16 auth_transaction, u16 resp,
 				    const u8 *ies, size_t ies_len),
-			 void *ctx);
+			 void *ctx
+#ifdef CONFIG_MTK_IEEE80211BE
+			, u8 *mladdr
+#endif
+		);
 int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
 			    size_t ies_len);
 int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
@@ -568,6 +586,7 @@ int hostapd_wpa_auth_send_eapol(void *ct
 				int encrypt);
 void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
 void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
+void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx);
 
 enum wpa_auth_ocv_override_frame {
 	WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
Index: hostapd-2022-07-29-b704dc72/src/ap/wpa_auth_ft.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/wpa_auth_ft.c
+++ hostapd-2022-07-29-b704dc72/src/ap/wpa_auth_ft.c
@@ -27,6 +27,14 @@
 #include "wpa_auth.h"
 #include "wpa_auth_i.h"
 #include "pmksa_cache_auth.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "hostapd.h"
+#include "wpa_auth_ie.h"
+
+#define STATE_MACHINE_ML_GROUP \
+	(((struct hostapd_data *)sm->wpa_auth->cb_ctx)->ml_group)
+#endif
 
 
 #ifdef CONFIG_IEEE80211R_AP
@@ -867,6 +875,325 @@ int wpa_write_ftie(struct wpa_auth_confi
 	return pos - buf;
 }
 
+#ifdef CONFIG_MTK_IEEE80211BE
+static inline int ft_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb->get_seqnum == NULL)
+		return -1;
+	return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+}
+
+static u8 * ml_ft_gtk_subelem(struct wpa_state_machine *sm, struct wpa_ml_link *link,
+	size_t *len)
+{
+	u8 *subelem;
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	struct wpa_authenticator *auth =
+		((struct hostapd_data *)link->ctx)->wpa_auth;
+	struct wpa_group *gsm = auth->group;
+	size_t subelem_len, pad_len;
+	const u8 *key;
+	size_t key_len;
+	u8 keybuf[WPA_GTK_MAX_LEN];
+	const u8 *kek;
+	size_t kek_len;
+
+	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+		kek = sm->PTK.kek2;
+		kek_len = sm->PTK.kek2_len;
+	} else {
+		kek = sm->PTK.kek;
+		kek_len = sm->PTK.kek_len;
+	}
+
+	key_len = gsm->GTK_len;
+	if (key_len > sizeof(keybuf))
+		return NULL;
+
+	/*
+	 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
+	 * than 16 bytes.
+	 */
+	pad_len = key_len % 8;
+	if (pad_len)
+		pad_len = 8 - pad_len;
+	if (key_len + pad_len < 16)
+		pad_len += 8;
+	if (pad_len && key_len < sizeof(keybuf)) {
+		os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+		if (conf->disable_gtk ||
+			sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+			/*
+			 * Provide unique random GTK to each STA to prevent use
+			 * of GTK in the BSS.
+			 */
+			if (random_get_bytes(keybuf, key_len) < 0)
+				return NULL;
+		}
+		os_memset(keybuf + key_len, 0, pad_len);
+		keybuf[key_len] = 0xdd;
+		key_len += pad_len;
+		key = keybuf;
+	} else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+		/*
+		 * Provide unique random GTK to each STA to prevent use of GTK
+		 * in the BSS.
+		 */
+		if (random_get_bytes(keybuf, key_len) < 0)
+			return NULL;
+		key = keybuf;
+	} else {
+		key = gsm->GTK[gsm->GN - 1];
+	}
+
+	/*
+	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Link Info[1] |Key Length[1] | RSC[8] |
+	 * Key[5..32].
+	 */
+	subelem_len = 14 + key_len + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	subelem[0] = FTIE_SUBELEM_GTK;
+	subelem[1] = 11 + key_len + 8;
+	/* Key ID in B0-B1 of Key Info */
+	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
+	subelem[4] = (link->link_id & 0x0f) << 4;
+	subelem[5] = gsm->GTK_len;
+	ft_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 6);
+	if (aes_wrap(kek, kek_len, key_len / 8, key, subelem + 14)) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: GTK subelem encryption failed: kek_len=%d",
+			   (int) kek_len);
+		os_free(subelem);
+		return NULL;
+	}
+
+	forced_memzero(keybuf, sizeof(keybuf));
+	*len = subelem_len;
+	return subelem;
+}
+
+static u8 * ml_ft_igtk_subelem(struct wpa_state_machine *sm, struct wpa_ml_link *link,
+	size_t *len)
+{
+	u8 *subelem, *pos;
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	struct wpa_authenticator *auth =
+		((struct hostapd_data *)link->ctx)->wpa_auth;
+	struct wpa_group *gsm = auth->group;
+	size_t subelem_len;
+	const u8 *kek, *igtk;
+	size_t kek_len;
+	size_t igtk_len;
+	u8 stub_igtk[WPA_IGTK_MAX_LEN];
+
+	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+		kek = sm->PTK.kek2;
+		kek_len = sm->PTK.kek2_len;
+	} else {
+		kek = sm->PTK.kek;
+		kek_len = sm->PTK.kek_len;
+	}
+
+	igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Link Info[1] | Key Length[1] |
+	 * Key[16+8] */
+	subelem_len = 1 + 1 + 2 + 6 + 1 + 1 + igtk_len + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	pos = subelem;
+	*pos++ = FTIE_SUBELEM_IGTK;
+	*pos++ = subelem_len - 2;
+	WPA_PUT_LE16(pos, gsm->GN_igtk);
+	pos += 2;
+	ft_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
+	pos += 6;
+	*pos++ = (link->link_id & 0x0f) << 4;
+	*pos++ = igtk_len;
+	igtk = gsm->IGTK[gsm->GN_igtk - 4];
+	if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+		/*
+		 * Provide unique random IGTK to each STA to prevent use of
+		 * IGTK in the BSS.
+		 */
+		if (random_get_bytes(stub_igtk, igtk_len / 8) < 0) {
+			os_free(subelem);
+			return NULL;
+		}
+		igtk = stub_igtk;
+	}
+	if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: IGTK subelem encryption failed: kek_len=%d",
+			   (int) kek_len);
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+
+static u8 * ml_ft_bigtk_subelem(struct wpa_state_machine *sm, struct wpa_ml_link *link,
+	size_t *len)
+{
+	u8 *subelem, *pos;
+	struct wpa_authenticator *auth =
+		((struct hostapd_data *)link->ctx)->wpa_auth;
+	struct wpa_group *gsm = auth->group;
+	size_t subelem_len;
+	const u8 *kek, *bigtk;
+	size_t kek_len;
+	size_t bigtk_len;
+	u8 stub_bigtk[WPA_IGTK_MAX_LEN];
+
+	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+		kek = sm->PTK.kek2;
+		kek_len = sm->PTK.kek2_len;
+	} else {
+		kek = sm->PTK.kek;
+		kek_len = sm->PTK.kek_len;
+	}
+
+	bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+	/* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Link Info[1] | Key Length[1] |
+	 * Key[16+8] */
+	subelem_len = 1 + 1 + 2 + 6 + 1 + 1 + bigtk_len + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	pos = subelem;
+	*pos++ = FTIE_SUBELEM_BIGTK;
+	*pos++ = subelem_len - 2;
+	WPA_PUT_LE16(pos, gsm->GN_bigtk);
+	pos += 2;
+	ft_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+	pos += 6;
+	*pos++ = (link->link_id & 0x0f) << 4;
+	*pos++ = bigtk_len;
+	bigtk = gsm->IGTK[gsm->GN_bigtk - 6];
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+		/*
+		 * Provide unique random BIGTK to each OSEN STA to prevent use
+		 * of BIGTK in the BSS.
+		 */
+		if (random_get_bytes(stub_bigtk, bigtk_len / 8) < 0) {
+			os_free(subelem);
+			return NULL;
+		}
+		bigtk = stub_bigtk;
+	}
+	if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "FT: BIGTK subelem encryption failed: kek_len=%d",
+			   (int) kek_len);
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+
+int wpa_write_mlie(struct wpa_auth_config *conf,
+		u8 *mladdr, struct hostapd_data *hapd, size_t ml_link_num,
+		u8 *buf, size_t len, bool is_auth)
+{
+	u8 *pos = buf;
+	u16 ctrl = 0;
+	u8 i = 0;
+
+	wpa_printf(MSG_DEBUG, "ML: write ml ie into ft auth/assoc");
+
+	*pos++ = WLAN_EID_EXTENSION;
+	/* extid: 1, common ctrl: 2, common info: 7(len:1, mac:6) */
+	if (is_auth)
+		*pos++ = 10;
+	else
+		*pos++ = 10 + (ml_link_num - 1) * 16;
+	*pos++ = WLAN_EID_EXT_MLD;
+
+	/* ml common control */
+	ML_SET_CTRL_TYPE(ctrl, ML_CTRL_TYPE_BASIC);
+
+	/* A Basic Multi-Link element in an Authentication frame:
+	 * the STA shall include the MLD MAC address of the MLD
+	 * the STA shall set all subfields in the Presence Bitmap subfield of
+	 * the Multi-Link Control field of the element to 0
+	 * the STA shall not include the Link Info field of the element.
+	 */
+	ML_SET_CTRL_PRESENCE(ctrl, 0);
+
+	WPA_PUT_LE16(pos, ctrl);
+	pos += 2;
+
+	/* len:1, mac:6 */
+	*pos++ = 7;
+
+	/* ml mac addr */
+	os_memcpy(pos, mladdr, ETH_ALEN);
+	pos += 6;
+
+
+	wpa_printf(MSG_DEBUG, "hapd->ml_group->links->link_id=%d", hapd->ml_group->links->link_id);
+	if (!is_auth) {
+		/* Add Per-STA Profile subelement*/
+		wpa_printf(MSG_DEBUG, "ML: add per-sta profile only for assoc response");
+		for (i = 0; i< ml_link_num; i++) {
+			u16 sta_ctrl = 0;
+			u8 nstr_bmap = 0;
+
+			/* Only add the other link's Per-STA info here,
+			 * own link's Per-STA info should be deleted.
+			*/
+			if (i == hapd->ml_group->links->link_id) {
+				wpa_printf(MSG_DEBUG, "skip per-sta profile for own link(link_id=%d)", i);
+				continue;
+			}
+
+			*pos++ = ML_SUB_ID_PER_STA_PROFILE;
+			*pos++ = 14;
+
+			sta_ctrl |= hapd->profiles[i].link_id & 0x0f;
+			sta_ctrl |= hapd->profiles[i].complete_profile << 4;
+			sta_ctrl |= hapd->profiles[i].mac_addr_present << 5;
+			sta_ctrl |= hapd->profiles[i].bcn_intvl_present << 6;
+			sta_ctrl |= hapd->profiles[i].dtim_present << 7;
+			sta_ctrl |= hapd->profiles[i].nstr_present << 8;
+
+			WPA_PUT_LE16(pos, sta_ctrl);
+			pos += 2;
+
+			*pos++ = 12;
+			os_memcpy(pos, hapd->profiles[i].addr, ETH_ALEN);
+			pos += 6;
+
+			WPA_PUT_LE16(pos, hapd->profiles[i].beacon_interval);
+			pos += 2;
+
+			WPA_PUT_LE16(pos, hapd->profiles[i].dtim);
+			pos += 2;
+
+			nstr_bmap = (u8)hapd->profiles[i].nstr_bmap;
+			os_memcpy(pos, &nstr_bmap, 1);
+			pos += 1;
+		}
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "ml ie", buf, pos - buf);
+
+	return pos - buf;
+}
+
+#endif
 
 /* A packet to be handled after seq response */
 struct ft_remote_item {
@@ -2506,7 +2833,11 @@ static u8 * wpa_ft_process_ric(struct wp
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 				 size_t max_len, int auth_alg,
 				 const u8 *req_ies, size_t req_ies_len,
-				 int omit_rsnxe)
+				 int omit_rsnxe
+#ifdef CONFIG_MTK_IEEE80211BE
+				, struct hostapd_data *hapd
+#endif
+	)
 {
 	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
 	u8 *fte_mic, *elem_count;
@@ -2597,60 +2928,134 @@ u8 * wpa_sm_write_assoc_resp_ies(struct
 
 	/* Fast BSS Transition Information */
 	if (auth_alg == WLAN_AUTH_FT) {
-		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
-		if (!subelem) {
-			wpa_printf(MSG_DEBUG,
-				   "FT: Failed to add GTK subelement");
-			return NULL;
-		}
-		r0kh_id = sm->r0kh_id;
-		r0kh_id_len = sm->r0kh_id_len;
-		anonce = sm->ANonce;
-		snonce = sm->SNonce;
-		if (sm->mgmt_frame_prot) {
-			u8 *igtk;
-			size_t igtk_len;
-			u8 *nbuf;
-			igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
-			if (igtk == NULL) {
-				wpa_printf(MSG_DEBUG,
-					   "FT: Failed to add IGTK subelement");
-				os_free(subelem);
-				return NULL;
-			}
-			nbuf = os_realloc(subelem, subelem_len + igtk_len);
-			if (nbuf == NULL) {
-				os_free(subelem);
-				os_free(igtk);
-				return NULL;
+#ifdef	CONFIG_IEEE80211R_AP
+		if (sm->dot11MultiLinkActivated) {
+			int i;
+			struct wpa_ml_group *ml_group = NULL;
+			struct wpa_ml_link *link;
+
+			ml_group = STATE_MACHINE_ML_GROUP;
+
+			wpa_printf(MSG_DEBUG, "FT: Add GTK/IGTK/BIGTK sub-element into reassoc response");
+			for (i = 0; i < ml_group->ml_link_num; i++) {
+				link = &ml_group->links[i];
+
+				subelem = ml_ft_gtk_subelem(sm, link, &subelem_len);
+				if (!subelem) {
+					wpa_printf(MSG_DEBUG,
+					   	"FT: Failed to add GTK subelement");
+					return NULL;
+				}
+
+				if (sm->mgmt_frame_prot) {
+					u8 *igtk;
+					size_t igtk_len;
+					u8 *nbuf;
+					igtk = ml_ft_igtk_subelem(sm, link, &igtk_len);
+					if (igtk == NULL) {
+						wpa_printf(MSG_DEBUG,
+							   "FT: Failed to add IGTK subelement");
+						os_free(subelem);
+						return NULL;
+					}
+					nbuf = os_realloc(subelem, subelem_len + igtk_len);
+					if (nbuf == NULL) {
+						os_free(subelem);
+						os_free(igtk);
+						return NULL;
+					}
+					subelem = nbuf;
+					os_memcpy(subelem + subelem_len, igtk, igtk_len);
+					subelem_len += igtk_len;
+					os_free(igtk);
+				}
+				if (sm->mgmt_frame_prot && conf->beacon_prot) {
+					u8 *bigtk;
+					size_t bigtk_len;
+					u8 *nbuf;
+
+					bigtk = ml_ft_bigtk_subelem(sm,  link, &bigtk_len);
+					if (!bigtk) {
+						wpa_printf(MSG_DEBUG,
+							   "FT: Failed to add BIGTK subelement");
+						os_free(subelem);
+						return NULL;
+					}
+					nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+					if (!nbuf) {
+						os_free(subelem);
+						os_free(bigtk);
+						return NULL;
+					}
+					subelem = nbuf;
+					os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+					subelem_len += bigtk_len;
+					os_free(bigtk);
+				}
 			}
-			subelem = nbuf;
-			os_memcpy(subelem + subelem_len, igtk, igtk_len);
-			subelem_len += igtk_len;
-			os_free(igtk);
-		}
-		if (sm->mgmt_frame_prot && conf->beacon_prot) {
-			u8 *bigtk;
-			size_t bigtk_len;
-			u8 *nbuf;
 
-			bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
-			if (!bigtk) {
+			r0kh_id = sm->r0kh_id;
+			r0kh_id_len = sm->r0kh_id_len;
+			anonce = sm->ANonce;
+			snonce = sm->SNonce;
+		} else
+#endif
+		{
+			subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+			if (!subelem) {
 				wpa_printf(MSG_DEBUG,
-					   "FT: Failed to add BIGTK subelement");
-				os_free(subelem);
+					   "FT: Failed to add GTK subelement");
 				return NULL;
 			}
-			nbuf = os_realloc(subelem, subelem_len + bigtk_len);
-			if (!nbuf) {
-				os_free(subelem);
+			r0kh_id = sm->r0kh_id;
+			r0kh_id_len = sm->r0kh_id_len;
+			anonce = sm->ANonce;
+			snonce = sm->SNonce;
+			if (sm->mgmt_frame_prot) {
+				u8 *igtk;
+				size_t igtk_len;
+				u8 *nbuf;
+				igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
+				if (igtk == NULL) {
+					wpa_printf(MSG_DEBUG,
+						   "FT: Failed to add IGTK subelement");
+					os_free(subelem);
+					return NULL;
+				}
+				nbuf = os_realloc(subelem, subelem_len + igtk_len);
+				if (nbuf == NULL) {
+					os_free(subelem);
+					os_free(igtk);
+					return NULL;
+				}
+				subelem = nbuf;
+				os_memcpy(subelem + subelem_len, igtk, igtk_len);
+				subelem_len += igtk_len;
+				os_free(igtk);
+			}
+			if (sm->mgmt_frame_prot && conf->beacon_prot) {
+				u8 *bigtk;
+				size_t bigtk_len;
+				u8 *nbuf;
+
+				bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+				if (!bigtk) {
+					wpa_printf(MSG_DEBUG,
+						   "FT: Failed to add BIGTK subelement");
+					os_free(subelem);
+					return NULL;
+				}
+				nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+				if (!nbuf) {
+					os_free(subelem);
+					os_free(bigtk);
+					return NULL;
+				}
+				subelem = nbuf;
+				os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+				subelem_len += bigtk_len;
 				os_free(bigtk);
-				return NULL;
 			}
-			subelem = nbuf;
-			os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
-			subelem_len += bigtk_len;
-			os_free(bigtk);
 		}
 #ifdef CONFIG_OCV
 		if (wpa_auth_uses_ocv(sm)) {
@@ -2764,6 +3169,17 @@ u8 * wpa_sm_write_assoc_resp_ies(struct
 	if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
 		*elem_count += 1;
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated) {
+		wpa_printf(MSG_DEBUG, "FT: Add ML IE into reassoc response");
+		res = wpa_write_mlie(conf, hapd->ml_group->ml_addr, hapd,
+			hapd->ml_group->ml_link_num, pos, end - pos, false);
+		if (res < 0)
+			return NULL;
+		pos += res;
+	}
+#endif
+
 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
 		kck = sm->PTK.kck2;
 		kck_len = sm->PTK.kck2_len;
@@ -2777,6 +3193,10 @@ u8 * wpa_sm_write_assoc_resp_ies(struct
 		       rsnie, rsnie_len,
 		       ric_start, ric_start ? pos - ric_start : 0,
 		       rsnxe_len ? rsnxe : NULL, rsnxe_len,
+#ifdef CONFIG_MTK_IEEE80211BE
+			   parse.mlie ? parse.mlie - 2 : NULL,
+			   parse.mlie ? parse.mlie_len + 2 : 0,
+#endif
 		       fte_mic) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
 		return NULL;
@@ -3052,7 +3472,11 @@ static int wpa_ft_local_derive_pmk_r1(st
 
 static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
 				   const u8 *ies, size_t ies_len,
-				   u8 **resp_ies, size_t *resp_ies_len)
+				   u8 **resp_ies, size_t *resp_ies_len
+#ifdef CONFIG_MTK_IEEE80211BE
+			 		, u8 *mladdr
+#endif
+	)
 {
 	struct rsn_mdie *mdie;
 	u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN];
@@ -3230,6 +3654,10 @@ pmk_r1_derived:
 
 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
 		2 + FT_R1KH_ID_LEN + 200;
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated)
+		buflen += 12;
+#endif
 	*resp_ies = os_zalloc(buflen);
 	if (*resp_ies == NULL)
 		goto fail;
@@ -3254,6 +3682,16 @@ pmk_r1_derived:
 		goto fail;
 	pos += ret;
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated) {
+		wpa_printf(MSG_DEBUG, "FT: Add ML IE in authentication response");
+		ret = wpa_write_mlie(conf, mladdr, NULL, 0, pos, end - pos, true);
+		if (ret < 0)
+			goto fail;
+		pos += ret;
+	}
+#endif
+
 	*resp_ies_len = pos - *resp_ies;
 
 	return WLAN_STATUS_SUCCESS;
@@ -3269,7 +3707,11 @@ void wpa_ft_process_auth(struct wpa_stat
 			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
 				    u16 auth_transaction, u16 status,
 				    const u8 *ies, size_t ies_len),
-			 void *ctx)
+			 void *ctx
+#ifdef CONFIG_MTK_IEEE80211BE
+			 , u8 *mladdr
+#endif
+	)
 {
 	u16 status;
 	u8 *resp_ies;
@@ -3290,7 +3732,11 @@ void wpa_ft_process_auth(struct wpa_stat
 	sm->ft_pending_auth_transaction = auth_transaction;
 	sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries;
 	res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
-				      &resp_ies_len);
+				      &resp_ies_len
+#ifdef CONFIG_MTK_IEEE80211BE
+					, mladdr
+#endif
+			);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
 		return;
@@ -3478,6 +3924,10 @@ int wpa_ft_validate_reassoc(struct wpa_s
 		       parse.ric, parse.ric_len,
 		       parse.rsnxe ? parse.rsnxe - 2 : NULL,
 		       parse.rsnxe ? parse.rsnxe_len + 2 : 0,
+#ifdef CONFIG_MTK_IEEE80211BE
+			   parse.mlie ? parse.mlie - 2 : NULL,
+			   parse.mlie ? parse.mlie_len + 2 : 0,
+#endif
 		       mic) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3663,7 +4113,11 @@ static int wpa_ft_rrb_rx_request(struct
 	os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
 	sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries;
 	res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
-				      &resp_ies_len);
+				      &resp_ies_len
+#ifdef CONFIG_MTK_IEEE80211BE
+					, NULL
+#endif
+				);
 	if (res < 0) {
 		wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
 		return 0;
@@ -4142,7 +4596,11 @@ static void ft_finish_pull(struct wpa_st
 
 	res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
 				      wpabuf_len(sm->ft_pending_req_ies),
-				      &resp_ies, &resp_ies_len);
+				      &resp_ies, &resp_ies_len
+#ifdef CONFIG_MTK_IEEE80211BE
+			 		  , NULL
+#endif
+				);
 	if (res < 0) {
 		/* this loop is broken by ft_pending_pull_left_retries */
 		wpa_printf(MSG_DEBUG,
Index: hostapd-2022-07-29-b704dc72/src/ap/wpa_auth_i.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/wpa_auth_i.h
+++ hostapd-2022-07-29-b704dc72/src/ap/wpa_auth_i.h
@@ -10,11 +10,17 @@
 #define WPA_AUTH_I_H
 
 #include "utils/list.h"
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+#include "wpa_auth.h"
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
 
 /* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
 #define RSNA_MAX_EAPOL_RETRIES 4
 
 struct wpa_group;
+#ifdef CONFIG_MTK_IEEE80211BE
+struct wpa_ml_ie_parse;
+#endif
 
 struct wpa_state_machine {
 	struct wpa_authenticator *wpa_auth;
@@ -99,6 +105,12 @@ struct wpa_state_machine {
 
 	unsigned int ptkstart_without_success;
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	unsigned int dot11MultiLinkActivated:1;
+	struct wpa_ml_ie_parse *sta_ml_ie;
+#endif
+
+
 #ifdef CONFIG_OCV
 	int ocv_enabled;
 #endif /* CONFIG_OCV */
Index: hostapd-2022-07-29-b704dc72/src/ap/wpa_auth_ie.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/ap/wpa_auth_ie.c
+++ hostapd-2022-07-29-b704dc72/src/ap/wpa_auth_ie.c
@@ -17,7 +17,7 @@
 #include "pmksa_cache_auth.h"
 #include "wpa_auth_ie.h"
 #include "wpa_auth_i.h"
-
+#include "ml/ml_common.h"
 
 #ifdef CONFIG_RSN_TESTING
 int rsn_testing = 0;
@@ -957,7 +957,7 @@ wpa_validate_wpa_ie(struct wpa_authentic
 	for (i = 0; i < data.num_pmkid; i++) {
 		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
 			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
-		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
+		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, ml_auth_spa(sm, sm->addr),
 						 &data.pmkid[i * PMKID_LEN]);
 		if (sm->pmksa) {
 			pmkid = sm->pmksa->pmkid;
Index: hostapd-2022-07-29-b704dc72/src/common/ieee802_11_common.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/ieee802_11_common.c
+++ hostapd-2022-07-29-b704dc72/src/common/ieee802_11_common.c
@@ -315,6 +315,18 @@ static int ieee802_11_parse_extension(co
 		elems->eht_operation = pos;
 		elems->eht_operation_len = elen;
 		break;
+#ifdef CONFIG_MTK_IEEE80211BE
+	case WLAN_EID_EXT_MLD:
+		wpa_printf(MSG_DEBUG,"EXISTS: elems-->ml.\n");
+		if (elen < 2) {
+			wpa_printf(MSG_DEBUG,"EXISTS: elems-->ml len(%zu) invalid.\n", elen);
+			break;
+		}
+		elems->ml = pos;
+		elems->ml_len = elen;
+		break;
+#endif
+
 	default:
 		if (show_errors) {
 			wpa_printf(MSG_MSGDUMP,
@@ -2740,6 +2752,12 @@ struct wpabuf * ieee802_11_defrag(struct
 			data = elems->wrapped_data;
 			len = elems->wrapped_data_len;
 			break;
+#ifdef CONFIG_MTK_IEEE80211BE
+		case WLAN_EID_EXT_MULTI_LINK:
+			data = elems->ml;
+			len = elems->ml_len;
+			break;
+#endif
 		default:
 			wpa_printf(MSG_DEBUG,
 				   "Defragmentation not supported. eid_ext=%u",
Index: hostapd-2022-07-29-b704dc72/src/common/ieee802_11_common.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/ieee802_11_common.h
+++ hostapd-2022-07-29-b704dc72/src/common/ieee802_11_common.h
@@ -120,6 +120,10 @@ struct ieee802_11_elems {
 	const u8 *eht_capabilities;
 	const u8 *eht_operation;
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	const u8 *ml;
+#endif
+
 	u8 ssid_len;
 	u8 supp_rates_len;
 	u8 challenge_len;
@@ -175,6 +179,9 @@ struct ieee802_11_elems {
 	u8 pasn_params_len;
 	u8 eht_capabilities_len;
 	u8 eht_operation_len;
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 ml_len;
+#endif
 
 	struct mb_ies_info mb_ies;
 	struct frag_ies_info frag_ies;
Index: hostapd-2022-07-29-b704dc72/src/common/ieee802_11_defs.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/ieee802_11_defs.h
+++ hostapd-2022-07-29-b704dc72/src/common/ieee802_11_defs.h
@@ -497,6 +497,12 @@
 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
 #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
 
+#define WLAN_EID_EXT_EHT_OP 106
+#define WLAN_EID_EXT_MLD 107
+#define WLAN_EID_EXT_EHT_CAPS 108
+#define WLAN_EID_EXT_TID2LNK_MAP 109
+#define WLAN_EID_EXT_MLT 110
+
 /* Extended Capabilities field */
 #define WLAN_EXT_CAPAB_20_40_COEX 0
 #define WLAN_EXT_CAPAB_GLK 1
Index: hostapd-2022-07-29-b704dc72/src/common/sae.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/sae.c
+++ hostapd-2022-07-29-b704dc72/src/common/sae.c
@@ -21,6 +21,9 @@
 #include "ieee802_11_defs.h"
 #include "dragonfly.h"
 #include "sae.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#endif
 
 
 int sae_set_group(struct sae_data *sae, int group)
@@ -121,12 +124,35 @@ void sae_clear_temp_data(struct sae_data
 
 void sae_clear_data(struct sae_data *sae)
 {
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 dot11MultiLinkActivated;
+	u8 own_ml_addr[ETH_ALEN];
+	u8 peer_ml_addr[ETH_ALEN];
+#endif
+
 	if (sae == NULL)
 		return;
+#ifdef CONFIG_MTK_IEEE80211BE
+	/* backup */
+	dot11MultiLinkActivated = sae->dot11MultiLinkActivated;
+	os_memcpy(own_ml_addr, sae->own_ml_addr, ETH_ALEN);
+	os_memcpy(peer_ml_addr, sae->peer_ml_addr, ETH_ALEN);
+#endif
 	sae_clear_temp_data(sae);
 	crypto_bignum_deinit(sae->peer_commit_scalar, 0);
 	crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
+#ifdef CONFIG_MTK_IEEE80211BE
+	os_free(sae->peer_ml_ie);
+#endif
 	os_memset(sae, 0, sizeof(*sae));
+#ifdef CONFIG_MTK_IEEE80211BE
+	sae->dot11MultiLinkActivated = dot11MultiLinkActivated;
+	os_memcpy(sae->own_ml_addr, own_ml_addr, ETH_ALEN);
+	os_memcpy(sae->peer_ml_addr, peer_ml_addr, ETH_ALEN);
+	wpa_printf(MSG_DEBUG, "ML: SAE own ml addr "MACSTR",peer ml addr "MACSTR"",
+		MAC2STR(sae->own_ml_addr), MAC2STR(sae->peer_ml_addr));
+#endif
+
 }
 
 
@@ -1872,15 +1898,16 @@ static void sae_parse_commit_token(struc
 
 
 static void sae_parse_token_container(struct sae_data *sae,
-				      const u8 *pos, const u8 *end,
+				      const u8 **pos, const u8 *end,
 				      const u8 **token, size_t *token_len)
 {
 	wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
-		    pos, end - pos);
-	if (!sae_is_token_container_elem(pos, end))
+		    *pos, end - *pos);
+	if (!sae_is_token_container_elem(*pos, end))
 		return;
-	*token = pos + 3;
-	*token_len = pos[1] - 1;
+	*token = *pos + 3;
+	*token_len = (*pos)[1] - 1;
+	*pos += *token_len + 3;
 	wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
 		    *token, *token_len);
 }
@@ -2193,7 +2220,7 @@ u16 sae_parse_commit(struct sae_data *sa
 
 	/* Optional Anti-Clogging Token Container element */
 	if (h2e)
-		sae_parse_token_container(sae, pos, end, token, token_len);
+		sae_parse_token_container(sae, &pos, end, token, token_len);
 
 	/* Conditional AKM Suite Selector element */
 	if (h2e) {
@@ -2220,6 +2247,13 @@ u16 sae_parse_commit(struct sae_data *sa
 			sae->akmp = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
 	}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	res = ml_sae_process_auth(sae, 1, pos, end - pos);
+	if (res < 0) {
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+#endif
+
 	/*
 	 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
 	 * the values we sent which would be evidence of a reflection attack.
@@ -2428,6 +2462,13 @@ int sae_check_confirm(struct sae_data *s
 		return -1;
 #endif /* CONFIG_SAE_PK */
 
+#ifdef CONFIG_MTK_IEEE80211BE /*if sae pk on, there will be error?*/
+	if (ml_sae_process_auth(sae, 2, data + 2 + hash_len,
+				len - 2 - hash_len) < 0) {
+		return -1;
+	}
+#endif
+
 	return 0;
 }
 
Index: hostapd-2022-07-29-b704dc72/src/common/sae.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/sae.h
+++ hostapd-2022-07-29-b704dc72/src/common/sae.h
@@ -119,6 +119,15 @@ struct sae_data {
 	unsigned int h2e:1;
 	unsigned int pk:1;
 	struct sae_temporary_data *tmp;
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 own_ml_addr[ETH_ALEN];
+	u8 peer_ml_addr[ETH_ALEN];/*sta the peer mld mac addr*/
+	/* ml ie from peer */
+	struct wpa_ml_ie_parse *own_ml_ie;
+	struct wpa_ml_ie_parse *peer_ml_ie;
+	unsigned int dot11MultiLinkActivated:1;
+#endif
+
 };
 
 int sae_set_group(struct sae_data *sae, int group);
Index: hostapd-2022-07-29-b704dc72/src/common/wpa_common.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/wpa_common.c
+++ hostapd-2022-07-29-b704dc72/src/common/wpa_common.c
@@ -889,6 +889,9 @@ int wpa_ft_mic(const u8 *kck, size_t kck
 	       const u8 *rsnie, size_t rsnie_len,
 	       const u8 *ric, size_t ric_len,
 	       const u8 *rsnxe, size_t rsnxe_len,
+#ifdef CONFIG_MTK_IEEE80211BE
+		   const u8 *mlie, size_t mlie_len,
+#endif
 	       u8 *mic)
 {
 	const u8 *addr[10];
@@ -965,6 +968,14 @@ int wpa_ft_mic(const u8 *kck, size_t kck
 		num_elem++;
 	}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (mlie) {
+		addr[num_elem] = mlie;
+		len[num_elem] = mlie_len;
+		num_elem++;
+	}
+#endif
+
 	for (i = 0; i < num_elem; i++)
 		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
 #ifdef CONFIG_SHA384
@@ -3143,6 +3154,9 @@ static int wpa_parse_generic(const u8 *p
 	size_t dlen = 2 + len;
 	u32 selector;
 	const u8 *p;
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 link_id;
+#endif
 	size_t left;
 
 	if (len == 0)
@@ -3251,6 +3265,91 @@ static int wpa_parse_generic(const u8 *p
 		wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", pos, dlen);
 		return 0;
 	}
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (left >= RSN_MLO_GTK_KDE_PREFIX_LENGTH &&
+		selector == RSN_KEY_DATA_MLO_GTK) {
+		struct kde_data *kde;
+
+		if (ie->mlo_gtk.num >= ML_MAX_LINK_NUM)
+			return 1;
+		link_id = (p[0] & RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK) >>
+			RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT;
+		if (link_id >= MAX_NUM_MLO_LINKS) {
+			wpa_printf(MSG_ERROR, "MLO_GTK link_id(%d) is invalid\n", link_id);
+			return 2;
+		}
+
+		kde = &ie->mlo_gtk.kdes[ie->mlo_gtk.num++];
+		kde->data = pos + 2 + RSN_SELECTOR_LEN;
+		kde->len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: MLO GTK in EAPOL-Key",
+				pos, dlen);
+		return 0;
+	}
+
+	if (left >= RSN_MLO_IGTK_KDE_PREFIX_LENGTH &&
+		selector == RSN_KEY_DATA_MLO_IGTK) {
+		struct kde_data *kde;
+
+		if (ie->mlo_igtk.num >= ML_MAX_LINK_NUM)
+			return 1;
+		link_id = (p[8] & RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK) >>
+			  RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT;
+		if (link_id >= MAX_NUM_MLO_LINKS){
+			wpa_printf(MSG_ERROR, "MLO_IGTK link_id(%d) is invalid\n", link_id);
+			return 2;
+		}
+
+		kde = &ie->mlo_igtk.kdes[ie->mlo_igtk.num++];
+		kde->data = pos + 2 + RSN_SELECTOR_LEN;
+		kde->len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: MLO IGTK in EAPOL-Key",
+				pos, dlen);
+		return 0;
+	}
+
+	if (left >= RSN_MLO_BIGTK_KDE_PREFIX_LENGTH &&
+	    selector == RSN_KEY_DATA_MLO_BIGTK) {
+		struct kde_data *kde;
+
+		if (ie->mlo_bigtk.num >= ML_MAX_LINK_NUM)
+			return 1;
+		link_id = (p[8] & RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK) >>
+			  RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT;
+		if (link_id >= MAX_NUM_MLO_LINKS){
+			wpa_printf(MSG_ERROR, "MLO_BIGTK link_id(%d) is invalid\n", link_id);
+			return 2;
+		}
+
+		kde = &ie->mlo_bigtk.kdes[ie->mlo_bigtk.num++];
+		kde->data = pos + 2 + RSN_SELECTOR_LEN;
+		kde->len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: MLO BIGTK in EAPOL-Key",
+				pos, dlen);
+		return 0;
+	}
+
+	if (left >= RSN_MLO_LINK_KDE_FIXED_LENGTH &&
+	    selector == RSN_KEY_DATA_MLO_LINK) {
+		struct kde_data *kde;
+
+		if (ie->mlo_link.num >= ML_MAX_LINK_NUM)
+			return 1;
+		link_id = (p[0] & RSN_MLO_LINK_KDE_LI_LINK_ID_MASK) >>
+			  RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT;
+		if (link_id >= MAX_NUM_MLO_LINKS){
+			wpa_printf(MSG_ERROR, "MLO_LINKS link_id(%d) is invalid\n", link_id);
+			return 2;
+		}
+
+		kde = &ie->mlo_link.kdes[ie->mlo_link.num++];
+		kde->data = pos + 2 + RSN_SELECTOR_LEN;
+		kde->len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: MLO Link in EAPOL-Key",
+				pos, dlen);
+		return 0;
+	}
+#endif
 
 	return 2;
 }
Index: hostapd-2022-07-29-b704dc72/src/common/wpa_common.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/wpa_common.h
+++ hostapd-2022-07-29-b704dc72/src/common/wpa_common.h
@@ -133,6 +133,13 @@ WPA_CIPHER_BIP_CMAC_256)
 #define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
 #define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#define RSN_KEY_DATA_MLO_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
+#define RSN_KEY_DATA_MLO_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
+#define RSN_KEY_DATA_MLO_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
+#define RSN_KEY_DATA_MLO_LINK RSN_SELECTOR(0x00, 0x0f, 0xac, 19)
+#endif
+
 #define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
 #define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
 #define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
@@ -421,6 +428,9 @@ int wpa_ft_mic(const u8 *kck, size_t kck
 	       const u8 *rsnie, size_t rsnie_len,
 	       const u8 *ric, size_t ric_len,
 	       const u8 *rsnxe, size_t rsnxe_len,
+#ifdef CONFIG_MTK_IEEE80211BE
+		   const u8 *mlie, size_t mlie_len,
+#endif
 	       u8 *mic);
 int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
 		      const u8 *ssid, size_t ssid_len,
@@ -517,6 +527,10 @@ struct wpa_ft_ies {
 	const u8 *oci;
 	size_t oci_len;
 #endif /* CONFIG_OCV */
+#ifdef CONFIG_MTK_IEEE80211BE
+	const u8 *mlie;
+	size_t mlie_len;
+#endif
 	const u8 *ric;
 	size_t ric_len;
 	int key_mgmt;
@@ -560,6 +574,59 @@ struct wpa_pasn_params_data {
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
 		     int use_sha384);
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#define MAX_NUM_MLO_LINKS 15
+#define ML_MAX_LINK_NUM 3
+
+#define RSN_MLO_GTK_KDE_PREFIX_LENGTH		(1 + 6)
+#define RSN_MLO_GTK_KDE_PREFIX0_KEY_ID_MASK	0x03
+#define RSN_MLO_GTK_KDE_PREFIX0_TX		0x04
+#define RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT	4
+#define RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK	0xF0
+
+#define RSN_MLO_IGTK_KDE_PREFIX_LENGTH		(2 + 6 + 1)
+#define RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT	4
+#define RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK	0xF0
+
+#define RSN_MLO_BIGTK_KDE_PREFIX_LENGTH		(2 + 6 + 1)
+#define RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT	4
+#define RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK	0xF0
+
+#define RSN_MLO_LINK_KDE_FIXED_LENGTH		(1 + 6)
+#define RSN_MLO_LINK_KDE_LINK_INFO_INDEX	0
+#define RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT	0
+#define RSN_MLO_LINK_KDE_LI_LINK_ID_MASK	0x0F
+#define RSN_MLO_LINK_KDE_LI_RSNE_INFO		0x10
+#define RSN_MLO_LINK_KDE_LI_RSNXE_INFO		0x20
+#define RSN_MLO_LINK_KDE_LINK_MAC_INDEX		1
+
+struct kde_data {
+	const u8 *data;
+	size_t len;
+};
+
+struct ml_kde {
+	size_t num;
+	struct kde_data kdes[ML_MAX_LINK_NUM];
+};
+
+struct ml_gtk_holder {
+	size_t num;
+	struct wpa_gtk gtks[ML_MAX_LINK_NUM];
+};
+
+struct ml_igtk_holder {
+	size_t num;
+	struct wpa_igtk igtks[ML_MAX_LINK_NUM];
+};
+
+struct ml_bigtk_holder {
+	size_t num;
+	struct wpa_bigtk bigtks[ML_MAX_LINK_NUM];
+};
+
+#endif
+
 struct wpa_eapol_ie_parse {
 	const u8 *wpa_ie;
 	size_t wpa_ie_len;
@@ -614,6 +681,13 @@ struct wpa_eapol_ie_parse {
 	u16 aid;
 	const u8 *wmm;
 	size_t wmm_len;
+#ifdef CONFIG_MTK_IEEE80211BE
+	struct ml_kde mlo_gtk;
+	struct ml_kde mlo_igtk;
+	struct ml_kde mlo_bigtk;
+	struct ml_kde mlo_link;
+#endif
+
 };
 
 int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
Index: hostapd-2022-07-29-b704dc72/src/common/wpa_ctrl.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/common/wpa_ctrl.h
+++ hostapd-2022-07-29-b704dc72/src/common/wpa_ctrl.h
@@ -161,6 +161,7 @@ extern "C" {
 #define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
 
 #define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+
 /** Result of SCS setup */
 #define WPA_EVENT_SCS_RESULT "CTRL-EVENT-SCS-RESULT "
 /* Event indicating DSCP policy */
Index: hostapd-2022-07-29-b704dc72/src/drivers/driver.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/drivers/driver.h
+++ hostapd-2022-07-29-b704dc72/src/drivers/driver.h
@@ -27,9 +27,12 @@
 #include "pae/ieee802_1x_kay.h"
 #endif /* CONFIG_MACSEC */
 #include "utils/list.h"
-#ifdef HOSTAPD_11R_SUPPORT
+#if defined(HOSTAPD_11R_SUPPORT) || defined(CONFIG_MTK_IEEE80211BE)
 #include "mtk_vendor_nl80211.h"
 #endif
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#endif
 
 #define HOSTAPD_CHAN_DISABLED 0x00000001
 #define HOSTAPD_CHAN_NO_IR 0x00000002
@@ -1270,6 +1273,15 @@ struct wowlan_triggers {
 	u8 rfkill_release;
 };
 
+#ifdef HOSTAPD_PMKID_IN_DRIVER_SUPPORT
+struct wpa_pmkid_entry {
+	u8 bssid[ETH_ALEN];
+	u8 sta[ETH_ALEN];
+	u8 pmkid[PMKID_LEN];
+	u8 AddRemove;   /*1- ADD, 0- Remove*/
+};
+#endif /*HOSTAPD_PMKID_IN_DRIVER_SUPPORT*/
+
 struct wpa_driver_ap_params {
 	/**
 	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
@@ -2609,6 +2621,10 @@ struct external_auth {
 	unsigned int key_mgmt_suite;
 	u16 status;
 	const u8 *pmkid;
+#ifdef CONFIG_MTK_IEEE80211BE
+	const u8 *ext_ie;
+	size_t ext_ie_len;
+#endif /* CONFIG_MTK_IEEE80211BE */
 };
 
 /* enum nested_attr - Used to specify if subcommand uses nested attributes */
@@ -3904,7 +3920,7 @@ struct wpa_driver_ops {
 	 */
 	int (*set_authmode)(void *priv, int authmode);
 
-#ifdef ANDROID
+#if defined ANDROID || defined(CONFIG_MTK_IEEE80211BE)
 	/**
 	 * driver_cmd - Execute driver-specific command
 	 * @priv: Private driver interface data
@@ -5272,6 +5288,14 @@ enum wpa_event_type {
 	 * EVENT_CCA_NOTIFY - Notification that CCA has completed
 	 */
 	EVENT_CCA_NOTIFY,
+	/**
+	  * EVENT_UPDATE_BSS_MLO_INFO - Notification of BSS MLO INFO
+	  */
+	EVENT_UPDATE_BSS_ML_INFO,
+	/**
+	  * EVENT_UPDATE_STA_PROFILE_UPDATE - Notification of PER-STA PROFILE INFO
+	  */
+	EVENT_UPDATE_STA_PROFILE_UPDATE,
 };
 
 
@@ -6174,6 +6198,18 @@ union wpa_event_data {
 	struct bss_color_collision {
 		u64 bitmap;
 	} bss_color_collision;
+
+	struct ml_info_event {
+		u8 link_cnt;
+		u8 mld_grp_idx;
+		u8 link_id;
+		u8 addr[ETH_ALEN];
+	} ml_info_event;
+
+	/**
+	  * struct per_sta_profile - Data for EVENT_UPDATE_STA_PROFILE_UPDATE
+    */
+	struct per_sta_profile profiles[ML_MAX_LINK_NUM];
 };
 
 /**
Index: hostapd-2022-07-29-b704dc72/src/drivers/driver_nl80211.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/drivers/driver_nl80211.c
+++ hostapd-2022-07-29-b704dc72/src/drivers/driver_nl80211.c
@@ -12930,7 +12930,7 @@ const struct wpa_driver_ops wpa_driver_n
 	.get_noa = wpa_driver_get_p2p_noa,
 	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
 #endif /* ANDROID_P2P */
-#ifdef ANDROID
+#if defined ANDROID || defined (CONFIG_MTK_IEEE80211BE)
 #ifndef ANDROID_LIB_STUB
 	.driver_cmd = wpa_driver_nl80211_driver_cmd,
 #endif /* !ANDROID_LIB_STUB */
Index: hostapd-2022-07-29-b704dc72/src/drivers/driver_nl80211.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/drivers/driver_nl80211.h
+++ hostapd-2022-07-29-b704dc72/src/drivers/driver_nl80211.h
@@ -295,7 +295,7 @@ const char * nl80211_iftype_str(enum nl8
 
 void nl80211_restore_ap_mode(struct i802_bss *bss);
 
-#ifdef ANDROID
+#if defined ANDROID || defined(CONFIG_MTK_IEEE80211BE)
 int android_nl_socket_set_nonblocking(struct nl_sock *handle);
 int android_pno_start(struct i802_bss *bss,
 		      struct wpa_driver_scan_params *params);
Index: hostapd-2022-07-29-b704dc72/src/drivers/driver_nl80211_event.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/drivers/driver_nl80211_event.c
+++ hostapd-2022-07-29-b704dc72/src/drivers/driver_nl80211_event.c
@@ -19,7 +19,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "driver_nl80211.h"
-
+#include "mediatek_driver_nl80211.h"
 
 static void
 nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
@@ -2380,6 +2380,7 @@ static void qca_nl80211_p2p_lo_stop_even
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
+
 static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
 				     u32 subcmd, u8 *data, size_t len)
 {
@@ -2504,7 +2505,7 @@ static void nl80211_vendor_event_brcm(st
 #endif /* CONFIG_DRIVER_NL80211_BRCM */
 
 
-static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
+static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, struct i802_bss *bss,
 				 struct nlattr **tb)
 {
 	u32 vendor_id, subcmd, wiphy = 0;
@@ -2548,11 +2549,17 @@ static void nl80211_vendor_event(struct
 	case OUI_QCA:
 		nl80211_vendor_event_qca(drv, subcmd, data, len);
 		break;
+		/* handle mediatek vendor event */
 #ifdef CONFIG_DRIVER_NL80211_BRCM
 	case OUI_BRCM:
 		nl80211_vendor_event_brcm(drv, subcmd, data, len);
 		break;
 #endif /* CONFIG_DRIVER_NL80211_BRCM */
+#ifdef CONFIG_MTK_IEEE80211BE
+	case OUI_MTK:
+	    nl80211_vendor_event_mtk(drv, bss, subcmd, data, len);
+		break;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
 		break;
@@ -2705,6 +2712,10 @@ static void nl80211_external_auth(struct
 	event.external_auth.ssid = nla_data(tb[NL80211_ATTR_SSID]);
 
 	event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]);
+#ifdef CONFIG_MTK_IEEE80211BE
+	event.external_auth.ext_ie = NULL;
+	event.external_auth.ext_ie_len = 0;
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	wpa_printf(MSG_DEBUG,
 		   "nl80211: External auth action: %u, AKM: 0x%x",
@@ -3187,7 +3198,7 @@ static void do_process_drv_event(struct
 		nl80211_stop_ap(drv, tb);
 		break;
 	case NL80211_CMD_VENDOR:
-		nl80211_vendor_event(drv, tb);
+		nl80211_vendor_event(drv, bss, tb);
 		break;
 	case NL80211_CMD_NEW_PEER_CANDIDATE:
 		nl80211_new_peer_candidate(drv, tb);
Index: hostapd-2022-07-29-b704dc72/src/drivers/mediatek_driver_cmd_nl80211.c
===================================================================
--- /dev/null
+++ hostapd-2022-07-29-b704dc72/src/drivers/mediatek_driver_cmd_nl80211.c
@@ -0,0 +1,344 @@
+/*
+ * Driver interaction with extended Linux CFG8021
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ */
+#include "includes.h"
+#include "netlink/genl/genl.h"
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "driver_nl80211.h"
+#include "linux_ioctl.h"
+#include "../../wpa_supplicant/wpa_supplicant_i.h"
+#include "config.h"
+#include "android_drv.h"
+
+#include "mediatek_driver_nl80211.h"
+#include "../../wpa_supplicant/driver_i.h"
+
+
+#include "eloop.h"
+
+/**********************************************************************
+* OVERLAPPED functins, previous defination is in driver_nl80211.c,
+* it will be modified
+***********************************************************************/
+
+/**********************************************************************/
+
+static int mtk_set_mlo_preset_link_id(void *priv, const char *cmd)
+{
+    struct i802_bss *bss = priv;
+    struct wpa_driver_nl80211_data *drv = bss->drv;
+    struct nl_msg *msg;
+    struct nlattr *params;
+    int ret;
+	int link_id = 0;
+
+    wpa_printf(MSG_DEBUG, "mtk string command: %s", cmd);
+
+	if (os_strncasecmp(cmd, "PRESET_LINKID=", os_strlen("PRESET_LINKID=")) != 0) {
+		wpa_printf(MSG_ERROR, "command: %s, not supported.", cmd);
+		return -1;
+	}
+	ret = sscanf(cmd, "PRESET_LINKID=%d", &link_id);
+	if (ret != 1 || link_id >= ML_MAX_LINK_NUM) {
+		wpa_printf(MSG_ERROR, "command: %s, invalid format or value.", cmd);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "mtk string command: %s, link_id=%d", cmd, link_id);
+    if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+        nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_MTK) ||
+        nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                    MTK_NL80211_VENDOR_SUBCMD_SET_MLO_PRESET_LINK)) {
+        wpa_printf(MSG_ERROR, "nl operation error");
+        goto fail;
+    }
+
+    params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+    if (!params) {
+        wpa_printf(MSG_ERROR, "nl start failed");
+        goto fail;
+    }
+
+	if (nla_put_u8(msg, MTK_NL80211_VENDOR_ATTR_MLO_PRESET_LINKID_INFO, (u8)link_id)) {
+        wpa_printf(MSG_ERROR, "nl put attribute failed");
+        goto fail;
+    }
+
+    nla_nest_end(msg, params);
+
+    ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+    msg = NULL;
+    if (ret) {
+        wpa_printf(MSG_ERROR, "str_vendor_cmd ret=%d", ret);
+        return ret;
+    }
+    return 0;
+fail:
+    nlmsg_free(msg);
+    return -1;
+}
+
+
+int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+                  size_t buf_len)
+{
+    struct i802_bss *bss = priv;
+    struct wpa_driver_nl80211_data *drv = bss->drv;
+    struct ifreq ifr;
+    struct wpa_supplicant *wpa_s = NULL;
+    struct hostapd_data *hapd;
+    int handled = 0;
+    int cmd_len = 0;
+    union wpa_event_data event;
+    static int user_force_band = 0;
+    int ret = -1;
+
+    if (drv == NULL) {
+        wpa_printf(MSG_ERROR, "%s: drv is NULL, exit", __func__);
+        return -1;
+    }
+    if (drv->ctx == NULL) {
+        wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL, exit", __func__);
+        return -1;
+    }
+
+    if (bss->drv->nlmode == NL80211_IFTYPE_AP) {
+        hapd = (struct hostapd_data *)(drv->ctx);
+    }
+    else {
+        wpa_s = (struct wpa_supplicant *)(drv->ctx);
+        if (wpa_s->conf == NULL) {
+            wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL, exit", __func__);
+            return -1;
+        }
+    }
+
+    wpa_printf(MSG_INFO, "%s: %s recv cmd %s", __func__, bss->ifname, cmd);
+    handled = 0;
+
+    if (os_strncasecmp(cmd, "PRESET_LINKID=", os_strlen("PRESET_LINKID=")) == 0) {
+        wpa_printf(MSG_DEBUG, "%s", cmd);
+		if (mtk_set_mlo_preset_link_id(priv, cmd) != 0) {
+			wpa_printf(MSG_ERROR, "%s: mtk_set_mlo_preset_link_id fail.", __func__);
+            return -1;
+		}
+	}else {
+		wpa_printf(MSG_ERROR, "%s command not supported.", cmd);
+	}
+    return ret;
+}
+
+
+
+void mtk_nl80211_mlo_response_event(struct wpa_driver_nl80211_data *drv,
+                u8 *data, size_t data_len)
+{
+    const u8 *end, *pos;
+
+    wpa_hexdump(MSG_INFO, "nl80211: mtk generic_response_event", data, data_len);
+
+    pos = data;
+    end = data + data_len;
+    while (end - pos >= 2) {
+        u8 id, len;
+
+        id = *pos++;
+        len = *pos++;
+        if (len > end - pos)
+            break;
+
+        switch (id) {
+        /* add cases for different event id here */
+        case MTK_GRID_MLO_EXTERNAL_AUTH:
+        {
+             struct mtk_externa_auth_info *info =
+                 (struct mtk_externa_auth_info *) pos;
+             union wpa_event_data event;
+             enum nl80211_external_auth_action act;
+
+             os_memset(&event, 0, sizeof(event));
+             act = info->action;
+             switch (act) {
+             case NL80211_EXTERNAL_AUTH_START:
+                     event.external_auth.action = EXT_AUTH_START;
+                     break;
+             case NL80211_EXTERNAL_AUTH_ABORT:
+                     event.external_auth.action = EXT_AUTH_ABORT;
+                     break;
+             default:
+                     return;
+             }
+
+             event.external_auth.key_mgmt_suite = info->key_mgmt_suite;
+             event.external_auth.ssid_len = info->ssid_len;
+             if (event.external_auth.ssid_len > SSID_MAX_LEN)
+                     return;
+             event.external_auth.ssid = info->ssid;
+             event.external_auth.bssid = info->bssid;
+#ifdef CONFIG_MTK_IEEE80211BE
+             event.external_auth.ext_ie = info->ext_ie;
+             event.external_auth.ext_ie_len = len - sizeof(*info);
+#endif /* CONFIG_MTK_IEEE80211BE */
+             wpa_printf(MSG_DEBUG,
+                        "nl80211: mtk external auth action: %u, AKM: 0x%x, bssid["MACSTR"], da["MACSTR"]",
+                        event.external_auth.action,
+                        event.external_auth.key_mgmt_suite,
+                        MAC2STR(info->bssid),
+                        MAC2STR(info->da));
+             wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event);
+        }
+             break;
+        default:
+            wpa_printf(MSG_DEBUG, "unknown generic response: %d", id);
+            break;
+        }
+        pos += len;
+    }
+}
+
+static void mtk_ml80211_bss_ml_info_event(struct wpa_driver_nl80211_data *drv, struct i802_bss *bss,
+					u8 *data, size_t len)
+{
+	union wpa_event_data *event = nla_data((struct nlattr *)data);
+
+	if (event)
+		wpa_supplicant_event(bss->ctx, EVENT_UPDATE_BSS_ML_INFO, event);
+}
+
+void mtk_nl80211_mlo_sta_profile_event(struct wpa_driver_nl80211_data *drv,
+                u8 *data, size_t data_len)
+{
+	const u8 *end, *pos;
+	u16 sta_ctrl;
+	u8 i = 0;
+	struct per_sta_profile profile[ML_MAX_LINK_NUM];
+	union wpa_event_data event;
+
+    wpa_hexdump(MSG_INFO, "nl80211: mtk_nl80211_mlo_sta_profile_event", data, data_len);
+	wpa_hexdump(MSG_MSGDUMP, "Per-STA Profile sub-IE", data, data_len);
+
+	pos = data;
+    end = data + data_len;
+
+	/* skip event header */
+	pos += 4;
+
+	/* pos point to link info, recusive parse it */
+	while (pos < end) {
+		u8 sta_info_len;
+		const u8 *head, *tail;
+
+		if (*pos != ML_SUB_ID_PER_STA_PROFILE)
+			break;
+
+		head = pos + 2;
+		tail = head + pos[1];
+		pos += 2;
+		sta_ctrl = WPA_GET_LE16(pos);
+		pos += 2;
+
+		profile[i].link_id = sta_ctrl & ML_STA_CTRL_LINK_ID_MASK;
+		profile[i].complete_profile =
+			(sta_ctrl & ML_STA_CTRL_COMPLETE_PROFILE) > 0;
+
+		wpa_printf(MSG_INFO, "ML: LinkID=%d Ctrl=0x%x(%s)",
+			profile[i].link_id, sta_ctrl,
+			profile[i].complete_profile ? "COMPLETE" : "PARTIAL");
+
+		sta_info_len = *pos++;
+
+		if (sta_ctrl & ML_STA_CTRL_MAC_ADDR_PRESENT) {
+			os_memcpy(profile[i].addr, pos, ETH_ALEN);
+			profile[i].mac_addr_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, LinkAddr="MACSTR"",
+				profile[i].link_id, MAC2STR(profile[i].addr));
+			pos += ETH_ALEN;
+		}
+		if (sta_ctrl & ML_STA_CTRL_BCN_INTV_PRESENT) {
+			profile[i].beacon_interval = WPA_GET_LE16(pos);
+			profile[i].bcn_intvl_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, BCN_INTV = %d",
+				profile[i].link_id, profile[i].beacon_interval);
+			pos += 2;
+		}
+		if (sta_ctrl & ML_STA_CTRL_DTIM_INFO_PRESENT) {
+			profile[i].dtim = WPA_GET_LE16(pos);
+			profile[i].dtim_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, DTIM_INFO = 0x%x",
+				profile[i].link_id, profile[i].dtim);
+			pos += 2;
+		}
+		/* If the Complete Profile subfield = 1 and
+		 * NSTR Link Pair Present = 1, then NSTR Indication Bitmap exist
+		 * NSTR Bitmap Size = 1 if the length of the corresponding
+		 * NSTR Indication Bitmap is 2 bytes, and = 0 if the
+		 * length of the corresponding NSTR Indication Bitmap = 1 byte
+		 */
+		if ((sta_ctrl & ML_STA_CTRL_COMPLETE_PROFILE) &&
+			(sta_ctrl & ML_STA_CTRL_NSTR_LINK_PAIR_PRESENT)) {
+			if (((sta_ctrl & ML_STA_CTRL_NSTR_BMP_SIZE) >>
+				ML_STA_CTRL_NSTR_BMP_SIZE_SHIFT) == 0) {
+				profile[i].nstr_bmap = *pos;
+				wpa_printf(MSG_INFO, "ML: LinkID=%d, NSTR_BMP0=0x%x",
+					profile[i].link_id, profile[i].nstr_bmap);
+				pos += 1;
+			} else {
+				profile[i].nstr_bmap = WPA_GET_LE16(pos);
+				wpa_printf(MSG_INFO, "ML: LinkID=%d, NSTR_BMP1=0x%x",
+					profile[i].link_id, profile[i].nstr_bmap);
+				pos += 2;
+			}
+			profile[i].nstr_present = 1;
+		}
+		if (pos - (head + 2) != sta_info_len) {
+			wpa_printf(MSG_INFO, "ML: invalid ML STA info len = %d",
+				sta_info_len);
+		}
+
+		os_memcpy(&event.profiles[i], &profile[i], sizeof(struct per_sta_profile));
+
+		/* point to next Per-STA profile*/
+		pos = tail;
+		i++;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_UPDATE_STA_PROFILE_UPDATE, &event);
+}
+
+
+void nl80211_vendor_event_mtk(struct wpa_driver_nl80211_data *drv, struct i802_bss *bss,
+                  u32 subcmd, u8 *data, size_t len)
+{
+    switch (subcmd) {
+		case MTK_NL80211_VENDOR_EVENT_SEND_ML_INFO:
+			mtk_ml80211_bss_ml_info_event(drv, bss, data, len);
+			break;
+	    case MTK_NL80211_VENDOR_EVENT_MLO_EVENT:
+			wpa_printf(MSG_INFO,
+	            "nl80211: MTK_NL80211_VENDOR_EVENT_MLO_EVENT event %u", subcmd);
+	        mtk_nl80211_mlo_response_event(drv, data, len);
+	        break;
+		case MTK_NL80211_VENDOR_EVENT_STA_PROFILE_EVENT:
+			wpa_printf(MSG_INFO,
+	            "nl80211: MTK_NL80211_VENDOR_EVENT_STA_PROFILE_EVENT event %u", subcmd);
+	        mtk_nl80211_mlo_sta_profile_event(drv, data, len);
+	        break;
+	    default:
+	        wpa_printf(MSG_ERROR,
+	            "nl80211:Ignore unsupported mtk vendor event %u, MTK_NL80211_VENDOR_EVENT_MLO_EVENT(%u)",
+	            subcmd, MTK_NL80211_VENDOR_EVENT_MLO_EVENT);
+	        break;
+    }
+}
+
+
+
Index: hostapd-2022-07-29-b704dc72/src/drivers/mediatek_driver_nl80211.h
===================================================================
--- /dev/null
+++ hostapd-2022-07-29-b704dc72/src/drivers/mediatek_driver_nl80211.h
@@ -0,0 +1,50 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef _MTK_DRIVER_NL80211_H_
+#define _MTK_DRIVER_NL80211_H_
+
+#include <linux/wireless.h>
+
+#ifndef BITS
+/* Eddie */
+/* bits range: for example BITS(16,23) = 0xFF0000
+ *   ==>  (BIT(m)-1)   = 0x0000FFFF     ~(BIT(m)-1)   => 0xFFFF0000
+ *   ==>  (BIT(n+1)-1) = 0x00FFFFFF
+ */
+#define BITS(m,n)                       (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n)))
+#endif /* BIT */
+#ifndef OUI_MTK
+#define OUI_MTK 0x000CE7
+#endif
+extern void nl80211_vendor_event_mtk(struct wpa_driver_nl80211_data *, struct i802_bss *, u32, u8 *, size_t);
+enum mtk_generic_response_element {
+    MTK_GRID_MLO_EXTERNAL_AUTH = 1,                         /* 1 */
+};
+
+struct mtk_externa_auth_info {
+    uint8_t ssid[SSID_MAX_LEN + 1];
+    uint8_t ssid_len;
+    uint8_t bssid[ETH_ALEN];
+    uint32_t key_mgmt_suite;
+    uint32_t action;
+    uint8_t da[ETH_ALEN];
+    uint8_t ext_ie[0];
+} STRUCT_PACKED;
+#endif
+
Index: hostapd-2022-07-29-b704dc72/src/ml/ml_common.c
===================================================================
--- /dev/null
+++ hostapd-2022-07-29-b704dc72/src/ml/ml_common.c
@@ -0,0 +1,1172 @@
+/*******************************************************************************
+ *
+ * This file is provided under a dual license.  When you use or
+ * distribute this software, you may choose to be licensed under
+ * version 2 of the GNU General Public License ("GPLv2 License")
+ * or BSD License.
+ *
+ * GPLv2 License
+ *
+ * Copyright(C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(C) 2016 MediaTek Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#include "includes.h"
+
+#include "common.h"
+
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/sae.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_i.h"
+#include "rsn_supp/wpa_ie.h"
+#include "ap/wpa_auth.h"
+#include "ap/wpa_auth_i.h"
+#include "ap/wpa_auth_ie.h"
+#include "ap/hostapd.h"
+#include "crypto/random.h"
+#include "utils/eloop.h"
+#include "ml/ml_common.h"
+
+
+#define STATE_MACHINE_ML_GROUP \
+	(((struct hostapd_data *)sm->wpa_auth->cb_ctx)->ml_group)
+#define STATE_MACHINE_ML_GROUP_ADDR \
+	(((struct hostapd_data *)sm->wpa_auth->cb_ctx)->ml_group)->ml_addr
+
+/* common */
+
+
+u8* ml_set_mac_kde(u8 *pos, const unsigned char *addr)
+{
+	if (addr == NULL)
+		return pos;
+
+	return wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, addr, ETH_ALEN, NULL, 0);
+}
+
+u8* ml_set_ml_link_kde(u8 *pos, u8 link_id, const unsigned char *addr,
+	const u8 *rsne, size_t rsne_len, const u8 *rsnxe, size_t rsnxe_len)
+{
+	u8 i;
+	u8 *buf, *cp, *ori;
+	size_t len = 1 /* Link Information */ + ETH_ALEN + rsne_len + rsnxe_len;
+
+	cp = buf = os_malloc(len);
+	os_memset(cp, 0, len);
+	*cp = link_id & BITS(0, 3);
+	if (rsne && rsne_len)
+		*cp |= BIT(4);
+	if (rsnxe && rsnxe_len)
+		*cp |= BIT(5);
+	cp++;
+	os_memcpy(cp, addr, ETH_ALEN);
+	cp += ETH_ALEN;
+
+	if (rsne && rsne_len) {
+		os_memcpy(cp, rsne, rsne_len);
+		cp += rsne_len;
+	}
+
+	if (rsnxe && rsnxe_len) {
+		os_memcpy(cp, rsnxe, rsnxe_len);
+		cp += rsnxe_len;
+	}
+
+	ori = pos;
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MLO_LINK, buf, cp - buf, NULL, 0);
+	wpa_hexdump(MSG_DEBUG, "ML: Link KDE", ori, pos - ori);
+
+	os_free(buf);
+
+	return pos;
+}
+
+int ml_parse_ie(const u8 *ie, size_t len, struct wpa_ml_ie_parse *ml, u8 *bssid)
+{
+	const u8 *pos, *end, *ci_end, *info_end;;
+	u16 ml_ctrl;
+	size_t ci_len = 0;
+
+	wpa_hexdump(MSG_DEBUG, "ML IE", ie, len);
+
+	os_memset(ml, 0, sizeof(*ml));
+	pos = ie + 2; /* skip common ctrl */
+	end = ie + len;
+	if (pos > end)
+		return -1;
+
+	ml_ctrl = WPA_GET_LE16(ie);
+	ml->type = ml_ctrl & ML_CTRL_TYPE_MASK;
+	if (ml->type != ML_CTRL_TYPE_BASIC) {
+		wpa_printf(MSG_INFO, "ML: invalid ML control type = %d",
+			ml->type);
+		return -1;
+	}
+	/*common info*/
+	/*pso:common info mini len check*/
+	if (end - pos < 1) {
+		wpa_printf(MSG_ERROR, "ML: No room for common info");
+		return -1;
+	}
+	/*pso: common info len check.*/
+	ci_len = *pos;
+	if (ci_len > end - pos) {
+		wpa_printf(MSG_ERROR, "ML: Truncated Multi-Link Common Info (len=%zu left=%zu)",
+			   ci_len, (size_t) (end - pos));
+		return -1;
+	}
+	/*pso: common info header mini len check*/
+	if (ci_len < 1 + ETH_ALEN) {
+		wpa_printf(MSG_ERROR, "ML: No room for MLD MAC Address in Multi-Link Common Info");
+		return -1;
+	}
+	ci_end = pos + ci_len;
+
+	ml->common_info_len = *pos++;
+
+	wpa_printf(MSG_INFO, "ML: common Info Len = %d", ml->common_info_len);
+
+	/* Check ML control that which common info exist */
+	os_memcpy(ml->ml_addr, pos, ETH_ALEN);
+	pos += ETH_ALEN;
+	wpa_printf(MSG_INFO, "ML: common Info MAC addr = "MACSTR"",
+		MAC2STR(ml->ml_addr));
+
+	if (ml_ctrl & ML_CTRL_LINK_ID_INFO_PRESENT) {
+		if (ci_end - pos < 1) {
+			wpa_printf(MSG_ERROR, "No room for Link ID Info in Multi-Link Common Info");
+			return -1;
+		}
+		ml->link_id = *pos;
+		ml->link_id_present = 1;
+		wpa_printf(MSG_INFO, "ML: common Info LinkID = %d", ml->link_id);
+		pos += 1;
+	}
+	if (ml_ctrl & ML_CTRL_BSS_PARA_CHANGE_COUNT_PRESENT) {
+		if (ci_end - pos < 1) {
+			wpa_printf(MSG_ERROR,
+				   "No room for BSS Parameters Change Count in Multi-Link Common Info");
+			return -1;
+		}
+		ml->bss_para_change_count = *pos;
+		ml->bss_para_change_cnt_present = 1;
+		wpa_printf(MSG_INFO, "ML: common Info BssParaChangeCount = %d", *pos);
+		pos += 1;
+	}
+	if (ml_ctrl & ML_CTRL_MEDIUM_SYN_DELAY_INFO_PRESENT) {
+		if (ci_end - pos < 2) {
+			wpa_printf(MSG_ERROR,
+				   "No room for Medium Synchronization Delay Information in Multi-Link Common Info");
+			return -1;
+		}
+		ml->medium_sync_delay = WPA_GET_LE16(pos);
+		ml->medium_sync_delay_present = 1;
+		wpa_printf(MSG_INFO, "ML: common Info MediumSynDelayInfo = %d", *pos);
+		pos += 2;
+	}
+	if (ml_ctrl & ML_CTRL_EML_CAPA_PRESENT) {
+		if (ci_end - pos < 2) {
+			wpa_printf(MSG_ERROR,
+				   "No room for EML Capabilities in Multi-Link Common Info");
+			return -1;
+		}
+		ml->eml_cap = WPA_GET_LE16(pos);
+		ml->eml_cap_present = 1;
+		wpa_printf(MSG_INFO, "ML: common Info EML capa = 0x%x", ml->eml_cap);
+		pos += 2;
+	}
+	if (ml_ctrl & ML_CTRL_MLD_CAPA_PRESENT) {
+		if (ci_end - pos < 2) {
+			wpa_printf(MSG_ERROR,
+				   "No room for MLD Capabilities and Operations in Multi-Link Common Info");
+			return -1;
+		}
+		ml->mld_cap = WPA_GET_LE16(pos);
+		ml->mld_cap_present = 1;
+		wpa_printf(MSG_INFO, "ML: common Info MLD capa = 0x%x", ml->mld_cap);
+		pos += 2;
+	}
+	if (ml_ctrl & ML_CTRL_MLD_ID_PRESENT) {
+		if (ci_end - pos < 1) {
+			wpa_printf(MSG_ERROR,
+				   "No room for AP MLD ID in Multi-Link Common Info");
+			return -1;
+		}
+		ml->mld_id = *pos;
+		ml->mld_id_present = 1;
+		wpa_printf(MSG_INFO, "ML:common Info MLD id = %d", ml->mld_id);
+		pos += 1;
+	}
+
+	if (pos - (ie + 2) != ml->common_info_len) {
+		ml->valid = false;
+		wpa_printf(MSG_INFO, "ML: invalid ML control info len = %d",
+			ml->common_info_len);
+		return -1;
+	} else {
+		ml->valid = true;
+	}
+
+	/* pos point to link info, recusive parse it */
+	while (pos < end) {
+		u16 sta_ctrl;
+		struct per_sta_profile *profile;
+		u8 sta_info_len;
+		const u8 *head, *tail;
+		u8 frag_flag = 0;
+
+		if (*pos != ML_SUB_ID_PER_STA_PROFILE ||
+			ml->prof_num >= ML_MAX_LINK_NUM)
+			break;
+
+		head = pos + 2;
+		tail = head + pos[1];
+		/*pso: subtvl mini length check.*/
+		if (head > tail) {
+			wpa_printf(MSG_ERROR, "ML: Truncated Per-STA Profile subelement");
+			continue;
+		}
+
+		if (pos[1] == 255)
+			frag_flag = 1;
+		pos += 2;
+		sta_ctrl = WPA_GET_LE16(pos);
+		pos += 2;
+		/*pso: left data len check*/
+		if (tail - pos < 1) {
+			wpa_printf(MSG_ERROR, "ML: No room for STA Info field");
+			continue;
+		}
+		/*pso: sta info len check */
+		ci_len = *pos;
+		if (ci_len < 1 || ci_len > tail - pos) {
+			wpa_printf(MSG_INFO, "ML: faild Truncated STA Info field(ci_len: %zu, tail - pos: %lu)",
+				ci_len, tail - pos);
+			continue;
+		}
+		info_end = pos + ci_len;
+
+		profile = &ml->profiles[ml->prof_num++];
+		profile->link_id = sta_ctrl & ML_STA_CTRL_LINK_ID_MASK;
+		profile->complete_profile =
+			(sta_ctrl & ML_STA_CTRL_COMPLETE_PROFILE) > 0;
+
+		wpa_printf(MSG_INFO, "ML: LinkID=%d Ctrl=0x%x(%s) Total=%d",
+			profile->link_id, sta_ctrl,
+			profile->complete_profile ? "COMPLETE" : "PARTIAL",
+			ml->prof_num);
+
+		sta_info_len = *pos++;
+
+		if (sta_ctrl & ML_STA_CTRL_MAC_ADDR_PRESENT) {
+			if (info_end - pos < ETH_ALEN) {
+				wpa_printf(MSG_ERROR,
+					   "ML: Truncated STA MAC Address in STA Info");
+				continue;
+			}
+			os_memcpy(profile->addr, pos, ETH_ALEN);
+			profile->mac_addr_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, LinkAddr="MACSTR"",
+				profile->link_id, MAC2STR(profile->addr));
+			pos += ETH_ALEN;
+		}
+		if (sta_ctrl & ML_STA_CTRL_BCN_INTV_PRESENT) {
+			if (info_end - pos < 2) {
+				wpa_printf(MSG_INFO,
+					   "ML:Truncated Beacon Interval in STA Info");
+				continue;
+			}
+			profile->beacon_interval = WPA_GET_LE16(pos);
+			profile->bcn_intvl_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, BCN_INTV = %d",
+				profile->link_id, profile->beacon_interval);
+			pos += 2;
+		}
+		if (sta_ctrl & ML_STA_CTRL_TSF_OFFSET_PRESENT) {
+			if (info_end - pos < 8) {
+				wpa_printf(MSG_INFO,
+					   "ML: Truncated TSF Offset in STA Info");
+				continue;
+			}
+			os_memcpy(&profile->tsf_offset, pos, 8);
+			profile->tsf_offset_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, TSF_OFFSET = %lu",
+				profile->link_id, profile->tsf_offset);
+			pos += 8;
+		}
+		if (sta_ctrl & ML_STA_CTRL_DTIM_INFO_PRESENT) {
+			if (info_end - pos < 2) {
+				wpa_printf(MSG_INFO,
+					   "ML:Truncated TSF Offset in STA Info");
+				continue;
+			}
+			profile->dtim = WPA_GET_LE16(pos);
+			profile->dtim_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, DTIM_INFO = 0x%x",
+				profile->link_id, profile->dtim);
+			pos += 2;
+		}
+		/* If the Complete Profile subfield = 1 and
+		 * NSTR Link Pair Present = 1, then NSTR Indication Bitmap exist
+		 * NSTR Bitmap Size = 1 if the length of the corresponding
+		 * NSTR Indication Bitmap is 2 bytes, and = 0 if the
+		 * length of the corresponding NSTR Indication Bitmap = 1 byte
+		 */
+		if ((sta_ctrl & ML_STA_CTRL_COMPLETE_PROFILE) &&
+			(sta_ctrl & ML_STA_CTRL_NSTR_LINK_PAIR_PRESENT)) {
+			if (((sta_ctrl & ML_STA_CTRL_NSTR_BMP_SIZE) >>
+				ML_STA_CTRL_NSTR_BMP_SIZE_SHIFT) == 0) {
+				if (info_end - pos < 1) {
+					wpa_printf(MSG_INFO,
+						   "ML: Truncated NSTR Indication Bitmap in STA Info");
+					continue;
+				}
+				profile->nstr_bmap = *pos;
+				wpa_printf(MSG_INFO, "ML: LinkID=%d, NSTR_BMP0=0x%x",
+					profile->link_id, profile->nstr_bmap);
+				pos += 1;
+			} else {
+				if (info_end - pos < 2) {
+					wpa_printf(MSG_INFO,
+						   "ML:Truncated NSTR Indication Bitmap in STA Info");
+					continue;
+				}
+				profile->nstr_bmap = WPA_GET_LE16(pos);
+				wpa_printf(MSG_INFO, "ML: LinkID=%d, NSTR_BMP1=0x%x",
+					profile->link_id, profile->nstr_bmap);
+				pos += 2;
+			}
+			profile->nstr_present = 1;
+		}
+		if (sta_ctrl & ML_STA_CTRL_BSS_CHG_CNT_PRESENT) {
+			if (info_end - pos < 1) {
+				wpa_printf(MSG_INFO,
+					   "ML:Truncated BSS Parameters Change Count in STA Info");
+				continue;
+			}
+			profile->bss_para_change_count = *pos;
+			profile->bss_para_change_count_present = 1;
+			wpa_printf(MSG_INFO, "ML: LinkID=%d, BSS_CHG_CNT = %d",
+				profile->link_id, profile->bss_para_change_count);
+			pos += 1;
+		}
+		if (pos - (head + 2) != sta_info_len) {
+			wpa_printf(MSG_WARNING, "ML: invalid ML STA info len = %d",
+				sta_info_len);
+			ml->prof_num--;
+		}
+
+		/* point to next Per-STA profile*/
+		pos = tail;
+
+		/* process sta profile subelement fragments, skip other information
+		 * because we do not need them.
+		 */
+		while (frag_flag && (pos + 1) < end) {
+			u8 frag_len = 0;
+
+			if (*pos != 254) {
+				wpa_printf(MSG_INFO,
+					"ML: invalid sta profile FragID(254) %d", *pos);
+				break;
+			}
+			frag_len = *(pos + 1);
+			frag_flag = frag_len == 255 ? 1 : 0;
+			pos += frag_len + 2;
+		}
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_SAE
+int ml_sae_process_auth(struct sae_data *sae, u16 auth_transaction,
+	const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+	struct wpa_ml_ie_parse ml;
+	struct wpabuf *frag_ml_ie = NULL;
+	const u8 *ml_ie;
+	size_t ml_ie_len = 0;
+
+	if (!sae)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "ML: SAE Possible elements at the end of the frame");
+	wpa_hexdump(MSG_DEBUG, "ML: SAE Possible elements at the end of the frame",
+			    ies, ies_len);
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "ML: SAE failed to parse elements");
+		return -1;
+	}
+
+	frag_ml_ie = ieee802_11_defrag(&elems,
+					 WLAN_EID_EXTENSION,
+					 WLAN_EID_EXT_MULTI_LINK);
+
+	if (!frag_ml_ie) {
+		wpa_printf(MSG_DEBUG, "ML: Missing frag_ml_ie");
+		ml_ie = elems.ml;
+		ml_ie_len = (size_t)elems.ml_len;
+	} else {
+		ml_ie_len = (size_t)wpabuf_len(frag_ml_ie);
+		ml_ie = wpabuf_head_u8(frag_ml_ie);
+
+		wpa_hexdump(MSG_DEBUG, "Multi-link IE defrag results:",
+			ml_ie, ml_ie_len);
+	}
+
+	if (auth_transaction == 1) {
+		os_free(sae->peer_ml_ie);
+		if (!ml_ie) {
+			wpa_printf(MSG_DEBUG, "ML: SAE clearing STA ML IE");
+			sae->peer_ml_ie = NULL;
+			sae->dot11MultiLinkActivated = 0;
+		} else {
+			if (ml_parse_ie(ml_ie, ml_ie_len, &ml, NULL) != 0) {
+				sae->peer_ml_ie = NULL;
+				sae->dot11MultiLinkActivated = 0;
+				if (frag_ml_ie)
+					wpabuf_free(frag_ml_ie);
+				return -1;
+			} else {
+				sae->peer_ml_ie = os_memdup(&ml, sizeof(ml));
+				if (sae->peer_ml_ie == NULL) {
+					sae->dot11MultiLinkActivated = 0;
+					if (frag_ml_ie)
+						wpabuf_free(frag_ml_ie);
+					return -1;
+				}
+				os_memcpy(sae->peer_ml_addr, ml.ml_addr, ETH_ALEN);
+				sae->dot11MultiLinkActivated = 1;
+			}
+		}
+	} else if (auth_transaction == 2) {
+		if (sae->dot11MultiLinkActivated && !ml_ie) {
+			wpa_printf(MSG_ERROR, "ML: SAE confirm should have ml ie");
+			if (frag_ml_ie)
+				wpabuf_free(frag_ml_ie);
+			return -1;
+		} else if (!sae->dot11MultiLinkActivated && ml_ie) {
+			wpa_printf(MSG_ERROR, "ML: SAE confirm should not have ml ie");
+			if (frag_ml_ie)
+				wpabuf_free(frag_ml_ie);
+			return -1;
+		}
+
+		if (ml_ie) {
+			if (ml_parse_ie(ml_ie, ml_ie_len, &ml, NULL) != 0) {
+				wpa_printf(MSG_ERROR, "ML: SAE confirm failed to parse ml ie");
+				if (frag_ml_ie)
+					wpabuf_free(frag_ml_ie);
+				return -1;
+			} else if (os_memcmp(sae->peer_ml_ie->ml_addr, ml.ml_addr, ETH_ALEN) != 0) {
+				wpa_printf(MSG_DEBUG,
+					"ML: SAE trans = %d, mismatch ML addr (peer="MACSTR", recv="MACSTR")",
+					auth_transaction, MAC2STR(sae->peer_ml_ie->ml_addr), MAC2STR(ml.ml_addr));
+				if (frag_ml_ie)
+					wpabuf_free(frag_ml_ie);
+				return -1;
+			}
+		}
+	} else {
+		wpa_printf(MSG_DEBUG,
+		       "ML: unexpected SAE authentication transaction %u",
+		       auth_transaction);
+		if (frag_ml_ie)
+			wpabuf_free(frag_ml_ie);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "(%s)[%d]ML: dot11MultiLinkActivated(%d). own_ml_addr"MACSTR", peer_ml_addr"MACSTR"",
+		__func__, __LINE__, sae->dot11MultiLinkActivated, MAC2STR(sae->own_ml_addr),MAC2STR(sae->peer_ml_addr));
+	if (frag_ml_ie)
+		wpabuf_free(frag_ml_ie);
+	return 0;
+}
+
+int ml_sae_write_auth(struct hostapd_data *hapd,
+		      struct sae_data *sae, struct wpabuf *buf)
+{
+	u16 ctrl = 0;
+	size_t i;
+
+	if (!sae || !sae->dot11MultiLinkActivated || !hapd || !hapd->ml_group)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "ML: write ml ie for sae auth");
+
+	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+	/* extid: 1, common ctrl: 2, common info: 7(len:1, mac:6) */
+	wpabuf_put_u8(buf, 10);
+	wpabuf_put_u8(buf, WLAN_EID_EXT_MLD);
+
+	/* ml common control */
+	ML_SET_CTRL_TYPE(ctrl, ML_CTRL_TYPE_BASIC);
+
+	/* A Basic Multi-Link element in an Authentication frame:
+	 * the STA shall include the MLD MAC address of the MLD
+	 * the STA shall set all subfields in the Presence Bitmap subfield of
+	 * the Multi-Link Control field of the element to 0
+	 * the STA shall not include the Link Info field of the element.
+	 */
+	ML_SET_CTRL_PRESENCE(ctrl, 0);
+	wpabuf_put_le16(buf, ctrl);
+
+	/* len:1, mac:6 */
+	wpabuf_put_u8(buf, 7);
+
+	/* ml mac addr */
+	wpabuf_put_data(buf, hapd->ml_group->ml_addr, ETH_ALEN);
+
+	return 0;
+}
+#endif /* CONFIG_SAE */
+
+
+
+/* AP */
+const u8 * ml_auth_spa(struct wpa_state_machine *sm, const u8 *peer_addr)
+{
+	if(sm && peer_addr && sm->dot11MultiLinkActivated) {
+		if (os_memcmp(peer_addr, sm->sta_ml_ie->ml_addr, ETH_ALEN) != 0) {
+			wpa_printf(MSG_INFO,
+				"ML: SPA[" MACSTR "] use ml addr[" MACSTR "]",
+				MAC2STR(peer_addr), MAC2STR(sm->sta_ml_ie->ml_addr));
+			return sm->sta_ml_ie->ml_addr;
+		}
+	}
+
+	return peer_addr;
+}
+
+const u8 * ml_auth_aa(struct wpa_state_machine *sm, const u8 *addr)
+{
+	if(sm && addr && sm->dot11MultiLinkActivated) {
+		struct wpa_ml_group *ml_group = STATE_MACHINE_ML_GROUP;
+
+		if (ml_group && os_memcmp(ml_group->ml_addr, addr, ETH_ALEN) != 0) {
+			wpa_printf(MSG_INFO,
+				"ML: AA[" MACSTR "] use ml addr[" MACSTR "]",
+				MAC2STR(addr), MAC2STR(ml_group->ml_addr));
+			return ml_group->ml_addr;
+		}
+	}
+
+	return addr;
+}
+
+/* AP */
+struct wpa_ml_link * ml_setup_link(struct hostapd_data *hapd,
+	struct wpa_ml_group *ml_group, u8 link_id)
+{
+	struct wpa_ml_link *links, *link;
+
+	links = os_realloc_array(ml_group->links, ml_group->ml_link_num + 1,
+				 sizeof(struct wpa_ml_link));
+	if (links == NULL || hapd == NULL) {
+		wpa_printf(MSG_ERROR, "ML: links alloc fail");
+		return NULL;
+	}
+	ml_group->links = links;
+	link = &links[ml_group->ml_link_num++];
+	link->ctx = hapd;
+	link->link_id = link_id;
+	os_memcpy(link->addr, hapd->own_addr, ETH_ALEN);
+	hapd->ml_group = ml_group;
+
+	wpa_printf(MSG_INFO, "ML: Join ML Group=%p, link_id=%d, ml_group->ml_link_num=%lu", ml_group, link_id, ml_group->ml_link_num);
+
+	return link;
+}
+
+struct wpa_ml_group *ml_alloc_group(struct hostapd_data *hapd,
+				    u8 group_id, u8 *mld_addr)
+{
+	struct wpa_ml_group *ml_group = NULL;
+	struct wpa_ml_link *link;
+	u8 i;
+
+	ml_group = os_zalloc(sizeof(*ml_group));
+	if (ml_group == NULL) {
+		wpa_printf(MSG_ERROR, "ML: ml_group alloc fail");
+		return NULL;
+	}
+
+	ml_group->ctx = hapd;
+	os_memcpy(ml_group->ml_addr, mld_addr, ETH_ALEN);
+	ml_group->ml_group_id = group_id;
+
+	wpa_printf(MSG_INFO,
+		"ML: Alloc ML Group=%p (ml_group_id=%d, ml_addr=" MACSTR ")",
+		ml_group, group_id, MAC2STR(ml_group->ml_addr));
+
+	return ml_group;
+}
+
+struct wpa_ml_group * ml_get_group(struct hapd_interfaces *interfaces,
+				u8 group_id)
+{
+	size_t i, j;
+
+	/* search interfaces to find existed ml group */
+	for (i = 0; i < interfaces->count; i++) {
+		struct hostapd_iface *iface = interfaces->iface[i];
+
+		for (j = 0; j < iface->num_bss; j++) {
+			struct hostapd_data *hapd = iface->bss[j];
+
+			if (hapd->ml_group &&
+			    hapd->ml_group->ml_group_id == group_id) {
+				return hapd->ml_group;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+int ml_group_init(struct hostapd_data *hapd,
+		u8 mld_grp_idx, u8 link_id, u8 *mld_addr)
+{
+	struct hapd_interfaces *interfaces = hapd->iface->interfaces;
+	struct wpa_ml_group *ml_group = NULL;
+	struct wpa_ml_link *link;
+	u8 i;
+
+	wpa_printf(MSG_INFO, "ML: " MACSTR " ml_group_init, ml_group_id=%d",
+			MAC2STR(hapd->own_addr), mld_grp_idx);
+
+	if (!interfaces)
+		goto done;
+
+	ml_group = ml_get_group(interfaces, mld_grp_idx);
+
+	/* found, join it */
+	if (ml_group) {
+		/* error check */
+		for (i = 0; i < ml_group->ml_link_num; i++) {
+			link = &ml_group->links[i];
+			if (link->ctx == hapd) {
+				wpa_printf(MSG_INFO, "ML: reinit link");
+				return -1;
+			}
+		}
+		wpa_printf(MSG_INFO, "ML: group has created,join it");
+		if (ml_setup_link(hapd, ml_group, link_id) == NULL)
+			return -1;
+	} else {
+		ml_group = ml_alloc_group(hapd, mld_grp_idx, mld_addr);
+		if (ml_group == NULL)
+			return -1;
+		wpa_printf(MSG_INFO, "ML: creat group");
+		if (ml_setup_link(hapd, ml_group, link_id) == NULL) {
+			os_free(ml_group);
+			return -1;
+		}
+	}
+
+done:
+	return 0;
+}
+
+int ml_group_deinit(struct hostapd_data *hapd)
+{
+	struct wpa_ml_group *ml_group = hapd->ml_group;
+	struct wpa_ml_link *link;
+	size_t i, k = 0;
+
+	if (!ml_group)
+		return -1;
+
+	for (i = 0; i < ml_group->ml_link_num; i++) {
+		link = &ml_group->links[i];
+		if (link == NULL)
+			continue;
+
+		if (link->ctx == hapd) {
+			wpa_printf(MSG_INFO, "Remove link %d", link->link_id);
+			k = i;
+			while (k < (ml_group->ml_link_num - 1)) {
+				os_memcpy(&ml_group->links[k],
+					&ml_group->links[k + 1], sizeof(*link));
+				k++;
+			}
+			ml_group->ml_link_num--;
+		}
+	}
+
+	/* free ml group by ml group owner */
+	if (ml_group->ctx == hapd) {
+		for (i = 0; i < ml_group->ml_link_num; i++) {
+			link = &ml_group->links[i];
+			if (link == NULL)
+				continue;
+			wpa_printf(MSG_INFO, "ML: free sub link interface hapd:%p->ml group:%p", link->ctx, ((struct hostapd_data *)link->ctx)->ml_group);
+			((struct hostapd_data *)link->ctx)->ml_group = NULL;  /*set other link's hapd->ml_group == NULL*/
+		}
+		os_free(ml_group->links);
+		os_free(ml_group);
+	}
+	hapd->ml_group = NULL;
+
+	return 0;
+}
+
+u8 ml_get_link_id(struct wpa_state_machine *sm)
+{
+	struct wpa_ml_group *ml_group = STATE_MACHINE_ML_GROUP;
+	struct hostapd_data *hapd = (struct hostapd_data *)sm->wpa_auth->cb_ctx;
+	struct wpa_ml_link *link;
+	size_t i;
+
+	for (i = 0; i < ml_group->ml_link_num; i++) {
+		link = &ml_group->links[i];
+
+		if (link->ctx == hapd)
+			return link->link_id;
+	}
+
+	return 0xff;
+}
+
+
+int ml_new_assoc_sta(struct wpa_state_machine *sm, const u8 *ie, size_t len)
+{
+	if (!sm)
+		return -1;
+	wpa_printf(MSG_INFO, "ML: new STA:");
+	os_free(sm->sta_ml_ie);
+	if (ie == NULL || len == 0 || STATE_MACHINE_ML_GROUP == NULL) {
+		sm->sta_ml_ie = NULL;
+		sm->dot11MultiLinkActivated = 0;
+	} else {
+		struct wpa_ml_ie_parse ml;
+		struct wpa_ml_group *ml_group = STATE_MACHINE_ML_GROUP;
+
+		if (ml_parse_ie(ie, len, &ml, NULL) != 0) {
+			sm->sta_ml_ie = NULL;
+			sm->dot11MultiLinkActivated = 0;
+			return -1;
+		} else {
+			sm->sta_ml_ie = os_memdup(&ml, sizeof(ml));
+			if (sm->sta_ml_ie == NULL) {
+				sm->dot11MultiLinkActivated = 0;
+				return -1;
+			}
+
+			sm->sta_ml_ie->link_id = ml_get_link_id(sm);
+			sm->dot11MultiLinkActivated = 1;
+			wpa_printf(MSG_INFO, "ML: new STA:dot11MultiLinkActivated(%d),(ml_addr:" MACSTR ")",
+				sm->dot11MultiLinkActivated, MAC2STR(sm->sta_ml_ie->ml_addr));
+		}
+	}
+
+
+	return 0;
+}
+
+u8* ml_add_m1_kde(struct wpa_state_machine *sm, u8 *pos)
+{
+	if (!sm->dot11MultiLinkActivated)
+		return pos;
+
+	wpa_printf(MSG_INFO, "ML: Add Mac:(" MACSTR ") into EAPOL-Key 1/4", MAC2STR(STATE_MACHINE_ML_GROUP_ADDR));
+	return ml_set_mac_kde(pos, STATE_MACHINE_ML_GROUP_ADDR);
+}
+
+int ml_process_m2_kde(struct wpa_state_machine *sm,
+			const u8 *key_data, size_t key_data_len)
+{
+	struct wpa_eapol_ie_parse kde;
+	size_t i, j;
+
+	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) != 0 ||
+		!sm->dot11MultiLinkActivated)
+		return 0;
+
+	if (!kde.mac_addr) {
+		wpa_printf(MSG_INFO, "ML: EAPOL-Key 2/4 no ml addr");
+		return -1;
+	}
+
+	if (os_memcmp(sm->sta_ml_ie->ml_addr, kde.mac_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO,
+		"ML: EAPOL-Key 2/4 wrong ml addr ["MACSTR"] expect ["MACSTR"]",
+			MAC2STR(kde.mac_addr), MAC2STR(sm->sta_ml_ie->ml_addr));
+		return -1;
+	}
+
+	/* single link doesn't need profile and mlo link kde */
+	if (sm->sta_ml_ie->prof_num != kde.mlo_link.num &&
+		sm->sta_ml_ie->prof_num + 1 != kde.mlo_link.num) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 2/4 mlo link num mismatch (kde=%d, prof=%d)",
+			(int)kde.mlo_link.num,
+			sm->sta_ml_ie->prof_num);
+		return -2;
+	}
+
+	wpa_printf(MSG_INFO,
+		"ML: EAPOL-Key 2/4 mlo setup link ["MACSTR", link_id=%d]",
+		MAC2STR(sm->addr), sm->sta_ml_ie->link_id);
+
+	for (i = 0; i < kde.mlo_link.num; i++) {
+		struct wpa_mlo_link_kde *mlo_link =
+			(struct wpa_mlo_link_kde *) kde.mlo_link.kdes[i].data;
+
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 2/4 mlo kde link ["MACSTR", link_id=%d]",
+			MAC2STR(mlo_link->addr), mlo_link->info & 0xf);
+
+		if (kde.mlo_link.kdes[i].len < 7) {
+			wpa_printf(MSG_INFO,
+				"ML: EAPOL-Key 2/4 error mlo link len=%d",
+				(int)kde.mlo_link.kdes[i].len);
+			return -3;
+		}
+
+		if (os_memcmp(sm->addr, mlo_link->addr, ETH_ALEN) == 0 &&
+				sm->sta_ml_ie->link_id == (mlo_link->info & 0xf))
+			continue;
+
+		for (j = 0; j < sm->sta_ml_ie->prof_num; j++) {
+			if (os_memcmp(sm->sta_ml_ie->profiles[j].addr,
+					mlo_link->addr, ETH_ALEN) == 0 &&
+				sm->sta_ml_ie->profiles[j].link_id ==
+					(mlo_link->info & 0xf))
+				break;
+		}
+
+		if (j == sm->sta_ml_ie->prof_num) {
+			wpa_printf(MSG_INFO,
+				"ML: EAPOL-Key 2/4 mlo link ["MACSTR", link_id=%d] not matched",
+				MAC2STR(mlo_link->addr), mlo_link->info & 0xf);
+			return -4;
+		}
+	}
+
+	return 0;
+}
+
+u8* ml_add_m3_kde(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_ml_group *ml_group = NULL;
+	struct wpa_ml_link *link;
+	u8 i,j;
+
+	if (!sm->dot11MultiLinkActivated)
+		return pos;
+
+	wpa_printf(MSG_INFO, "ML: Add Mac/Link/GTK into EAPOL-Key 3/4");
+	ml_group = STATE_MACHINE_ML_GROUP;
+	pos = ml_set_mac_kde(pos, ml_group->ml_addr);
+
+	for (i = 0; i < ml_group->ml_link_num; i++) {
+		struct wpa_authenticator *auth;
+		u8 found = false;
+#ifdef CONFIG_IEEE80211R_AP
+		u8 *rsn_ie_buf = NULL;
+		const u8 *mde;
+		size_t mde_len;
+#endif
+		const u8 *rsne, *rsnxe;
+		size_t rsne_len, rsnxe_len;
+
+		link = &ml_group->links[i];
+		if (link->link_id == sm->sta_ml_ie->link_id) {
+			found = true;
+		} else {
+			for (j = 0; j < sm->sta_ml_ie->prof_num; j++) {
+				if (sm->sta_ml_ie->profiles[j].link_id ==
+					link->link_id)
+					found = true;
+			}
+		}
+		if (!found)
+			continue;
+
+		auth = ((struct hostapd_data *)link->ctx)->wpa_auth;
+		if (!auth) {
+			wpa_printf(MSG_ERROR,
+					"ML: wpa_auth is NULL--link_id=%d, link_addr=" MACSTR "",
+					link->link_id, MAC2STR(link->addr));
+			return NULL;
+		}
+		rsne = get_ie(auth->wpa_ie, auth->wpa_ie_len, WLAN_EID_RSN);
+		rsne_len = rsne ? rsne[1] + 2 : 0;
+		rsnxe = get_ie(auth->wpa_ie, auth->wpa_ie_len, WLAN_EID_RSNX);
+		rsnxe_len = rsnxe ? rsnxe[1] + 2 : 0;
+
+#ifdef CONFIG_IEEE80211R_AP
+		if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && rsne) {
+			int res;
+			wpa_hexdump(MSG_MSGDUMP, "ML: WPA IE before FT processing",
+					rsne, rsne_len);
+
+			mde = get_ie(auth->wpa_ie, auth->wpa_ie_len, WLAN_EID_MOBILITY_DOMAIN);
+			mde_len = mde ? mde[1] + 2 : 0;
+
+			wpa_hexdump(MSG_MSGDUMP, "ML: MDE", mde, mde_len);
+
+			if (mde && i == 0) {
+				os_memcpy(pos, mde, mde_len);
+				pos += mde_len;
+			}
+
+			/* Add PMKR1Name into RSN IE (PMKID-List) */
+			rsn_ie_buf = os_malloc(rsne_len + 2 + 2 + PMKID_LEN);
+			if (rsn_ie_buf == NULL) {
+				wpa_printf(MSG_INFO, "ML: OOM for FT");
+				return pos;
+			}
+			os_memcpy(rsn_ie_buf, rsne, rsne_len);
+			res = wpa_insert_pmkid(rsn_ie_buf, &rsne_len,
+						   sm->pmk_r1_name);
+			if (res < 0) {
+				wpa_printf(MSG_INFO, "ML: insert pmk for FT failed");
+				os_free(rsn_ie_buf);
+				return pos;
+			}
+			wpa_hexdump(MSG_MSGDUMP,
+					"ML: WPA IE after PMKID[PMKR1Name] addition into RSNE",
+					rsn_ie_buf, rsne_len);
+			rsne = rsn_ie_buf;
+		}
+#endif /* CONFIG_IEEE80211R_AP */
+
+		pos = ml_set_ml_link_kde(pos, link->link_id, link->addr,
+			rsne, rsne_len, rsnxe, rsnxe_len);
+		pos = ml_set_gtk_kde(sm, pos, link);
+		pos = ml_set_ieee80211w_kde(sm, pos, link);
+
+#ifdef CONFIG_IEEE80211R_AP
+		os_free(rsn_ie_buf);
+#endif
+	}
+
+	return pos;
+}
+
+int ml_process_m4_kde(struct wpa_state_machine *sm,
+		const u8 *key_data, size_t key_data_len)
+{
+	struct wpa_eapol_ie_parse kde;
+
+	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) != 0 ||
+	    !sm->dot11MultiLinkActivated)
+		return 0;
+
+	if (os_memcmp(sm->sta_ml_ie->ml_addr, kde.mac_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO, "ML: EAPOL-Key 4/4 wrong ml addr");
+		return -1;
+	}
+
+	return 0;
+}
+
+u8* ml_set_gtk_kde(struct wpa_state_machine *sm, u8 *pos,
+		   struct wpa_ml_link *link)
+{
+	struct wpa_authenticator *auth =
+		((struct hostapd_data *)link->ctx)->wpa_auth;
+	struct wpa_group *gsm = auth->group;
+	int gtkidx;
+	u8 *gtk, dummy_gtk[32], *ori;
+	size_t gtk_len;
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	u8 hdr[7];
+
+	if (sm->wpa != WPA_VERSION_WPA2)
+		return pos;
+
+	gtk = gsm->GTK[gsm->GN - 1];
+	gtk_len = gsm->GTK_len;
+	if (conf->disable_gtk ||
+	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+		/*
+		 * Provide unique random GTK to each STA to prevent use
+		 * of GTK in the BSS.
+		 */
+		if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+			goto done;
+		gtk = dummy_gtk;
+	}
+	gtkidx = gsm->GN;
+
+	os_memset(hdr, 0, 7);
+	hdr[0] = (gtkidx & 0x03) | (link->link_id & 0x0f) << 4;
+	ori = pos;
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MLO_GTK, hdr, 7,
+			  gtk, gtk_len);
+	wpa_hexdump(MSG_DEBUG, "ML: GTK KDE", ori, pos - ori);
+done:
+	return pos;
+}
+
+static inline int ml_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	int res;
+
+	if (!wpa_auth->cb->get_seqnum)
+		return -1;
+	res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+	return res;
+}
+
+u8* ml_set_ieee80211w_kde(struct wpa_state_machine *sm, u8 *pos,
+			  struct wpa_ml_link *link)
+{
+	struct wpa_authenticator *auth =
+		((struct hostapd_data *)link->ctx)->wpa_auth;
+	struct wpa_mlo_igtk_kde igtk;
+	struct wpa_mlo_bigtk_kde bigtk;
+	struct wpa_group *gsm = auth->group;
+	u8 rsc[WPA_KEY_RSC_LEN], *ori;
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+
+	if (!sm->mgmt_frame_prot)
+		return pos;
+
+	igtk.keyid[0] = gsm->GN_igtk;
+	igtk.keyid[1] = 0;
+	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+	    ml_get_seqnum(auth, NULL, gsm->GN_igtk, rsc) < 0)
+		os_memset(igtk.pn, 0, sizeof(igtk.pn));
+	else
+		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
+	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
+	if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+		/*
+		 * Provide unique random IGTK to each STA to prevent use of
+		 * IGTK in the BSS.
+		 */
+		if (random_get_bytes(igtk.igtk, len) < 0)
+			return pos;
+	}
+	igtk.info = (link->link_id & 0x0f) << 4;
+	ori = pos;
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MLO_IGTK,
+			  (const u8 *) &igtk, WPA_MLO_IGTK_KDE_PREFIX_LEN + len,
+			  NULL, 0);
+	wpa_hexdump_key(MSG_DEBUG, "ML: IGTK KDE", ori, pos - ori);
+
+	if (!conf->beacon_prot)
+		return pos;
+
+	bigtk.keyid[0] = gsm->GN_bigtk;
+	bigtk.keyid[1] = 0;
+	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+	    ml_get_seqnum(auth, NULL, gsm->GN_bigtk, rsc) < 0)
+		os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+	else
+		os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+	os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+		/*
+		 * Provide unique random BIGTK to each OSEN STA to prevent use
+		 * of BIGTK in the BSS.
+		 */
+		if (random_get_bytes(bigtk.bigtk, len) < 0)
+			return pos;
+	}
+	bigtk.info = (link->link_id & 0x0f) << 4;
+	ori = pos;
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MLO_BIGTK,
+			  (const u8 *) &bigtk, WPA_MLO_BIGTK_KDE_PREFIX_LEN + len,
+			  NULL, 0);
+	wpa_hexdump(MSG_DEBUG, "ML: BIGTK KDE", ori, pos - ori);
+
+	return pos;
+}
+
+u8* ml_add_rekey_kde(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_ml_group *ml_group = NULL;
+	struct wpa_ml_link *link;
+	u8 i;
+
+	if (!sm->dot11MultiLinkActivated)
+		return pos;
+
+	wpa_printf(MSG_INFO, "ML: Add Mac/GTK into EAPOL-Key rekey");
+	ml_group = STATE_MACHINE_ML_GROUP;
+	pos = ml_set_mac_kde(pos, ml_group->ml_addr);
+
+	for (i = 0; i < ml_group->ml_link_num; i++) {
+		link = &ml_group->links[i];
+		pos = ml_set_gtk_kde(sm, pos, link);
+		pos = ml_set_ieee80211w_kde(sm, pos, link);
+	}
+
+	return pos;
+}
+
+int ml_rekey_gtk(struct wpa_state_machine *sm, struct wpa_eapol_ie_parse *kde)
+{
+	if (sm->dot11MultiLinkActivated &&
+	    os_memcmp(kde->mac_addr, sm->sta_ml_ie->ml_addr, ETH_ALEN) == 0) {
+		struct wpa_ml_group *ml_group;
+		size_t i;
+
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			"received EAPOL-Key Request for ML GTK rekeying");
+
+		ml_group = STATE_MACHINE_ML_GROUP;
+		for (i = 0; i < ml_group->ml_link_num; i++) {
+			struct wpa_authenticator *wpa_auth =
+				((struct hostapd_data *)ml_group->links[i].ctx)->wpa_auth;
+
+			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+			wpa_rekey_gtk(wpa_auth,	NULL);
+		}
+	}
+	return 0;
+}
+
+
Index: hostapd-2022-07-29-b704dc72/src/ml/ml_common.h
===================================================================
--- /dev/null
+++ hostapd-2022-07-29-b704dc72/src/ml/ml_common.h
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ *
+ * This file is provided under a dual license.  When you use or
+ * distribute this software, you may choose to be licensed under
+ * version 2 of the GNU General Public License ("GPLv2 License")
+ * or BSD License.
+ *
+ * GPLv2 License
+ *
+ * Copyright(C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(C) 2016 MediaTek Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#ifndef WPA_ML_COMMON_H
+#define WPA_ML_COMMON_H
+
+#include "common/wpa_common.h"
+
+struct hostapd_data;
+struct wpa_state_machine;
+struct wpa_authenticator;
+struct wpa_sm;
+struct sae_data;
+
+#ifndef OUI_MTK
+#define OUI_MTK 0x000ce7
+#endif
+
+#define MTK_MLD_IE_VENDOR_TYPE 0x000ce701
+
+
+#define MTK_VENDOR_ATTR_P2P_ML_CHAN_LIST  0
+
+#define ML_CTRL_TYPE_MASK				BITS(0, 2)
+#define ML_CTRL_TYPE_BASIC				0
+#define ML_ELEMENT_TYPE_PROBE_REQ			1
+
+#define ML_CTRL_PRE_BMP_MASK				BITS(4, 15)
+#define ML_CTRL_LINK_ID_INFO_PRESENT			BIT(4)
+#define ML_CTRL_BSS_PARA_CHANGE_COUNT_PRESENT		BIT(5)
+#define ML_CTRL_MEDIUM_SYN_DELAY_INFO_PRESENT		BIT(6)
+#define ML_CTRL_EML_CAPA_PRESENT			BIT(7)
+#define ML_CTRL_MLD_CAPA_PRESENT			BIT(8)
+#define ML_CTRL_MLD_ID_PRESENT				BIT(9)
+
+#define ML_SUB_ID_PER_STA_PROFILE			0
+#define ML_STA_CTRL_LINK_ID_MASK			BITS(0, 3)
+#define ML_STA_CTRL_LINK_ID_SHIFT			0
+#define ML_STA_CTRL_COMPLETE_PROFILE			BIT(4)
+#define ML_STA_CTRL_MAC_ADDR_PRESENT			BIT(5)
+#define ML_STA_CTRL_BCN_INTV_PRESENT			BIT(6)
+#define ML_STA_CTRL_TSF_OFFSET_PRESENT			BIT(7)
+#define ML_STA_CTRL_DTIM_INFO_PRESENT			BIT(8)
+#define ML_STA_CTRL_NSTR_LINK_PAIR_PRESENT		BIT(9)
+#define ML_STA_CTRL_NSTR_BMP_SIZE			BIT(10)
+#define ML_STA_CTRL_NSTR_BMP_SIZE_SHIFT		10
+#define ML_STA_CTRL_BSS_CHG_CNT_PRESENT		BIT(11)
+
+#define ML_SET_CTRL_TYPE(_u2ctrl, _ctrl_type) \
+{\
+	(_u2ctrl) &= ~(ML_CTRL_TYPE_MASK); \
+	(_u2ctrl) |= ((_ctrl_type) & (ML_CTRL_TYPE_MASK)); \
+}
+
+#define ML_SET_CTRL_PRESENCE(_u2ctrl, _ctrl_type) \
+{\
+	(_u2ctrl) &= ~(ML_CTRL_PRE_BMP_MASK); \
+	(_u2ctrl) |= ((_ctrl_type) & (ML_CTRL_PRE_BMP_MASK)); \
+}
+
+
+#define ML_IS_CTRL_TYPE(__ie, __TYPE) \
+	((__ie) && (__ie)[0] == WLAN_EID_EXTENSION && (__ie)[1] >= 3 && \
+	 (__ie)[2] == WLAN_EID_EXT_MULTI_LINK && \
+	 ((__ie)[3] & ML_CTRL_TYPE_MASK) == __TYPE)
+
+
+#define WPA_MLO_GTK_KDE_PREFIX_LEN (1 + 6)
+struct wpa_mlo_gtk_kde {
+	u8 info; /* KeyId 2 | Tx 1 | Reserved 1 | LinkId 4 */
+	u8 pn[6];
+	u8 gtk[WPA_GTK_MAX_LEN];
+} STRUCT_PACKED;
+
+#define WPA_MLO_IGTK_KDE_PREFIX_LEN (2 + 6 + 1)
+struct wpa_mlo_igtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 info; /* Reserved 4 | LinkId 4 */
+	u8 igtk[WPA_IGTK_MAX_LEN];
+} STRUCT_PACKED;
+
+#define WPA_MLO_BIGTK_KDE_PREFIX_LEN (2 + 6 + 1)
+struct wpa_mlo_bigtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 info; /* Reserved 4 | LinkId 4 */
+	u8 bigtk[WPA_BIGTK_MAX_LEN];
+} STRUCT_PACKED;
+
+struct wpa_mlo_link_kde {
+	u8 info; /* LinkId 4 | RSNEInfo 1 | RSNXEInfo 1 | Reserved 2 */
+	u8 addr[ETH_ALEN];
+	u8 var[]; /* RSNE | RSNXE */
+} STRUCT_PACKED;
+
+struct wpa_ml_link {
+	u8 link_id;
+	u8 addr[ETH_ALEN];
+
+	void *ctx;
+};
+
+struct wpa_ml_group {
+	void *ctx;
+	u8 ml_addr[ETH_ALEN];
+	u8 ml_group_id;
+	size_t ml_link_num;
+
+	struct wpa_ml_link *links;
+};
+
+struct per_sta_profile {
+	u8 link_id;
+	u8 addr[ETH_ALEN];
+	u16 dtim;
+	u16 beacon_interval;
+	u64 tsf_offset;
+	u16 nstr_bmap;
+	u8 bss_para_change_count;
+	unsigned int complete_profile:1;
+	unsigned int mac_addr_present:1;
+	unsigned int bcn_intvl_present:1;
+	unsigned int tsf_offset_present:1;
+	unsigned int dtim_present:1;
+	unsigned int nstr_present:1;
+	unsigned int bss_para_change_count_present:1;
+};
+
+struct wpa_ml_ie_parse {
+	u8 type;
+	u8 ml_addr[ETH_ALEN];
+	u8 common_info_len;
+	u8 link_id;
+	u8 bss_para_change_count;
+	u16 medium_sync_delay;
+	u16 eml_cap;
+	u16 mld_cap;
+	u8 mld_id;
+	u8 prof_num;
+	unsigned int valid:1;
+	unsigned int link_id_present:1;
+	unsigned int bss_para_change_cnt_present:1;
+	unsigned int medium_sync_delay_present:1;
+	unsigned int eml_cap_present:1;
+	unsigned int mld_cap_present:1;
+	unsigned int mld_id_present:1;
+
+	struct per_sta_profile profiles[ML_MAX_LINK_NUM];
+};
+
+/* common */
+#ifdef CONFIG_MTK_IEEE80211BE
+const u8 * ml_auth_spa(struct wpa_state_machine *sm, const u8 *own_addr);
+const u8 * ml_auth_aa(struct wpa_state_machine *sm, const u8 *bssid);
+#else
+#define ml_auth_spa(__sm, __addr) __addr
+#define ml_auth_aa(__sm, __addr) __addr
+#endif
+u8* ml_set_mac_kde(u8 *buf, const unsigned char *addr);
+u8* ml_set_ml_link_kde(u8 *pos, u8 id, const unsigned char *addr,
+	const u8 *rsne, size_t rsne_len, const u8 *rsnxe, size_t rsnxe_len);
+int ml_parse_ie(const u8 *pos, size_t len, struct wpa_ml_ie_parse *ml, u8 *bssid);
+
+#ifdef CONFIG_SAE
+int ml_sae_process_auth(struct sae_data *sae, u16 auth_transaction,
+	const u8 *ies, size_t ies_len);
+int ml_sae_write_auth(struct hostapd_data *hapd,
+	struct sae_data *sae, struct wpabuf *buf);
+#endif
+
+/* AP */
+int ml_group_init(struct hostapd_data *hapd, u8 mld_grp_idx, u8 link_id, u8 *mld_addr);
+int ml_group_deinit(struct hostapd_data *hapd);
+
+int ml_new_assoc_sta(struct wpa_state_machine *sm, const u8 *ie, size_t len);
+u8* ml_add_m1_kde(struct wpa_state_machine *sm, u8 *pos);
+int ml_process_m2_kde(struct wpa_state_machine *sm,
+		const u8 *key_data, size_t key_data_len);
+u8* ml_add_m3_kde(struct wpa_state_machine *sm, u8 *pos);
+int ml_process_m4_kde(struct wpa_state_machine *sm,
+		const u8 *key_data, size_t key_data_len);
+u8* ml_set_gtk_kde(struct wpa_state_machine *sm, u8 *pos,
+		   struct wpa_ml_link *link);
+u8* ml_set_ieee80211w_kde(struct wpa_state_machine *sm, u8 *pos,
+			  struct wpa_ml_link *link);
+u8* ml_add_rekey_kde(struct wpa_state_machine *sm, u8 *pos);
+int ml_rekey_gtk(struct wpa_state_machine *sm, struct wpa_eapol_ie_parse *kde);
+
+#endif /* WPA_ML_COMMON_H */
Index: hostapd-2022-07-29-b704dc72/src/ml/ml_supplicant.c
===================================================================
--- /dev/null
+++ hostapd-2022-07-29-b704dc72/src/ml/ml_supplicant.c
@@ -0,0 +1,1343 @@
+/*******************************************************************************
+ *
+ * This file is provided under a dual license.  When you use or
+ * distribute this software, you may choose to be licensed under
+ * version 2 of the GNU General Public License ("GPLv2 License")
+ * or BSD License.
+ *
+ * GPLv2 License
+ *
+ * Copyright(C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(C) 2016 MediaTek Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+#include "includes.h"
+
+#include "common.h"
+
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/sae.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_i.h"
+#include "rsn_supp/wpa_ie.h"
+#include "ap/wpa_auth.h"
+#include "ap/wpa_auth_i.h"
+#include "ap/wpa_auth_ie.h"
+#include "ap/hostapd.h"
+#include "crypto/random.h"
+#include "utils/eloop.h"
+
+#include "ml/ml_common.h"
+#include "ml/ml_supplicant.h"
+
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "driver_i.h" /* for drv cmd*/
+
+
+#define CMD_PRESET_LINKID	"PRESET_LINKID"
+static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
+struct mtk_vendor_ie {
+	u8 id;
+	u8 len;
+	u8 oui[3];
+	u8 cap[4];
+	u8 data[0];
+};
+
+struct mtk_pre_wifi7_ie {
+	u8 id;
+	u8 len;
+	u8 version0;
+	u8 version1;
+	u8 data[0];
+};
+
+#define MTK_SYNERGY_CAP_SUPPORT_TLV		BIT(0)
+
+#define MTK_OUI_ID_MLR				1
+#define MTK_OUI_ID_PRE_WIFI7			2
+#define MTK_OUI_ID_ICI				3
+#define MTK_OUI_ID_CHIP_CAP			4
+
+
+struct wpa_ie_parse {
+	const u8 *ap_rsn_ie;
+	const u8 *ap_rsnxe;
+	size_t ap_rsn_ie_len;
+	size_t ap_rsnxe_len;
+};
+
+struct ml_gtk_data {
+	u8 link_id;
+	enum wpa_alg alg;
+	int tx, key_rsc_len, keyidx;
+	u8 gtk[32];
+	int gtk_len;
+};
+
+
+/* STA */
+
+const u8 * ml_get_ie(const u8 *ies, size_t ie_len, u32 ml_ie_type)
+{
+	const struct element *elem;
+
+/*
+	for_each_element_extid(elem, WLAN_EID_EXT_MULTI_LINK, ies, ie_len) {
+		if (ML_IS_CTRL_TYPE(&elem->id, ml_ie_type))
+			return &elem->id;
+	}
+*/
+	for_each_element(elem, ies, ie_len) {
+		u8 id = elem->id, elen = elem->datalen;
+		const u8 *pos = elem->data;
+
+		if (id == WLAN_EID_EXTENSION &&
+		    elen > 0 && pos[0] == WLAN_EID_EXT_MULTI_LINK) {
+			if (ML_IS_CTRL_TYPE(&elem->id, ml_ie_type))
+				return &elem->id;
+		}
+
+		if (id == WLAN_EID_VENDOR_SPECIFIC && elen > 7 &&
+		    WPA_GET_BE24(pos) == OUI_MTK) {
+			struct mtk_vendor_ie *ie = (struct mtk_vendor_ie *)elem;
+
+			if (ie->cap[0] & MTK_SYNERGY_CAP_SUPPORT_TLV) {
+				const struct element *sub_elem;
+				const u8 *sub;
+				size_t sub_len;
+
+				sub = ie->data;
+				sub_len = ie->len - 7;
+
+				for_each_element_id(sub_elem, MTK_OUI_ID_PRE_WIFI7, sub, sub_len) {
+					struct mtk_pre_wifi7_ie *pre7 = (struct mtk_pre_wifi7_ie *) sub_elem;
+					const struct element *pre_elem;
+					const u8 *pre;
+					size_t pre_len;
+
+					pre = pre7->data;
+					pre_len = pre7->len - 2;
+
+					for_each_element_extid(pre_elem, WLAN_EID_EXT_MULTI_LINK, pre, pre_len) {
+						if (ML_IS_CTRL_TYPE(&pre_elem->id, ml_ie_type))
+							return &pre_elem->id;
+					}
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+const u8 * ml_sm_spa(struct wpa_sm *sm, const u8 *own_addr)
+{
+	if(sm && own_addr && sm->dot11MultiLinkActivated) {
+		if (os_memcmp(own_addr, sm->sta_ml_ie->ml_addr, ETH_ALEN) != 0) {
+			wpa_printf(MSG_INFO,
+				"ML: SPA[" MACSTR "]  use ml addr[" MACSTR "]",
+				MAC2STR(own_addr), MAC2STR(sm->sta_ml_ie->ml_addr));
+			return sm->sta_ml_ie->ml_addr;
+		}
+	}
+
+	return own_addr;
+}
+
+const u8 * ml_sm_aa(struct wpa_sm *sm, const u8 *bssid)
+{
+	if(sm && bssid && sm->dot11MultiLinkActivated) {
+		if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0) {
+			if (os_memcmp(bssid, sm->ap_ml_ie->ml_addr, ETH_ALEN) != 0) {
+				wpa_printf(MSG_INFO,
+					"ML: AA[" MACSTR "]  use ml addr[" MACSTR "]",
+					MAC2STR(bssid), MAC2STR(sm->ap_ml_ie->ml_addr));
+				return sm->ap_ml_ie->ml_addr;
+			}
+		} else {
+			/* for preauth */
+			struct wpa_supplicant *wpa_s = sm->ctx->ctx;
+			struct wpa_bss *bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+
+			if (bss && os_memcmp(bssid, bss->aa, ETH_ALEN) != 0) {
+				wpa_printf(MSG_INFO,
+					"ML: AA[" MACSTR "] use ml addr[" MACSTR "]",
+					MAC2STR(bssid), MAC2STR(bss->aa));
+				return bss->aa;
+			}
+
+		}
+	}
+
+	return bssid;
+}
+
+int ml_set_sae_auth_commit_req_ml_ie (struct sae_data *sae, const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+	struct wpa_ml_ie_parse ml;
+	struct wpabuf *frag_ml_ie = NULL;
+	const u8 *ml_ie;
+	size_t ml_ie_len = 0;
+
+	if (sae == NULL)
+		return -1;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "ML: Failed to parse elements");
+		return -1;
+	}
+
+	frag_ml_ie = ieee802_11_defrag(&elems,
+							 WLAN_EID_EXTENSION,
+							 WLAN_EID_EXT_MULTI_LINK);
+	if (!frag_ml_ie) {
+		wpa_printf(MSG_DEBUG, "ML: Missing frag_ml_ie");
+		ml_ie = elems.ml;
+		ml_ie_len = (size_t)elems.ml_len;
+	} else {
+		ml_ie_len = (size_t)wpabuf_len(frag_ml_ie);
+		ml_ie = wpabuf_head_u8(frag_ml_ie);
+
+		wpa_hexdump(MSG_DEBUG, "Multi-link IE defrag results:",
+			ml_ie, ml_ie_len);
+	}
+
+	if (!ml_ie) {
+		wpa_printf(MSG_DEBUG, "ML: clearing STA ML IE");
+		sae->dot11MultiLinkActivated = 0;
+	} else {
+		if (ml_parse_ie(ml_ie, ml_ie_len, &ml, NULL) != 0) {
+			sae->dot11MultiLinkActivated = 0;
+			if (frag_ml_ie)
+				wpabuf_free(frag_ml_ie);
+			return -1;
+		} else {
+			os_memcpy(sae->own_ml_addr, ml.ml_addr, ETH_ALEN);
+			sae->dot11MultiLinkActivated = 1;
+			wpa_printf(MSG_DEBUG, "(%s)[%d]ML:succcown_ml_addr: "MACSTR", dot11MultiLinkActivated: %d",
+				__func__, __LINE__,MAC2STR(sae->own_ml_addr), sae->dot11MultiLinkActivated);
+		}
+	}
+	if (frag_ml_ie)
+		wpabuf_free(frag_ml_ie);
+	wpa_printf(MSG_DEBUG, "(%s)[%d]ML:own_ml_addr: "MACSTR", dot11MultiLinkActivated: %d",
+		__func__, __LINE__,MAC2STR(sae->own_ml_addr), sae->dot11MultiLinkActivated);
+	return 0;
+}
+
+
+
+int ml_set_assoc_req_ml_ie(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+	struct wpa_ml_ie_parse ml;
+	struct wpabuf *frag_ml_ie = NULL;
+	const u8 *ml_ie = NULL;
+	size_t ml_ie_len = 0;
+
+	if (sm == NULL)
+		return -1;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "ML: Failed to parse elements");
+		return -1;
+	}
+
+	frag_ml_ie = ieee802_11_defrag(&elems,
+						 WLAN_EID_EXTENSION,
+						 WLAN_EID_EXT_MULTI_LINK);
+	if (!frag_ml_ie) {
+		wpa_printf(MSG_DEBUG, "ML: Missing frag_ml_ie");
+		ml_ie = elems.ml;
+		ml_ie_len = (size_t)elems.ml_len;
+	} else {
+		ml_ie_len = (size_t)wpabuf_len(frag_ml_ie);
+		ml_ie = wpabuf_head_u8(frag_ml_ie);
+
+		wpa_hexdump(MSG_DEBUG, "Multi-link IE defrag results:",
+			ml_ie, ml_ie_len);
+	}
+
+	os_free(sm->sta_ml_ie);
+	if (!ml_ie) {
+		wpa_printf(MSG_DEBUG, "ML:[%s] clearing STA ML IE", __func__);
+		goto err;
+	} else {
+		if (ml_parse_ie(ml_ie, ml_ie_len, &ml, NULL) != 0 ||
+		    ml.prof_num > ML_MAX_LINK_NUM) {
+			wpa_printf(MSG_DEBUG, "ML:[%s] ml_parse_ie fails", __func__);
+			goto err;
+		} else {
+			sm->sta_ml_ie = os_memdup(&ml, sizeof(ml));
+			if (sm->sta_ml_ie == NULL) {
+				wpa_printf(MSG_DEBUG, "ML:[%s] sta_ml_ie is null.", __func__);
+				goto err;
+			}
+
+			os_memcpy(sm->own_ml_addr, ml.ml_addr, ETH_ALEN);
+			sm->prof_num = ml.prof_num;
+			sm->dot11MultiLinkActivated = 1;
+		}
+	}
+	if (frag_ml_ie)
+		wpabuf_free(frag_ml_ie);
+	return 0;
+
+err:
+	if (frag_ml_ie)
+		wpabuf_free(frag_ml_ie);
+	sm->sta_ml_ie = NULL;
+	sm->prof_num = 0;
+	sm->dot11MultiLinkActivated = 0;
+	return -1;
+}
+
+int ml_set_assoc_resp_ml_ie(struct wpa_sm *sm, const u8 *ies, size_t ies_len, u8 *bssid)
+{
+	struct ieee802_11_elems elems;
+	struct wpa_ml_ie_parse ml;
+	struct wpabuf *frag_ml_ie = NULL;
+	const u8 *ml_ie;
+	size_t ml_ie_len = 0;
+
+	if (sm == NULL)
+		return -1;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "ML: Failed to parse elements");
+		return -1;
+	}
+	frag_ml_ie = ieee802_11_defrag(&elems,
+					 WLAN_EID_EXTENSION,
+					 WLAN_EID_EXT_MULTI_LINK);
+
+	if (!frag_ml_ie) {
+		wpa_printf(MSG_DEBUG, "ML: Missing frag_ml_ie");
+		ml_ie = elems.ml;
+		ml_ie_len = (size_t)elems.ml_len;
+	} else {
+		ml_ie_len = (size_t)wpabuf_len(frag_ml_ie);
+		ml_ie = wpabuf_head_u8(frag_ml_ie);
+
+		wpa_hexdump(MSG_DEBUG, "Multi-link IE defrag results:",
+			ml_ie, ml_ie_len);
+	}
+
+	os_free(sm->ap_ml_ie);
+	if (!ml_ie) {
+		WPA_ASSERT(!sm->dot11MultiLinkActivated);
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "ML: clearing AP ML IE");
+		goto err;
+	} else {
+		WPA_ASSERT(sm->dot11MultiLinkActivated);
+
+		if (ml_parse_ie(ml_ie, ml_ie_len, &ml, bssid) != 0  ||
+		    ml.prof_num > ML_MAX_LINK_NUM) {
+			wpa_printf(MSG_DEBUG, "ML:[%s] ml_parse_ie fails", __func__);
+			goto err;
+		} else {
+			WPA_ASSERT(ml.prof_num == sm->prof_num);
+
+			sm->ap_ml_ie = os_memdup(&ml, sizeof(ml));
+			if (sm->ap_ml_ie == NULL) {
+				wpa_printf(MSG_DEBUG, "ML:[%s] ap_ml_ie is null.", __func__);
+				goto err;
+			}
+			os_memcpy(sm->ml_bssid, ml.ml_addr, ETH_ALEN);
+		}
+	}
+	if (frag_ml_ie)
+		wpabuf_free(frag_ml_ie);
+	wpa_printf(MSG_DEBUG, "(%s)[%d]:sm->dot11MultiLinkActivated: %d.\n",
+		__func__, __LINE__, sm->dot11MultiLinkActivated);
+	return 0;
+
+err:
+	if (frag_ml_ie)
+		wpabuf_free(frag_ml_ie);
+	if (sm->dot11MultiLinkActivated) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_ERROR, "ML: clearing STA ML IE");
+		if (sm->sta_ml_ie)
+			os_free(sm->sta_ml_ie);
+		sm->sta_ml_ie = NULL;
+		sm->prof_num = 0;
+		sm->dot11MultiLinkActivated = 0;
+	}
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "ML: clearing AP ML IE");
+	sm->ap_ml_ie = NULL;
+
+	return -1;
+}
+
+size_t ml_add_m2_kde(struct wpa_sm *sm, u8 *pos)
+{
+	struct wpa_ml_ie_parse *ml = sm->sta_ml_ie;
+	size_t i, count = 0;
+	u8 *buf = pos;
+
+	if (!sm->dot11MultiLinkActivated)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "ML: Add Mac/Link into EAPOL-Key 2/4");
+	wpa_printf(MSG_DEBUG, "(%s)[%d] ML: Add Mac: "MACSTR"", __func__, __LINE__, MAC2STR(sm->own_ml_addr));
+	pos = ml_set_mac_kde(pos, sm->own_ml_addr);
+
+	for (i = 0; i < sm->prof_num; i++) {
+		struct per_sta_profile *sta = &ml->profiles[i];
+
+		/* normally this won't happen, just in case sta carries
+		 * sta profile for main link and it's for single link setup
+		 */
+		if (sta->link_id == sm->ap_ml_ie->link_id)
+			continue;
+		count++;
+	}
+
+	/* single link doesn't mlo link kde */
+	if (count) {
+		wpa_printf(MSG_DEBUG, "ML: Add Link into EAPOL-Key 2/4");
+
+		for (i = 0; i < sm->prof_num; i++) {
+			struct per_sta_profile *sta = &ml->profiles[i];
+
+			if (sta->link_id == sm->ap_ml_ie->link_id)
+				continue;
+
+			pos = ml_set_ml_link_kde(pos, sta->link_id, sta->addr,
+				NULL, 0, NULL, 0);
+		}
+	}
+
+	return pos - buf;
+}
+
+static int ml_get_wpa_ie(struct wpa_supplicant *wpa_s, u8 *bssid,
+			 struct wpa_ie_parse *wpa)
+{
+	int ret = 0;
+	struct wpa_bss *curr = NULL, *bss;
+	const u8 *ie;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		wpa_printf(MSG_DEBUG, "scan table bss bssid: "MACSTR"", MAC2STR(bss->bssid));
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
+			continue;
+		curr = bss;
+		wpa_printf(MSG_DEBUG, "target bssid: "MACSTR"", MAC2STR(bssid));
+		break;
+	}
+
+	if (!curr) {
+		wpa_printf(MSG_DEBUG, "can't find the curr BSSID Add Mac: "MACSTR"", MAC2STR(bssid));
+		return -1;
+	}
+
+	os_memset(wpa, 0, sizeof(*wpa));
+
+	ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
+	if (ie) {
+		wpa->ap_rsn_ie = ie;
+		wpa->ap_rsn_ie_len = 2 + ie[1];
+	}
+
+	ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+	if (ie) {
+		wpa->ap_rsnxe = ie;
+		wpa->ap_rsnxe_len = 2 + ie[1];
+	}
+
+	return 0;
+}
+
+int ml_validate_m3_kde(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+	struct wpa_eapol_ie_parse *ie)
+{
+	u16 key_info;
+	size_t i, j;
+	u8 found = 0;
+	struct wpa_ie_parse wpa, *target_wpa = NULL;
+	struct wpa_mlo_link_kde *mlo_link = NULL;
+
+	key_info = WPA_GET_BE16(key->key_info);
+
+	if(!sm->dot11MultiLinkActivated) {
+		if (ie->mlo_gtk.num == 0 && ie->mlo_igtk.num == 0 &&
+		    ie->mlo_bigtk.num == 0 && ie->mlo_link.num == 0) {
+			wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 inactive");
+			return 0;
+		} else {
+			wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 inactive but "
+				"with ml kde (gtk=%d, igtk=%d, bigtk=%d link=%d)",
+				(int)ie->mlo_gtk.num, (int)ie->mlo_igtk.num,
+				(int)ie->mlo_bigtk.num, (int)ie->mlo_link.num);
+			return -1;
+		}
+	}
+
+	/* mac addr */
+	if (sm->ap_ml_ie &&
+	    os_memcmp(sm->ap_ml_ie->ml_addr, ie->mac_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 wrong ml addr");
+		return -1;
+	}
+
+	/* mlo link */
+	if (ie->mlo_link.num != sm->prof_num + 1) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 wrong mlo link num=%d, expect=%d",
+			(int)ie->mlo_link.num, sm->prof_num + 1);
+		return -1;
+	}
+
+	if (ie->rsn_ie) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 should not have Basic RSN IE");
+		return -1;
+	}
+
+	if (ie->rsnxe) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 should not have Basic RSNXE IE");
+		return -1;
+	}
+	for (i = 0; i < ie->mlo_link.num; i++) {
+		mlo_link = (struct wpa_mlo_link_kde *) ie->mlo_link.kdes[i].data;
+		if (ml_get_wpa_ie(sm->ctx->ctx, mlo_link->addr, &wpa) < 0) {
+			wpa_printf(MSG_ERROR, "ML: Could not find mlo_link("MACSTR") from the scan results", MAC2STR(mlo_link->addr));
+		} else {
+			target_wpa = &wpa;
+			break;
+		}
+	}
+	if (target_wpa == NULL) {
+		wpa_printf(MSG_ERROR,
+			"ML: can't find one of the mlo link ssid in the scan table.");
+		return -1;
+	}
+
+	/* mlo link id & rsne & rsnxe */
+	for (i = 0; i < ie->mlo_link.num; i++) {
+		struct wpa_mlo_link_kde *mlo_link =
+			(struct wpa_mlo_link_kde *) ie->mlo_link.kdes[i].data;
+		size_t len = ie->mlo_link.kdes[i].len;
+		u8 *rsne = NULL, *rsnxe = NULL;
+		u8 rsne_len = 0, rsnxe_len = 0; /* including hdr */
+
+
+		if (len < sizeof(struct wpa_mlo_link_kde)) {
+			wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 error mlo link");
+			return -1;
+		}
+
+		len -= sizeof(struct wpa_mlo_link_kde);
+		if (mlo_link->info & BIT(4)) {
+			if (len < 2 || len < mlo_link->var[1] + 2) {
+				wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 wrong mlo rsne len");
+				return -1;
+			} else {
+				rsne = &mlo_link->var[0];
+				rsne_len = mlo_link->var[1] + 2;
+				len -= rsne_len;
+			}
+		}
+
+		if (mlo_link->info & BIT(5)) {
+			if (len < 2 || len < mlo_link->var[rsne_len + 1] + 2) {
+				wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 wrong mlo rsnxe len");
+				return -1;
+			} else {
+				rsnxe = &mlo_link->var[rsne_len];
+				rsnxe_len = mlo_link->var[rsne_len + 1] + 2;
+				len -= rsnxe_len;
+			}
+		}
+
+		if (len != 0) {
+			wpa_printf(MSG_INFO,
+				"ML: EAPOL-Key 3/4 (%d/%d) link id=%d wrong data len, rsne_len=%d, rsnxe_len=%d, left=%d",
+					(int)i, (int)ie->mlo_link.num, mlo_link->info & 0xf,
+					rsne_len, rsnxe_len, (int)len);
+			return -1;
+		}
+		/*mlo link kde*/
+		if (sm->ap_ml_ie) {
+			found = 0;
+			for (j = 0; j < sm->ap_ml_ie->prof_num; j++) {
+				if (os_memcmp(sm->ap_ml_ie->profiles[j].addr,
+						mlo_link->addr, ETH_ALEN) == 0 &&
+				    sm->ap_ml_ie->profiles[j].link_id ==
+						(mlo_link->info & 0xf)) {
+					found = 1;
+					break;
+				}
+			}
+
+			if (!found) {
+				/*setup link kde not check*/
+				if (os_memcmp(sm->bssid,
+					mlo_link->addr, ETH_ALEN) != 0 ||
+				    sm->ap_ml_ie->link_id != (mlo_link->info & 0xf)) {
+					wpa_printf(MSG_INFO,
+						"ML: EAPOL-Key 3/4 wrong link, expect["MACSTR", %d] input["MACSTR", %d]",
+						MAC2STR(sm->bssid), sm->ap_ml_ie->link_id,
+						MAC2STR(mlo_link->addr), mlo_link->info & 0xf);
+					return -1;
+				}
+			}
+		}
+
+		/* mlo without rsn/rsx but beacon does or length not matched */
+		if ((!(mlo_link->info & 0xf0) && (target_wpa->ap_rsn_ie || target_wpa->ap_rsnxe))) {
+			wpa_printf(MSG_INFO, "ML: IE in 3/4 msg does not match "
+					     "with IE in Beacon/ProbeResp (no IE?)");
+			return -1;
+		}
+
+		/* rsne */
+		if (rsne && target_wpa->ap_rsn_ie &&
+		    wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+					target_wpa->ap_rsn_ie, target_wpa->ap_rsn_ie_len,
+					rsne, rsne_len)) {
+			wpa_printf(MSG_INFO, "ML: IE in 3/4 msg does not match "
+					     "with IE in Beacon/ProbeResp (rsne)");
+			wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
+				    target_wpa->ap_rsn_ie, target_wpa->ap_rsn_ie_len);
+			wpa_hexdump(MSG_INFO, "RSNE in EAPOL-Key msg 3/4",
+				    rsne, rsne_len);
+			{
+				size_t ie1len=  target_wpa->ap_rsn_ie_len, ie2len = rsne_len;
+				struct wpa_ie_data ie1d, ie2d;
+				if (wpa_parse_wpa_ie_rsn(target_wpa->ap_rsn_ie, ie1len, &ie1d) < 0 ||
+				    wpa_parse_wpa_ie_rsn(rsne, ie2len, &ie2d) < 0)
+			return -1;
+				wpa_printf(MSG_INFO, "ML: IE in 3/4 msg GTK/PTK COUNTER: 0x%04x- 0x%04x",
+					     ie1d.capabilities, ie2d.capabilities);
+				if (ie1d.proto == ie2d.proto &&
+				    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
+				    ie1d.group_cipher == ie2d.group_cipher &&
+				    (ie1d.key_mgmt & ie2d.key_mgmt) &&
+				    ((ie1d.capabilities & 0xffbf) == (ie2d.capabilities & 0xffbf))&&
+				    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
+					/*
+				    spec draft2.0
+					12.6.2 RSNA selection
+					Insert the following paragraph after the third paragraph ("A STA shall advertise the same
+					RSNE..."):
+					All APs affiliated with an AP MLD shall advertise the same RSNE and RSNXE if included, with the
+					exception of the AKM Suite List field and the MFPR subfield of the RSN Capabilities field. All APs
+					affiliated with an AP MLD shall advertise at least one common AKM suite selector in the AKM Suite List
+					field.
+					*/
+					wpa_printf(MSG_INFO, "ML: PASS: IE in 3/4 msg RSN AKM have common suite or MFPR not same."
+					     "with IE in Beacon/ProbeResp (rsne), check pass.");
+				else
+					return -1;
+			}
+		}
+
+		if (sm->proto == WPA_PROTO_WPA &&
+		    rsne && target_wpa->ap_rsn_ie == NULL && sm->rsn_enabled) {
+			wpa_printf(MSG_INFO, "ML: Possible downgrade attack "
+					       "detected - RSN was enabled and RSN IE "
+					       "was in msg 3/4, but not in "
+					       "Beacon/ProbeResp");
+			return -1;
+		}
+
+		if (sm->proto == WPA_PROTO_RSN &&
+		    ((target_wpa->ap_rsnxe && !rsnxe) ||
+		     (!target_wpa->ap_rsnxe && rsnxe) ||
+		     (target_wpa->ap_rsnxe && rsnxe &&
+		      (target_wpa->ap_rsnxe_len != rsnxe_len ||
+		       os_memcmp(target_wpa->ap_rsnxe, rsnxe, target_wpa->ap_rsnxe_len) != 0)))) {
+			wpa_printf(MSG_INFO, "ML: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+			wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+				    target_wpa->ap_rsnxe, target_wpa->ap_rsnxe_len);
+			wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
+				    rsnxe, rsnxe_len);
+			return -1;
+		}
+	}
+
+	/* mlo gtk */
+	if (ie->gtk) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 should not have Basic GTK IE");
+		return -1;
+	}
+
+	if (ie->mlo_gtk.num > 0 && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 MLO GTK IE in unencrypted key data");
+		return -1;
+	}
+
+
+	for (i = 0; i < ie->mlo_gtk.num; i++) {
+		struct wpa_mlo_gtk_kde *mlo_gtk =
+			(struct wpa_mlo_gtk_kde *) ie->mlo_gtk.kdes[i].data;
+		u8 link_id = (mlo_gtk->info & 0xf0) >> 4;
+
+		if (sm->ap_ml_ie) {
+			found = 0;
+			for (j = 0; j < sm->ap_ml_ie->prof_num; j++) {
+				if (link_id == sm->ap_ml_ie->profiles[j].link_id) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found) {
+				if (link_id != sm->ap_ml_ie->link_id) {
+					wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 wrong gtk link id, expect=%d input=%d",
+						   sm->ap_ml_ie->link_id, link_id);
+					return -1;
+				}
+			}
+		}
+	}
+
+
+	/* mlo igtk */
+	if (ie->igtk) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 should not have Basic IGTK IE");
+		return -1;
+	}
+
+	if (ie->mlo_igtk.num > 0 && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 MLO IGTK IE in unencrypted key data");
+		return -1;
+	}
+
+	for (i = 0; i < ie->mlo_igtk.num; i++) {
+		struct wpa_mlo_igtk_kde *mlo_igtk =
+			(struct wpa_mlo_igtk_kde *) ie->mlo_igtk.kdes[i].data;
+		u8 link_id = (mlo_igtk->info & 0xf0) >> 4;
+		size_t len = ie->mlo_igtk.kdes[i].len;
+
+		if (sm->ap_ml_ie) {
+			found = 0;
+			for (j = 0; j < sm->ap_ml_ie->prof_num; j++) {
+				if (link_id == sm->ap_ml_ie->profiles[j].link_id) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found) {
+				if (link_id != sm->ap_ml_ie->link_id) {
+					wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 wrong igtk link id, expect=%d input=%d",
+						   sm->ap_ml_ie->link_id, link_id);
+					return -1;
+				}
+			}
+		}
+
+		if (sm->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+		    wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
+		    len != WPA_MLO_IGTK_KDE_PREFIX_LEN +
+		    (unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
+			wpa_printf(MSG_INFO, "ML: Invalid IGTK KDE length %lu",
+				(unsigned long) len);
+			return -1;
+		}
+	}
+
+	/* mlo bigtk */
+	if (ie->bigtk) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 should not have Basic BIGTK IE");
+		return -1;
+	}
+
+	if (ie->mlo_bigtk.num > 0 && !sm->beacon_prot) {
+		wpa_printf(MSG_INFO,
+			"ML: EAPOL-Key 3/4 MLO BIGTK IE in unencrypted key data");
+		return -1;
+	}
+
+	for (i = 0; i < ie->mlo_bigtk.num; i++) {
+		struct wpa_mlo_bigtk_kde *mlo_bigtk =
+			(struct wpa_mlo_bigtk_kde *) ie->mlo_bigtk.kdes[i].data;
+		u8 link_id = (mlo_bigtk->info & 0xf0) >> 4;
+		size_t len = ie->mlo_bigtk.kdes[i].len;
+
+		if (sm->ap_ml_ie) {
+			found = 0;
+			for (j = 0; j < sm->ap_ml_ie->prof_num; j++) {
+				if (link_id == sm->ap_ml_ie->profiles[j].link_id) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found) {
+				if (link_id != sm->ap_ml_ie->link_id) {
+					wpa_printf(MSG_INFO, "ML: EAPOL-Key 3/4 wrong bigtk link id, expect=%d input=%d",
+						   sm->ap_ml_ie->link_id, link_id);
+					return -1;
+				}
+			}
+		}
+		if (sm->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+		    wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
+		    len != WPA_MLO_BIGTK_KDE_PREFIX_LEN +
+		    (unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
+			wpa_printf(MSG_INFO, "ML: Invalid BIGTK KDE length %lu",
+				(unsigned long) len);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int ml_rsc_relaxation(const struct wpa_sm *sm, const u8 *rsc)
+{
+	int rsclen;
+
+	if (!sm->wpa_rsc_relaxation)
+		return 0;
+
+	rsclen = wpa_cipher_rsc_len(sm->group_cipher);
+
+	/*
+	 * Try to detect RSC (endian) corruption issue where the AP sends
+	 * the RSC bytes in EAPOL-Key message in the wrong order, both if
+	 * it's actually a 6-byte field (as it should be) and if it treats
+	 * it as an 8-byte field.
+	 * An AP model known to have this bug is the Sapido RB-1632.
+	 */
+	if (rsclen == 6 && ((rsc[5] && !rsc[0]) || rsc[6] || rsc[7])) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"RSC %02x%02x%02x%02x%02x%02x%02x%02x is likely bogus, using 0",
+			rsc[0], rsc[1], rsc[2], rsc[3],
+			rsc[4], rsc[5], rsc[6], rsc[7]);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int ml_gtk_tx_bit_workaround(const struct wpa_sm *sm,
+						int tx)
+{
+	if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) {
+		/* Ignore Tx bit for GTK if a pairwise key is used. One AP
+		 * seemed to set this bit (incorrectly, since Tx is only when
+		 * doing Group Key only APs) and without this workaround, the
+		 * data connection does not work because wpa_supplicant
+		 * configured non-zero keyidx to be used for unicast. */
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"ML: Tx bit set for GTK, but pairwise "
+			"keys are used - ignore Tx bit");
+		return 0;
+	}
+	return tx;
+}
+
+static int ml_check_group_cipher(struct wpa_sm *sm,
+					     int group_cipher,
+					     int keylen, int maxkeylen,
+					     int *key_rsc_len,
+					     enum wpa_alg *alg)
+{
+	int klen;
+
+	*alg = wpa_cipher_to_alg(group_cipher);
+	if (*alg == WPA_ALG_NONE) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"ML: Unsupported Group Cipher %d",
+			group_cipher);
+		return -1;
+	}
+	*key_rsc_len = wpa_cipher_rsc_len(group_cipher);
+
+	klen = wpa_cipher_key_len(group_cipher);
+	if (keylen != klen || maxkeylen < klen) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"ML: Unsupported %s Group Cipher key length %d (%d)",
+			wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+		return -1;
+	}
+	return 0;
+}
+
+static int ml_install_gtk(struct wpa_sm *sm,
+			const struct wpa_eapol_key *key,
+			struct wpa_eapol_ie_parse *ie, u8 wnm_sleep)
+{
+	struct wpa_supplicant *wpa_s = sm->ctx->ctx;
+	struct ml_gtk_data data, *gd = &data;
+	const u8 *key_rsc, *gtk;
+	size_t gtk_len, i;
+	char cmd[32], buf[256];
+	u8 gtk_buf[32], *_gtk;
+
+	for (i = 0; i < ie->mlo_gtk.num; i++) {
+		gtk = ie->mlo_gtk.kdes[i].data;
+		gtk_len = ie->mlo_gtk.kdes[i].len;
+
+		os_memset(gd, 0, sizeof(*gd));
+		wpa_hexdump_key(MSG_DEBUG, "ML: received GTK in pairwise handshake",
+				gtk, gtk_len);
+
+		if (gtk_len < WPA_MLO_GTK_KDE_PREFIX_LEN ||
+		    gtk_len - WPA_MLO_GTK_KDE_PREFIX_LEN > sizeof(gd->gtk))
+			return -1;
+
+		gd->link_id = (gtk[0] & 0xf0) >> 4;
+		gd->keyidx = gtk[0] & 0x3;
+		gd->tx = ml_gtk_tx_bit_workaround(sm, !!(gtk[0] & BIT(2)));
+		gtk += WPA_MLO_GTK_KDE_PREFIX_LEN ;
+		gtk_len -= WPA_MLO_GTK_KDE_PREFIX_LEN;
+
+		os_memcpy(gd->gtk, gtk, gtk_len);
+		gd->gtk_len = gtk_len;
+
+		key_rsc = key->key_rsc;
+		if (ml_rsc_relaxation(sm, key->key_rsc))
+			key_rsc = null_rsc;
+
+
+		if (ml_check_group_cipher(sm, sm->group_cipher,
+				       gtk_len, gtk_len,
+				       &gd->key_rsc_len, &gd->alg)) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"ML: Check group cipher failed");
+			forced_memzero(gd, sizeof(*gd));
+			return -1;
+		}
+
+		_gtk = gd->gtk;
+
+		/* Detect possible key reinstallation */
+		if ((sm->ml_gtk.gtks[i].gtk_len == (size_t) gd->gtk_len &&
+		     os_memcmp(sm->ml_gtk.gtks[i].gtk, gd->gtk, sm->ml_gtk.gtks[i].gtk_len) == 0) ||
+		    (sm->ml_gtk_wnm_sleep.gtks[i].gtk_len == (size_t) gd->gtk_len &&
+		     os_memcmp(sm->ml_gtk_wnm_sleep.gtks[i].gtk, gd->gtk,
+			       sm->ml_gtk_wnm_sleep.gtks[i].gtk_len) == 0)) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"ML: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
+				gd->keyidx, gd->tx, gd->gtk_len);
+			continue;
+		}
+
+		wpa_hexdump_key(MSG_INFO, "ML: Group Key", gd->gtk, gd->gtk_len);
+		wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+			"ML: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
+			gd->keyidx, gd->tx, gd->gtk_len);
+		wpa_hexdump(MSG_INFO, "WPA: RSC", key_rsc, gd->key_rsc_len);
+		if (sm->group_cipher == WPA_CIPHER_TKIP) {
+			/* Swap Tx/Rx keys for Michael MIC */
+			os_memcpy(gtk_buf, gd->gtk, 16);
+			os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
+			os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
+			_gtk = gtk_buf;
+		}
+
+		// TODO: remove this when kernel is ready
+		os_snprintf(cmd, sizeof(cmd), CMD_PRESET_LINKID "=%d", gd->link_id);
+		wpa_drv_driver_cmd(wpa_s, cmd, buf, sizeof(buf));
+
+		if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+			if (wpa_sm_set_key(sm, gd->alg, NULL,
+					   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
+					   _gtk, gd->gtk_len,
+					   KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
+				wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+					"ML: Failed to set GTK to the driver "
+					"(Group only)");
+				forced_memzero(gtk_buf, sizeof(gtk_buf));
+				return -1;
+			}
+		} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
+					  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
+					  _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"ML: Failed to set GTK to "
+				"the driver (alg=%d keylen=%d keyidx=%d)",
+				gd->alg, gd->gtk_len, gd->keyidx);
+			forced_memzero(gtk_buf, sizeof(gtk_buf));
+			return -1;
+		}
+
+		if (wnm_sleep) {
+			sm->ml_gtk_wnm_sleep.gtks[i].gtk_len = gd->gtk_len;
+			os_memcpy(sm->ml_gtk_wnm_sleep.gtks[i].gtk, gd->gtk,
+				  sm->ml_gtk_wnm_sleep.gtks[i].gtk_len);
+		} else {
+			sm->ml_gtk.gtks[i].gtk_len = gd->gtk_len;
+			os_memcpy(sm->ml_gtk.gtks[i].gtk, gd->gtk,
+				  sm->ml_gtk.gtks[i].gtk_len);
+		}
+
+		forced_memzero(gd, sizeof(*gd));
+		forced_memzero(gtk_buf, sizeof(gtk_buf));
+	}
+
+	return 0;
+}
+
+static int ml_install_igtk(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+		struct wpa_eapol_ie_parse *ie, u8 wnm_sleep)
+{
+	struct wpa_supplicant *wpa_s = sm->ctx->ctx;
+	char cmd[32], buf[256];
+	size_t i;
+	size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+	struct wpa_mlo_igtk_kde *igtk;
+	size_t igtk_len;
+	u16 keyidx;
+	u8 link_id;
+
+	for (i = 0; i < ie->mlo_igtk.num; i++) {
+		igtk = (struct wpa_mlo_igtk_kde *) ie->mlo_igtk.kdes[i].data;
+		igtk_len = ie->mlo_igtk.kdes[i].len;
+		keyidx = WPA_GET_LE16(igtk->keyid);
+		link_id = (igtk->info & 0xf0) >> 4;
+
+		if (igtk_len != WPA_MLO_IGTK_KDE_PREFIX_LEN + len)
+			return -1;
+
+		/* Detect possible key reinstallation */
+		if ((sm->ml_igtk.igtks[i].igtk_len == len &&
+		     os_memcmp(sm->ml_igtk.igtks[i].igtk, igtk->igtk,
+			       sm->ml_igtk.igtks[i].igtk_len) == 0) ||
+		    (sm->ml_igtk_wnm_sleep.igtks[i].igtk_len == len &&
+		     os_memcmp(sm->ml_igtk_wnm_sleep.igtks[i].igtk, igtk->igtk,
+			       sm->ml_igtk_wnm_sleep.igtks[i].igtk_len) == 0)){
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"ML: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
+				keyidx);
+			continue;
+		}
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+			"ML: IGTK keyid %d pn " COMPACT_MACSTR,
+			keyidx, MAC2STR(igtk->pn));
+		wpa_hexdump_key(MSG_DEBUG, "ML: IGTK", igtk->igtk, len);
+		if (keyidx > 4095) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"ML: Invalid IGTK KeyID %d", keyidx);
+			return -1;
+		}
+
+
+		// TODO: remove this when kernel is ready
+		os_snprintf(cmd, sizeof(cmd), CMD_PRESET_LINKID "=%d", link_id);
+		wpa_drv_driver_cmd(wpa_s, cmd, buf, sizeof(buf));
+
+		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+				   broadcast_ether_addr,
+				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
+				   igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
+			if (keyidx == 0x0400 || keyidx == 0x0500) {
+				/* Assume the AP has broken PMF implementation since it
+				 * seems to have swapped the KeyID bytes. The AP cannot
+				 * be trusted to implement BIP correctly or provide a
+				 * valid IGTK, so do not try to configure this key with
+				 * swapped KeyID bytes. Instead, continue without
+				 * configuring the IGTK so that the driver can drop any
+				 * received group-addressed robust management frames due
+				 * to missing keys.
+				 *
+				 * Normally, this error behavior would result in us
+				 * disconnecting, but there are number of deployed APs
+				 * with this broken behavior, so as an interoperability
+				 * workaround, allow the connection to proceed. */
+				wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+					"ML: Ignore IGTK configuration error due to invalid IGTK KeyID byte order");
+			} else {
+				wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+					"ML: Failed to configure IGTK to the driver");
+				return -1;
+			}
+		}
+
+		if (wnm_sleep) {
+			sm->ml_igtk_wnm_sleep.igtks[i].igtk_len = len;
+			os_memcpy(sm->ml_igtk_wnm_sleep.igtks[i].igtk, igtk->igtk, len);
+		} else {
+			sm->ml_igtk.igtks[i].igtk_len = len;
+			os_memcpy(sm->ml_igtk.igtks[i].igtk, igtk->igtk, len);
+		}
+	}
+
+	return 0;
+}
+
+static int ml_install_bigtk(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+		struct wpa_eapol_ie_parse *ie, u8 wnm_sleep)
+{
+	struct wpa_supplicant *wpa_s = sm->ctx->ctx;
+	char cmd[32], buf[256];
+	size_t i;
+	size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+	struct wpa_mlo_bigtk_kde *bigtk;
+	size_t bigtk_len;
+	u16 keyidx;
+	u8 link_id;
+
+	for (i = 0; i < ie->mlo_bigtk.num; i++) {
+		bigtk = (struct wpa_mlo_bigtk_kde *) ie->mlo_bigtk.kdes[i].data;
+		bigtk_len = ie->mlo_igtk.kdes[i].len;
+		keyidx = WPA_GET_LE16(bigtk->keyid);
+		link_id = (bigtk->info & 0xf0) >> 4;
+
+		if (bigtk_len != WPA_MLO_BIGTK_KDE_PREFIX_LEN + len)
+			return -1;
+
+		/* Detect possible key reinstallation */
+		if ((sm->ml_bigtk.bigtks[i].bigtk_len == len &&
+		     os_memcmp(sm->ml_bigtk.bigtks[i].bigtk, bigtk->bigtk,
+			       sm->ml_bigtk.bigtks[i].bigtk_len) == 0) ||
+		    (sm->ml_bigtk_wnm_sleep.bigtks[i].bigtk_len == len &&
+		     os_memcmp(sm->ml_bigtk_wnm_sleep.bigtks[i].bigtk, bigtk->bigtk,
+			       sm->ml_bigtk_wnm_sleep.bigtks[i].bigtk_len) == 0)) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"ML: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+				keyidx);
+			return  0;
+		}
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"ML: BIGTK keyid %d pn " COMPACT_MACSTR,
+			keyidx, MAC2STR(bigtk->pn));
+		wpa_hexdump_key(MSG_DEBUG, "ML: BIGTK", bigtk->bigtk, len);
+		if (keyidx < 6 || keyidx > 7) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"ML: Invalid BIGTK KeyID %d", keyidx);
+			return -1;
+		}
+
+		// TODO: remove this when kernel is ready
+		os_snprintf(cmd, sizeof(cmd), CMD_PRESET_LINKID "=%d", link_id);
+		wpa_drv_driver_cmd(wpa_s, cmd, buf, sizeof(buf));
+
+		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+				   broadcast_ether_addr,
+				   keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+				   bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to configure BIGTK to the driver");
+			return -1;
+		}
+
+		if (wnm_sleep) {
+			sm->ml_bigtk_wnm_sleep.bigtks[i].bigtk_len = len;
+			os_memcpy(sm->ml_bigtk_wnm_sleep.bigtks[i].bigtk, bigtk->bigtk,
+				  sm->ml_bigtk_wnm_sleep.bigtks[i].bigtk_len);
+		} else {
+			sm->ml_bigtk.bigtks[i].bigtk_len = len;
+			os_memcpy(sm->ml_bigtk.bigtks[i].bigtk, bigtk->bigtk,
+				  sm->ml_bigtk.bigtks[i].bigtk_len);
+		}
+	}
+
+	return 0;
+}
+
+int ml_process_m1_kde(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie)
+{
+	wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "(%s)[%d]:sm->dot11MultiLinkActivated: %d. MSG1\n",
+				__func__, __LINE__, sm->dot11MultiLinkActivated);
+	if (sm->dot11MultiLinkActivated) {
+		if (ie->mac_addr) {
+			wpa_hexdump(MSG_DEBUG, "ML: MAC from "
+			    "Authenticator", ie->mac_addr, ie->mac_addr_len);
+			if (os_memcmp(ie->mac_addr, sm->ml_bssid, ETH_ALEN) != 0) {
+				wpa_dbg(sm->ctx->msg_ctx, MSG_ERROR,
+				"ML: ML MAC Addr from M1 is different");
+				return -1;
+			}
+		} else {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_ERROR,
+				"ML: ML MAC Addr should be in M1");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int ml_process_m3_kde(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+	struct wpa_eapol_ie_parse *ie)
+{
+	u16 key_info;
+	size_t i, j;
+	u8 found = 0;
+
+	key_info = WPA_GET_BE16(key->key_info);
+
+	if(!sm->dot11MultiLinkActivated)
+		return 0;
+
+	/* mlo gtk */
+	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+		/* No GTK to be set to the driver */
+	} else if (ie->mlo_gtk.num > 0 &&
+		ml_install_gtk(sm, key, ie, 0) < 0) {
+		    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			    "ML: Failed to configure GTK");
+		return -1;
+	}
+
+	if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) ||
+	    sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+		/* No IGTK to be set to the driver */
+	} else if (ie->mlo_igtk.num > 0 &&
+		ml_install_igtk(sm, key, ie, 0) < 0) {
+		    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			    "ML: Failed to configure IGTK");
+		return -1;
+	}
+
+	if (!sm->beacon_prot) {
+		/* No BIGTK to be set to the driver */
+	} else if (ie->mlo_bigtk.num > 0 &&
+		ml_install_bigtk(sm, key, ie, 0) < 0) {
+		    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			    "ML: Failed to configure BIGTK");
+		return -1;
+	}
+
+	return 0;
+}
+
+int ml_process_1_of_2(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+	const u8 *key_data, size_t key_data_len, u16 key_info)
+{
+	struct wpa_eapol_ie_parse parse;
+	struct wpa_eapol_ie_parse *ie = &parse;
+
+	if(!sm->dot11MultiLinkActivated)
+		return 0;
+
+	wpa_hexdump(MSG_INFO, "ML: Group 1/2 IE KeyData", key_data, key_data_len);
+	if (wpa_supplicant_parse_ies(key_data, key_data_len, ie) < 0)
+		return -1;
+
+	/* mlo gtk */
+	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+		/* No GTK to be set to the driver */
+	} else if (ie->mlo_gtk.num > 0 &&
+		ml_install_gtk(sm, key, ie, 0) < 0) {
+		    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			    "ML: Failed to configure GTK");
+		return -1;
+	}
+
+	if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) ||
+	    sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+		/* No IGTK to be set to the driver */
+	} else if (ie->mlo_igtk.num > 0 &&
+		ml_install_igtk(sm, key, ie, 0) < 0) {
+		    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			    "ML: Failed to configure IGTK");
+		return -1;
+	}
+
+	if (!sm->beacon_prot) {
+		/* No BIGTK to be set to the driver */
+	} else if (ie->mlo_bigtk.num > 0 &&
+		ml_install_bigtk(sm, key, ie, 0) < 0) {
+		    wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			    "ML: Failed to configure BIGTK");
+		return -1;
+	}
+
+	return 0;
+}
+
+size_t ml_add_key_request_kde(struct wpa_sm *sm, u8 *pos)
+{
+	struct wpa_ml_ie_parse *ml = sm->sta_ml_ie;
+	u8 i;
+
+	if (!sm->dot11MultiLinkActivated)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "ML: Add Mac into Key Request");
+	return ml_set_mac_kde(pos, sm->own_ml_addr) - pos;
+}
+
+size_t ml_add_m4_kde(struct wpa_sm *sm, u8 *pos)
+{
+	struct wpa_ml_ie_parse *ml = sm->sta_ml_ie;
+	u8 i;
+
+	if (!sm->dot11MultiLinkActivated)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "ML: Add Mac into EAPOL-Key 4/4");
+	return ml_set_mac_kde(pos, sm->own_ml_addr) - pos;
+}
+
+size_t ml_add_2_of_2_kde(struct wpa_sm *sm, u8 *pos)
+{
+	struct wpa_ml_ie_parse *ml = sm->sta_ml_ie;
+	u8 i;
+
+	if (!sm->dot11MultiLinkActivated)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "ML: Add Mac into EAPOL-Key Group 2/2");
+	return ml_set_mac_kde(pos, sm->own_ml_addr) - pos;
+}
+
+	/*
+	 * First, determine the number of P2P supported channels in the
+	 * pref_freq_list returned from driver. This is needed for calculations
+	 * of the vendor IE size.
+	 */
+
+
+
+
+
Index: hostapd-2022-07-29-b704dc72/src/ml/ml_supplicant.h
===================================================================
--- /dev/null
+++ hostapd-2022-07-29-b704dc72/src/ml/ml_supplicant.h
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ *
+ * This file is provided under a dual license.  When you use or
+ * distribute this software, you may choose to be licensed under
+ * version 2 of the GNU General Public License ("GPLv2 License")
+ * or BSD License.
+ *
+ * GPLv2 License
+ *
+ * Copyright(C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(C) 2016 MediaTek Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+#ifndef WPA_ML_SUPPLICANT_H
+#define WPA_ML_SUPPLICANT_H
+
+int ml_set_sae_auth_commit_req_ml_ie(struct sae_data * sae,const u8 * ies,size_t ies_len);
+int ml_set_assoc_req_ml_ie(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
+int ml_set_assoc_resp_ml_ie(struct wpa_sm *sm, const u8 *ies, size_t ies_len, u8 *bssid);
+size_t ml_add_m2_kde(struct wpa_sm *sm, u8 *pos);
+int ml_validate_m3_kde(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+	struct wpa_eapol_ie_parse *ie);
+int ml_process_m1_kde(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie);
+int ml_process_m3_kde(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+	struct wpa_eapol_ie_parse *ie);
+size_t ml_add_m4_kde(struct wpa_sm *sm, u8 *pos);
+size_t ml_add_key_request_kde(struct wpa_sm *sm, u8 *pos);
+size_t ml_add_2_of_2_kde(struct wpa_sm *sm, u8 *pos);
+int ml_process_1_of_2(struct wpa_sm *sm, const struct wpa_eapol_key *key,
+		const u8 *key_data, size_t key_data_len, u16 key_info);
+const u8 * ml_get_ie(const u8 *ies, size_t ie_len, u32 ml_ie_type);
+
+#ifdef CONFIG_MTK_IEEE80211BE
+const u8 * ml_sm_spa(struct wpa_sm *sm, const u8 *own_addr);
+const u8 * ml_sm_aa(struct wpa_sm *sm, const u8 *bssid);
+#else
+#define ml_sm_spa(__sm, __addr) __addr
+#define ml_sm_aa(__sm, __addr) __addr
+#endif
+
+#endif /* WPA_ML_SUPPLICANT_H */
Index: hostapd-2022-07-29-b704dc72/src/p2p/p2p_i.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/p2p/p2p_i.h
+++ hostapd-2022-07-29-b704dc72/src/p2p/p2p_i.h
@@ -657,6 +657,10 @@ struct p2p_message {
 
 	const u8 *pref_freq_list;
 	size_t pref_freq_list_len;
+#ifdef CONFIG_MTK_IEEE80211BE
+	const u8 *ml_channel_list;
+	size_t ml_channel_list_len;
+#endif
 };
 
 
Index: hostapd-2022-07-29-b704dc72/src/rsn_supp/pmksa_cache.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/rsn_supp/pmksa_cache.c
+++ hostapd-2022-07-29-b704dc72/src/rsn_supp/pmksa_cache.c
@@ -14,6 +14,11 @@
 #include "wpa.h"
 #include "wpa_i.h"
 #include "pmksa_cache.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "ml/ml_supplicant.h"
+#endif
+
 
 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
 
@@ -184,6 +189,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *
 	if (wpa_key_mgmt_suite_b(akmp) && !kck)
 		return NULL;
 
+	spa = ml_sm_spa(pmksa->sm, spa);
+	aa = ml_sm_aa(pmksa->sm, aa);
+
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL)
 		return NULL;
@@ -400,6 +408,8 @@ struct rsn_pmksa_cache_entry * pmksa_cac
 					       int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+	aa = ml_sm_aa(pmksa->sm, aa);
+
 	while (entry) {
 		if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
 		    (pmkid == NULL ||
Index: hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/rsn_supp/wpa.c
+++ hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa.c
@@ -32,6 +32,10 @@
 #include "pmksa_cache.h"
 #include "wpa_i.h"
 #include "wpa_ie.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "ml/ml_supplicant.h"
+#endif
 
 
 static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -211,6 +215,10 @@ void wpa_sm_key_request(struct wpa_sm *s
 
 	mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
 	hdrlen = sizeof(*reply) + mic_len + 2;
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated)
+		hdrlen += (2 + RSN_SELECTOR_LEN + ETH_ALEN); /* MAC addr KDE */
+#endif
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
 				  hdrlen, &rlen, (void *) &reply);
 	if (rbuf == NULL)
@@ -235,7 +243,12 @@ void wpa_sm_key_request(struct wpa_sm *s
 	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
 
 	mic = (u8 *) (reply + 1);
+#ifdef CONFIG_MTK_IEEE80211BE
+	WPA_PUT_BE16(mic + mic_len, ml_add_key_request_kde(sm, mic +
+		mic_len + 2 /* offset for key data len */));
+#else
 	WPA_PUT_BE16(mic + mic_len, 0);
+#endif
 	if (!(key_info & WPA_KEY_INFO_MIC))
 		key_mic = NULL;
 	else
@@ -245,7 +258,7 @@ void wpa_sm_key_request(struct wpa_sm *s
 		"WPA: Sending EAPOL-Key Request (error=%d "
 		"pairwise=%d ptk_set=%d len=%lu)",
 		error, pairwise, sm->ptk_set, (unsigned long) rlen);
-	wpa_eapol_key_send(sm, &sm->ptk, ver, bssid, ETH_P_EAPOL, rbuf, rlen,
+	wpa_eapol_key_send(sm, &sm->ptk, ver, ml_sm_aa(sm, bssid), ETH_P_EAPOL, rbuf, rlen,
 			   key_mic);
 }
 
@@ -490,7 +503,7 @@ int wpa_supplicant_send_2_of_4(struct wp
 	size_t mic_len, hdrlen, rlen;
 	struct wpa_eapol_key *reply;
 	u8 *rbuf, *key_mic;
-	u8 *rsn_ie_buf = NULL;
+	u8 *rsn_ie_buf = NULL, *ml_ie_buf = NULL;;
 	u16 key_info;
 
 	if (wpa_ie == NULL) {
@@ -536,6 +549,22 @@ int wpa_supplicant_send_2_of_4(struct wp
 		wpa_ie = rsn_ie_buf;
 	}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated) {
+		wpa_hexdump(MSG_DEBUG, "ML: WPA IE before ML processing",
+				wpa_ie, wpa_ie_len);
+		ml_ie_buf = os_malloc(wpa_ie_len + 100);
+		if (ml_ie_buf == NULL) {
+			os_free(rsn_ie_buf);
+			return -1;
+		}
+		os_memcpy(ml_ie_buf, wpa_ie, wpa_ie_len);
+		wpa_ie_len += ml_add_m2_kde(sm, ml_ie_buf + wpa_ie_len);
+		wpa_ie = ml_ie_buf;
+		wpa_hexdump(MSG_DEBUG, "ML: WPA IE after ml kde added",
+			ml_ie_buf, wpa_ie_len);
+	}
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
 
@@ -546,6 +575,7 @@ int wpa_supplicant_send_2_of_4(struct wp
 				  &rlen, (void *) &reply);
 	if (rbuf == NULL) {
 		os_free(rsn_ie_buf);
+		os_free(ml_ie_buf);
 		return -1;
 	}
 
@@ -573,11 +603,12 @@ int wpa_supplicant_send_2_of_4(struct wp
 	WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len); /* Key Data Length */
 	os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */
 	os_free(rsn_ie_buf);
+	os_free(ml_ie_buf);
 
 	os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
-	return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+	return wpa_eapol_key_send(sm, ptk, ver, ml_sm_aa(sm, dst), ETH_P_EAPOL, rbuf, rlen,
 				  key_mic);
 }
 
@@ -619,7 +650,7 @@ static int wpa_derive_ptk(struct wpa_sm
 		kdk_len = 0;
 
 	return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
-			      sm->own_addr, sm->bssid, sm->snonce,
+			      ml_sm_spa(sm, sm->own_addr), ml_sm_aa(sm, sm->bssid), sm->snonce,
 			      key->key_nonce, ptk, akmp,
 			      sm->pairwise_cipher, z, z_len,
 			      kdk_len);
@@ -724,6 +755,10 @@ static void wpa_supplicant_process_1_of_
 				    "Authenticator", ie.pmkid, PMKID_LEN);
 		}
 	}
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (ml_process_m1_kde(sm, &ie) < 0)
+		goto failed;
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
 	if (res == -2) {
@@ -1544,6 +1579,10 @@ static int wpa_supplicant_validate_ie(st
 				      const unsigned char *src_addr,
 				      struct wpa_eapol_ie_parse *ie)
 {
+#ifdef CONFIG_MTK_IEEE80211BE
+		if(sm->dot11MultiLinkActivated)
+			goto skip;
+#endif
 	if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 			"WPA: No WPA/RSN IE for this AP known. "
@@ -1607,7 +1646,9 @@ static int wpa_supplicant_validate_ie(st
 		wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
 		return -1;
 	}
-
+#ifdef CONFIG_MTK_IEEE80211BE
+	skip:
+#endif
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt) &&
 	    wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@@ -1639,6 +1680,10 @@ int wpa_supplicant_send_4_of_4(struct wp
 
 	mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
 	hdrlen = sizeof(*reply) + mic_len + 2;
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated)
+		hdrlen += (2 + RSN_SELECTOR_LEN + ETH_ALEN); /* MAC addr KDE */
+#endif /* CONFIG_MTK_IEEE80211BE */
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
 				  hdrlen, &rlen, (void *) &reply);
 	if (rbuf == NULL)
@@ -1662,10 +1707,15 @@ int wpa_supplicant_send_4_of_4(struct wp
 		  WPA_REPLAY_COUNTER_LEN);
 
 	key_mic = (u8 *) (reply + 1);
+#ifdef CONFIG_MTK_IEEE80211BE
+	WPA_PUT_BE16(key_mic + mic_len, ml_add_m4_kde(sm, key_mic +
+		mic_len + 2 /* offset for key data len */));
+#else
 	WPA_PUT_BE16(key_mic + mic_len, 0);
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
-	return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+	return wpa_eapol_key_send(sm, ptk, ver, ml_sm_aa(sm, dst), ETH_P_EAPOL, rbuf, rlen,
 				  key_mic);
 }
 
@@ -1711,6 +1761,10 @@ static void wpa_supplicant_process_3_of_
 
 	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
 		goto failed;
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (ml_validate_m3_kde(sm, key, &ie) < 0)
+		goto failed;
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	if (wpa_handle_ext_key_id(sm, &ie))
 		goto failed;
@@ -1808,10 +1862,18 @@ static void wpa_supplicant_process_3_of_
 		eapol_sm_notify_portValid(sm->eapol, true);
 	}
 	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (ml_process_m3_kde(sm, key, &ie) < 0)
+		goto failed;
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
 		/* No GTK to be set to the driver */
-	} else if (!ie.gtk && sm->proto == WPA_PROTO_RSN) {
+	} else if (!ie.gtk &&
+#ifdef CONFIG_MTK_IEEE80211BE
+		!sm->dot11MultiLinkActivated &&
+#endif /* CONFIG_MTK_IEEE80211BE */
+		sm->proto == WPA_PROTO_RSN) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"RSN: No GTK KDE included in EAPOL-Key msg 3/4");
 		goto failed;
@@ -1829,11 +1891,19 @@ static void wpa_supplicant_process_3_of_
 		goto failed;
 	}
 
-	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk)
+	if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk
+#ifdef CONFIG_MTK_IEEE80211BE
+		|| ie.mlo_gtk.num > 0
+#endif /* CONFIG_MTK_IEEE80211BE */
+		)
 		wpa_supplicant_key_neg_complete(sm, sm->bssid,
 						key_info & WPA_KEY_INFO_SECURE);
 
-	if (ie.gtk)
+	if (ie.gtk
+#ifdef CONFIG_MTK_IEEE80211BE
+		|| ie.mlo_gtk.num > 0
+#endif /* CONFIG_MTK_IEEE80211BE */
+		)
 		wpa_sm_set_rekey_offload(sm);
 
 	/* Add PMKSA cache entry for Suite B AKMs here since PMKID can be
@@ -2053,6 +2123,11 @@ static int wpa_supplicant_send_2_of_2(st
 
 	mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
 	hdrlen = sizeof(*reply) + mic_len + 2;
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (sm->dot11MultiLinkActivated)
+		hdrlen += (2 + RSN_SELECTOR_LEN + ETH_ALEN); /* MAC addr KDE */
+#endif /* CONFIG_MTK_IEEE80211BE */
+
 	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
 				  hdrlen + kde_len, &rlen, (void *) &reply);
 	if (rbuf == NULL)
@@ -2076,7 +2151,12 @@ static int wpa_supplicant_send_2_of_2(st
 		  WPA_REPLAY_COUNTER_LEN);
 
 	key_mic = (u8 *) (reply + 1);
+#ifdef CONFIG_MTK_IEEE80211BE
+	WPA_PUT_BE16(key_mic + mic_len,
+		ml_add_2_of_2_kde(sm, key_mic + mic_len + 2 /* offset for key data len */) + kde_len);
+#else
 	WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 #ifdef CONFIG_OCV
 	if (wpa_sm_ocv_enabled(sm)) {
@@ -2108,7 +2188,7 @@ static int wpa_supplicant_send_2_of_2(st
 #endif /* CONFIG_OCV */
 
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
-	return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
+	return wpa_eapol_key_send(sm, &sm->ptk, ver, ml_sm_aa(sm, sm->bssid), ETH_P_EAPOL,
 				  rbuf, rlen, key_mic);
 }
 
@@ -2123,6 +2203,7 @@ static void wpa_supplicant_process_1_of_
 	int rekey, ret;
 	struct wpa_gtk_data gd;
 	const u8 *key_rsc;
+	u8 need_install = true;
 
 	if (!sm->msg_3_of_4_ok && !wpa_fils_is_completed(sm)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -2142,6 +2223,22 @@ static void wpa_supplicant_process_1_of_
 		ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data,
 							key_data_len, key_info,
 							&gd);
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (sm->dot11MultiLinkActivated) {
+			wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+			need_install = false;
+			if (ret != -1) {
+				goto failed;
+			} else {
+				ret = ml_process_1_of_2(sm, key, key_data,
+					key_data_len, key_info);
+				if (ret)
+					goto failed;
+				else
+					goto skip;
+			}
+		}
+#endif /* CONFIG_MTK_IEEE80211BE */
 	} else {
 		ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data,
 							key_data_len,
@@ -2156,6 +2253,9 @@ static void wpa_supplicant_process_1_of_
 	key_rsc = key->key_rsc;
 	if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
 		key_rsc = null_rsc;
+#ifdef CONFIG_MTK_IEEE80211BE
+skip:
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
 	    wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
@@ -3012,6 +3112,10 @@ void wpa_sm_deinit(struct wpa_sm *sm)
 #ifdef CONFIG_DPP2
 	wpabuf_clear_free(sm->dpp_z);
 #endif /* CONFIG_DPP2 */
+#ifdef CONFIG_MTK_IEEE80211BE
+	os_free(sm->sta_ml_ie);
+	os_free(sm->ap_ml_ie);
+#endif
 	os_free(sm);
 }
 
@@ -3144,7 +3248,7 @@ void wpa_sm_notify_disassoc(struct wpa_s
  * Configure the PMK for WPA state machine.
  */
 void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
-		    const u8 *pmkid, const u8 *bssid)
+		    const u8 *pmkid, const u8 *spa, const u8 *aa)
 {
 	if (sm == NULL)
 		return;
@@ -3160,10 +3264,10 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, c
 	os_memcpy(sm->xxkey, pmk, pmk_len);
 #endif /* CONFIG_IEEE80211R */
 
-	if (bssid) {
+	if (aa) {
 		sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len,
-						pmkid, NULL, 0, bssid,
-						sm->own_addr,
+						pmkid, NULL, 0, aa,
+						spa,
 						sm->network_ctx, sm->key_mgmt,
 						NULL);
 	}
@@ -3880,6 +3984,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
 	os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
 	os_memset(&sm->igtk, 0, sizeof(sm->igtk));
 	os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
+#ifdef CONFIG_MTK_IEEE80211BE
+	os_memset(&sm->ml_gtk, 0, sizeof(sm->ml_gtk));
+	os_memset(&sm->ml_igtk, 0, sizeof(sm->ml_igtk));
+	os_memset(&sm->ml_bigtk, 0, sizeof(sm->ml_bigtk));
+#endif /* CONFIG_MTK_IEEE80211BE */
 #ifdef CONFIG_IEEE80211R
 	os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
 	sm->xxkey_len = 0;
@@ -4584,7 +4693,7 @@ static int fils_ft_build_assoc_req_rsne(
 	wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
 		   MAC2STR(sm->r1kh_id));
 	pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
-	if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, sm->own_addr,
+	if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, ml_sm_spa(sm, sm->own_addr),
 				   sm->pmk_r1_name, use_sha384) < 0) {
 		wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
 		return -1;
Index: hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/rsn_supp/wpa.h
+++ hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa.h
@@ -147,7 +147,7 @@ void wpa_sm_deinit(struct wpa_sm *sm);
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
 void wpa_sm_notify_disassoc(struct wpa_sm *sm);
 void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
-		    const u8 *pmkid, const u8 *bssid);
+		    const u8 *pmkid, const u8 *spa, const u8 *aa);
 void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
 void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
 void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
@@ -241,7 +241,8 @@ static inline void wpa_sm_notify_disasso
 
 static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
 				  size_t pmk_len, const u8 *pmkid,
-				  const u8 *bssid)
+				  const u8 *spa,
+				  const u8 *aa)
 {
 }
 
Index: hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa_ft.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/rsn_supp/wpa_ft.c
+++ hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa_ft.c
@@ -21,6 +21,9 @@
 #include "wpa_i.h"
 #include "wpa_ie.h"
 #include "pmksa_cache.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_supplicant.h"
+#endif
 
 #ifdef CONFIG_IEEE80211R
 
@@ -57,12 +60,12 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm,
 	sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
 	if (wpa_derive_pmk_r0(mpmk, mpmk_len, sm->ssid,
 			      sm->ssid_len, sm->mobility_domain,
-			      sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
+			      sm->r0kh_id, sm->r0kh_id_len, ml_sm_spa(sm, sm->own_addr),
 			      sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
 		return -1;
 	sm->pmk_r1_len = sm->pmk_r0_len;
 	if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
-			      sm->r1kh_id, sm->own_addr, sm->pmk_r1,
+			      sm->r1kh_id, ml_sm_spa(sm, sm->own_addr), sm->pmk_r1,
 			      sm->pmk_r1_name) < 0)
 		return -1;
 
@@ -76,7 +79,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm,
 		kdk_len = 0;
 
 	return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
-				 sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
+				 ml_sm_spa(sm, sm->own_addr), ml_sm_aa(sm, sm->bssid), sm->pmk_r1_name, ptk,
 				 ptk_name, sm->key_mgmt, sm->pairwise_cipher,
 				 kdk_len);
 }
@@ -428,11 +431,15 @@ static u8 * wpa_ft_gen_req_ies(struct wp
 		*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
 		if (rsnxe_len)
 			*elem_count += 1;
-		if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
+		if (wpa_ft_mic(kck, kck_len, ml_sm_spa(sm, sm->own_addr), ml_sm_aa(sm, target_ap), 5,
 			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
 			       ftie_pos, 2 + *ftie_len,
 			       (u8 *) rsnie, 2 + rsnie->len, ric_ies,
 			       ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len,
+#ifdef CONFIG_MTK_IEEE80211BE
+				   NULL,
+				   0,
+#endif
 			       fte_mic) < 0) {
 			wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
 			os_free(buf);
@@ -665,7 +672,7 @@ int wpa_ft_process_response(struct wpa_s
 	wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
 	os_memcpy(sm->anonce, anonce, WPA_NONCE_LEN);
 	if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
-			      sm->r1kh_id, sm->own_addr, sm->pmk_r1,
+			      sm->r1kh_id, ml_sm_spa(sm, sm->own_addr), sm->pmk_r1,
 			      sm->pmk_r1_name) < 0)
 		return -1;
 	sm->pmk_r1_len = sm->pmk_r0_len;
@@ -682,7 +689,7 @@ int wpa_ft_process_response(struct wpa_s
 		kdk_len = 0;
 
 	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
-			      anonce, sm->own_addr, bssid,
+			      anonce, ml_sm_spa(sm, sm->own_addr), ml_sm_aa(sm, bssid),
 			      sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
 			      sm->pairwise_cipher,
 			      kdk_len) < 0)
@@ -1120,13 +1127,18 @@ int wpa_ft_validate_reassoc_resp(struct
 		kck_len = sm->ptk.kck_len;
 	}
 
-	if (wpa_ft_mic(kck, kck_len, sm->own_addr, src_addr, 6,
+	if (wpa_ft_mic(kck, kck_len, ml_sm_spa(sm, sm->own_addr),
+		       ml_sm_aa(sm, src_addr), 6,
 		       parse.mdie - 2, parse.mdie_len + 2,
 		       parse.ftie - 2, parse.ftie_len + 2,
 		       parse.rsn - 2, parse.rsn_len + 2,
 		       parse.ric, parse.ric_len,
 		       parse.rsnxe ? parse.rsnxe - 2 : NULL,
 		       parse.rsnxe ? parse.rsnxe_len + 2 : 0,
+#ifdef CONFIG_MTK_IEEE80211BE
+			   parse.mlie ? parse.mlie - 2 : NULL,
+			   parse.mlie ? parse.mlie_len + 2 : 0,
+#endif
 		       mic) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
 		return -1;
Index: hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa_i.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/rsn_supp/wpa_i.h
+++ hostapd-2022-07-29-b704dc72/src/rsn_supp/wpa_i.h
@@ -13,6 +13,9 @@
 
 struct wpa_tdls_peer;
 struct wpa_eapol_key;
+#ifdef CONFIG_MTK_IEEE80211BE
+struct wpa_ml_ie_parse;
+#endif
 
 struct pasn_ft_r1kh {
 	u8 bssid[ETH_ALEN];
@@ -119,6 +122,20 @@ struct wpa_sm {
 	size_t assoc_rsnxe_len;
 	u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
 	size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 dot11MultiLinkActivated;
+	struct wpa_ml_ie_parse *sta_ml_ie; /* Own ML IE from (Re)AssocReq */
+	struct wpa_ml_ie_parse *ap_ml_ie; /* AP ML IE from (Re)AssocResp */
+	struct ml_gtk_holder ml_gtk;
+	struct ml_gtk_holder ml_gtk_wnm_sleep;
+	struct ml_igtk_holder ml_igtk;
+	struct ml_igtk_holder ml_igtk_wnm_sleep;
+	struct ml_bigtk_holder ml_bigtk;
+	struct ml_bigtk_holder ml_bigtk_wnm_sleep;
+	u8 ml_bssid[ETH_ALEN]; /* ap mld addr */
+	u8 own_ml_addr[ETH_ALEN];
+	u8 prof_num;
+#endif
 
 #ifdef CONFIG_TDLS
 	struct wpa_tdls_peer *tdls;
Index: hostapd-2022-07-29-b704dc72/src/utils/common.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/utils/common.h
+++ hostapd-2022-07-29-b704dc72/src/utils/common.h
@@ -429,6 +429,9 @@ void perror(const char *s);
 #define BIT(x) (1U << (x))
 #endif
 
+#ifndef BITS
+#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n)))
+#endif
 /*
  * Definitions for sparse validation
  * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
Index: hostapd-2022-07-29-b704dc72/src/wps/wps_attr_parse.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/wps/wps_attr_parse.c
+++ hostapd-2022-07-29-b704dc72/src/wps/wps_attr_parse.c
@@ -583,6 +583,7 @@ static int wps_set_attr(struct wps_parse
 		}
 		attr->ap_channel = pos;
 		break;
+
 	default:
 		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
 			   "len=%u", type, len);
Index: hostapd-2022-07-29-b704dc72/src/wps/wps_registrar.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/src/wps/wps_registrar.c
+++ hostapd-2022-07-29-b704dc72/src/wps/wps_registrar.c
@@ -1010,6 +1010,7 @@ int wps_registrar_unlock_pin(struct wps_
 
 static void wps_registrar_stop_pbc(struct wps_registrar *reg)
 {
+
 	reg->selected_registrar = 0;
 	reg->pbc = 0;
 	os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
@@ -1046,6 +1047,7 @@ static void wps_registrar_pbc_timeout(vo
 int wps_registrar_button_pushed(struct wps_registrar *reg,
 				const u8 *p2p_dev_addr)
 {
+
 	if (p2p_dev_addr == NULL &&
 	    wps_registrar_pbc_overlap(reg, NULL, NULL)) {
 		wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
@@ -1085,6 +1087,7 @@ static void wps_registrar_pbc_completed(
 
 static void wps_registrar_pin_completed(struct wps_registrar *reg)
 {
+
 	wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
 	reg->selected_registrar = 0;
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/Makefile
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/Makefile
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/Makefile
@@ -377,6 +377,14 @@ NEED_MD5=y
 endif
 endif
 
+#ifdef CONFIG_MTK_IEEE80211BE
+CFLAGS += -I../wpa_supplicant
+CFLAGS += -DCONFIG_MTK_IEEE80211BE
+OBJS += ../src/drivers/mediatek_driver_cmd_nl80211.o
+OBJS += ../src/ml/ml_common.o
+OBJS += ../src/ml/ml_supplicant.o
+#endif
+
 ifdef CONFIG_IBSS_RSN
 NEED_RSN_AUTHENTICATOR=y
 CFLAGS += -DCONFIG_IBSS_RSN
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/ap.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/ap.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/ap.c
@@ -1019,7 +1019,11 @@ int wpa_supplicant_create_ap(struct wpa_
 		return -1;
 	}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+	wpa_s->ap_iface = hapd_iface = hostapd_iface_alloc(&wpa_s->global->hapd_ifaces);
+#else
 	wpa_s->ap_iface = hapd_iface = hostapd_alloc_iface();
+#endif
 	if (hapd_iface == NULL)
 		return -1;
 	hapd_iface->owner = wpa_s;
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/bss.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/bss.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/bss.c
@@ -19,6 +19,10 @@
 #include "notify.h"
 #include "scan.h"
 #include "bss.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "ml/ml_supplicant.h"
+#endif
 
 static void wpa_bss_set_hessid(struct wpa_bss *bss)
 {
@@ -764,7 +768,7 @@ void wpa_bss_update_scan_res(struct wpa_
 			     struct wpa_scan_res *res,
 			     struct os_reltime *fetch_time)
 {
-	const u8 *ssid, *p2p, *mesh;
+	const u8 *ssid, *p2p, *mesh, *ml_ie;
 	struct wpa_bss *bss;
 
 	if (wpa_s->conf->ignore_old_scan_res) {
@@ -837,6 +841,20 @@ void wpa_bss_update_scan_res(struct wpa_
 
 	if (bss == NULL)
 		return;
+#ifdef CONFIG_MTK_IEEE80211BE
+		os_memcpy(bss->aa, bss->bssid, ETH_ALEN);
+		ml_ie = ml_get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ML_CTRL_TYPE_BASIC);
+		if (ml_ie) {
+			struct wpa_ml_ie_parse ml;
+
+			if (ml_parse_ie(&ml_ie[3], ml_ie[1] - 1, &ml, NULL) == 0) {
+				os_memcpy(bss->aa, ml.ml_addr, ETH_ALEN);
+				wpa_printf(MSG_DEBUG,
+					"ML: BSS[" MACSTR "] set AA[" MACSTR "]",
+					MAC2STR(bss->bssid), MAC2STR(ml.ml_addr));
+			}
+		}
+#endif /* CONFIG_MTK_IEEE80211BE */
 	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
 		struct wpa_bss **n;
 		unsigned int siz;
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/bss.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/bss.h
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/bss.h
@@ -10,6 +10,7 @@
 #define BSS_H
 
 struct wpa_scan_res;
+struct wpa_supplicant;
 
 #define WPA_BSS_QUAL_INVALID		BIT(0)
 #define WPA_BSS_NOISE_INVALID		BIT(1)
@@ -88,6 +89,10 @@ struct wpa_bss {
 	unsigned int flags;
 	/** BSSID */
 	u8 bssid[ETH_ALEN];
+#ifdef CONFIG_MTK_IEEE80211BE
+	/** Authenticator */
+	u8 aa[ETH_ALEN];
+#endif /* CONFIG_MTK_IEEE80211BE */
 	/** HESSID */
 	u8 hessid[ETH_ALEN];
 	/** SSID */
@@ -122,6 +127,9 @@ struct wpa_bss {
 	int snr;
 	/** ANQP data */
 	struct wpa_bss_anqp *anqp;
+#ifdef CONFIG_MTK_IEEE80211BE
+	u8 dot11MultiLinkActivated;
+#endif
 	/** Length of the following IE field in octets (from Probe Response) */
 	size_t ie_len;
 	/** Length of the following Beacon IE field in octets */
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/ctrl_iface.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/ctrl_iface.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/ctrl_iface.c
@@ -59,6 +59,10 @@
 #include "dpp_supplicant.h"
 #include "sme.h"
 
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_supplicant.h"
+#endif /* CONFIG_MTK_IEEE80211BE */
+
 #ifdef __NetBSD__
 #include <net/if_ether.h>
 #elif !defined(__CYGWIN__) && !defined(CONFIG_NATIVE_WINDOWS)
@@ -3164,6 +3168,15 @@ static int wpa_supplicant_ctrl_iface_sca
 		pos += ret;
 	}
 
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (ml_get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ML_CTRL_TYPE_BASIC)) {
+			ret = os_snprintf(pos, end - pos, "[MLO]");
+			if (os_snprintf_error(end - pos, ret))
+				return -1;
+			pos += ret;
+		}
+#endif /* CONFIG_MTK_IEEE80211BE */
+
 	ret = os_snprintf(pos, end - pos, "\t%s",
 			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	if (os_snprintf_error(end - pos, ret))
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/driver_i.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/driver_i.h
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/driver_i.h
@@ -599,7 +599,7 @@ static inline int wpa_drv_tdls_oper(stru
 	return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
 }
 
-#ifdef ANDROID
+#if defined ANDROID || defined(CONFIG_MTK_IEEE80211BE)
 static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s,
 				     char *cmd, char *buf, size_t buf_len)
 {
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/events.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/events.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/events.c
@@ -50,6 +50,10 @@
 #include "mesh_mpm.h"
 #include "wmm_ac.h"
 #include "dpp_supplicant.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ml/ml_common.h"
+#include "ml/ml_supplicant.h"
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 
 #define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
@@ -1603,7 +1607,6 @@ struct wpa_ssid * wpa_scan_res_match(str
 			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - channel disabled");
 		return NULL;
 	}
-
 	for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
 		if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
 				    bss, bssid_ignore_count, debug_print))
@@ -3225,6 +3228,21 @@ no_pfs:
 
 	wpas_handle_assoc_resp_qos_mgmt(wpa_s, data->assoc_info.resp_ies,
 					data->assoc_info.resp_ies_len);
+#ifdef CONFIG_MTK_IEEE80211BE
+	wpa_printf(MSG_DEBUG, "(%s)[%d]: ml_set_assoc_req_ml_ie.\n",
+		__func__, __LINE__);
+	if (!ml_set_assoc_req_ml_ie(wpa_s->wpa, data->assoc_info.req_ies, data->assoc_info.req_ies_len)) {
+		wpa_printf(MSG_DEBUG, "(%s)[%d]: ml_set_assoc_req_ml_ie success.\n",
+		__func__, __LINE__);
+	}
+	wpa_printf(MSG_DEBUG, "(%s)[%d]: ml_set_assoc_resp_ml_ie .\n",
+		__func__, __LINE__);
+	if (!ml_set_assoc_resp_ml_ie(wpa_s->wpa,
+		data->assoc_info.resp_ies, data->assoc_info.resp_ies_len, bssid)) {
+		wpa_printf(MSG_DEBUG, "(%s)[%d]: ml_set_assoc_resp_ml_ie success.\n",
+		__func__, __LINE__);
+	}
+#endif
 
 	return 0;
 }
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/ibss_rsn.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/ibss_rsn.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/ibss_rsn.c
@@ -245,7 +245,7 @@ static int ibss_rsn_supp_init(struct ibs
 	wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
 	wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
 	wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
-	wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL);
+	wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL, NULL);
 
 	peer->supp_ie_len = sizeof(peer->supp_ie);
 	if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/sme.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/sme.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/sme.c
@@ -30,6 +30,9 @@
 #include "scan.h"
 #include "sme.h"
 #include "hs20_supplicant.h"
+#include "ml/ml_supplicant.h"
+#include "ml/ml_common.h"
+#include "rsn_supp/wpa_i.h"
 
 #define SME_AUTH_TIMEOUT 5
 #define SME_ASSOC_TIMEOUT 5
@@ -38,6 +41,7 @@ static void sme_auth_timer(void *eloop_c
 static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
 static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
 static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
+static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid);
 
 
 #ifdef CONFIG_SAE
@@ -95,7 +99,11 @@ static struct wpabuf * sme_auth_build_sa
 	int use_pt = 0;
 	bool use_pk = false;
 	u8 rsnxe_capa = 0;
-
+	const u8 *own_addr = wpa_s->own_addr;
+	const u8 *peer_addr = bssid;
+#ifdef CONFIG_SAE
+	struct sae_data sae;
+#endif
 	if (ret_use_pt)
 		*ret_use_pt = 0;
 	if (ret_use_pk)
@@ -151,6 +159,78 @@ static struct wpabuf * sme_auth_build_sa
 		if (rsnxe && rsnxe[1] >= 1)
 			rsnxe_capa = rsnxe[2];
 	}
+#ifdef CONFIG_MTK_IEEE80211BE
+	ml_set_sae_auth_commit_req_ml_ie(&sae, wpa_s->sme.ext_ie, wpa_s->sme.ext_ie_len);
+	/*update*/
+	wpa_s->sme.sae.dot11MultiLinkActivated = sae.dot11MultiLinkActivated;
+	/*update*/
+	if (wpa_s->sme.sae.dot11MultiLinkActivated) {
+		struct ieee802_11_elems elems;
+		struct wpa_ml_ie_parse ml;
+		struct wpabuf *frag_ml_ie = NULL;
+		const u8 *ml_ie;
+		size_t ml_ie_len = 0;
+		os_memcpy(wpa_s->sme.sae.own_ml_addr, sae.own_ml_addr, ETH_ALEN);
+		wpa_printf(MSG_DEBUG, "(%s)[%d]ML: UPDATE dot11MultiLinkActivated(%d), own_ml_addr:"MACSTR"",
+			__func__, __LINE__, sae.dot11MultiLinkActivated, MAC2STR(sae.own_ml_addr));
+		wpa_hexdump(MSG_DEBUG, "bss_ies probe rsp", bss->ies, bss->ie_len);
+		wpa_hexdump(MSG_DEBUG, "bss_ies    beacon", bss->ies + bss->ie_len, bss->beacon_ie_len);
+		if (ieee802_11_parse_elems(bss->ies, bss->ie_len, &elems, 1) == ParseFailed &&
+			ieee802_11_parse_elems(bss->ies + bss->ie_len, bss->beacon_ie_len, &elems, 1) == ParseFailed) {
+			wpa_printf(MSG_DEBUG, "ML: Failed to parse elements");
+		}
+
+		frag_ml_ie = ieee802_11_defrag(&elems,
+								 WLAN_EID_EXTENSION,
+								 WLAN_EID_EXT_MULTI_LINK);
+		if (!frag_ml_ie) {
+			wpa_printf(MSG_DEBUG, "ML: Missing frag_ml_ie");
+			ml_ie = elems.ml;
+			ml_ie_len = (size_t)elems.ml_len;
+		} else {
+			ml_ie_len = (size_t)wpabuf_len(frag_ml_ie);
+			ml_ie = wpabuf_head_u8(frag_ml_ie);
+
+			wpa_hexdump(MSG_DEBUG, "Multi-link IE defrag results:",
+				ml_ie, ml_ie_len);
+		}
+
+		/* For MLOV1, if no mlo ie in beacon and probe response, try to get it from mtk vendor ie,
+		 * so no need to do defragment
+		 */
+		if (!ml_ie && ml_ie_len == 0) {
+			wpa_printf(MSG_DEBUG, "ML: no standard mlo ie, try to get ml info from mtk vendor ie");
+			ml_ie = ml_get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ML_CTRL_TYPE_BASIC);
+			if (ml_ie) {
+				wpa_printf(MSG_DEBUG, "ML: find ml ie in mtk vendor ie, use it!");
+				ml_ie_len = (size_t)(ml_ie[1] - 1);
+				/*goto common info pos*/
+				ml_ie += 3;
+			}
+		}
+
+		if (!ml_ie) {
+			wpa_printf(MSG_DEBUG, "ML: clearing STA ML IE");
+			bss->dot11MultiLinkActivated = 0;
+		} else {
+			if (ml_parse_ie(ml_ie, ml_ie_len, &ml, NULL) != 0) {
+				bss->dot11MultiLinkActivated = 0;
+			} else {
+				bss->dot11MultiLinkActivated = 1;
+			}
+		}
+		if (bss->dot11MultiLinkActivated) {
+			own_addr = (u8*)wpa_s->sme.sae.own_ml_addr;
+			peer_addr = (u8*)ml.ml_addr;
+			os_memcpy(wpa_s->sme.sae.peer_ml_addr, peer_addr, ETH_ALEN);
+			wpa_printf(MSG_DEBUG, "(%s)[%d] ML:SAE dot11MultiLinkActivated: %d(%d), own_addr:"MACSTR" peer addr:""MAC"MACSTR"\n",
+			__func__, __LINE__, wpa_s->sme.sae.dot11MultiLinkActivated, bss->dot11MultiLinkActivated,
+			MAC2STR(own_addr), MAC2STR(peer_addr));
+		}
+		if (frag_ml_ie)
+			wpabuf_free(frag_ml_ie);
+	}
+#endif /* CONFIG_MTK_IEEE80211BE */
 
 	if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
 		use_pt = 1;
@@ -190,11 +270,11 @@ static struct wpabuf * sme_auth_build_sa
 
 	if (use_pt &&
 	    sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
-				  wpa_s->own_addr, bssid,
+				  own_addr, peer_addr,
 				  wpa_s->sme.sae_rejected_groups, NULL) < 0)
 		return NULL;
 	if (!use_pt &&
-	    sae_prepare_commit(wpa_s->own_addr, bssid,
+	    sae_prepare_commit(own_addr, peer_addr,
 			       (u8 *) password, os_strlen(password),
 			       &wpa_s->sme.sae) < 0) {
 		wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
@@ -1100,6 +1180,13 @@ static int sme_external_auth_send_sae_co
 		status = WLAN_STATUS_SUCCESS;
 	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
 				    bssid, 1, wpa_s->sme.seq_num, status);
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (wpabuf_resize(&buf, wpa_s->sme.ext_ie_len) == 0) {
+		wpa_hexdump(MSG_DEBUG, "ML: SAE VENDOR IE",
+			wpa_s->sme.ext_ie, wpa_s->sme.ext_ie_len);
+		wpabuf_put_data(buf, wpa_s->sme.ext_ie, wpa_s->sme.ext_ie_len);
+	}
+#endif /* CONFIG_MTK_IEEE80211BE */
 	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
@@ -1136,7 +1223,7 @@ static int sme_handle_external_auth_star
 		if (!wpas_network_disabled(wpa_s, ssid) &&
 		    ssid_str_len == ssid->ssid_len &&
 		    os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
-		    (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)))
+		    (wpa_key_mgmt_sae(ssid->key_mgmt)))
 			break;
 	}
 	if (!ssid ||
@@ -1170,6 +1257,13 @@ static void sme_external_auth_send_sae_c
 	sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
 				    da, 2, wpa_s->sme.seq_num,
 				    WLAN_STATUS_SUCCESS);
+#ifdef CONFIG_MTK_IEEE80211BE
+	if (wpabuf_resize(&buf, wpa_s->sme.ext_ie_len) == 0) {
+		wpa_hexdump(MSG_DEBUG, "ML: SAE VENDOR IE",
+			wpa_s->sme.ext_ie, wpa_s->sme.ext_ie_len);
+		wpabuf_put_data(buf, wpa_s->sme.ext_ie, wpa_s->sme.ext_ie_len);
+	}
+#endif /* CONFIG_MTK_IEEE80211BE */
 	wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
 	wpabuf_free(resp);
 	wpabuf_free(buf);
@@ -1180,7 +1274,9 @@ void sme_external_auth_trigger(struct wp
 			       union wpa_event_data *data)
 {
 	if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
-	    RSN_AUTH_KEY_MGMT_SAE)
+	    RSN_AUTH_KEY_MGMT_SAE &&
+	    RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
+	    RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
 		return;
 
 	if (data->external_auth.action == EXT_AUTH_START) {
@@ -1195,6 +1291,12 @@ void sme_external_auth_trigger(struct wp
 		wpa_s->sme.sae.state = SAE_NOTHING;
 		wpa_s->sme.sae.send_confirm = 0;
 		wpa_s->sme.sae_group_index = 0;
+#ifdef CONFIG_MTK_IEEE80211BE
+		os_memcpy(wpa_s->sme.sae.own_ml_addr, wpa_s->own_addr, ETH_ALEN);
+		wpa_s->sme.ext_ie_len = data->external_auth.ext_ie_len;
+		os_memcpy(wpa_s->sme.ext_ie, data->external_auth.ext_ie,
+			wpa_s->sme.ext_ie_len);
+#endif /* CONFIG_MTK_IEEE80211BE */
 		if (sme_handle_external_auth_start(wpa_s, data) < 0)
 			sme_send_external_auth_status(wpa_s,
 					      WLAN_STATUS_UNSPECIFIED_FAILURE);
@@ -1449,7 +1551,10 @@ static int sme_sae_auth(struct wpa_suppl
 			return -1;
 		wpa_s->sme.sae.state = SAE_ACCEPTED;
 		sae_clear_temp_data(&wpa_s->sme.sae);
-
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0)
+			return -1;
+#endif
 		if (external) {
 			/* Report success to driver */
 			sme_send_external_auth_status(wpa_s,
@@ -1467,8 +1572,15 @@ static int sme_sae_set_pmk(struct wpa_su
 {
 	wpa_printf(MSG_DEBUG,
 		   "SME: SAE completed - setting PMK for 4-way handshake");
-	wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, wpa_s->sme.sae.pmk_len,
-		       wpa_s->sme.sae.pmkid, bssid);
+#ifdef CONFIG_MTK_IEEE80211BE
+		if (wpa_s->sme.sae.dot11MultiLinkActivated)
+			wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, wpa_s->sme.sae.pmk_len,
+					   wpa_s->sme.sae.pmkid, wpa_s->sme.sae.own_ml_addr,
+					   wpa_s->sme.sae.peer_ml_addr);
+		else
+#endif /* CONFIG_MTK_IEEE80211BE */
+			wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, wpa_s->sme.sae.pmk_len,
+			wpa_s->sme.sae.pmkid, wpa_s->wpa->own_addr, bssid);
 	if (wpa_s->conf->sae_pmkid_in_assoc) {
 		/* Update the own RSNE contents now that we have set the PMK
 		 * and added a PMKSA cache entry based on the successfully
@@ -1529,9 +1641,10 @@ void sme_external_auth_mgmt_rx(struct wp
 		}
 		if (res != 1)
 			return;
-
+#ifndef CONFIG_MTK_IEEE80211BE
 		if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0)
 			return;
+#endif
 	}
 }
 
@@ -1579,7 +1692,6 @@ void sme_event_auth(struct wpa_supplican
 		if (res < 0) {
 			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-
 		}
 		if (res != 1)
 			return;
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/wpa_supplicant.c
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/wpa_supplicant.c
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/wpa_supplicant.c
@@ -1825,7 +1825,7 @@ int wpa_supplicant_set_suites(struct wpa
 			wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
 					ssid->psk, PMK_LEN);
 			wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
-				       NULL);
+				       NULL, NULL);
 			psk_set = 1;
 		}
 
@@ -1847,7 +1847,7 @@ int wpa_supplicant_set_suites(struct wpa
 			}
 			wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
 					psk, PMK_LEN);
-			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
+			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL, NULL);
 			psk_set = 1;
 			os_memset(psk, 0, sizeof(psk));
 		}
Index: hostapd-2022-07-29-b704dc72/wpa_supplicant/wpa_supplicant_i.h
===================================================================
--- hostapd-2022-07-29-b704dc72.orig/wpa_supplicant/wpa_supplicant_i.h
+++ hostapd-2022-07-29-b704dc72/wpa_supplicant/wpa_supplicant_i.h
@@ -21,6 +21,9 @@
 #include "config_ssid.h"
 #include "wmm_ac.h"
 #include "ubus.h"
+#ifdef CONFIG_MTK_IEEE80211BE
+#include "ap/hostapd.h"
+#endif
 
 extern const char *const wpa_supplicant_version;
 extern const char *const wpa_supplicant_license;
@@ -316,6 +319,9 @@ struct wpa_global {
 	unsigned int pending_p2ps_group:1;
 	unsigned int pending_group_iface_for_p2ps:1;
 	unsigned int pending_p2ps_group_freq;
+#ifdef CONFIG_MTK_IEEE80211BE
+	struct hapd_interfaces hapd_ifaces;
+#endif
 
 #ifdef CONFIG_WIFI_DISPLAY
 	int wifi_display;
@@ -1027,6 +1033,10 @@ struct wpa_supplicant {
 		u8 ext_auth_bssid[ETH_ALEN];
 		u8 ext_auth_ssid[SSID_MAX_LEN];
 		size_t ext_auth_ssid_len;
+#ifdef CONFIG_MTK_IEEE80211BE
+		u8 ext_ie[500];
+		size_t ext_ie_len;
+#endif /* CONFIG_MTK_IEEE80211BE */
 		int *sae_rejected_groups;
 #endif /* CONFIG_SAE */
 	} sme;
