Browse Source

qcacld-3.0: Pack TPE IE manually to avoid beacon malform

As part of 802.11be_D4.1 new param Ext Max Tx power is added
in TPE for 320 MHz and while packing the TPE IE in beacon frame
max tx power will be calculated based on max_tx_pwr_interpret.
And max_tx_pwr_interpret is filled irrespective of channel bandwidth
which leads to TPE IE length more than 9 for legacy case also.

Pack tpe ie manually to consider max_tx_pwr_interpret to calculate
tx power only for 320 MHz and legacy method for less than 320 MHz.

CRs-Fixed: 3750566
Change-Id: Ibacb634c24d08886ccf2848a8dc8e2ecdf6b247a
Krupali Dhanvijay 1 year ago
parent
commit
727a1ebf9a

+ 35 - 10
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -667,6 +667,9 @@ lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx,
 	tDot11fIEExtCap extracted_ext_cap = {0};
 	bool extracted_ext_cap_flag = false;
 	uint16_t mlo_ie_len = 0;
+	uint16_t tpe_ie_len = 0;
+	tDot11fIEtransmit_power_env *transmit_power_env = NULL;
+	uint16_t num_transmit_power_env = 0;
 
 	/* We don't answer requests in this case*/
 	if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG)
@@ -770,11 +773,6 @@ lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx,
 		populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps);
 		populate_dot11f_vht_operation(mac_ctx, pe_session,
 			&frm->VHTOperation);
-		populate_dot11f_tx_power_env(mac_ctx,
-					     &frm->transmit_power_env[0],
-					     pe_session->ch_width,
-					     pe_session->curr_op_freq,
-					     &frm->num_transmit_power_env, false);
 		/*
 		 * we do not support multi users yet.
 		 * populate_dot11f_vht_ext_bss_load( mac_ctx,
@@ -783,13 +781,23 @@ lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx,
 		is_vht_enabled = true;
 	}
 
-	if (wlan_reg_is_6ghz_chan_freq(pe_session->curr_op_freq)) {
+	if (pe_session->vhtCapability ||
+	    wlan_reg_is_6ghz_chan_freq(pe_session->curr_op_freq)) {
+		transmit_power_env = qdf_mem_malloc(
+					WLAN_MAX_NUM_TPE_IE *
+					sizeof(tDot11fIEtransmit_power_env));
+		if (!transmit_power_env)
+			goto err_ret;
+
 		populate_dot11f_tx_power_env(mac_ctx,
-					     &frm->transmit_power_env[0],
+					     transmit_power_env,
 					     pe_session->ch_width,
 					     pe_session->curr_op_freq,
-					     &frm->num_transmit_power_env,
+					     &num_transmit_power_env,
 					     false);
+		tpe_ie_len = lim_get_tpe_ie_length(pe_session->ch_width,
+						   transmit_power_env,
+						   num_transmit_power_env);
 	}
 
 	if (lim_is_session_he_capable(pe_session)) {
@@ -920,7 +928,7 @@ lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx,
 			status);
 	}
 
-	bytes += payload + sizeof(tSirMacMgmtHdr) + mlo_ie_len;
+	bytes += payload + sizeof(tSirMacMgmtHdr) + mlo_ie_len + tpe_ie_len;
 
 	qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame,
 				      (void **)&packet);
@@ -953,6 +961,19 @@ lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx,
 		pe_warn("Probe Response pack warning (0x%08x)", status);
 	}
 
+	if (tpe_ie_len) {
+		qdf_status = lim_fill_complete_tpe_ie(
+					pe_session->ch_width, tpe_ie_len,
+					transmit_power_env,
+					num_transmit_power_env, frame +
+					sizeof(tSirMacMgmtHdr) + payload);
+		if (QDF_IS_STATUS_ERROR(qdf_status)) {
+			pe_debug("assemble tpe ie error");
+			tpe_ie_len = 0;
+		}
+		payload += tpe_ie_len;
+	}
+
 	if (mlo_ie_len) {
 		qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len,
 				    frame + sizeof(tSirMacMgmtHdr) + payload);
@@ -989,8 +1010,9 @@ lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx,
 
 	if (add_ie)
 		qdf_mem_free(add_ie);
-
+	qdf_mem_free(transmit_power_env);
 	qdf_mem_free(frm);
+
 	return;
 
 err_ret:
@@ -1000,6 +1022,9 @@ err_ret:
 		qdf_mem_free(frm);
 	if (packet)
 		cds_packet_free((void *)packet);
+	if (transmit_power_env)
+		qdf_mem_free(transmit_power_env);
+
 	return;
 
 } /* End lim_send_probe_rsp_mgmt_frame. */

