ソースを参照

qcacld-3.0: Add support to encode and decode EHT operations IE

Currently parser code doesn't have support for packing and
unpacking of optional fields in EHT operation IE which are
dependent on HT op, VHT op and HE op IE.

To achive this, add API to encode and decode EHT op IE and include
the generated EHT operation IE bytes in beacon and assoc response
frames.

Change-Id: Iab955903a3112cdbe4c9acb6e59eca4ea31bdabe
CRs-Fixed: 3197354
Deeksha Gupta 2 年 前
コミット
a556ae6e75

+ 59 - 2
core/mac/src/include/parser_api.h

@@ -1516,7 +1516,7 @@ QDF_STATUS populate_dot11f_eht_operation(struct mac_context *mac_ctx,
  * @dot11f_he_cap: dot11f HE capabilities IE structure
  * @is_band_2g: Flag to indicate whether operating band is 2g or not
  *
- * This API is used to enacode EHT capabilities IE which is of variable in
+ * This API is used to encode EHT capabilities IE which is of variable in
  * length depending on the HE capabilities IE content.
  *
  * Return: Void
@@ -1533,7 +1533,8 @@ void lim_ieee80211_pack_ehtcap(uint8_t *ie, tDot11fIEeht_cap dot11f_eht_cap,
  * @freq: frequency
  *
  * This API is used to strip and decode EHT caps IE which is of varaible in
- * in length depending on the HE capabilities IE content.
+ * length depending on the HE capabilities IE content.
+ *
  * Return: QDF_STATUS
  */
 QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len,
@@ -1541,6 +1542,44 @@ QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len,
 					tDot11fIEhe_cap dot11f_he_cap,
 					uint16_t freq);
 
+/**
+ * lim_ieee80211_pack_ehtop() - Pack EHT Operations IE
+ * @ie: output pointer for eht operations IE
+ * @dot11f_eht_cap: dot11f EHT operations IE structure
+ * @dot11f_vht_op: dot11f VHT operation IE structure
+ * @dot11f_he_op: dot11f HE operation IE structure
+ * @dot11f_ht_info: dot11f HT info IE structure
+ *
+ * This API is used to encode EHT operations IE which is of variable in
+ * length depending on the HE capabilities IE content.
+ *
+ * Return: Void
+ */
+void lim_ieee80211_pack_ehtop(uint8_t *ie, tDot11fIEeht_op dot11f_eht_op,
+			      tDot11fIEVHTOperation dot11f_vht_op,
+			      tDot11fIEhe_op dot11f_he_op,
+			      tDot11fIEHTInfo dot11f_ht_info);
+
+/**
+ * lim_strip_and_decode_eht_op() - API to decode EHT Operations IE
+ * @ie: source ie address
+ * @ie_len: source ie length
+ * @dot11f_eht_op: output pointer to dot11f EHT Operations IE structure
+ * @dot11f_vht_op: dot11f VHT operation IE structure
+ * @dot11f_he_op: dot11f HE operation IE structure
+ * @dot11f_ht_info: dot11f HT info IE structure
+ *
+ * This API is used to strip and decode EHT operations IE which is of varaible
+ * in length depending on the HE capabilities IE content.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS lim_strip_and_decode_eht_op(uint8_t *ie, uint16_t ie_len,
+				       tDot11fIEeht_op *dot11f_eht_op,
+				       tDot11fIEVHTOperation dot11f_vht_op,
+				       tDot11fIEhe_op dot11f_he_op,
+				       tDot11fIEHTInfo dot11f_ht_info);
+
 #else
 static inline QDF_STATUS
 populate_dot11f_eht_caps(struct mac_context *mac_ctx,
@@ -1580,6 +1619,24 @@ QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline void lim_ieee80211_pack_ehtop(uint8_t *ie,
+					    tDot11fIEeht_op dot11f_eht_op,
+					    tDot11fIEVHTOperation dot11f_vht_op,
+					    tDot11fIEhe_op dot11f_he_op,
+					    tDot11fIEHTInfo dot11f_ht_info)
+{
+}
+
+static inline
+QDF_STATUS lim_strip_and_decode_eht_op(uint8_t *ie, uint16_t ie_len,
+				       tDot11fIEeht_op *dot11f_eht_op,
+				       tDot11fIEVHTOperation dot11f_vht_op,
+				       tDot11fIEhe_op dot11f_he_op,
+				       tDot11fIEHTInfo dot11f_ht_info)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
 
 #ifdef WLAN_FEATURE_11BE_MLO

+ 13 - 0
core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c

@@ -1017,6 +1017,19 @@ lim_process_assoc_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
 	}
 
 	if (lim_is_session_eht_capable(session_entry)) {
+		status = lim_strip_and_decode_eht_op(
+					body + WLAN_ASSOC_RSP_IES_OFFSET,
+					frame_len - WLAN_ASSOC_RSP_IES_OFFSET,
+					&assoc_rsp->eht_op,
+					assoc_rsp->VHTOperation,
+					assoc_rsp->he_op,
+					assoc_rsp->HTInfo);
+
+		if (status != QDF_STATUS_SUCCESS) {
+			pe_err("Failed to extract eht op");
+			return;
+		}
+
 		status = lim_strip_and_decode_eht_cap(
 					body + WLAN_ASSOC_RSP_IES_OFFSET,
 					frame_len - WLAN_ASSOC_RSP_IES_OFFSET,

+ 9 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -5191,6 +5191,15 @@ void lim_process_tpe_ie_from_beacon(struct mac_context *mac,
 		pe_debug("warnings (0x%08x, %d bytes):", status, buf_len);
 	}
 
+	status = lim_strip_and_decode_eht_op(buf, buf_len, &bcn_ie->eht_op,
+					     bcn_ie->VHTOperation,
+					     bcn_ie->he_op,
+					     bcn_ie->HTInfo);
+	if (status != QDF_STATUS_SUCCESS) {
+		pe_err("Failed to extract eht op");
+		return;
+	}
+
 	status = lim_strip_and_decode_eht_cap(buf, buf_len, &bcn_ie->eht_cap,
 					      bcn_ie->he_cap,
 					      session->curr_op_freq);

+ 52 - 0
core/mac/src/pe/lim/lim_prop_exts_utils.c

@@ -341,6 +341,58 @@ void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc,
 static void lim_extract_eht_op(struct pe_session *session,
 			       tSirProbeRespBeacon *beacon_struct)
 {
+	uint32_t max_eht_bw;
+
+	if (!session->eht_capable)
+		return;
+
+	if (!beacon_struct->eht_op.present) {
+		pe_debug("EHT OP not present in beacon");
+		return;
+	}
+
+	if (!beacon_struct->eht_op.eht_op_information_present) {
+		pe_debug("EHT Operation Information Present not set");
+		return;
+	}
+
+	qdf_mem_copy(&session->eht_op, &beacon_struct->eht_op,
+		     sizeof(session->eht_op));
+
+	max_eht_bw = wma_get_eht_ch_width();
+
+	if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_320) {
+		if (max_eht_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) {
+			session->ch_width = CH_WIDTH_320MHZ;
+		} else if (max_eht_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) {
+			session->ch_width = CH_WIDTH_160MHZ;
+		} else {
+			session->ch_width = CH_WIDTH_80MHZ;
+			session->ch_center_freq_seg1 = 0;
+		}
+	} else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_160) {
+		if (max_eht_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) {
+			session->ch_width = CH_WIDTH_160MHZ;
+		} else {
+			session->ch_width = CH_WIDTH_80MHZ;
+			session->ch_center_freq_seg1 = 0;
+		}
+	} else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_80) {
+		session->ch_width = CH_WIDTH_80MHZ;
+		session->ch_center_freq_seg1 = 0;
+	} else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_40) {
+		session->ch_width = CH_WIDTH_40MHZ;
+		session->ch_center_freq_seg1 = 0;
+	} else {
+		session->ch_width = CH_WIDTH_20MHZ;
+		session->ch_center_freq_seg1 = 0;
+	}
+
+	session->ch_center_freq_seg0 = session->eht_op.ccfs0;
+	session->ch_center_freq_seg1 = session->eht_op.ccfs1;
+
+	pe_debug("session ch_width %d ccfs0 %d ccfs1 %d", session->ch_width,
+		 session->ch_center_freq_seg0, session->ch_center_freq_seg1);
 }
 
 void lim_update_eht_bw_cap_mcs(struct pe_session *session,

+ 48 - 2
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -1516,6 +1516,17 @@ QDF_STATUS lim_strip_eht_cap_ie(struct mac_context *mac_ctx,
 			    EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE,
 			    eht_cap_ie,	WLAN_MAX_IE_LEN);
 }
+
+QDF_STATUS lim_strip_eht_op_ie(struct mac_context *mac_ctx,
+			       uint8_t *frame_ies,
+			       uint16_t *ie_buf_size,
+			       uint8_t *eht_op_ie)
+{
+	return lim_strip_ie(mac_ctx, frame_ies, ie_buf_size,
+			    WLAN_ELEMID_EXTN_ELEM, ONE_BYTE,
+			    EHT_OP_OUI_TYPE, EHT_OP_OUI_SIZE,
+			    eht_op_ie, WLAN_MAX_IE_LEN);
+}
 #endif
 
 void
@@ -1547,6 +1558,7 @@ lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx,
 	bool extracted_flag = false;
 	uint8_t retry_int;
 	uint16_t max_retries;
+	uint8_t *eht_op_ie = NULL, eht_op_ie_len = 0;
 	uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0;
 	bool is_band_2g;
 	uint16_t ie_buf_size;
@@ -1856,10 +1868,44 @@ lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx,
 			status);
 	}
 
-	/* Strip EHT capabilities IE */
+	/* Strip EHT operation and EHT capabilities IEs */
 	if (lim_is_session_eht_capable(pe_session)) {
 		ie_buf_size = payload - WLAN_ASSOC_RSP_IES_OFFSET;
+		eht_op_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2);
+		if (!eht_op_ie) {
+			pe_err("malloc failed for eht_op_ie");
+			cds_packet_free((void *)packet);
+			goto error;
+		}
 
+		qdf_status = lim_strip_eht_op_ie(mac_ctx, frame +
+						 sizeof(tSirMacMgmtHdr) +
+						 WLAN_ASSOC_RSP_IES_OFFSET,
+						 &ie_buf_size, eht_op_ie);
+		if (QDF_IS_STATUS_ERROR(qdf_status)) {
+			pe_err("Failed to strip EHT op IE");
+			qdf_mem_free(eht_cap_ie);
+			cds_packet_free((void *)packet);
+			cds_packet_free((void *)packet);
+		}
+
+		lim_ieee80211_pack_ehtop(eht_op_ie, frm.eht_op,
+					 frm.VHTOperation,
+					 frm.he_op,
+					 frm.HTInfo);
+		eht_op_ie_len = eht_op_ie[1] + 2;
+
+		/* Copy the EHT operation IE to the end of the frame */
+		qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) +
+			     WLAN_ASSOC_RSP_IES_OFFSET + ie_buf_size,
+			     eht_op_ie, eht_op_ie_len);
+		qdf_mem_free(eht_op_ie);
+		bytes = bytes - payload;
+		payload = ie_buf_size + WLAN_ASSOC_RSP_IES_OFFSET +
+			  eht_op_ie_len;
+		bytes = bytes + payload;
+
+		ie_buf_size = payload - WLAN_ASSOC_RSP_IES_OFFSET;
 		eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2);
 		if (!eht_cap_ie) {
 			pe_err("malloc failed for eht_cap_ie");
@@ -1885,7 +1931,7 @@ lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx,
 
 		eht_cap_ie_len = eht_cap_ie[1] + 2;
 
-		/* Copy the EHT IE to the end of the frame */
+		/* Copy the EHT capability IE to the end of the frame */
 		qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) +
 			     WLAN_ASSOC_RSP_IES_OFFSET + ie_buf_size,
 			     eht_cap_ie, eht_cap_ie_len);

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

