Bläddra i källkod

qcacmn: Delete pmkid and single pmkid on connect failure

Add logic to delete the pmkid and single pmkid depending on
connect response status code and failure.

Change-Id: I7a27f887173ba7cdc13c3ce49ded5d2fcc8198fa
CRs-Fixed: 2792774
gaurank kathpalia 4 år sedan
förälder
incheckning
77f0dd0632

+ 67 - 11
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -401,6 +401,30 @@ void cm_calculate_scores(struct wlan_objmgr_pdev *pdev,
 }
 #endif
 
+static inline void cm_delete_pmksa_for_bssid(struct cnx_mgr *cm_ctx,
+					     struct qdf_mac_addr *bssid)
+{
+	struct wlan_crypto_pmksa pmksa = {0};
+
+	qdf_copy_macaddr(&pmksa.bssid, bssid);
+	wlan_crypto_set_del_pmksa(cm_ctx->vdev, &pmksa, false);
+}
+
+#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
+static inline
+void cm_delete_pmksa_for_single_pmk_bssid(struct cnx_mgr *cm_ctx,
+					  struct qdf_mac_addr *bssid)
+{
+	cm_delete_pmksa_for_bssid(cm_ctx, bssid);
+}
+#else
+static inline
+void cm_delete_pmksa_for_single_pmk_bssid(struct cnx_mgr *cm_ctx,
+					  struct qdf_mac_addr *bssid)
+{
+}
+#endif
+
 static inline void
 cm_set_pmf_caps(struct cm_connect_req *cm_req, struct scan_filter *filter)
 {
@@ -708,27 +732,28 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
 {
 	struct scan_cache_node *scan_node = NULL;
 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
-	struct scan_cache_node *cur_candidate;
+	struct scan_cache_node *new_candidate = NULL, *prev_candidate;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
 
+	prev_candidate = cm_req->connect_req.cur_candidate;
 	if (cm_req->connect_req.connect_attempts >=
 	    cm_ctx->max_connect_attempts) {
 		mlme_info(CM_PREFIX_FMT "%d attempts tried, max %d",
 			  CM_PREFIX_REF(vdev_id, cm_req->cm_id),
 			  cm_req->connect_req.connect_attempts,
 			  cm_ctx->max_connect_attempts);
-		return QDF_STATUS_E_FAILURE;
+		status = QDF_STATUS_E_FAILURE;
+		goto flush_single_pmk;
 	}
 
-	cur_candidate = cm_req->connect_req.cur_candidate;
 	/*
-	 * Get next candidate if cur_candidate is not NULL, else get
+	 * Get next candidate if prev_candidate is not NULL, else get
 	 * the first candidate
 	 */
-	if (cur_candidate)
+	if (prev_candidate)
 		qdf_list_peek_next(cm_req->connect_req.candidate_list,
-				   &cur_candidate->node, &cur_node);
+				   &prev_candidate->node, &cur_node);
 	else
 		qdf_list_peek_front(cm_req->connect_req.candidate_list,
 				    &cur_node);
@@ -740,7 +765,7 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
 					     node);
 		status = cm_validate_candidate(cm_ctx, scan_node->entry);
 		if (QDF_IS_STATUS_SUCCESS(status)) {
-			cur_candidate = scan_node;
+			new_candidate = scan_node;
 			break;
 		}
 
@@ -756,13 +781,23 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
 		mlme_debug(CM_PREFIX_FMT "No more candidates left",
 			   CM_PREFIX_REF(vdev_id, cm_req->cm_id));
 		cm_req->connect_req.cur_candidate = NULL;
-		return QDF_STATUS_E_FAILURE;
+		status = QDF_STATUS_E_FAILURE;
+		goto flush_single_pmk;
 	}
 
 	cm_req->connect_req.connect_attempts++;
-	cm_req->connect_req.cur_candidate = cur_candidate;
+	cm_req->connect_req.cur_candidate = new_candidate;
 
