Ver código fonte

qcacld-3.0: Validate CSA WBW IE before processing channel switch

Check new channel width and center frequency segments in CSA
wider BW IE before processing the channel switch and if CSA IE
has invalid data for any of these parameters then do not do the
channel switch with wider BW.
Also check for self capability for BW that is supported by device
before processing wider BW channel switch. If AP advertises the new
channel width with valid data that is greater than self capability
BW value then limit the channel switch BW to self capability.

Change-Id: I1d567e5cdc6347b56b513ea002b5a3978cb447e9
CRs-Fixed: 2182054
Kiran Kumar Lokere 7 anos atrás
pai
commit
05a0658af1

+ 77 - 9
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -64,6 +64,7 @@
 
 #include "wlan_tdls_tgt_api.h"
 #include "lim_process_fils.h"
+#include "wma.h"
 
 static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx,
 	tpPESession session_entry, tSirResultCodes result_code,
@@ -1980,7 +1981,7 @@ lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac,
  *
  * Return: None
  */
-static void lim_process_csa_wbw_ie(tpAniSirGlobal mac_ctx,
+static QDF_STATUS lim_process_csa_wbw_ie(tpAniSirGlobal mac_ctx,
 		struct csa_offload_params *csa_params,
 		tLimWiderBWChannelSwitchInfo *chnl_switch_info,
 		tpPESession session_entry)
@@ -1989,8 +1990,27 @@ static void lim_process_csa_wbw_ie(tpAniSirGlobal mac_ctx,
 	uint8_t ap_new_ch_width;
 	bool new_ch_width_dfn = false;
 	uint8_t center_freq_diff;
+	uint32_t fw_vht_ch_wd = wma_get_vht_ch_width() + 1;
 
 	ap_new_ch_width = csa_params->new_ch_width + 1;
+
+	pe_info("new channel: %d new_ch_width: %d seg0: %d seg1: %d",
+			csa_params->channel, ap_new_ch_width,
+			csa_params->new_ch_freq_seg1,
+			csa_params->new_ch_freq_seg2);
+
+	if ((ap_new_ch_width != CH_WIDTH_80MHZ) &&
+			(ap_new_ch_width != CH_WIDTH_160MHZ) &&
+			(ap_new_ch_width != CH_WIDTH_80P80MHZ)) {
+		pe_err("CSA wide BW IE has wrong ch_width %d",
+				csa_params->new_ch_width);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!csa_params->new_ch_freq_seg1 && !csa_params->new_ch_freq_seg2) {
+		pe_err("CSA wide BW IE has invalid center freq");
+		return QDF_STATUS_E_INVAL;
+	}
 	if ((ap_new_ch_width == CH_WIDTH_80MHZ) &&
 			csa_params->new_ch_freq_seg2) {
 		new_ch_width_dfn = true;
@@ -2012,12 +2032,55 @@ static void lim_process_csa_wbw_ie(tpAniSirGlobal mac_ctx,
 		eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY;
 	if ((ap_new_ch_width == CH_WIDTH_160MHZ) &&
 			!new_ch_width_dfn) {
-		ch_params.ch_width = CH_WIDTH_160MHZ;
+		if (csa_params->new_ch_freq_seg1 != csa_params->channel +
+				CH_TO_CNTR_FREQ_DIFF_160MHz) {
+			pe_err("CSA wide BW IE has invalid center freq");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		if (ap_new_ch_width > fw_vht_ch_wd) {
+			pe_info("New BW is not supported, setting BW to %d",
+					fw_vht_ch_wd);
+			ap_new_ch_width = fw_vht_ch_wd;
+		}
+		ch_params.ch_width = ap_new_ch_width ;
 		wlan_reg_set_channel_params(mac_ctx->pdev,
 					    csa_params->channel, 0, &ch_params);
 		ap_new_ch_width = ch_params.ch_width;
 		csa_params->new_ch_freq_seg1 = ch_params.center_freq_seg0;
 		csa_params->new_ch_freq_seg2 = ch_params.center_freq_seg1;
+	} else if (!new_ch_width_dfn) {
+		if (ap_new_ch_width > fw_vht_ch_wd) {
+			pe_info("New BW is not supported, setting BW to %d",
+					fw_vht_ch_wd);
+			ap_new_ch_width = fw_vht_ch_wd;
+		}
+		if (csa_params->new_ch_freq_seg1 != csa_params->channel +
+				CH_TO_CNTR_FREQ_DIFF_80MHz) {
+			pe_err("CSA wide BW IE has invalid center freq");
+			return QDF_STATUS_E_INVAL;
+		}
+		csa_params->new_ch_freq_seg2 = 0;
+	}
+	if (new_ch_width_dfn) {
+		if (csa_params->new_ch_freq_seg1 != csa_params->channel +
+				CH_TO_CNTR_FREQ_DIFF_80MHz) {
+			pe_err("CSA wide BW IE has invalid center freq");
+			return QDF_STATUS_E_INVAL;
+		}
+		if (ap_new_ch_width > fw_vht_ch_wd) {
+			pe_info("New width is not supported, setting BW to %d",
+					fw_vht_ch_wd);
+			ap_new_ch_width = fw_vht_ch_wd;
+		}
+		if ((ap_new_ch_width == CH_WIDTH_160MHZ) &&
+				(csa_params->new_ch_freq_seg1 !=
+				 csa_params->channel +
+				 CH_TO_CNTR_FREQ_DIFF_160MHz)) {
+			pe_err("wide BW IE has invalid 160M center freq");
+			csa_params->new_ch_freq_seg2 = 0;
+			ap_new_ch_width = CH_WIDTH_80MHZ;
+		}
 	}
 	chnl_switch_info->newChanWidth = ap_new_ch_width;
 	chnl_switch_info->newCenterChanFreq0 = csa_params->new_ch_freq_seg1;
@@ -2039,7 +2102,10 @@ prnt_log:
 			chnl_switch_info->newChanWidth,
 			chnl_switch_info->newCenterChanFreq0,
 			chnl_switch_info->newCenterChanFreq1);
+
+	return QDF_STATUS_SUCCESS;
 }
+
 /**
  * lim_handle_csa_offload_msg() - Handle CSA offload message
  * @mac_ctx:         pointer to global adapter context
@@ -2116,12 +2182,13 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx,
 	chnl_switch_info =
 		&session_entry->gLimWiderBWChannelSwitch;
 
-	pe_debug("vht: %d ht: %d flag: %x chan: %d",
+	pe_info("vht: %d ht: %d flag: %x chan: %d, sec_ch_offset %d",
 			session_entry->vhtCapability,
 			session_entry->htSupportedChannelWidthSet,
 			csa_params->ies_present_flag,
-			csa_params->channel);
-	pe_debug("seg1: %d seg2: %d width: %d country: %s class: %d",
+			csa_params->channel,
+			csa_params->sec_chan_offset);
+	pe_info("seg1: %d seg2: %d width: %d country: %s class: %d",
 			csa_params->new_ch_freq_seg1,
 			csa_params->new_ch_freq_seg2,
 			csa_params->new_ch_width,
@@ -2130,10 +2197,11 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx,
 
 	if (session_entry->vhtCapability &&
 			session_entry->htSupportedChannelWidthSet) {
-		if (csa_params->ies_present_flag & lim_wbw_ie_present &&
-				csa_params->new_ch_width) {
-			lim_process_csa_wbw_ie(mac_ctx, csa_params,
-					chnl_switch_info, session_entry);
+		if ((csa_params->ies_present_flag & lim_wbw_ie_present) &&
+			(QDF_STATUS_SUCCESS == lim_process_csa_wbw_ie(mac_ctx,
+					csa_params, chnl_switch_info,
+					session_entry))) {
+			pe_debug("CSA wide BW IE process successful");
 			lim_ch_switch->sec_ch_offset =
 				PHY_SINGLE_CHANNEL_CENTERED;
 			if (chnl_switch_info->newChanWidth) {

+ 5 - 2
core/mac/src/pe/lim/lim_utils.c

@@ -4279,6 +4279,7 @@ void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac,
 						   tpPESession psessionEntry)
 {
 	uint8_t center_freq = 0;
+	enum phy_ch_width ch_width = CH_WIDTH_20MHZ;
 
 	/* If self capability is set to '20Mhz only', then do not change the CB mode. */
 	if (!lim_get_ht_capability
@@ -4330,12 +4331,15 @@ void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac,
 			(uint8_t) pHTInfo->recommendedTxWidthSet;
 		if (eHT_CHANNEL_WIDTH_40MHZ ==
 		    psessionEntry->htRecommendedTxWidthSet) {
+			ch_width = CH_WIDTH_40MHZ;
 			if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY ==
 					pHTInfo->secondaryChannelOffset)
 				center_freq = pHTInfo->primaryChannel + 2;
 			else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY ==
 					pHTInfo->secondaryChannelOffset)
 				center_freq = pHTInfo->primaryChannel - 2;
+			else
+				ch_width = CH_WIDTH_20MHZ;
 		}
 
 		/* notify HAL */
@@ -4351,8 +4355,7 @@ void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac,
 		pMac->lim.gpchangeChannelData = NULL;
 
 		lim_send_switch_chnl_params(pMac, (uint8_t) pHTInfo->primaryChannel,
-					    center_freq, 0,
-					    psessionEntry->htRecommendedTxWidthSet,
+					    center_freq, 0, ch_width,
 					    psessionEntry->maxTxPower,
 					    psessionEntry->peSessionId,
 					    true, 0, 0);

+ 3 - 0
core/mac/src/pe/lim/lim_utils.h

@@ -67,6 +67,9 @@ typedef enum {
 #define CENTER_FREQ_DIFF_160MHz 8
 #define CENTER_FREQ_DIFF_80P80MHz 16
 
+#define CH_TO_CNTR_FREQ_DIFF_160MHz 14
+#define CH_TO_CNTR_FREQ_DIFF_80MHz 6
+
 #define IS_VHT_NSS_1x1(__mcs_map)	((__mcs_map & 0xFFFC) == 0xFFFC)
 
 #define MGMT_RX_PACKETS_THRESHOLD 200

+ 46 - 19
core/wma/src/wma_dev_if.c

@@ -2486,6 +2486,7 @@ QDF_STATUS wma_vdev_start(tp_wma_handle wma,
 	struct wma_txrx_node *iface = &wma->interfaces[req->vdev_id];
 	struct wma_target_req *req_msg;
 	uint32_t chan_mode;
+	enum phy_ch_width ch_width;
 
 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
 	if (mac_ctx == NULL) {
@@ -2493,14 +2494,56 @@ QDF_STATUS wma_vdev_start(tp_wma_handle wma,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	chan_mode = wma_chan_phy_mode(req->chan, req->chan_width,
-					     req->dot11_mode);
+	params.band_center_freq1 = cds_chan_to_freq(req->chan);
+	ch_width = req->chan_width;
+	bw_val = wlan_reg_get_bw_value(req->chan_width);
+	if (20 < bw_val) {
+		if (req->ch_center_freq_seg0) {
+			params.band_center_freq1 =
+				cds_chan_to_freq(req->ch_center_freq_seg0);
+		} else {
+			WMA_LOGE("%s: invalid cntr_freq for bw %d, drop to 20",
+					__func__, bw_val);
+			params.band_center_freq1 = cds_chan_to_freq(req->chan);
+			ch_width = CH_WIDTH_20MHZ;
+			bw_val = 20;
+		}
+	}
+	if (80 < bw_val) {
+		if (req->ch_center_freq_seg1) {
+			params.band_center_freq2 =
+				cds_chan_to_freq(req->ch_center_freq_seg1);
+		} else {
+			WMA_LOGE("%s: invalid cntr_freq for bw %d, drop to 80",
+					__func__, bw_val);
+			params.band_center_freq2 = 0;
+			ch_width = CH_WIDTH_80MHZ;
+		}
+	} else {
+		params.band_center_freq2 = 0;
+	}
+	chan_mode = wma_chan_phy_mode(req->chan, ch_width,
+				      req->dot11_mode);
 
 	if (chan_mode == MODE_UNKNOWN) {
 		WMA_LOGE("%s: invalid phy mode!", __func__);
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	if (!params.band_center_freq1) {
+		WMA_LOGE("%s: invalid center freq1", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (((ch_width == CH_WIDTH_160MHZ) || (ch_width == CH_WIDTH_80P80MHZ))
+				&& !params.band_center_freq2) {
+		WMA_LOGE("%s: invalid center freq2 for 160MHz", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+	/* Fill channel info */
+	params.chan_freq = cds_chan_to_freq(req->chan);
+	params.chan_mode = chan_mode;
+
 	if (!isRestart &&
 	    qdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) {
 		req_msg = wma_find_vdev_req(wma, req->vdev_id,
@@ -2524,10 +2567,6 @@ QDF_STATUS wma_vdev_start(tp_wma_handle wma,
 		 req->vdev_id);
 	params.vdev_id = req->vdev_id;
 
-	/* Fill channel info */
-	params.chan_freq = cds_chan_to_freq(req->chan);
-	params.chan_mode = chan_mode;
-
 	intr[params.vdev_id].chanmode = params.chan_mode;
 	intr[params.vdev_id].ht_capable = req->ht_capable;
 	intr[params.vdev_id].vht_capable = req->vht_capable;
@@ -2555,24 +2594,12 @@ QDF_STATUS wma_vdev_start(tp_wma_handle wma,
 	intr[params.vdev_id].config.gtx_info.gtxBWMask =
 		CFG_TGT_DEFAULT_GTX_BW_MASK;
 	intr[params.vdev_id].mhz = params.chan_freq;
-	intr[params.vdev_id].chan_width = req->chan_width;
+	intr[params.vdev_id].chan_width = ch_width;
 	wma_copy_txrxnode_he_ops(&intr[params.vdev_id], req);
 
 	temp_chan_info &= 0xffffffc0;
 	temp_chan_info |= params.chan_mode;
 
-	params.band_center_freq1 = params.chan_freq;
-
-	bw_val = wlan_reg_get_bw_value(req->chan_width);
-	if (20 < bw_val)
-		params.band_center_freq1 =
-			cds_chan_to_freq(req->ch_center_freq_seg0);
-	if (80 < bw_val)
-		params.band_center_freq2 =
-			cds_chan_to_freq(req->ch_center_freq_seg1);
-	else
-		params.band_center_freq2 = 0;
-
 	/* Set half or quarter rate WMI flags */
 	params.is_half_rate = req->is_half_rate;
 	params.is_quarter_rate = req->is_quarter_rate;