+ 137 - 0
core/mac/src/pe/lim/lim_utils.c

@@ -12232,3 +12232,140 @@ void lim_cp_stats_cstats_log_csa_evt(struct pe_session *pe_session,
 	wlan_cstats_host_stats(sizeof(struct cstats_csa_evt), &stat);
 }
 #endif /* WLAN_CHIPSET_STATS */
+
+uint16_t lim_get_tpe_ie_length(enum phy_ch_width chan_width,
+			       tDot11fIEtransmit_power_env *tpe_ie,
+			       uint16_t num_tpe)
+{
+	uint16_t total_ie_len = 0;
+	uint16_t idx = 0;
+
+	for (idx = 0; idx < num_tpe; idx++) {
+		if (!tpe_ie[idx].present)
+			return total_ie_len;
+
+		/* +2 for including element id and length */
+		total_ie_len += 2;
+		/* +1 for including tx power info */
+		total_ie_len += 1;
+		total_ie_len += tpe_ie[idx].num_tx_power;
+
+		if (!(chan_width == CH_WIDTH_320MHZ &&
+		      tpe_ie[idx].max_tx_pwr_interpret))
+			continue;
+
+		if (tpe_ie[idx].max_tx_pwr_interpret == LOCAL_EIRP ||
+		    tpe_ie[idx].max_tx_pwr_interpret == REGULATORY_CLIENT_EIRP) {
+			/* Maximum Transmit Power For 320 MHz */
+			total_ie_len += 1;
+		} else if (tpe_ie[idx].max_tx_pwr_interpret == LOCAL_EIRP_PSD ||
+			   tpe_ie[idx].max_tx_pwr_interpret == REGULATORY_CLIENT_EIRP_PSD) {
+			/* Extension Transmit PSD Information */
+			total_ie_len += 1;
+			/* Maximum Transmit PSD power */
+			total_ie_len += MAX_TX_PSD_POWER;
+		}
+	}
+
+	return total_ie_len;
+}
+
+QDF_STATUS lim_fill_complete_tpe_ie(enum phy_ch_width chan_width,
+				    uint16_t tpe_ie_len,
+				    tDot11fIEtransmit_power_env *tpe_ptr,
+				    uint16_t num_tpe, uint8_t *target)
+{
+	uint8_t *ie_len = NULL;
+	uint32_t consumed = 0;
+	uint32_t total_consumed = 0;
+	uint8_t tx_pwr_info = 0U;
+	uint8_t local_psd = 0U;
+	uint8_t reg_psd = 0U;
+	uint8_t *on_entry_target = target;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint16_t idx = 0;
+
+	for (idx = 0; idx < num_tpe; idx++) {
+		if (!tpe_ptr[idx].present)
+			return QDF_STATUS_E_INVAL;
+
+		consumed = 0;
+		*target = WLAN_ELEMID_VHT_TX_PWR_ENVLP;
+		++target;
+		++consumed;
+
+		ie_len = target;
+		++target;
+		++consumed;
+
+		tx_pwr_info = 0U;
+		tx_pwr_info |= (tpe_ptr[idx].max_tx_pwr_count << 0);
+		tx_pwr_info |= (tpe_ptr[idx].max_tx_pwr_interpret << 3);
+		tx_pwr_info |= (tpe_ptr[idx].max_tx_pwr_category << 6);
+		*target = tx_pwr_info;
+		++consumed;
+		++target;
+
+		qdf_mem_copy(target, &tpe_ptr[idx].tx_power, tpe_ptr[idx].num_tx_power);
+		consumed += tpe_ptr[idx].num_tx_power;
+		target += tpe_ptr[idx].num_tx_power;
+
+		if (!(chan_width == CH_WIDTH_320MHZ &&
+		      tpe_ptr[idx].max_tx_pwr_interpret))
+			goto end;
+
+		switch (tpe_ptr[idx].max_tx_pwr_interpret) {
+		case LOCAL_EIRP:
+			/* Maximum Local EIRP Transmit Power For 320 MHz */
+			*target = tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_eirp.max_tx_power_for_320;
+			target += 1;
+			consumed += 1;
+			break;
+		case LOCAL_EIRP_PSD:
+			local_psd = 0U;
+			local_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_psd.ext_count << 0);
+			local_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_psd.reserved << 4);
+			/* Extension Transmit Local PSD Information */
+			*target = local_psd;
+			target += 1;
+			consumed += 1;
+			/* Maximum Transmit Local PSD power */
+			qdf_mem_copy(target, tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power, MAX_TX_PSD_POWER);
+			target += MAX_TX_PSD_POWER;
+			consumed += MAX_TX_PSD_POWER;
+			break;
+		case REGULATORY_CLIENT_EIRP:
+			/* Maximum Regulatory EIRP Transmit Power For 320 MHz */
+			*target = tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_eirp.max_tx_power_for_320;
+			target += 1;
+			consumed += 1;
+			break;
+		case REGULATORY_CLIENT_EIRP_PSD:
+			reg_psd = 0U;
+			reg_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_psd.ext_count << 0);
+			reg_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_psd.reserved << 4);
+			/* Extension Transmit Regulatory PSD Information */
+			*target = reg_psd;
+			consumed += 1;
+			target += 1;
+			/* Maximum Transmit Regulatory PSD power */
+			qdf_mem_copy(target, tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_psd.max_tx_psd_power, MAX_TX_PSD_POWER);
+			target += MAX_TX_PSD_POWER;
+			consumed += MAX_TX_PSD_POWER;
+			break;
+		}
+end:
+		if (ie_len && consumed >= 2) {
+			total_consumed += consumed;
+			/* -2 for element id and length */
+			*ie_len = consumed - 2;
+		}
+	}
+
+	pe_debug("pack tpe ie %d bytes, expected to copy %d bytes",
+		 total_consumed, tpe_ie_len);
+	qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			   on_entry_target, total_consumed);
+
+	return status;
+}

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

