Selaa lähdekoodia

qcacld-3.0: Update SA and DA addresses to the SAE auth frame

Currently, for SAE ML connection, in SAE auth frame
1. Userspace send source address as STA link address and
   destination address as AP link address.
2. Driver send STA and AP link addresses to userspace
   while receiving the SAE auth frame.

Now as a part of userspace changes,
1. Userspace shall send source address as STA MLD address and
   destination address as AP MLD address, those addresses
   driver can not send OTA.
2. Driver needs to send STA MLD and AP MLD address to userspace
   while receiving the SAE auth frame.

Fix is, driver updates the SA and DA as link or MLD address
internally and send OTA or to userspace in SAE auth frame.

Change-Id: Iabd73b7704b5f93cdebe29b920d3c797819f41c1
CRs-Fixed: 3367021
Deeksha Gupta 2 vuotta sitten
vanhempi
sitoutus
50b1c4941f

+ 55 - 6
core/hdd/src/wlan_hdd_assoc.c

@@ -231,16 +231,24 @@ static const int beacon_filter_extn_table[] = {
 		(defined(CFG80211_EXTERNAL_AUTH_SUPPORT) || \
 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0))
 #if defined (CFG80211_SAE_AUTH_TA_ADDR_SUPPORT)
+/**
+ * wlan_hdd_sae_copy_ta_addr() - Send TA address to supplicant
+ * @params: pointer to external auth params
+ * @adapter: pointer adapter context
+ *
+ * This API is used to copy TA address info in supplicant structure.
+ *
+ * Return: None
+ */
 static inline
 void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params,
-			       struct hdd_adapter *adapter,
-			       struct sir_sae_info *sae_info)
+			       struct hdd_adapter *adapter)
 {
 	struct qdf_mac_addr ta = QDF_MAC_ADDR_ZERO_INIT;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	status = ucfg_cm_get_sae_auth_ta(adapter->hdd_ctx->pdev,
-					 sae_info->vdev_id,
+					 adapter->vdev_id,
 					 &ta);
 	if (QDF_IS_STATUS_SUCCESS(status))
 		qdf_mem_copy(params->tx_addr, ta.bytes, QDF_MAC_ADDR_SIZE);
@@ -256,9 +264,46 @@ void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params,
 #else
 static inline
 void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params,
-			       struct hdd_adapter *adapter,
-			       struct sir_sae_info *sae_info)
+			       struct hdd_adapter *adapter)
+{
+}
+#endif
+
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_EXTERNAL_AUTH_MLO_SUPPORT)
+/**
+ * wlan_hdd_sae_update_mld_addr() - Send mld address to supplicant
+ * @params: pointer to external auth params
+ * @adapter: pointer adapter context
+ *
+ * This API is used to copy MLD address info in supplicant structure.
+ *
+ * Return: QDF_STATUS
+ */
+static inline QDF_STATUS
+wlan_hdd_sae_update_mld_addr(struct cfg80211_external_auth_params *params,
+			     struct hdd_adapter *adapter)
+{
+	struct qdf_mac_addr mld_addr;
+	QDF_STATUS status;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(adapter->vdev))
+		return QDF_STATUS_SUCCESS;
+
+	status = wlan_vdev_get_bss_peer_mld_mac(adapter->vdev, &mld_addr);
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_INVAL;
+
+	qdf_mem_copy(params->mld_addr, mld_addr.bytes,
+		     QDF_MAC_ADDR_SIZE);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static inline QDF_STATUS
+wlan_hdd_sae_update_mld_addr(struct cfg80211_external_auth_params *params,
+			     struct hdd_adapter *adapter)
 {
+	return QDF_STATUS_SUCCESS;
 }
 #endif
 
