Эх сурвалжийг харах

qcacmn: Add synchronization to copied conn req

When accessing the copied connect request, concurrent accesses may
arise. This could cause a double free in certain scenarios. Add locks to
any write access so there is no unexpected behavior.

Change-Id: I011b8980d5756d7105704449af2dba6df1f23a8d
CRs-fixed: 3070966
Lincoln Tran 3 жил өмнө
parent
commit
b9c91b6554

+ 81 - 1
umac/mlo_mgr/inc/wlan_mlo_mgr_main.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 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 above
@@ -404,7 +405,62 @@ void ml_peerlist_lock_release(struct wlan_mlo_peer_list *ml_peerlist)
 	qdf_spin_unlock_bh(&ml_peerlist->peer_list_lock);
 }
 
-#else
+/**
+ * copied_conn_req_lock_create - Create original connect req mutex/spinlock
+ * @sta_ctx:  MLO STA related information
+ *
+ * Create mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void copied_conn_req_lock_create(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_spinlock_create(&sta_ctx->copied_conn_req_lock);
+}
+
+/**
+ * copied_conn_req_lock_destroy - Destroy original connect req mutex/spinlock
+ * @sta_ctx:  MLO STA related information
+ *
+ * Destroy mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void copied_conn_req_lock_destroy(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_spinlock_destroy(&sta_ctx->copied_conn_req_lock);
+}
+
+/**
+ * copied_conn_req_lock_acquire - Acquire original connect req mutex/spinlock
+ * @sta_ctx:  MLO STA related information
+ *
+ * Acquire mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void copied_conn_req_lock_acquire(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_spin_lock_bh(&sta_ctx->copied_conn_req_lock);
+}
+
+/**
+ * copied_conn_req_lock_release - Release original connect req mutex/spinlock
+ * @sta_ctx:  MLO STA related information
+ *
+ * Release mutex/spinlock
+ *
+ * return: void
+ */
+static inline
+void copied_conn_req_lock_release(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_spin_unlock_bh(&sta_ctx->copied_conn_req_lock);
+}
+#else /* WLAN_MLO_USE_SPINLOCK */
 static inline
 void ml_link_lock_create(struct mlo_mgr_context *mlo_ctx)
 {
@@ -546,6 +602,30 @@ void ml_peerlist_lock_release(struct wlan_mlo_peer_list *ml_peerlist)
 {
 	qdf_mutex_release(&ml_peerlist->peer_list_lock);
 }
+
+static inline
+void copied_conn_req_lock_create(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_mutex_create(&sta_ctx->copied_conn_req_lock);
+}
+
+static inline
+void copied_conn_req_lock_destroy(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_mutex_destroy(&sta_ctx->copied_conn_req_lock);
+}
+
+static inline
+void copied_conn_req_lock_acquire(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_mutex_acquire(&sta_ctx->copied_conn_req_lock);
+}
+
+static inline
+void copied_conn_req_lock_release(struct wlan_mlo_sta *sta_ctx)
+{
+	qdf_mutex_release(&sta_ctx->copied_conn_req_lock);
+}
 #endif /* WLAN_MLO_USE_SPINLOCK */
 
 #else

+ 8 - 2
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -172,7 +172,8 @@ struct wlan_mlo_key_mgmt {
  * @wlan_connect_req_links: list of vdevs selected for connection with the MLAP
  * @wlan_connected_links: list of vdevs associated with this MLO connection
  * @connect req: connect params
- * @orig_conn_req: original connect req
+ * @copied_conn_req: original connect req
+ * @copied_conn_req_lock: lock for the original connect request
  * @assoc_rsp: Raw assoc response frame
  */
 struct wlan_mlo_sta {
@@ -180,7 +181,12 @@ struct wlan_mlo_sta {
 	qdf_bitmap(wlan_connected_links, WLAN_UMAC_MLO_MAX_VDEVS);
 	struct wlan_mlo_key_mgmt key_mgmt[WLAN_UMAC_MLO_MAX_VDEVS - 1];
 	struct wlan_cm_connect_req *connect_req;
-	struct wlan_cm_connect_req *orig_conn_req;
+	struct wlan_cm_connect_req *copied_conn_req;
+#ifdef WLAN_MLO_USE_SPINLOCK
+	qdf_spinlock_t copied_conn_req_lock;
+#else
+	qdf_mutex_t copied_conn_req_lock;
+#endif
 	struct element_info assoc_rsp;
 };
 

+ 3 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_main.c

@@ -277,6 +277,7 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 			qdf_mem_free(ml_dev);
 			return QDF_STATUS_E_NOMEM;
 		}
+		copied_conn_req_lock_create(ml_dev->sta_ctx);
 	} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
 		if (mlo_ap_ctx_init(ml_dev) != QDF_STATUS_SUCCESS) {
 			mlo_dev_lock_destroy(ml_dev);
@@ -354,6 +355,8 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
 			if (ml_dev->sta_ctx->assoc_rsp.ptr)
 				qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr);
 
+			copied_conn_req_lock_destroy(ml_dev->sta_ctx);
+
 			qdf_mem_free(ml_dev->sta_ctx);
 		}
 		else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)

+ 46 - 24
umac/mlo_mgr/src/wlan_mlo_mgr_sta.c

@@ -281,10 +281,16 @@ static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
 
 	if (mlo_dev_ctx)
 		sta_ctx = mlo_dev_ctx->sta_ctx;
