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
diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
index ce4d45f..9de78d5 100644
--- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
+++ b/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 @@
  *
  * 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 @@
 	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 @@
 		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 @@
 			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 @@
 	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 @@
 
 	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) {