@@ -3658,4 +3658,33 @@ lim_cp_stats_cstats_log_csa_evt(struct pe_session *pe_session,
 {
 }
 #endif /* WLAN_CHIPSET_STATS */
+
+#define MAX_TX_PSD_POWER 15
+
+/**
+ * lim_get_tpe_ie_length() : Get the tpe ie length
+ * @ch_width: phy channel width
+ * @tpe_ie: pointer to dot11f TPE IE structure
+ * @num_tpe: number of TPE IE
+ *
+ * Return: tpe ie length
+ */
+uint16_t lim_get_tpe_ie_length(enum phy_ch_width ch_width,
+			       tDot11fIEtransmit_power_env *tpe_ie,
+			       uint16_t num_tpe);
+
+/**
+ * lim_fill_complete_tpe_ie() : fill tpe ie to target buffer
+ * @ch_width: phy channel width
+ * @tpe_ie_len: the total bytes to fill target buffer
+ * @tpe_ptr: pointer to dot11f TPE IE structure
+ * @num_tpe: number of TPE IE
+ * @target: the buffer to fill data
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS lim_fill_complete_tpe_ie(enum phy_ch_width ch_width,
+				    uint16_t tpe_ie_len,
+				    tDot11fIEtransmit_power_env *tpe_ptr,
+				    uint16_t num_tpe, uint8_t *target);
 #endif /* __LIM_UTILS_H */

+ 35 - 14
core/mac/src/pe/sch/sch_beacon_gen.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -571,6 +571,9 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 	uint16_t mlo_ie_len = 0;
 	uint16_t tim_size;
 	uint8_t reg_cc[REG_ALPHA2_LEN + 1];
+	uint16_t tpe_ie_len = 0;
+	tDot11fIEtransmit_power_env *transmit_power_env = NULL;
+	uint16_t num_transmit_power_env = 0;
 
 	tim_size = sch_get_tim_size(HAL_NUM_STA);
 
@@ -743,21 +746,26 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 		/*
 		populate_dot11f_vht_ext_bss_load( mac_ctx, &bcn2.VHTExtBssLoad);
 		*/
-		populate_dot11f_tx_power_env(mac_ctx,
-					     &bcn_2->transmit_power_env[0],
-					     session->ch_width,
-					     session->curr_op_freq,
-					     &bcn_2->num_transmit_power_env,
-					     false);
 	}
 
