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
This commit is contained in:
Edhar, Mahesh Kumar 2015-10-26 16:53:30 +05:30 committed by Prakash Dhavali
parent e3eaebe339
commit b0319c4725
9 changed files with 90 additions and 31 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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;
}

View File

@ -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!
*/

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
/**

View File

@ -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 =

View File

@ -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;
}