Jelajahi Sumber

qcacld-3.0: Defer Assoc indication to SME if auth is in progress

SAE authentication is offloaded to hostapd and hostapd sends
authentication status to driver after the authentication
completion. But hostapd sends external authentication (e.g., SAE)
status after sending out the final auth frame(e.g., confirm
response in SAE). Driver may receive association request from
station before getting external auth status. Defer the
initialization of PE/SME entries corresponding to that station
till status is received from hostapd. Once status is received
from hostapd, PE entries can be initialized and send
assoc indication to SME.

Change-Id: Ice95519f2bf25d483cc164182b3f3be87f59884a
CRs-Fixed: 2396373
Srinivas Dasari 6 tahun lalu
induk
melakukan
3e54a4a564

+ 31 - 0
core/mac/src/pe/include/lim_global.h

@@ -184,6 +184,33 @@ typedef struct sLimMlmJoinReq {
 	 */
 } tLimMlmJoinReq, *tpLimMlmJoinReq;
 
+/* Forward declarations */
+struct sSirAssocReq;
+struct sDphHashNode;
+
+/* struct lim_assoc_data - Assoc data to be cached to defer association
+ *			   indication to SME
+ * @present: Indicates whether assoc data is present or not
+ * @sub_type: Indicates whether it is Association Request(=0) or Reassociation
+ *            Request(=1) frame
+ * @hdr: MAC header
+ * @assoc_req: pointer to parsed ASSOC/REASSOC Request frame
+ * @pmf_connection: flag indicating pmf connection
+ * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above
+ * @dup_entry: flag indicating if duplicate entry found
+ * @sta_ds: station dph entry
+ */
+struct lim_assoc_data {
+	bool present;
+	uint8_t sub_type;
+	tSirMacMgmtHdr hdr;
+	struct sSirAssocReq *assoc_req;
+	bool pmf_connection;
+	bool assoc_req_copied;
+	bool dup_entry;
+	struct sDphHashNode *sta_ds;
+};
+
 /* Pre-authentication structure definition */
 typedef struct tLimPreAuthNode {
 	struct tLimPreAuthNode *next;
@@ -199,6 +226,10 @@ typedef struct tLimPreAuthNode {
 	TX_TIMER timer;
 	uint16_t seq_num;
 	unsigned long timestamp;
+	/* keeping copy of association request received, this is
+	 * to defer the association request processing
+	 */
+	struct lim_assoc_data assoc_req;
 } tLimPreAuthNode, *tpLimPreAuthNode;
 
 /* Pre-authentication table definition */

+ 67 - 33
core/mac/src/pe/lim/lim_process_assoc_req_frame.c

@@ -1828,25 +1828,11 @@ static bool lim_update_sta_ctx(struct mac_context *mac_ctx, struct pe_session *s
 	return true;
 }
 
-/**
- * lim_process_assoc_cleanup() - frees up resources used in function
- * lim_process_assoc_req_frame()
- * @mac_ctx: pointer to Global MAC structure
- * @session: pointer to pe session entry
- * @assoc_req: pointer to ASSOC/REASSOC Request frame
- * @sta_ds: station dph entry
- * @tmp_assoc_req: pointer to tmp ASSOC/REASSOC Request frame
- * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above
- *
- * Frees up resources used in function lim_process_assoc_req_frame
- *
- * Return: void
- */
-static void lim_process_assoc_cleanup(struct mac_context *mac_ctx,
-				      struct pe_session *session,
-				      tpSirAssocReq assoc_req,
-				      tpDphHashNode sta_ds,
-				      bool *assoc_req_copied)
+void lim_process_assoc_cleanup(struct mac_context *mac_ctx,
+			       struct pe_session *session,
+			       tpSirAssocReq assoc_req,
+			       tpDphHashNode sta_ds,
+			       bool assoc_req_copied)
 {
 	tpSirAssocReq tmp_assoc_req;
 
@@ -1859,7 +1845,7 @@ static void lim_process_assoc_cleanup(struct mac_context *mac_ctx,
 
 		qdf_mem_free(assoc_req);
 		/* to avoid double free */
-		if (*assoc_req_copied && session->parsedAssocReq)
+		if (assoc_req_copied && session->parsedAssocReq)
 			session->parsedAssocReq[sta_ds->assocId] = NULL;
 	}
 
@@ -1884,8 +1870,7 @@ static void lim_process_assoc_cleanup(struct mac_context *mac_ctx,
 }
 
 /**
- * lim_send_assoc_ind_to_sme() - Initialize PE data structures and send assoc
- *				 indication to SME.
+ * lim_defer_sme_indication() - Defer assoc indication to SME
  * @mac_ctx: Pointer to Global MAC structure
  * @session: pe session entry
  * @sub_type: Indicates whether it is Association Request(=0) or Reassociation
@@ -1896,18 +1881,44 @@ static void lim_process_assoc_cleanup(struct mac_context *mac_ctx,
  * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above
  * @dup_entry: flag indicating if duplicate entry found
  *
- * This function is called to process RE/ASSOC Request frame.
+ * Defer Initialization of PE data structures and wait for an external event.
+ * lim_send_assoc_ind_to_sme() will be called to initialize PE data structures
+ * when the expected event is received.
  *
- * @Return: void
+ * Return: void
  */
-static bool lim_send_assoc_ind_to_sme(struct mac_context *mac_ctx,
-				      struct pe_session *session,
-				      uint8_t sub_type,
-				      tpSirMacMgmtHdr hdr,
-				      tpSirAssocReq assoc_req,
-				      bool pmf_connection,
-				      bool *assoc_req_copied,
-				      bool dup_entry)
+static void lim_defer_sme_indication(struct mac_context *mac_ctx,
+				     struct pe_session *session,
+				     uint8_t sub_type,
+				     tpSirMacMgmtHdr hdr,
+				     struct sSirAssocReq *assoc_req,
+				     bool pmf_connection,
+				     bool assoc_req_copied,
+				     bool dup_entry,
+				     struct sDphHashNode *sta_ds)
+{
+	struct tLimPreAuthNode *sta_pre_auth_ctx;
+	/* Extract pre-auth context for the STA, if any. */
+	sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, hdr->sa);
+	sta_pre_auth_ctx->assoc_req.present = true;
+	sta_pre_auth_ctx->assoc_req.sub_type = sub_type;
+	qdf_mem_copy(&sta_pre_auth_ctx->assoc_req.hdr, hdr,
+		     sizeof(tSirMacMgmtHdr));
+	sta_pre_auth_ctx->assoc_req.assoc_req = assoc_req;
+	sta_pre_auth_ctx->assoc_req.pmf_connection = pmf_connection;
+	sta_pre_auth_ctx->assoc_req.assoc_req_copied = assoc_req_copied;
+	sta_pre_auth_ctx->assoc_req.dup_entry = dup_entry;
+	sta_pre_auth_ctx->assoc_req.sta_ds = sta_ds;
+}
+
+bool lim_send_assoc_ind_to_sme(struct mac_context *mac_ctx,
+			       struct pe_session *session,
+			       uint8_t sub_type,
+			       tpSirMacMgmtHdr hdr,
+			       tpSirAssocReq assoc_req,
+			       bool pmf_connection,
+			       bool *assoc_req_copied,
+			       bool dup_entry)
 {
 	uint16_t peer_idx;
 	struct tLimPreAuthNode *sta_pre_auth_ctx;
@@ -2044,6 +2055,7 @@ void lim_process_assoc_req_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_in
 	uint32_t phy_mode;
 	tHalBitVal qos_mode;
 	tpSirMacMgmtHdr hdr;
+	struct tLimPreAuthNode *sta_pre_auth_ctx;
 	tSirMacCapabilityInfo local_cap;
 	tpDphHashNode sta_ds = NULL;
 	tpSirAssocReq assoc_req;
@@ -2265,6 +2277,28 @@ void lim_process_assoc_req_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_in
 				assoc_req, sub_type, &pmf_connection))
 		goto error;
 
