Jelajahi Sumber

qcacld-3.0: Fix vdev count leak in pre CAC

At present Pre CAC work queue callback pre_cac_handle_failure
doesn't release the vdev ref count. And the pre_cac_handle_radar_ind
doesn't take ref count before schedule work pre_cac_work.
To fix inconsistency by using psoc as work queue callback parameter
and get pre CAC vdev id from psoc context.

Change-Id: I65339ca9f3ac4b91faf31090978337d041320f99
CRs-Fixed: 3288125
Liangwei Dong 2 tahun lalu
induk
melakukan
86a7824781

+ 34 - 21
components/pre_cac/core/src/wlan_pre_cac_main.c

@@ -34,7 +34,7 @@ void pre_cac_stop(struct wlan_objmgr_psoc *psoc)
 
 	if (!psoc_priv)
 		return;
-
+	pre_cac_debug("cancel pre_cac_work");
 	if (psoc_priv->pre_cac_work.fn)
 		qdf_cancel_work(&psoc_priv->pre_cac_work);
 }
@@ -146,19 +146,27 @@ bool pre_cac_complete_get(struct wlan_objmgr_vdev *vdev)
 	return vdev_priv->pre_cac_complete;
 }
 
-static void pre_cac_complete(struct wlan_objmgr_vdev *vdev,
+static void pre_cac_complete(struct wlan_objmgr_psoc *psoc,
+			     uint8_t vdev_id,
 			     QDF_STATUS status)
 {
 	if (glbl_pre_cac_ops &&
 	    glbl_pre_cac_ops->pre_cac_complete_cb)
-		glbl_pre_cac_ops->pre_cac_complete_cb(vdev, status);
+		glbl_pre_cac_ops->pre_cac_complete_cb(psoc, vdev_id, status);
 }
 
 static void pre_cac_handle_success(void *data)
 {
-	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)data;
+	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data;
+	struct pre_cac_psoc_priv *psoc_priv;
 
-	pre_cac_complete(vdev, QDF_STATUS_SUCCESS);
+	psoc_priv = pre_cac_psoc_get_priv(psoc);
+	if (!psoc_priv) {
+		pre_cac_err("Invalid psoc priv");
+		return;
+	}
+	pre_cac_debug("vdev id %d", psoc_priv->pre_cac_vdev_id);
+	pre_cac_complete(psoc, psoc_priv->pre_cac_vdev_id, QDF_STATUS_SUCCESS);
 }
 
 static void pre_cac_conditional_csa_ind(struct wlan_objmgr_psoc *psoc,
@@ -172,15 +180,22 @@ static void pre_cac_conditional_csa_ind(struct wlan_objmgr_psoc *psoc,
 
 static void pre_cac_handle_failure(void *data)
 {
-	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)data;
+	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data;
+	struct pre_cac_psoc_priv *psoc_priv;
 
-	pre_cac_complete(vdev, QDF_STATUS_E_FAILURE);
+	psoc_priv = pre_cac_psoc_get_priv(psoc);
+	if (!psoc_priv) {
+		pre_cac_err("Invalid psoc priv");
+		return;
+	}
+	pre_cac_debug("vdev id %d", psoc_priv->pre_cac_vdev_id);
+	pre_cac_complete(psoc, psoc_priv->pre_cac_vdev_id,
+			 QDF_STATUS_E_FAILURE);
 }
 
 void pre_cac_clean_up(struct wlan_objmgr_psoc *psoc)
 {
 	struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc);
-	struct wlan_objmgr_vdev *vdev;
 	uint8_t vdev_id;
 
 	if (!psoc_priv) {
@@ -192,17 +207,11 @@ void pre_cac_clean_up(struct wlan_objmgr_psoc *psoc)
 		return;
 
 	pre_cac_get_vdev_id(psoc, &vdev_id);
-
-	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
-						    WLAN_PRE_CAC_ID);
-	if (!vdev) {
-		pre_cac_err("Invalid vdev");
-		return;
-	}
-
+	pre_cac_debug("schedue pre_cac_work vdev %d", vdev_id);
+	psoc_priv->pre_cac_vdev_id = vdev_id;
 	qdf_create_work(0, &psoc_priv->pre_cac_work,
 			pre_cac_handle_failure,
-			vdev);
+			psoc);
 	qdf_sched_work(0, &psoc_priv->pre_cac_work);
 }
 
@@ -211,11 +220,13 @@ void pre_cac_handle_radar_ind(struct wlan_objmgr_vdev *vdev)
 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
 	struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc);
 
-	pre_cac_conditional_csa_ind(psoc, vdev->vdev_objmgr.vdev_id, false);
+	pre_cac_conditional_csa_ind(psoc, wlan_vdev_get_id(vdev), false);
 
+	pre_cac_debug("schedue pre_cac_work vdev %d", wlan_vdev_get_id(vdev));
+	psoc_priv->pre_cac_vdev_id = wlan_vdev_get_id(vdev);
 	qdf_create_work(0, &psoc_priv->pre_cac_work,
 			pre_cac_handle_failure,
-			vdev);
+			psoc);
 	qdf_sched_work(0, &psoc_priv->pre_cac_work);
 }
 
@@ -224,11 +235,13 @@ void pre_cac_handle_cac_end(struct wlan_objmgr_vdev *vdev)
 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
 	struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc);
 
-	pre_cac_conditional_csa_ind(psoc, vdev->vdev_objmgr.vdev_id, true);
+	pre_cac_conditional_csa_ind(psoc, wlan_vdev_get_id(vdev), true);
 