-	if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) {
+	if (session->vhtCapability ||
+	    wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) {
+		transmit_power_env = qdf_mem_malloc(
+					WLAN_MAX_NUM_TPE_IE *
+					sizeof(tDot11fIEtransmit_power_env));
+		if (!transmit_power_env) {
+			status = QDF_STATUS_E_NOMEM;
+			goto free_and_exit;
+		}
 		populate_dot11f_tx_power_env(mac_ctx,
-					     &bcn_2->transmit_power_env[0],
+					     transmit_power_env,
 					     session->ch_width,
 					     session->curr_op_freq,
-					     &bcn_2->num_transmit_power_env,
+					     &num_transmit_power_env,
 					     false);
+		tpe_ie_len = lim_get_tpe_ie_length(session->ch_width,
+						   transmit_power_env,
+						   num_transmit_power_env);
 	}
 
 	if (lim_is_session_he_capable(session)) {
@@ -883,10 +891,8 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 		addn_ielen = session->add_ie_params.probeRespBCNDataLen;
 		addn_ie = qdf_mem_malloc(addn_ielen);
 		if (!addn_ie) {
-			qdf_mem_free(bcn_1);
-			qdf_mem_free(bcn_2);
-			qdf_mem_free(wsc_prb_res);
-			return QDF_STATUS_E_NOMEM;
+			status = QDF_STATUS_E_NOMEM;
+			goto free_and_exit;
 		}
 		qdf_mem_copy(addn_ie,
 			session->add_ie_params.probeRespBCNData_buff,
@@ -998,6 +1004,19 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 		n_bytes = ie_buf_size + eht_cap_ie_len;
 	}
 
+	if (tpe_ie_len) {
+		status = lim_fill_complete_tpe_ie(
+					session->ch_width, tpe_ie_len,
+					transmit_power_env,
+					num_transmit_power_env,
+					session->pSchBeaconFrameEnd + n_bytes);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_debug("assemble tpe ie error");
+			tpe_ie_len = 0;
+		}
+		n_bytes += tpe_ie_len;
+	}
+
 	if (mlo_ie_len) {
 		status = lim_fill_complete_mlo_ie(session, mlo_ie_len,
 					 session->pSchBeaconFrameEnd + n_bytes);
@@ -1088,6 +1107,8 @@ free_and_exit:
 	qdf_mem_free(bcn_2);
 	qdf_mem_free(wsc_prb_res);
 	qdf_mem_free(addn_ie);
+	qdf_mem_free(transmit_power_env);
+
 	return status;
 }