+	/* Extract pre-auth context for the STA, if any. */
+	sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, hdr->sa);
+
+	/* SAE authentication is offloaded to hostapd. Hostapd sends
+	 * authentication status to driver after completing SAE
+	 * authentication (after sending out 4/4 SAE auth frame).
+	 * There is a possible race condition where driver gets
+	 * assoc request from SAE station before getting authentication
+	 * status from hostapd. Don't reject the association in such
+	 * cases and defer the processing of assoc request frame by caching
+	 * the frame and process it when the auth status is received.
+	 */
+	if (sta_pre_auth_ctx &&
+	    sta_pre_auth_ctx->authType == eSIR_AUTH_TYPE_SAE &&
+	    sta_pre_auth_ctx->mlmState == eLIM_MLM_WT_SAE_AUTH_STATE) {
+		pe_debug("Received assoc request frame while SAE authentication is in progress; Defer association request handling till SAE auth status is received");
+		lim_defer_sme_indication(mac_ctx, session, sub_type, hdr,
+					 assoc_req, pmf_connection,
+					 assoc_req_copied, dup_entry, sta_ds);
+		return;
+	}
+
 	/* Send assoc indication to SME */
 	if (!lim_send_assoc_ind_to_sme(mac_ctx, session, sub_type, hdr,
 				       assoc_req, pmf_connection,
@@ -2275,7 +2309,7 @@ void lim_process_assoc_req_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_in
 
 error:
 	lim_process_assoc_cleanup(mac_ctx, session, assoc_req, sta_ds,
-				  &assoc_req_copied);
+				  assoc_req_copied);
 	return;
 }
 