@@ -1727,6 +1727,11 @@ static inline bool lim_is_sta_eht_capable(tpDphHashNode sta_ds)
 	return sta_ds->mlmStaContext.eht_capable;
 }
 
+QDF_STATUS lim_strip_eht_op_ie(struct mac_context *mac_ctx,
+			       uint8_t *frame_ies,
+			       uint16_t *ie_buf_size,
+			       uint8_t *eht_op_ie);
+
 QDF_STATUS lim_strip_eht_cap_ie(struct mac_context *mac_ctx,
 				uint8_t *frame_ies,
 				uint16_t *ie_buf_size,
@@ -2021,6 +2026,15 @@ static inline bool lim_is_sta_eht_capable(tpDphHashNode sta_ds)
 	return false;
 }
 
+static inline
+QDF_STATUS lim_strip_eht_op_ie(struct mac_context *mac_ctx,
+			       uint8_t *frame_ies,
+			       uint16_t *ie_buf_size,
+			       uint8_t *eht_op_ie)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
 static inline
 QDF_STATUS lim_strip_eht_cap_ie(struct mac_context *mac_ctx,
 				uint8_t *frame_ies,

+ 32 - 1
core/mac/src/pe/sch/sch_beacon_gen.c

@@ -498,6 +498,7 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 	tDot11fIEExtCap extracted_extcap;
 	bool extcap_present = true, addnie_present = false;
 	bool is_6ghz_chsw;
+	uint8_t *eht_op_ie = NULL, eht_op_ie_len = 0;
 	uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0;
 	bool is_band_2g;
 	uint16_t ie_buf_size;
@@ -908,6 +909,36 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 	if (lim_is_session_eht_capable(session)) {
 		ie_buf_size = n_bytes;
 
+		eht_op_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2);
+		if (!eht_op_ie) {
+			pe_err("malloc failed for eht_op_ie");
+			status = QDF_STATUS_E_FAILURE;
+			goto free_and_exit;
+		}
+
+		status = lim_strip_eht_op_ie(mac_ctx,
+					     session->pSchBeaconFrameEnd,
+					     &ie_buf_size, eht_op_ie);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pe_err("Failed to strip EHT op IE");
+			qdf_mem_free(eht_op_ie);
+			status = QDF_STATUS_E_FAILURE;
+			goto free_and_exit;
+		}
+
+		lim_ieee80211_pack_ehtop(eht_op_ie, bcn_2->eht_op,
+					 bcn_2->VHTOperation,
+					 bcn_2->he_op,
+					 bcn_2->HTInfo);
+		eht_op_ie_len = eht_op_ie[1] + 2;
+
+		/* Copy the EHT operation IE to the end of the frame */
+		qdf_mem_copy(session->pSchBeaconFrameEnd + ie_buf_size,
+			     eht_op_ie, eht_op_ie_len);
+		qdf_mem_free(eht_op_ie);
+		n_bytes = ie_buf_size + eht_op_ie_len;
+
+		ie_buf_size = n_bytes;
 		eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2);
 		if (!eht_cap_ie) {
 			pe_err("malloc failed for eht_cap_ie");
@@ -931,7 +962,7 @@ sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *sess
 					  bcn_2->he_cap, is_band_2g);
 		eht_cap_ie_len = eht_cap_ie[1] + 2;
 
