qcacmn: Fix DFS nol memory leak

Problem:- If the driver is unloaded before a nol timer fires, the unload
function frees the NOl element. But the memory associated with the nol timer
argument which has a one-to-one mapping with nol still remains in the system
since the nol timer argument memory is freed in the timer function.

Solution:-
1)Instead of allocating a separate structure as input to the timer function
use the NOL element itself as input since NOL element already has the
information needed by the timer function.
2)A NOL element for which  the timer is yet to fire is freed
by the driver unload (dfs_nol_timer_cleanup).
3)When dfs_nol_timer_cleanup is about to free a NOL element the corresponding
timer may be already running. Therefore, it is required to sync/wait for the
timer to finish before the NOL element can be freed. If we do not wait and
free the NOL element the timer may access an invalid memory location.

Change-Id: I4f37b66777491d92a51ff1ffc2651af1ccf5de29
CRs-Fixed: 2045993
diff --git a/umac/dfs/core/src/misc/dfs_nol.c b/umac/dfs/core/src/misc/dfs_nol.c
index 2eb7392..04be39d 100644
--- a/umac/dfs/core/src/misc/dfs_nol.c
+++ b/umac/dfs/core/src/misc/dfs_nol.c
@@ -101,17 +101,17 @@
  */
 static os_timer_func(dfs_remove_from_nol)
 {
-	struct dfs_nol_timer_arg *nol_arg;
+	struct dfs_nolelem *nol_arg;
 	struct wlan_dfs *dfs;
 	uint16_t delfreq;
 	uint16_t delchwidth;
 	uint8_t chan;
 
-	OS_GET_TIMER_ARG(nol_arg, struct dfs_nol_timer_arg *);
+	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
 
-	dfs = nol_arg->dfs;
-	delfreq = nol_arg->delfreq;
-	delchwidth = nol_arg->delchwidth;
+	dfs = nol_arg->nol_dfs;
+	delfreq = nol_arg->nol_freq;
+	delchwidth = nol_arg->nol_chwidth;
 
 	/* Delete the given NOL entry. */
 	dfs_nol_delete(dfs, delfreq, delchwidth);
@@ -126,7 +126,6 @@
 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
 			(uint8_t *)&chan, 1, DFS_NOL_RESET);
 	dfs_save_nol(dfs->dfs_pdev_obj);
-	qdf_mem_free(nol_arg);
 }
 
 void dfs_print_nol(struct wlan_dfs *dfs)
@@ -256,7 +255,6 @@
 #define TIME_IN_MS 1000
 #define TIME_IN_US (TIME_IN_MS * 1000)
 	struct dfs_nolelem *nol, *elem, *prev;
-	struct dfs_nol_timer_arg *dfs_nol_arg;
 	/* For now, assume all events are 20MHz wide. */
 	int ch_width = 20;
 
@@ -292,12 +290,7 @@
 	if (elem == NULL)
 		goto bad;
 
-	dfs_nol_arg = (struct dfs_nol_timer_arg *)qdf_mem_malloc(
-			sizeof(struct dfs_nol_timer_arg));
-	if (dfs_nol_arg == NULL) {
-		qdf_mem_free(elem);
-		goto bad;
-	}
+	elem->nol_dfs = dfs;
 	elem->nol_freq = freq;
 	elem->nol_chwidth = ch_width;
 	elem->nol_start_ticks = qdf_system_ticks();
@@ -309,13 +302,10 @@
 		/* This is the first element in the NOL. */
 		dfs->dfs_nol = elem;
 	}
-	dfs_nol_arg->dfs = dfs;
-	dfs_nol_arg->delfreq = elem->nol_freq;
-	dfs_nol_arg->delchwidth = elem->nol_chwidth;
 
 	qdf_timer_init(NULL,
 			&elem->nol_timer, dfs_remove_from_nol,
-			dfs_nol_arg, QDF_TIMER_TYPE_WAKE_APPS);
+			elem, QDF_TIMER_TYPE_WAKE_APPS);
 	OS_SET_TIMER(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
 
 	/* Update the NOL counter. */
@@ -414,7 +404,7 @@
 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
 
 	while (nol) {
-		qdf_timer_stop(&nol->nol_timer);
+		qdf_timer_sync_cancel(&nol->nol_timer);
 		nol = nol->nol_next;
 	}