+ 1 - 0
core/mac/src/pe/lim/lim_process_auth_frame.c

@@ -311,6 +311,7 @@ static void lim_external_auth_add_pre_auth_node(struct mac_context *mac_ctx,
 	auth_node->timestamp = qdf_mc_timer_get_system_ticks();
 	auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) |
 			      (mac_hdr->seqControl.seqNumLo));
+	auth_node->assoc_req.present = false;
 	lim_add_pre_auth_node(mac_ctx, auth_node);
 }
 

+ 38 - 4
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -117,6 +117,8 @@ static void lim_process_sae_msg_ap(struct mac_context *mac,
 				   struct sir_sae_msg *sae_msg)
 {
 	struct tLimPreAuthNode *sta_pre_auth_ctx;
+	struct lim_assoc_data *assoc_req;
+
 	/* Extract pre-auth context for the STA and move limMlmState
 	 * of preauth node to eLIM_MLM_AUTHENTICATED_STATE
 	 */
@@ -130,14 +132,46 @@ static void lim_process_sae_msg_ap(struct mac_context *mac,
 		return;
 	}
 
-	if (sae_msg->sae_status == IEEE80211_STATUS_SUCCESS) {
-		sta_pre_auth_ctx->mlmState = eLIM_MLM_AUTHENTICATED_STATE;
-	} else {
+	assoc_req = &sta_pre_auth_ctx->assoc_req;
+
+	if (sae_msg->sae_status != IEEE80211_STATUS_SUCCESS) {
 		pe_debug("SAE authentication failed for "
 			 QDF_MAC_ADDR_STR " status: %u",
 			 QDF_MAC_ADDR_ARRAY(sae_msg->peer_mac_addr),
 			 sae_msg->sae_status);
+		if (assoc_req->present) {
+			pe_debug("Assoc req cached; clean it up");
+			lim_process_assoc_cleanup(mac, session,
+						  assoc_req->assoc_req,
+						  assoc_req->sta_ds,
+						  assoc_req->assoc_req_copied);
+			assoc_req->present = false;
+		}
 		lim_delete_pre_auth_node(mac, sae_msg->peer_mac_addr);
+		return;
+	}
+	sta_pre_auth_ctx->mlmState = eLIM_MLM_AUTHENTICATED_STATE;
+	/* Send assoc indication to SME if any assoc request is cached*/
+	if (assoc_req->present) {
+		/* Assoc request is present in preauth context. Get the assoc
+		 * request and make it invalid in preauth context. It'll be
+		 * freed later in the legacy path.
+		 */
+		bool assoc_req_copied;
+
+		assoc_req->present = false;
+		pe_debug("Assoc req cached; handle it");
+		if (lim_send_assoc_ind_to_sme(mac, session,
+					      assoc_req->sub_type,
+					      &assoc_req->hdr,
+					      assoc_req->assoc_req,
+					      assoc_req->pmf_connection,
+					      &assoc_req_copied,
+					      assoc_req->dup_entry) == false)
+			lim_process_assoc_cleanup(mac, session,
+						  assoc_req->assoc_req,
+						  assoc_req->sta_ds,
+						  assoc_req_copied);
 	}
 }
 
@@ -181,7 +215,7 @@ static void lim_process_sae_msg(struct mac_context *mac, struct sir_sae_msg *bod
 	else if (LIM_IS_AP_ROLE(session))
 		lim_process_sae_msg_ap(mac, session, sae_msg);
 	else
-		pe_debug("Unsupported interface");
+		pe_debug("SAE message on unsupported interface");
 }
 #else
 static inline void lim_process_sae_msg(struct mac_context *mac, void *body)

+ 12 - 1
core/mac/src/pe/lim/lim_security_utils.c

@@ -302,9 +302,20 @@ void lim_add_pre_auth_node(struct mac_context *mac, struct tLimPreAuthNode *pAut
  * @return None
  */
 
-void lim_release_pre_auth_node(struct mac_context *mac, tpLimPreAuthNode pAuthNode)
+void lim_release_pre_auth_node(struct mac_context *mac,
+			       tpLimPreAuthNode pAuthNode)
 {
 	pAuthNode->fFree = 1;
+	if (pAuthNode->authType == eSIR_AUTH_TYPE_SAE &&
+	    pAuthNode->assoc_req.present) {
+		tpSirAssocReq assoc =
+			 (tpSirAssocReq)pAuthNode->assoc_req.assoc_req;
+
+		if (assoc->assocReqFrameLength)
+			qdf_mem_free(assoc->assocReqFrame);
+		qdf_mem_free(assoc);
+		pAuthNode->assoc_req.present = false;
+	}
 	MTRACE(mac_trace
 		       (mac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION,
 		       eLIM_PRE_AUTH_CLEANUP_TIMER));

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

@@ -1091,4 +1091,46 @@ void lim_process_mlm_deauth_req(struct mac_context *mac_ctx, uint32_t *msg_buf);
 QDF_STATUS lim_sta_mlme_vdev_disconnect_bss(struct vdev_mlme_obj *vdev_mlme,
 					    uint16_t data_len, void *data);
 #endif
+/**
+ * lim_process_assoc_cleanup() - frees up resources used in function
+ * lim_process_assoc_req_frame()
+ * @mac_ctx: pointer to Global MAC structure
+ * @session: pointer to pe session entry
+ * @assoc_req: pointer to ASSOC/REASSOC Request frame
+ * @sta_ds: station dph entry
+ * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above
+ *
+ * Frees up resources used in function lim_process_assoc_req_frame
+ *
+ * Return: void
+ */
+void lim_process_assoc_cleanup(struct mac_context *mac_ctx,
+			       struct pe_session *session,
+			       tpSirAssocReq assoc_req,
+			       tpDphHashNode sta_ds,
+			       bool assoc_req_copied);
+
+/**
+ * lim_send_assoc_ind_to_sme() - Initialize PE data structures and send assoc
+ *				 indication to SME.
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session: pe session entry
+ * @sub_type: Indicates whether it is Association Request(=0) or Reassociation
+ *            Request(=1) frame
+ * @hdr: A pointer to the MAC header
+ * @assoc_req: pointer to ASSOC/REASSOC Request frame
+ * @pmf_connection: flag indicating pmf connection
+ * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above
+ * @dup_entry: flag indicating if duplicate entry found
+ *
+ * Return: void
+ */
+bool lim_send_assoc_ind_to_sme(struct mac_context *mac_ctx,
+			       struct pe_session *session,
+			       uint8_t sub_type,
+			       tpSirMacMgmtHdr hdr,
+			       tpSirAssocReq assoc_req,
+			       bool pmf_connection,
+			       bool *assoc_req_copied,
+			       bool dup_entry);
 #endif /* __LIM_TYPES_H */