@@ -305,6 +350,7 @@ static void wlan_hdd_sae_callback(struct hdd_adapter *adapter,
 	int flags;
 	struct sir_sae_info *sae_info = roam_info->sae_info;
 	struct cfg80211_external_auth_params params = {0};
+	QDF_STATUS status;
 
 	if (wlan_hdd_validate_context(hdd_ctx))
 		return;
@@ -322,7 +368,10 @@ static void wlan_hdd_sae_callback(struct hdd_adapter *adapter,
 	params.action = NL80211_EXTERNAL_AUTH_START;
 	qdf_mem_copy(params.bssid, sae_info->peer_mac_addr.bytes,
 		     QDF_MAC_ADDR_SIZE);
-	wlan_hdd_sae_copy_ta_addr(&params, adapter, sae_info);
+	wlan_hdd_sae_copy_ta_addr(&params, adapter);
+	status = wlan_hdd_sae_update_mld_addr(&params, adapter);
+	if (QDF_IS_STATUS_ERROR(status))
+		return;
 
 	qdf_mem_copy(params.ssid.ssid, sae_info->ssid.ssId,
 		     sae_info->ssid.length);

+ 20 - 0
core/hdd/src/wlan_hdd_main.c

@@ -217,6 +217,7 @@
 #ifdef WLAN_FEATURE_11BE_MLO
 #include <wlan_mlo_mgr_ap.h>
 #endif
+#include "wlan_osif_features.h"
 #include "wlan_vdev_mgr_ucfg_api.h"
 #include <wlan_objmgr_psoc_obj_i.h>
 #include <wlan_objmgr_vdev_obj_i.h>
@@ -6489,6 +6490,22 @@ hdd_populate_vdev_create_params(struct hdd_adapter *adapter,
 }
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_EXTERNAL_AUTH_MLO_SUPPORT)
+static void
+hdd_set_vdev_mlo_external_sae_auth_conversion(struct wlan_objmgr_vdev *vdev,
+					      enum QDF_OPMODE mode)
+{
+	if (mode == QDF_STA_MODE || mode == QDF_SAP_MODE)
+		wlan_vdev_set_mlo_external_sae_auth_conversion(vdev, true);
+}
+#else
+static inline void
+hdd_set_vdev_mlo_external_sae_auth_conversion(struct wlan_objmgr_vdev *vdev,
+					      enum QDF_OPMODE mode)
+{
+}
+#endif
+
 int hdd_vdev_create(struct hdd_adapter *adapter)
 {
 	QDF_STATUS status;
@@ -6588,6 +6605,9 @@ int hdd_vdev_create(struct hdd_adapter *adapter)
 	}
 	hdd_store_nss_chains_cfg_in_vdev(adapter);
 
+	hdd_set_vdev_mlo_external_sae_auth_conversion(vdev,
+						      adapter->device_mode);
+
 	/* Configure vdev params */
 	ucfg_fwol_configure_vdev_params(hdd_ctx->psoc, hdd_ctx->pdev,
 					adapter->device_mode, adapter->vdev_id);

+ 4 - 1
core/mac/src/pe/include/lim_global.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -220,6 +220,9 @@ typedef struct tLimPreAuthNode {
 	 */
 	struct lim_assoc_data assoc_req;
 	bool is_mlo_ie_present;
+#ifdef WLAN_FEATURE_11BE_MLO
+	tSirMacAddr peer_mld;
+#endif
 } tLimPreAuthNode, *tpLimPreAuthNode;
 
 /* Pre-authentication table definition */

+ 202 - 2
core/mac/src/pe/lim/lim_process_auth_frame.c

@@ -320,12 +320,14 @@ static void lim_process_auth_open_system_algo(struct mac_context *mac_ctx,
  * @mac_ctx: MAC context
  * @mac_hdr: Mac header of the packet
  * @mlm_state: MLM state to be marked to track SAE authentication
+ * @peer_mld: Peer MLD address
  *
  * Return: None
  */
 static void lim_external_auth_add_pre_auth_node(struct mac_context *mac_ctx,
 						tpSirMacMgmtHdr mac_hdr,
-						tLimMlmStates mlm_state)
+						tLimMlmStates mlm_state,
+						struct qdf_mac_addr *peer_mld)
 {
 	struct tLimPreAuthNode *auth_node;
 	tpLimPreAuthTable preauth_table = &mac_ctx->lim.gLimPreAuthTimerTable;
@@ -342,6 +344,10 @@ static void lim_external_auth_add_pre_auth_node(struct mac_context *mac_ctx,
 		 QDF_MAC_ADDR_REF(mac_hdr->sa));
 	qdf_mem_copy((uint8_t *)auth_node->peerMacAddr,
 		     mac_hdr->sa, sizeof(tSirMacAddr));
+#ifdef WLAN_FEATURE_11BE_MLO
+	qdf_mem_copy((uint8_t *)auth_node->peer_mld, peer_mld->bytes,
+		     QDF_MAC_ADDR_SIZE);
+#endif
 	auth_node->mlmState = mlm_state;
 	auth_node->authType = eSIR_AUTH_TYPE_SAE;
 	auth_node->timestamp = qdf_mc_timer_get_system_ticks();
@@ -409,6 +415,172 @@ static bool lim_is_sae_auth_algo_match(uint8_t *queued_frame, uint16_t q_len,
 	return false;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/*
+ * lim_skip_sae_fixed_field: This API is called to parse the SAE auth frame and
+ * skip the SAE fixed fields
+ * @body_ptr: Pointer to a SAE auth frame
+ * @frame_len: Length of SAE auth frame
+ * @ie_ptr: Buffer to be searched for the Multi-Link element or the start of the
+ * Multi-Link element fragment sequence
+ * @ie_len: Length of the buffer
+ *
+ * Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving
+ * the reason for error in the case of failure
+ */
+static QDF_STATUS lim_skip_sae_fixed_field(uint8_t *body_ptr,
+					   uint32_t frame_len,
+					   uint8_t **ie_ptr, qdf_size_t *ie_len)
+{
+	uint16_t sae_status_code = 0;
+	uint16_t sae_group_id = 0;
+
+	if (!body_ptr || !frame_len || !ie_ptr || !ie_len)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	if (frame_len < (SAE_AUTH_GROUP_ID_OFFSET + 2))
+		return QDF_STATUS_E_INVAL;
+
+	sae_status_code = *(uint16_t *)(body_ptr + SAE_AUTH_STATUS_CODE_OFFSET);
+
+	if (sae_status_code != WLAN_SAE_STATUS_HASH_TO_ELEMENT &&
+	    sae_status_code != WLAN_SAE_STATUS_PK)
+		return QDF_STATUS_E_NOSUPPORT;
+
+	sae_group_id = *(uint16_t *)(body_ptr + SAE_AUTH_GROUP_ID_OFFSET);
+	*ie_ptr = body_ptr + SAE_AUTH_GROUP_ID_OFFSET + 2;
+	*ie_len = frame_len - SAE_AUTH_GROUP_ID_OFFSET - 2;
+
+	switch (sae_group_id) {
+	case SAE_GROUP_ID_19:
+		if (*ie_len < SAE_GROUP_19_FIXED_FIELDS_LEN)
+			return QDF_STATUS_E_NOSUPPORT;
+
+		*ie_ptr = *ie_ptr + SAE_GROUP_19_FIXED_FIELDS_LEN;
+		*ie_len = *ie_len - SAE_GROUP_19_FIXED_FIELDS_LEN;
+		break;
+	case SAE_GROUP_ID_20:
+		if (*ie_len < SAE_GROUP_20_FIXED_FIELDS_LEN)
+			return QDF_STATUS_E_NOSUPPORT;
+
+		*ie_ptr = *ie_ptr + SAE_GROUP_20_FIXED_FIELDS_LEN;
+		*ie_len = *ie_len - SAE_GROUP_20_FIXED_FIELDS_LEN;
+		break;
+	case SAE_GROUP_ID_21:
+		if (*ie_len < SAE_GROUP_21_FIXED_FIELDS_LEN)
+			return QDF_STATUS_E_NOSUPPORT;
+
+		*ie_ptr = *ie_ptr + SAE_GROUP_21_FIXED_FIELDS_LEN;
+		*ie_len = *ie_len - SAE_GROUP_21_FIXED_FIELDS_LEN;
+		break;
+	default:
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	if (*ie_len == 0)
+		return QDF_STATUS_E_NOSUPPORT;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * lim_get_sta_mld_address: This API is called to get the STA MLD address
+ * from SAE 1st auth frame.
+ * @body_ptr: Pointer to a SAE auth frame
+ * @frame_len: Length of SAE auth frame
+ * @peer_mld: fill peer MLD address
+ *
+ * Return: void
+ */
+static void lim_get_sta_mld_address(uint8_t *body_ptr, uint32_t frame_len,
+				    struct qdf_mac_addr *peer_mld)
+{
+	uint8_t *ie_ptr = NULL;
+	uint8_t *ml_ie = NULL;
+	qdf_size_t ml_ie_total_len = 0;
+	qdf_size_t ie_len = 0;
+	QDF_STATUS status;
+
+	status = lim_skip_sae_fixed_field(body_ptr, frame_len, &ie_ptr,
+					  &ie_len);
+	if (QDF_IS_STATUS_ERROR(status))
+		return;
+
+	status = util_find_mlie(ie_ptr, ie_len, &ml_ie, &ml_ie_total_len);
+	if (QDF_IS_STATUS_ERROR(status))
+		return;
+
+	util_get_bvmlie_mldmacaddr(ml_ie, ml_ie_total_len, peer_mld);
+}
+
+/**
+ * lim_update_link_to_mld_address:This API is called to update SA and DA address
+ * @mac_ctx: Pointer to mac context
+ * @vdev: vdev
+ * @mac_hdr: Pointer to MAC management header
+ *
+ * Return: void
+ */
+static QDF_STATUS lim_update_link_to_mld_address(struct mac_context *mac_ctx,
+						 struct wlan_objmgr_vdev *vdev,
+						 tpSirMacMgmtHdr mac_hdr)
+{
+	struct qdf_mac_addr *self_mld_addr;
+	struct tLimPreAuthNode *pre_auth_node;
+	struct qdf_mac_addr peer_mld_addr;
+	enum QDF_OPMODE opmode;
+	QDF_STATUS status;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev) ||
+	    !wlan_vdev_get_mlo_external_sae_auth_conversion(vdev))
+		return QDF_STATUS_SUCCESS;
+
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
+	self_mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
+
+	switch (opmode) {
+	case QDF_SAP_MODE:
+		pre_auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa);
+		if (!pre_auth_node)
+			return QDF_STATUS_E_INVAL;
+
+		qdf_mem_copy(mac_hdr->sa, pre_auth_node->peer_mld,
+			     QDF_MAC_ADDR_SIZE);
+		qdf_mem_copy(mac_hdr->bssId, self_mld_addr->bytes,
+			     QDF_MAC_ADDR_SIZE);
+		break;
+	case QDF_STA_MODE:
+		status = wlan_vdev_get_bss_peer_mld_mac(vdev, &peer_mld_addr);
+		if (QDF_IS_STATUS_ERROR(status))
+			return status;
+
+		qdf_mem_copy(mac_hdr->sa, peer_mld_addr.bytes,
+			     QDF_MAC_ADDR_SIZE);
+		qdf_mem_copy(mac_hdr->bssId, peer_mld_addr.bytes,
+			     QDF_MAC_ADDR_SIZE);
+		break;
+	default:
+		return QDF_STATUS_SUCCESS;
+	}
+
+	qdf_mem_copy(mac_hdr->da, self_mld_addr->bytes, QDF_MAC_ADDR_SIZE);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static void lim_get_sta_mld_address(uint8_t *body_ptr, uint32_t frame_len,
+				    struct qdf_mac_addr *peer_mld)
+{
+}
+
+static QDF_STATUS lim_update_link_to_mld_address(struct mac_context *mac_ctx,
+						 struct wlan_objmgr_vdev *vdev,
+						 tpSirMacMgmtHdr mac_hdr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * lim_process_sae_auth_frame()-Process SAE authentication frame
  * @mac_ctx: MAC context
@@ -427,6 +599,7 @@ static void lim_process_sae_auth_frame(struct mac_context *mac_ctx,
 	struct sae_auth_retry *sae_retry;
 	uint16_t sae_auth_seq = 0, sae_status_code = 0;
 	uint16_t auth_algo;
+	QDF_STATUS status;
 
 	mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
 	body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info);
@@ -443,6 +616,7 @@ static void lim_process_sae_auth_frame(struct mac_context *mac_ctx,
 
 	if (LIM_IS_AP_ROLE(pe_session)) {
 		struct tLimPreAuthNode *pre_auth_node;
+		struct qdf_mac_addr peer_mld;
 
 		rx_flags = RXMGMT_FLAG_EXTERNAL_AUTH;
 		/* Add preauth node when the first SAE authentication frame
@@ -462,8 +636,28 @@ static void lim_process_sae_auth_frame(struct mac_context *mac_ctx,
 					 QDF_MAC_ADDR_REF(mac_hdr->sa));
 				lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
 			}
+			/* case: when SAP receives auth SAE 1st frame with
+			 * SA, DA and bssid as link address. Driver needs to
+			 * get the STA MLD address and save it in preauth node
+			 * struct for further use.
+			 * For the 1st SAE RX frame,
+			 * driver does not need to convert it in mld_address.
+			 */
+			lim_get_sta_mld_address(body_ptr, frame_len,
+						&peer_mld);
 			lim_external_auth_add_pre_auth_node(mac_ctx, mac_hdr,
-						eLIM_MLM_WT_SAE_AUTH_STATE);
+						eLIM_MLM_WT_SAE_AUTH_STATE,
+						&peer_mld);
+		} else {
+			/* case: when SAP receives Auth SAE 3rd frame with
+			 * SA, DA and bssid as link address. Needs to convert
+			 * it into MLD address and send it userspace.
+			 */
+			status = lim_update_link_to_mld_address(mac_ctx,
+								pe_session->vdev,
+								mac_hdr);
+			if (QDF_IS_STATUS_ERROR(status))
+				return;
 		}
 	}
 
@@ -478,6 +672,12 @@ static void lim_process_sae_auth_frame(struct mac_context *mac_ctx,
 	}
 
 	if (LIM_IS_STA_ROLE(pe_session)) {
+		status = lim_update_link_to_mld_address(mac_ctx,
+							pe_session->vdev,
+							mac_hdr);
+		if (QDF_IS_STATUS_ERROR(status))
+			return;
+
 		auth_algo = *(uint16_t *)body_ptr;
 		if (frame_len >= (SAE_AUTH_STATUS_CODE_OFFSET + 2)) {
 			sae_auth_seq =

+ 20 - 0
core/mac/src/pe/lim/lim_security_utils.c

@@ -207,6 +207,26 @@ struct tLimPreAuthNode *lim_search_pre_auth_list(struct mac_context *mac,
 	return pTempNode;
 } /*** end lim_search_pre_auth_list() ***/
 
+#ifdef WLAN_FEATURE_11BE_MLO
+struct tLimPreAuthNode *
+lim_search_pre_auth_list_by_mld_addr(struct mac_context *mac,
+				     tSirMacAddr mldaddr)
+{
+	struct tLimPreAuthNode *pTempNode = mac->lim.pLimPreAuthList;
+
+	while (pTempNode) {
+		if (!qdf_mem_cmp((uint8_t *)mldaddr,
+				 (uint8_t *)&pTempNode->peer_mld,
+				 sizeof(tSirMacAddr)))
+			break;
+
+		pTempNode = pTempNode->next;
+	}
+
+	return pTempNode;
+}
+#endif
+
 /**
  * lim_delete_open_auth_pre_auth_node() - delete any stale preauth nodes
  * @mac_ctx: Pointer to Global MAC structure

+ 17 - 0
core/mac/src/pe/lim/lim_security_utils.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2011-2015, 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -57,6 +58,22 @@ void lim_init_pre_auth_list(struct mac_context *);
 void lim_delete_pre_auth_list(struct mac_context *);
 struct tLimPreAuthNode *lim_search_pre_auth_list(struct mac_context *,
 						 tSirMacAddr);
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * lim_search_pre_auth_list_by_mld_addr() - This function is called when
+ * Authentication frame is received by AP (or at a STA in IBSS supporting MAC
+ * based authentication) to search using MLD address if a STA is in the middle
+ * of MAC Authentication transaction sequence.
+ * @mac: MAC context
+ * @mldaddr: MLD address of the STA that sent
+ *
+ * Return: Pointer to pre-auth node if found, else NULL
+ */
+struct tLimPreAuthNode *lim_search_pre_auth_list_by_mld_addr(
+							struct mac_context *mac,
+							tSirMacAddr mldaddr);
+#endif
 void lim_add_pre_auth_node(struct mac_context *, struct tLimPreAuthNode *);
 void lim_delete_pre_auth_node(struct mac_context *, tSirMacAddr);
 void lim_release_pre_auth_node(struct mac_context *mac,

+ 79 - 2
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -6687,6 +6687,65 @@ lim_handle_sae_auth_retry(struct mac_context *mac_ctx, uint8_t vdev_id,
 	}
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static QDF_STATUS lim_update_mld_to_link_address(struct mac_context *mac_ctx,
+						 struct wlan_objmgr_vdev *vdev,
+						 tpSirMacMgmtHdr mac_hdr)
+{
+	struct qdf_mac_addr *self_link_addr;
+	struct tLimPreAuthNode *pre_auth_node;
+	struct qdf_mac_addr peer_link_addr;
+	enum QDF_OPMODE opmode;
+	QDF_STATUS status;
+
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev) ||
+	    !wlan_vdev_get_mlo_external_sae_auth_conversion(vdev))
+		return QDF_STATUS_SUCCESS;
+
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
+	self_link_addr = (struct qdf_mac_addr *)
+				wlan_vdev_mlme_get_linkaddr(vdev);
+
+	switch (opmode) {
+	case QDF_SAP_MODE:
+		pre_auth_node =
+			lim_search_pre_auth_list_by_mld_addr(mac_ctx,
+							     mac_hdr->da);
+		if (!pre_auth_node)
+			return QDF_STATUS_E_INVAL;
+
+		qdf_mem_copy(mac_hdr->da, pre_auth_node->peerMacAddr,
+			     QDF_MAC_ADDR_SIZE);
+		qdf_mem_copy(mac_hdr->bssId, self_link_addr->bytes,
+			     QDF_MAC_ADDR_SIZE);
+		break;
+	case QDF_STA_MODE:
+		status = wlan_vdev_get_bss_peer_mac(vdev, &peer_link_addr);
+		if (QDF_IS_STATUS_ERROR(status))
+			return status;
+
+		qdf_mem_copy(mac_hdr->da, peer_link_addr.bytes,
+			     QDF_MAC_ADDR_SIZE);
+		qdf_mem_copy(mac_hdr->bssId, peer_link_addr.bytes,
+			     QDF_MAC_ADDR_SIZE);
+		break;
+	default:
+		return QDF_STATUS_SUCCESS;
+	}
+
+	qdf_mem_copy(mac_hdr->sa, self_link_addr->bytes, QDF_MAC_ADDR_SIZE);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS lim_update_mld_to_link_address(struct mac_context *mac_ctx,
+						 struct wlan_objmgr_vdev *vdev,
+						 tpSirMacMgmtHdr mac_hdr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 void lim_send_frame(struct mac_context *mac_ctx, uint8_t vdev_id, uint8_t *buf,
 		    uint16_t buf_len)
 {
@@ -6695,9 +6754,27 @@ void lim_send_frame(struct mac_context *mac_ctx, uint8_t vdev_id, uint8_t *buf,
 	void *packet;
 	tpSirMacFrameCtl fc = (tpSirMacFrameCtl)buf;
 	tpSirMacMgmtHdr mac_hdr = (tpSirMacMgmtHdr)buf;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	pe_debug("sending fc->type: %d fc->subType: %d", fc->type, fc->subType);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id,
+						    WLAN_LEGACY_MAC_ID);
+	if (!vdev)
+		return;
 
-	pe_debug("sending fc->type: %d fc->subType: %d",
-		 fc->type, fc->subType);
+	/* Case:
+	 * 1. In case of SAP, userspace will send MLD addresses in 2nd and 4th
+	 *    SAE auth frames. Driver needs to convert it into link address.
+	 * 2. In case of STA, userspace will send MLD addresses in 1st and 3rd
+	 *    SAE auth frames. Driver needs to convert it into link address.
+	 */
+	status = lim_update_mld_to_link_address(mac_ctx, vdev, mac_hdr);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return;
 
 	lim_add_mgmt_seq_num(mac_ctx, mac_hdr);
 	qdf_status = cds_packet_alloc(buf_len, (void **)&frame,

+ 12 - 0
core/mac/src/pe/lim/lim_types.h

@@ -53,6 +53,18 @@
 
 #define SAE_AUTH_SEQ_NUM_OFFSET       2
 #define SAE_AUTH_STATUS_CODE_OFFSET   4
+#define SAE_AUTH_GROUP_ID_OFFSET      6
+
+#define SAE_GROUP_ID_19                    19
+#define SAE_GROUP_ID_20                    20
+#define SAE_GROUP_ID_21                    21
+
+#define SAE_GROUP_19_FIXED_FIELDS_LEN      96
+#define SAE_GROUP_20_FIXED_FIELDS_LEN      144
+#define SAE_GROUP_21_FIXED_FIELDS_LEN      198
+
+#define WLAN_SAE_STATUS_HASH_TO_ELEMENT    126
+#define WLAN_SAE_STATUS_PK                 127
 
 /* MLM message types */
 enum mlmmsgtype {