-	return QDF_STATUS_SUCCESS;
+flush_single_pmk:
+	/*
+	 * If connection fails with Single PMK bssid (prev candidate),
+	 * clear the pmk entry.
+	 */
+	if (prev_candidate && util_scan_entry_single_pmk(prev_candidate->entry))
+		cm_delete_pmksa_for_single_pmk_bssid(cm_ctx,
+						&prev_candidate->entry->bssid);
+
+	return status;
 }
 
 static void cm_create_bss_peer(struct cnx_mgr *cm_ctx,
@@ -1115,6 +1150,13 @@ QDF_STATUS cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
 	}
 
 	if (QDF_IS_STATUS_SUCCESS(resp->connect_status)) {
+		/*
+		 * On successful connection to sae single pmk AP,
+		 * clear all the single pmk AP.
+		 */
+		if (cm_is_cm_id_current_candidate_single_pmk(cm_ctx, cm_id))
+			wlan_crypto_selective_clear_sae_single_pmk_entries(vdev,
+								&resp->bssid);
 		qdf_status =
 			cm_sm_deliver_event(vdev,
 					    WLAN_CM_SM_EV_CONNECT_SUCCESS,
@@ -1128,6 +1170,15 @@ QDF_STATUS cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
 		goto post_err;
 	}
 
+	/*
+	 * Delete the PMKID of the BSSID for which the assoc reject is
+	 * received from the AP due to invalid PMKID reason.
+	 * This will avoid the driver trying to connect to same AP with
+	 * the same stale PMKID. when connection is tried again with this AP.
+	 */
+	if (resp->reason_code == STATUS_INVALID_PMKID)
+		cm_delete_pmksa_for_bssid(cm_ctx, &resp->bssid);
+
 	/* In case of failure try with next candidate */
 	qdf_status =
 		cm_sm_deliver_event(vdev,
@@ -1136,7 +1187,12 @@ QDF_STATUS cm_connect_rsp(struct wlan_objmgr_vdev *vdev,
 
 	if (QDF_IS_STATUS_SUCCESS(qdf_status))
 		return qdf_status;
-
+	/*
+	 * If connection fails with Single PMK bssid, clear this pmk
+	 * entry in case of post failure.
+	 */
+	if (cm_is_cm_id_current_candidate_single_pmk(cm_ctx, cm_id))
+		cm_delete_pmksa_for_single_pmk_bssid(cm_ctx, &resp->bssid);
 post_err:
 	/*
 	 * If there is a event posting error it means the SM state is not in

+ 12 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h

@@ -504,6 +504,18 @@ cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
 					 wlan_cm_id cm_id,
 					 struct wlan_cm_connect_rsp *resp);
 
+#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
+bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx,
+					      wlan_cm_id cm_id);
+#else
+static inline
+bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx,
+					      wlan_cm_id cm_id)
+{
+	return false;
+}
+#endif
+
 /**
  * cm_flush_pending_request() - Flush all pending requests matching flush prefix
  * @cm_ctx: connection manager context

+ 36 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_util.c

@@ -402,6 +402,42 @@ cm_fill_bss_info_in_connect_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
 	return QDF_STATUS_E_FAILURE;
 }
 
+#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
+bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx,
+					      wlan_cm_id cm_id)
+{
+	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
+	struct cm_req *cm_req;
+	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
+	struct scan_cache_node *candidate;
+	bool is_single_pmk = false;
+
+	if (prefix != CONNECT_REQ_PREFIX)
+		return is_single_pmk;
+
+	cm_req_lock_acquire(cm_ctx);
+	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
+	while (cur_node) {
+		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
+		cm_req = qdf_container_of(cur_node, struct cm_req, node);
+
+		if (cm_req->cm_id == cm_id) {
+			candidate = cm_req->connect_req.cur_candidate;
+			if (candidate &&
+			    util_scan_entry_single_pmk(candidate->entry))
+				is_single_pmk = true;
+			break;
+		}
+
+		cur_node = next_node;
+		next_node = NULL;
+	}
+	cm_req_lock_release(cm_ctx);
+
+	return is_single_pmk;
+}
+#endif
+
 QDF_STATUS cm_add_req_to_list_and_indicate_osif(struct cnx_mgr *cm_ctx,
 						struct cm_req *cm_req,
 						enum wlan_cm_source source)