-	if (sta_ctx && sta_ctx->orig_conn_req) {
-		mlo_free_connect_ies(sta_ctx->orig_conn_req);
-		qdf_mem_free(sta_ctx->orig_conn_req);
-		sta_ctx->orig_conn_req = NULL;
+	if (sta_ctx) {
+		copied_conn_req_lock_acquire(sta_ctx);
+		if (sta_ctx->copied_conn_req) {
+			mlo_free_connect_ies(sta_ctx->copied_conn_req);
+			qdf_mem_free(sta_ctx->copied_conn_req);
+			sta_ctx->copied_conn_req = NULL;
+		}
+		copied_conn_req_lock_release(sta_ctx);
+	} else {
+		return QDF_STATUS_E_FAILURE;
 	}
 
 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
@@ -375,19 +381,23 @@ QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,
 		mlo_dev_lock_acquire(mlo_dev_ctx);
 		status = mlo_validate_connect_req(vdev, mlo_dev_ctx, req);
 
-		if (!sta_ctx->orig_conn_req)
-			sta_ctx->orig_conn_req = qdf_mem_malloc(
+		copied_conn_req_lock_acquire(sta_ctx);
+		if (!sta_ctx->copied_conn_req)
+			sta_ctx->copied_conn_req = qdf_mem_malloc(
 					sizeof(struct wlan_cm_connect_req));
 		else
-			mlo_free_connect_ies(sta_ctx->orig_conn_req);
+			mlo_free_connect_ies(sta_ctx->copied_conn_req);
 
 		mlo_debug("storing orig connect req");
-		if (sta_ctx->orig_conn_req) {
-			qdf_mem_copy(sta_ctx->orig_conn_req, req,
+		if (sta_ctx->copied_conn_req) {
+			qdf_mem_copy(sta_ctx->copied_conn_req, req,
 				     sizeof(struct wlan_cm_connect_req));
-			mlo_allocate_and_copy_ies(sta_ctx->orig_conn_req, req);
+			mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req,
+						  req);
+			copied_conn_req_lock_release(sta_ctx);
 		} else {
 			mlo_err("Failed to allocate orig connect req");
+			copied_conn_req_lock_release(sta_ctx);
 			return QDF_STATUS_E_NOMEM;
 		}
 
@@ -441,7 +451,7 @@ mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev,
 		  QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
 		  wlan_vdev_get_id(vdev));
 
-	qdf_mem_copy(&req, sta_ctx->orig_conn_req,
+	qdf_mem_copy(&req, sta_ctx->copied_conn_req,
 		     sizeof(struct wlan_cm_connect_req));
 
 	mlo_update_connect_req_chan_info(&req);
@@ -457,7 +467,7 @@ mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev,
 	req.ssid.length = ssid.length;
 	qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length);
 
-	mlo_allocate_and_copy_ies(&req, sta_ctx->orig_conn_req);
+	mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req);
 	if (!req.assoc_ie.ptr)
 		mlo_err("Failed to allocate assoc IEs");
 
@@ -697,10 +707,14 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
 		sta_ctx = mlo_dev_ctx->sta_ctx;
 
 	if (wlan_cm_is_vdev_disconnected(vdev)) {
-		if (sta_ctx && sta_ctx->orig_conn_req) {
-			mlo_free_connect_ies(sta_ctx->orig_conn_req);
-			qdf_mem_free(sta_ctx->orig_conn_req);
-			sta_ctx->orig_conn_req = NULL;
+		if (sta_ctx) {
+			copied_conn_req_lock_acquire(sta_ctx);
+			if (sta_ctx->copied_conn_req) {
+				mlo_free_connect_ies(sta_ctx->copied_conn_req);
+				qdf_mem_free(sta_ctx->copied_conn_req);
+				sta_ctx->copied_conn_req = NULL;
+			}
+			copied_conn_req_lock_release(sta_ctx);
 		}
 	}
 
@@ -802,10 +816,14 @@ QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	if (mlo_dev_ctx)
 		sta_ctx = mlo_dev_ctx->sta_ctx;
-	if (sta_ctx && sta_ctx->orig_conn_req) {
-		mlo_free_connect_ies(sta_ctx->orig_conn_req);
-		qdf_mem_free(sta_ctx->orig_conn_req);
-		sta_ctx->orig_conn_req = NULL;
+	if (sta_ctx) {
+		copied_conn_req_lock_acquire(sta_ctx);
+		if (sta_ctx->copied_conn_req) {
+			mlo_free_connect_ies(sta_ctx->copied_conn_req);
+			qdf_mem_free(sta_ctx->copied_conn_req);
+			sta_ctx->copied_conn_req = NULL;
+		}
+		copied_conn_req_lock_release(sta_ctx);
 	}
 
 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
@@ -840,10 +858,14 @@ QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
 	mlo_dev_ctx = vdev->mlo_dev_ctx;
 	if (mlo_dev_ctx)
 		sta_ctx = mlo_dev_ctx->sta_ctx;
-	if (sta_ctx && sta_ctx->orig_conn_req) {
-		mlo_free_connect_ies(sta_ctx->orig_conn_req);
-		qdf_mem_free(sta_ctx->orig_conn_req);
-		sta_ctx->orig_conn_req = NULL;
+	if (sta_ctx) {
+		copied_conn_req_lock_acquire(sta_ctx);
+		if (sta_ctx->copied_conn_req) {
+			mlo_free_connect_ies(sta_ctx->copied_conn_req);
+			qdf_mem_free(sta_ctx->copied_conn_req);
+			sta_ctx->copied_conn_req = NULL;
+		}
+		copied_conn_req_lock_release(sta_ctx);
 	}
 
 	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {