Răsfoiți Sursa

qcacld-3.0: synchronize concurrent access of shared variable

qcacld-2.0 to qcacld-3.0 propagation

Currently DFS variables are accessed in different context without
protection leading to NULL pointer dereferences.

Ensure lock is taken before accessing the DFS shared variable.

Change-Id: Ie78dd50ff4b32ef52f78e2944d175a6c10577882
CRs-Fixed: 910586
Edhar, Mahesh Kumar 9 ani în urmă
părinte
comite
952ec474d8

+ 2 - 0
core/sap/dfs/src/dfs.c

@@ -169,7 +169,9 @@ static os_timer_func(dfs_task)
 			 */
 			OS_CANCEL_TIMER(&dfs->ath_dfstesttimer);
 			dfs->ath_dfstest = 1;
+			cdf_spin_lock_bh(&ic->chan_lock);
 			dfs->ath_dfstest_ieeechan = ic->ic_curchan->ic_ieee;
+			cdf_spin_unlock_bh(&ic->chan_lock);
 			dfs->ath_dfstesttime = 1;       /* 1ms */
 			OS_SET_TIMER(&dfs->ath_dfstesttimer,
 				     dfs->ath_dfstesttime);

+ 8 - 0
core/sap/dfs/src/dfs_fcc_bin5.c

@@ -99,9 +99,12 @@ dfs_bin5_check_pulse(struct ath_dfs *dfs, struct dfs_event *re,
 	}
 
 	/* Adjust the filter threshold for rssi in non TURBO mode */
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
 	if (!(dfs->ic->ic_curchan->ic_flags & CHANNEL_TURBO))
 		b5_rssithresh += br->br_pulse.b5_rssimargin;
 
+	cdf_spin_unlock_bh(&dfs->ic->chan_lock);
+
 	/*
 	 * Check if the pulse is within duration and rssi
 	 * thresholds.
@@ -560,6 +563,7 @@ dfs_check_chirping_merlin(struct ath_dfs *dfs, void *buf, uint16_t datalen,
 	int same_sign;
 	int temp;
 
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
 	if (IS_CHAN_HT40(dfs->ic->ic_curchan)) {
 		num_fft_bytes = NUM_FFT_BYTES_HT40;
 		num_bin_bytes = NUM_BIN_BYTES_HT40;
@@ -590,6 +594,7 @@ dfs_check_chirping_merlin(struct ath_dfs *dfs, void *buf, uint16_t datalen,
 		upper_mag_byte = UPPER_MAG_BYTE_HT20;
 	}
 
+	cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 	ptr = (uint8_t *) buf;
 	/*
 	 * sanity check for FFT buffer
@@ -625,6 +630,7 @@ dfs_check_chirping_merlin(struct ath_dfs *dfs, void *buf, uint16_t datalen,
 		max_index_upper[i] =
 			(ptr[fft_start + upper_index_byte] >> 2) + num_subchan_bins;
 
+		cdf_spin_lock_bh(&dfs->ic->chan_lock);
 		if (!IS_CHAN_HT40(dfs->ic->ic_curchan)) {
 			/*
 			 * for HT20 mode indices are 6 bit signed number
@@ -632,6 +638,8 @@ dfs_check_chirping_merlin(struct ath_dfs *dfs, void *buf, uint16_t datalen,
 			max_index_lower[i] ^= 0x20;
 			max_index_upper[i] = 0;
 		}
+
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 		/*
 		 * Reconstruct the maximum magnitude for each sub-channel. Also select
 		 * and flag the max overall magnitude between the two sub-channels.

+ 8 - 0
core/sap/dfs/src/dfs_misc.c

@@ -107,7 +107,9 @@ dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect,
 	else
 		pri_margin = DFS_DEFAULT_PRI_MARGIN;
 
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
 	if (IS_CHAN_HT40(dfs->ic->ic_curchan)) {
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 		ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic);
 		if (ext_chan_busy >= 0) {
 			dfs->dfs_rinfo.ext_chan_busy_ts =
@@ -131,6 +133,8 @@ dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect,
 			adjust_pri_per_chan_busy(ext_chan_busy, pri_margin);
 
 		pri_margin -= adjust_pri;
+	} else {
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 	}
 	return pri_margin;
 }
@@ -146,7 +150,9 @@ int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf,
 
 	thresh = rf->rf_threshold;
 
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
 	if (IS_CHAN_HT40(dfs->ic->ic_curchan)) {
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 		ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic);
 		if (ext_chan_busy >= 0) {
 			dfs->dfs_rinfo.ext_chan_busy_ts =
@@ -179,6 +185,8 @@ int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf,
 			    rf->rf_pulseid, ext_chan_busy, adjust_thresh);
 
 		thresh += adjust_thresh;
+	} else {
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 	}
 	return thresh;
 }

+ 13 - 7
core/sap/dfs/src/dfs_phyerr_tlv.c

@@ -228,6 +228,7 @@ radar_summary_parse(struct ath_dfs *dfs, const char *buf, size_t len,
 	 *   Set pulse duration to 20 us
 	 */
 
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
 	freq = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan);
 	freq_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1;
 
@@ -238,6 +239,7 @@ radar_summary_parse(struct ath_dfs *dfs, const char *buf, size_t len,
 		rsu->pulse_duration = 20;
 	}
 
+	cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 }
 
 static void
@@ -435,13 +437,16 @@ static int tlv_calc_freq_info(struct ath_dfs *dfs, struct rx_radar_status *rs)
 		DFS_PRINTK("%s: dfs->ic=%p, that or curchan is null?",
 			   __func__, dfs->ic);
 		return 0;
-		/*
-		 * For now, the only 11ac channel with freq1/freq2 setup is
-		 * VHT80.
-		 *
-		 * XXX should have a flag macro to check this!
-		 */
-	} else if (IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan)) {
+	}
+
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
+	/*
+	 * For now, the only 11ac channel with freq1/freq2 setup is
+	 * VHT80.
+	 *
+	 * XXX should have a flag macro to check this!
+	 */
+	if (IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan)) {
 		/* 11AC, so cfreq1/cfreq2 are setup */
 
 		/*
@@ -477,6 +482,7 @@ static int tlv_calc_freq_info(struct ath_dfs *dfs, struct rx_radar_status *rs)
 		chan_centre += (chan_offset / 2);
 	}
 
+	cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 	/*
 	 * XXX half/quarter rate support!
 	 */

+ 32 - 7
core/sap/dfs/src/dfs_process_phyerr.c

@@ -72,6 +72,7 @@ dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc)
 {
 	struct ieee80211com *ic;
 	int chan_offset = 0, chan_width;
+	uint16_t freq;
 
 	/* Handle edge cases during startup/transition, shouldn't happen! */
 	if (dfs == NULL)
@@ -87,7 +88,7 @@ dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc)
 	 * based on whether it's an upper or lower channel.
 	 */
 	chan_width = dfs_get_event_freqwidth(dfs);
-
+	cdf_spin_lock_bh(&ic->chan_lock);
 	if (IEEE80211_IS_CHAN_11N_HT40PLUS(ic->ic_curchan))
 		chan_offset = chan_width;
 	else if (IEEE80211_IS_CHAN_11N_HT40MINUS(ic->ic_curchan))
@@ -95,6 +96,8 @@ dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc)
 	else
 		chan_offset = 0;
 
+	cdf_spin_unlock_bh(&ic->chan_lock);
+
 	/*
 	 * Check for DC events first - the sowl code may just set all
 	 * the bits together..
@@ -103,22 +106,36 @@ dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc)
 		/*
 		 * XXX TODO: Should DC events be considered 40MHz wide here?
 		 */
-		return ieee80211_chan2freq(ic, ic->ic_curchan) +
+		cdf_spin_lock_bh(&ic->chan_lock);
+		freq = ieee80211_chan2freq(ic, ic->ic_curchan) +
 			(chan_offset / 2);
+		cdf_spin_unlock_bh(&ic->chan_lock);
+		return freq;
 	}
 
 	/*
 	 * For non-wide channels, the centre frequency is just ic_freq.
 	 * The centre frequency for pri events is still ic_freq.
 	 */
-	if (is_pri)
-		return ieee80211_chan2freq(ic, ic->ic_curchan);
+	if (is_pri) {
+		cdf_spin_lock_bh(&ic->chan_lock);
+		freq = ieee80211_chan2freq(ic, ic->ic_curchan);
+		cdf_spin_unlock_bh(&ic->chan_lock);
+		return freq;
+	}
 
-	if (is_ext)
-		return ieee80211_chan2freq(ic, ic->ic_curchan) + chan_width;
+	if (is_ext) {
+		cdf_spin_lock_bh(&ic->chan_lock);
+		freq = ieee80211_chan2freq(ic, ic->ic_curchan) + chan_width;
+		cdf_spin_unlock_bh(&ic->chan_lock);
+		return freq;
+	}
 
 	/* XXX shouldn't get here */
-	return ieee80211_chan2freq(ic, ic->ic_curchan);
+	cdf_spin_lock_bh(&ic->chan_lock);
+	freq = ieee80211_chan2freq(ic, ic->ic_curchan);
+	cdf_spin_unlock_bh(&ic->chan_lock);
+	return freq;
 }
 
 /*
@@ -497,13 +514,16 @@ dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen,
 		return;
 	}
 
+	cdf_spin_lock_bh(&ic->chan_lock);
 	if (IEEE80211_IS_CHAN_RADAR(chan)) {
+		cdf_spin_unlock_bh(&ic->chan_lock);
 		DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
 			    "%s: Radar already found in the channel, "
 			    " do not queue radar data\n", __func__);
 		return;
 	}
 
+	cdf_spin_unlock_bh(&ic->chan_lock);
 	dfs->ath_dfs_stats.total_phy_errors++;
 	DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
 		    "%s[%d] phyerr %d len %d\n",
@@ -691,7 +711,9 @@ dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen,
 	 * for the adaptive radio (AR) pattern matching rather than
 	 * radar detection.
 	 */
+	cdf_spin_lock_bh(&ic->chan_lock);
 	if ((chan->ic_flags & CHANNEL_108G) == CHANNEL_108G) {
+		cdf_spin_unlock_bh(&ic->chan_lock);
 		if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) {
 			DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
 				    "%s: DFS_AR_EN not enabled\n", __func__);
@@ -732,6 +754,7 @@ dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen,
 		ATH_ARQ_UNLOCK(dfs);
 	} else {
 		if (IEEE80211_IS_CHAN_DFS(chan)) {
+			cdf_spin_unlock_bh(&ic->chan_lock);
 			if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) {
 				DFS_DPRINTK(dfs, ATH_DEBUG_DFS3,
 					    "%s: DFS_RADAR_EN not enabled\n",
@@ -824,6 +847,8 @@ dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen,
 			ATH_DFSQ_LOCK(dfs);
 			STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
 			ATH_DFSQ_UNLOCK(dfs);
+		} else {
+			cdf_spin_unlock_bh(&ic->chan_lock);
 		}
 	}
 

+ 8 - 0
core/sap/dfs/src/dfs_process_radarevent.c

@@ -140,13 +140,17 @@ int dfs_process_radarevent(struct ath_dfs *dfs, struct ieee80211_channel *chan)
 		return 0;
 	}
 	pl = dfs->pulses;
+	cdf_spin_lock_bh(&dfs->ic->chan_lock);
 	if (!(IEEE80211_IS_CHAN_DFS(dfs->ic->ic_curchan))) {
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 		DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
 			    "%s: radar event on non-DFS chan", __func__);
 		dfs_reset_radarq(dfs);
 		dfs_reset_alldelaylines(dfs);
 		return 0;
 	}
+
+	cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 #ifndef ATH_DFS_RADAR_DETECTION_ONLY
 	/* TEST : Simulate radar bang, make sure we add the channel to NOL (bug 29968) */
 	if (dfs->dfs_bangradar) {
@@ -781,11 +785,15 @@ dfsfound:
 		DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
 			    "Primary channel freq = %u flags=0x%x",
 			    chan->ic_freq, chan->ic_flagext);
+		cdf_spin_lock_bh(&dfs->ic->chan_lock);
 		if ((dfs->ic->ic_curchan->ic_freq != thischan->ic_freq)) {
+			cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 			DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
 				    "Ext channel freq = %u flags=0x%x",
 				    thischan->ic_freq, thischan->ic_flagext);
 		}
+
+		cdf_spin_unlock_bh(&dfs->ic->chan_lock);
 		dfs->dfs_phyerr_freq_min = 0x7fffffff;
 		dfs->dfs_phyerr_freq_max = 0;
 		dfs->dfs_phyerr_w53_counter = 0;

+ 1 - 1
core/wma/inc/wma_dfs_interface.h

@@ -232,7 +232,7 @@ typedef struct ieee80211com {
 	uint8_t vdev_id;
 	uint8_t last_radar_found_chan;
 	int32_t dfs_pri_multiplier;
-	cdf_mutex_t chan_lock;
+	cdf_spinlock_t chan_lock;
 } IEEE80211COM, *PIEEE80211COM;
 
 /**

+ 2 - 6
core/wma/src/wma_dev_if.c

@@ -2050,17 +2050,13 @@ CDF_STATUS wma_vdev_start(tp_wma_handle wma,
 				return CDF_STATUS_E_FAILURE;
 			}
 
-			cdf_mutex_acquire(&wma->dfs_ic->chan_lock);
-			if (wma->dfs_ic->ic_curchan) {
-				OS_FREE(wma->dfs_ic->ic_curchan);
-				wma->dfs_ic->ic_curchan = NULL;
-			}
+			cdf_spin_lock_bh(&wma->dfs_ic->chan_lock);
 
 			/* provide the current channel to DFS */
 			wma->dfs_ic->ic_curchan =
 				wma_dfs_configure_channel(wma->dfs_ic, chan,
 							  chanmode, req);