+	pre_cac_debug("schedue pre_cac_work vdev %d", wlan_vdev_get_id(vdev));
+	psoc_priv->pre_cac_vdev_id = wlan_vdev_get_id(vdev);
 	qdf_create_work(0, &psoc_priv->pre_cac_work,
 			pre_cac_handle_success,
-			vdev);
+			psoc);
 	qdf_sched_work(0, &psoc_priv->pre_cac_work);
 }
 

+ 4 - 2
components/pre_cac/core/src/wlan_pre_cac_main.h

@@ -77,9 +77,11 @@ struct pre_cac_vdev_priv {
 /**
  * struct pre_cac_psoc_priv - Private object to be stored in psoc
  * @pre_cac_work: pre cac work handler
+ * @pre_cac_vdev_id: pre cac vdev id
  */
 struct pre_cac_psoc_priv {
 	qdf_work_t pre_cac_work;
+	uint8_t pre_cac_vdev_id;
 };
 
 /**
@@ -158,8 +160,8 @@ pre_cac_psoc_get_priv_fl(struct wlan_objmgr_psoc *psoc,
  *
  * Return: pre_cac psoc private object
  */
-#define pre_cac_psoc_get_priv(vdev) \
-			      pre_cac_psoc_get_priv_fl(vdev, __func__, __LINE__)
+#define pre_cac_psoc_get_priv(psoc) \
+			      pre_cac_psoc_get_priv_fl(psoc, __func__, __LINE__)
 
 /**
  * pre_cac_init() - pre cac component initialization.

+ 3 - 2
components/pre_cac/dispatcher/inc/wlan_pre_cac_public_struct.h

@@ -29,7 +29,8 @@ struct pre_cac_ops {
 	void (*pre_cac_conditional_csa_ind_cb)(
 			struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			bool status);
-	void (*pre_cac_complete_cb)(struct wlan_objmgr_vdev *vdev,
-				    QDF_STATUS status);
+	void (*pre_cac_complete_cb)(
+			struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
+			QDF_STATUS status);
 };
 #endif /* _WLAN_PRE_CAC_PUBLIC_STRUCT_H_ */

+ 3 - 4
core/hdd/src/wlan_hdd_pre_cac.c

@@ -538,16 +538,15 @@ wlan_hdd_pre_cac_conditional_freq_switch_ind(struct wlan_objmgr_vdev *vdev,
 }
 
 static void
-wlan_hdd_pre_cac_complete(struct wlan_objmgr_vdev *vdev,
+wlan_hdd_pre_cac_complete(struct wlan_objmgr_psoc *psoc,
+			  uint8_t vdev_id,
 			  QDF_STATUS status)
 {
-	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
-	uint8_t vdev_id = vdev->vdev_objmgr.vdev_id;
 	struct hdd_adapter *adapter;
 
 	adapter = wlan_hdd_get_adapter_from_vdev(psoc, vdev_id);
 	if (!adapter) {
-		hdd_err("Invalid adapter");
+		hdd_err("Invalid adapter vdev %d", vdev_id);
 		return;
 	}
 

+ 2 - 1
os_if/pre_cac/inc/osif_pre_cac.h

@@ -42,7 +42,8 @@ typedef void
  * Return: None
  */
 typedef void
-	(*osif_pre_cac_complete_status_legacy_cb)(struct wlan_objmgr_vdev *vdev,
+	(*osif_pre_cac_complete_status_legacy_cb)(struct wlan_objmgr_psoc *psoc,
+						  uint8_t vdev_id,
 						  QDF_STATUS status);
 
 /**

+ 17 - 5
os_if/pre_cac/src/osif_pre_cac.c

@@ -26,7 +26,8 @@
 static struct osif_pre_cac_legacy_ops *osif_pre_cac_legacy_ops;
 
 static void
-osif_pre_cac_complete_legacy_cb(struct wlan_objmgr_vdev *vdev,
+osif_pre_cac_complete_legacy_cb(struct wlan_objmgr_psoc *psoc,
+				uint8_t vdev_id,
 				QDF_STATUS status)
 {
 	osif_pre_cac_complete_status_legacy_cb cb = NULL;
@@ -35,22 +36,33 @@ osif_pre_cac_complete_legacy_cb(struct wlan_objmgr_vdev *vdev,
 		cb = osif_pre_cac_legacy_ops->pre_cac_complete_legacy_cb;
 
 	if (cb)
-		cb(vdev, status);
+		cb(psoc, vdev_id, status);
 }
 
-static void osif_pre_cac_complete_cb(struct wlan_objmgr_vdev *vdev,
+static void osif_pre_cac_complete_cb(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id,
 				     QDF_STATUS status)
 {
-	struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
+	struct vdev_osif_priv *osif_priv;
 	struct osif_vdev_sync *vdev_sync;
 	int errno;
+	struct wlan_objmgr_vdev *vdev;
 
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+				psoc, vdev_id,
+				WLAN_PRE_CAC_ID);
+	if (!vdev) {
+		osif_err("Invalid vdev for %d", vdev_id);
+		return;
+	}
+	osif_priv = wlan_vdev_get_ospriv(vdev);
 	errno = osif_vdev_sync_trans_start_wait(osif_priv->wdev->netdev,
 						&vdev_sync);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_PRE_CAC_ID);
 	if (errno)
 		return;
 
-	osif_pre_cac_complete_legacy_cb(vdev, status);
+	osif_pre_cac_complete_legacy_cb(psoc, vdev_id, status);
 
 	osif_vdev_sync_trans_stop(vdev_sync);
 }