-		/* Copy the EHT IE to the end of the frame */
+		/* Copy the EHT cap IE to the end of the frame */
 		qdf_mem_copy(session->pSchBeaconFrameEnd + ie_buf_size,
 			     eht_cap_ie, eht_cap_ie_len);
 

+ 277 - 6
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -4247,6 +4247,18 @@ sir_beacon_ie_ese_bcn_report(struct mac_context *mac,
 			status, nPayload);
 	}
 
+	status = lim_strip_and_decode_eht_op(pPayload + WLAN_BEACON_IES_OFFSET,
+					     nPayload - WLAN_BEACON_IES_OFFSET,
+					     &pBies->eht_op,
+					     pBies->VHTOperation,
+					     pBies->he_op,
+					     pBies->HTInfo);
+	if (status != QDF_STATUS_SUCCESS) {
+		pe_err("Failed to extract eht op");
+		qdf_mem_free(pBies);
+		return status;
+	}
+
 	status = lim_strip_and_decode_eht_cap(pPayload + WLAN_BEACON_IES_OFFSET,
 					      nPayload - WLAN_BEACON_IES_OFFSET,
 					      &pBies->eht_cap,
@@ -4529,8 +4541,20 @@ sir_parse_beacon_ie(struct mac_context *mac,
 		pe_debug("warnings (0x%08x, %d bytes):", status, nPayload);
 	}
 
-	status = lim_strip_and_decode_eht_cap(pPayload + WLAN_BEACON_IES_OFFSET,
-					      nPayload - WLAN_BEACON_IES_OFFSET,
+	status = lim_strip_and_decode_eht_op(pPayload,
+					     nPayload,
+					     &pBies->eht_op,
+					     pBies->VHTOperation,
+					     pBies->he_op,
+					     pBies->HTInfo);
+	if (status != QDF_STATUS_SUCCESS) {
+		pe_err("Failed to extract eht op");
+		qdf_mem_free(pBies);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = lim_strip_and_decode_eht_cap(pPayload,
+					      nPayload,
 					      &pBies->eht_cap,
 					      pBies->he_cap,
 					      freq);
@@ -4803,6 +4827,10 @@ sir_parse_beacon_ie(struct mac_context *mac,
 		qdf_mem_copy(&pBeaconStruct->eht_cap, &pBies->eht_cap,
 			     sizeof(tDot11fIEeht_cap));
 	}
+	if (pBies->eht_op.present) {
+		qdf_mem_copy(&pBeaconStruct->eht_op, &pBies->eht_op,
+			    sizeof(tDot11fIEeht_op));
+	}
 
 	update_bss_color_change_from_beacon_ies(pBies, pBeaconStruct);
 
@@ -4864,6 +4892,18 @@ sir_convert_beacon_frame2_struct(struct mac_context *mac,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	status = lim_strip_and_decode_eht_op(pPayload + WLAN_BEACON_IES_OFFSET,
+					     nPayload - WLAN_BEACON_IES_OFFSET,
+					     &pBeacon->eht_op,
+					     pBeacon->VHTOperation,
+					     pBeacon->he_op,
+					     pBeacon->HTInfo);
+	if (status != QDF_STATUS_SUCCESS) {
+		pe_err("Failed to extract eht op");
+		qdf_mem_free(pBeacon);
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	status = lim_strip_and_decode_eht_cap(pPayload + WLAN_BEACON_IES_OFFSET,
 					      nPayload - WLAN_BEACON_IES_OFFSET,
 					      &pBeacon->eht_cap,
@@ -7059,13 +7099,65 @@ populate_dot11f_he_bss_color_change(struct mac_context *mac_ctx,
  */
 static
 const uint8_t *lim_get_ext_ie_ptr_from_ext_id(const uint8_t *ie,
-					      uint16_t ie_len)
+					      uint16_t ie_len,
+					      const uint8_t *oui,
+					      uint8_t oui_size)
 {
-	return wlan_get_ext_ie_ptr_from_ext_id(EHT_CAP_OUI_TYPE,
-					       EHT_CAP_OUI_SIZE,
+	return wlan_get_ext_ie_ptr_from_ext_id(oui, oui_size,
 					       ie, ie_len);
 }
 
+/* EHT Opeartion */
+/* 1 byte ext id, 1 byte eht op params*/
+#define EHTOP_FIXED_LEN         2
+
+#define EHTOP_PARAMS_INFOP_IDX  0
+#define EHTOP_PARAMS_INFOP_BITS 1
+
+#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_IDX    1
+#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_BITS   1
+
+#define EHTOP_INFO_CHANWIDTH_IDX                   0
+#define EHTOP_INFO_CHANWIDTH_BITS                  3
+
+#define WLAN_MAX_DISABLED_SUB_CHAN_BITMAP          2
+
+#define ehtop_ie_set(eht_op, index, num_bits, val) \
+			QDF_SET_BITS((*eht_op), qdf_do_div_rem(index, 8),\
+				     (num_bits), (val))
+#define ehtop_ie_get(eht_op, index, num_bits) \
+			QDF_GET_BITS((eht_op), qdf_do_div_rem(index, 8), \
+				     (num_bits))
+
+/* byte 0 */
+#define EHTOP_PARAMS_INFOP_GET_FROM_IE(__eht_op_params) \
+			ehtop_ie_get(__eht_op_params, \
+				     EHTOP_PARAMS_INFOP_IDX, \
+				     EHTOP_PARAMS_INFOP_BITS)
+#define EHTOP_PARAMS_INFOP_SET_TO_IE(__eht_op_params, __value) \
+			ehtop_ie_set(&__eht_op_params, \
+				     EHTOP_PARAMS_INFOP_IDX, \
+				     EHTOP_PARAMS_INFOP_BITS, __value)
+
+#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_GET_FROM_IE(__eht_op_params) \
+			ehtop_ie_get(__eht_op_params, \
+				     EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_IDX, \
+				     EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_BITS)
+#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_SET_TO_IE(__eht_op_params, __value) \
+			ehtop_ie_set(&__eht_op_params, \
+				     EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_IDX, \
+				     EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_BITS, \
+				     __value)
+
+#define EHTOP_INFO_CHANWIDTH_GET_FROM_IE(__eht_op_control) \
+			ehtop_ie_get(__eht_op_control, \
+				     EHTOP_INFO_CHANWIDTH_IDX, \
+				     EHTOP_INFO_CHANWIDTH_BITS)
+#define EHTOP_INFO_CHANWIDTH_SET_TO_IE(__eht_op_control, __value) \
+			ehtop_ie_set(&__eht_op_control, \
+				     EHTOP_INFO_CHANWIDTH_IDX, \
+				     EHTOP_INFO_CHANWIDTH_BITS, __value)
+
 /* 1 byte ext id, 2 bytes mac cap, 9 bytes phy cap */
 #define EHTCAP_FIXED_LEN 12
 #define EHTCAP_MACBYTE_IDX0      0
@@ -7633,6 +7725,53 @@ enum EHT_PER_BW_TXRX_MCS_NSS_MAP_IDX {
 			      EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_IDX, \
 			      EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_BITS, \
 			      value)
+
+static
+QDF_STATUS lim_ieee80211_unpack_ehtop(const uint8_t *eht_op_ie,
+				      tDot11fIEeht_op *dot11f_eht_op,
+				      tDot11fIEVHTOperation dot11f_vht_op,
+				      tDot11fIEhe_op dot11f_he_op,
+				      tDot11fIEHTInfo dot11f_ht_info)
+{
+	struct wlan_ie_ehtops *ehtop = (struct wlan_ie_ehtops *)eht_op_ie;
+	uint8_t i;
+
+	if (!eht_op_ie || !(ehtop->elem_id == DOT11F_EID_EHT_OP &&
+			    ehtop->elem_id_extn == 0x6a)) {
+		pe_err("Invalid EHT op IE");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	qdf_mem_zero(dot11f_eht_op, (sizeof(tDot11fIEeht_op)));
+
+	dot11f_eht_op->present = 1;
+	dot11f_eht_op->eht_op_information_present =
+		EHTOP_PARAMS_INFOP_GET_FROM_IE(ehtop->ehtop_param);
+
+	dot11f_eht_op->disabled_sub_chan_bitmap_present =
+		EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_GET_FROM_IE(
+							ehtop->ehtop_param);
+
+	if (dot11f_eht_op->eht_op_information_present) {
+		dot11f_eht_op->channel_width =
+			EHTOP_INFO_CHANWIDTH_GET_FROM_IE(ehtop->control);
+
+		dot11f_eht_op->ccfs0 = ehtop->ccfs0;
+
+		dot11f_eht_op->ccfs1 = ehtop->ccfs1;
+
+		if (dot11f_eht_op->disabled_sub_chan_bitmap_present) {
+			for (i = 0; i < WLAN_MAX_DISABLED_SUB_CHAN_BITMAP;
+			     i++) {
+				dot11f_eht_op->disabled_sub_chan_bitmap[0][i] =
+					ehtop->disabled_sub_chan_bitmap[i];
+			}
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 static
 QDF_STATUS lim_ieee80211_unpack_ehtcap(const uint8_t *eht_cap_ie,
 				       tDot11fIEeht_cap *dot11f_eht_cap,
@@ -8020,7 +8159,9 @@ QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len,
 	bool is_band_2g;
 	QDF_STATUS status;
 
-	eht_cap_ie = lim_get_ext_ie_ptr_from_ext_id(ie, ie_len);
+	eht_cap_ie = lim_get_ext_ie_ptr_from_ext_id(ie, ie_len,
+						    EHT_CAP_OUI_TYPE,
+						    EHT_CAP_OUI_SIZE);
 
 	if (!eht_cap_ie)
 		return QDF_STATUS_SUCCESS;
@@ -8454,6 +8595,101 @@ populate_dot11f_eht_caps_by_band(struct mac_context *mac_ctx,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS lim_strip_and_decode_eht_op(uint8_t *ie, uint16_t ie_len,
+				       tDot11fIEeht_op *dot11f_eht_op,
+				       tDot11fIEVHTOperation dot11f_vht_op,
+				       tDot11fIEhe_op dot11f_he_op,
+				       tDot11fIEHTInfo dot11f_ht_info)
+{
+	const uint8_t *eht_op_ie;
+	QDF_STATUS status;
+
+	eht_op_ie = lim_get_ext_ie_ptr_from_ext_id(ie, ie_len,
+						   EHT_OP_OUI_TYPE,
+						   EHT_OP_OUI_SIZE);
+
+	if (!eht_op_ie)
+		return QDF_STATUS_SUCCESS;
+
+	status = lim_ieee80211_unpack_ehtop(eht_op_ie, dot11f_eht_op,
+					    dot11f_vht_op, dot11f_he_op,
+					    dot11f_ht_info);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		pe_err("Failed to extract eht op");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void lim_ieee80211_pack_ehtop(uint8_t *ie, tDot11fIEeht_op dot11f_eht_op,
+			      tDot11fIEVHTOperation dot11f_vht_op,
+			      tDot11fIEhe_op dot11f_he_op,
+			      tDot11fIEHTInfo dot11f_ht_info)
+{
+	struct wlan_ie_ehtops *ehtop = (struct wlan_ie_ehtops *)ie;
+	uint32_t val;
+	uint32_t i;
+	uint32_t eht_op_info_len = 0;
+	uint32_t ehtoplen;
+	bool diff_chan_width = false;
+
+	if (!ie) {
+		pe_err("ie is null");
+		return;
+	}
+
+	qdf_mem_zero(ehtop, (sizeof(struct wlan_ie_ehtops)));
+
+	ehtop->elem_id = DOT11F_EID_EHT_OP;
+
+	qdf_mem_copy(&ehtop->elem_id_extn, EHT_OP_OUI_TYPE, EHT_OP_OUI_SIZE);
+
+	if (dot11f_he_op.present && dot11f_he_op.oper_info_6g_present &&
+	    (dot11f_he_op.oper_info_6g.info.ch_width !=
+	     dot11f_eht_op.channel_width)) {
+		diff_chan_width = true;
+	} else if (dot11f_vht_op.present &&
+		   (dot11f_vht_op.chanWidth != dot11f_eht_op.channel_width)) {
+		diff_chan_width = true;
+	} else if (dot11f_ht_info.present &&
+		   (dot11f_ht_info.recommendedTxWidthSet !=
+		    dot11f_eht_op.channel_width)) {
+		diff_chan_width = true;
+	}
+
+	if (diff_chan_width) {
+		val = dot11f_eht_op.eht_op_information_present;
+		EHTOP_PARAMS_INFOP_SET_TO_IE(ehtop->ehtop_param, val);
+	}
+
+	if (EHTOP_PARAMS_INFOP_GET_FROM_IE(ehtop->ehtop_param)) {
+		val = dot11f_eht_op.channel_width;
+		EHTOP_INFO_CHANWIDTH_SET_TO_IE(ehtop->control, val);
+
+		ehtop->ccfs0 = dot11f_eht_op.ccfs0;
+
+		ehtop->ccfs1 = dot11f_eht_op.ccfs1;
+		/*1 byte for Control, 1 byte for CCFS0, 1 bytes for CCFS1*/
+		eht_op_info_len += 3;
+
+		if (dot11f_eht_op.disabled_sub_chan_bitmap_present) {
+			val = dot11f_eht_op.disabled_sub_chan_bitmap_present;
+			EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_SET_TO_IE(ehtop->ehtop_param, val);
+
+			eht_op_info_len += WLAN_MAX_DISABLED_SUB_CHAN_BITMAP;
+
+			for (i = 0; i < WLAN_MAX_DISABLED_SUB_CHAN_BITMAP; i++)
+				ehtop->disabled_sub_chan_bitmap[i] =
+				dot11f_eht_op.disabled_sub_chan_bitmap[0][i];
+		}
+	}
+
+	ehtop->elem_len = EHTOP_FIXED_LEN + eht_op_info_len;
+	ehtoplen = ehtop->elem_len + WLAN_IE_HDR_LEN;
+}
+
 QDF_STATUS populate_dot11f_eht_operation(struct mac_context *mac_ctx,
 					 struct pe_session *session,
 					 tDot11fIEeht_op *eht_op)
@@ -8461,6 +8697,31 @@ QDF_STATUS populate_dot11f_eht_operation(struct mac_context *mac_ctx,
 	qdf_mem_copy(eht_op, &session->eht_op, sizeof(*eht_op));
 
 	eht_op->present = 1;
+
+	eht_op->eht_op_information_present = 1;
+	if (session->ch_width == CH_WIDTH_320MHZ) {
+		eht_op->channel_width = WLAN_EHT_CHWIDTH_320;
+		eht_op->ccfs0 = session->ch_center_freq_seg0;
+		eht_op->ccfs1 = session->ch_center_freq_seg1;
+	} else if (session->ch_width == CH_WIDTH_160MHZ ||
+		   session->ch_width == CH_WIDTH_80P80MHZ) {
+		eht_op->channel_width = WLAN_EHT_CHWIDTH_160;
+		eht_op->ccfs0 = session->ch_center_freq_seg0;
+		eht_op->ccfs1 = session->ch_center_freq_seg1;
+	} else if (session->ch_width == CH_WIDTH_80MHZ) {
+		eht_op->channel_width = WLAN_EHT_CHWIDTH_80;
+		eht_op->ccfs0 = session->ch_center_freq_seg0;
+		eht_op->ccfs1 = 0;
+	} else if (session->ch_width == CH_WIDTH_40MHZ) {
+		eht_op->channel_width = WLAN_EHT_CHWIDTH_40;
+		eht_op->ccfs0 = session->ch_center_freq_seg0;
+		eht_op->ccfs1 = 0;
+	} else if (session->ch_width == CH_WIDTH_20MHZ) {
+		eht_op->channel_width = WLAN_EHT_CHWIDTH_20;
+		eht_op->ccfs0 = session->ch_center_freq_seg0;
+		eht_op->ccfs1 = 0;
+	}
+
 	lim_log_eht_op(mac_ctx, eht_op, session);
 
 	return QDF_STATUS_SUCCESS;
@@ -9449,6 +9710,16 @@ QDF_STATUS wlan_parse_bss_description_ies(struct mac_context *mac_ctx,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	status = lim_strip_and_decode_eht_op((uint8_t *)bss_desc->ieFields,
+					     ie_len, &ie_struct->eht_op,
+					     ie_struct->VHTOperation,
+					     ie_struct->he_op,
+					     ie_struct->HTInfo);
+	if (status != QDF_STATUS_SUCCESS) {
+		pe_err("Failed to extract eht op");
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	status = lim_strip_and_decode_eht_cap((uint8_t *)bss_desc->ieFields,
 					      ie_len, &ie_struct->eht_cap,
 					      ie_struct->he_cap,