-			cdf_mutex_release(&wma->dfs_ic->chan_lock);
+			cdf_spin_unlock_bh(&wma->dfs_ic->chan_lock);
 
 			wma_unified_dfs_phyerr_filter_offload_enable(wma);
 			dfs->disable_dfs_ch_switch =

+ 16 - 10
core/wma/src/wma_features.c

@@ -1732,17 +1732,17 @@ static int wma_unified_dfs_radar_rx_event_handler(void *handle,
 
 	radar_event = param_tlvs->fixed_param;
 
-	cdf_mutex_acquire(&ic->chan_lock);
+	cdf_spin_lock_bh(&ic->chan_lock);
 	chan = ic->ic_curchan;
 	if (CHANNEL_STATE_DFS != cds_get_channel_state(chan->ic_ieee)) {
 		WMA_LOGE
 			("%s: Invalid DFS Phyerror event. Channel=%d is Non-DFS",
 			__func__, chan->ic_ieee);
-		cdf_mutex_release(&ic->chan_lock);
+		cdf_spin_unlock_bh(&ic->chan_lock);
 		return 0;
 	}
 
-	cdf_mutex_release(&ic->chan_lock);
+	cdf_spin_unlock_bh(&ic->chan_lock);
 	dfs->ath_dfs_stats.total_phy_errors++;
 
 	if (dfs->dfs_caps.ath_chip_is_bb_tlv) {
@@ -6625,7 +6625,7 @@ struct ieee80211com *wma_dfs_attach(struct ieee80211com *dfs_ic)
 	 * and shared DFS code
 	 */
 	dfs_ic->ic_dfs_notify_radar = ieee80211_mark_dfs;
-	cdf_mutex_init(&dfs_ic->chan_lock);
+	cdf_spinlock_init(&dfs_ic->chan_lock);
 	/* Initializes DFS Data Structures and queues */
 	dfs_attach(dfs_ic);
 
@@ -6642,7 +6642,7 @@ void wma_dfs_detach(struct ieee80211com *dfs_ic)
 {
 	dfs_detach(dfs_ic);
 
-	cdf_mutex_destroy(&dfs_ic->chan_lock);
+	cdf_spinlock_destroy(&dfs_ic->chan_lock);
 	if (NULL != dfs_ic->ic_curchan) {
 		OS_FREE(dfs_ic->ic_curchan);
 		dfs_ic->ic_curchan = NULL;
@@ -6757,14 +6757,18 @@ struct ieee80211_channel *wma_dfs_configure_channel(struct ieee80211com *dfs_ic,
 		WMA_LOGE("%s: DFS ic is Invalid", __func__);
 		return NULL;
 	}
-	dfs_ic->ic_curchan = (struct ieee80211_channel *)os_malloc(NULL,
+
+	if (!dfs_ic->ic_curchan) {
+		dfs_ic->ic_curchan = (struct ieee80211_channel *)os_malloc(NULL,
 					sizeof(struct ieee80211_channel),
 								   GFP_ATOMIC);
-	if (dfs_ic->ic_curchan == NULL) {
-		WMA_LOGE("%s: allocation of dfs_ic->ic_curchan failed %zu",
-			 __func__, sizeof(struct ieee80211_channel));
-		return NULL;
+		if (dfs_ic->ic_curchan == NULL) {
+			WMA_LOGE("%s: allocation of dfs_ic->ic_curchan failed %zu",
+				 __func__, sizeof(struct ieee80211_channel));
+			return NULL;
+		}
 	}
+
 	OS_MEMZERO(dfs_ic->ic_curchan, sizeof(struct ieee80211_channel));
 
 	dfs_ic->ic_curchan->ic_ieee = req->chan;
@@ -6916,6 +6920,7 @@ int wma_dfs_indicate_radar(struct ieee80211com *ic,
 	 * But, when DFS test mode is enabled, allow multiple dfs
 	 * radar events to be posted on the same channel.
 	 */
+	cdf_spin_lock_bh(&ic->chan_lock);
 	if ((ichan->ic_ieee != (wma->dfs_ic->last_radar_found_chan)) ||
 	    (pmac->sap.SapDfsInfo.disable_dfs_ch_switch == true)) {
 		wma->dfs_ic->last_radar_found_chan = ichan->ic_ieee;
@@ -6937,6 +6942,7 @@ int wma_dfs_indicate_radar(struct ieee80211com *ic,
 		wma_send_msg(wma, WMA_DFS_RADAR_IND, (void *)radar_event, 0);
 		WMA_LOGE("%s:DFS- WMA_DFS_RADAR_IND Message Posted", __func__);
 	}
+	cdf_spin_unlock_bh(&ic->chan_lock);
 
 	return 0;
 }