diff --git a/umac/mlo_mgr/inc/wlan_mlo_epcs.h b/umac/mlo_mgr/inc/wlan_mlo_epcs.h index 25d55664b9..f164133a16 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_epcs.h +++ b/umac/mlo_mgr/inc/wlan_mlo_epcs.h @@ -49,12 +49,22 @@ enum wlan_epcs_category { /** * struct ml_pa_partner_link_info - Priority Access ML partner information * @link_id: Link ID + * @edca_ie_present: EDCA IE present + * @muedca_ie_present: MU EDCA IE present + * @ven_wme_ie_present: WME IE present * @edca: EDCA IE * @muedca: MU EDCA IE + * @ven_wme_ie_bytes: WME IE */ struct ml_pa_partner_link_info { uint8_t link_id; - struct edca_ie edca; + uint8_t edca_ie_present:1, + muedca_ie_present:1, + ven_wme_ie_present:1; + union { + struct edca_ie edca; + uint8_t ven_wme_ie_bytes[WLAN_VENDOR_WME_IE_LEN + 2]; + }; struct muedca_ie muedca; }; diff --git a/umac/mlo_mgr/src/utils_mlo.c b/umac/mlo_mgr/src/utils_mlo.c index 34cb4aed64..22bcd2c0d2 100644 --- a/umac/mlo_mgr/src/utils_mlo.c +++ b/umac/mlo_mgr/src/utils_mlo.c @@ -4762,6 +4762,8 @@ util_parse_pamlie_perstaprofile_stactrl(uint8_t *subelempayload, { qdf_size_t parsed_payload_len = 0; uint16_t stacontrol; + struct ie_header *ie; + struct extn_ie_header *extn_ie; /* This helper returns the location(s) and where required, the length(s) * of (sub)field(s) inferable after parsing the STA Control field in the @@ -4817,18 +4819,108 @@ util_parse_pamlie_perstaprofile_stactrl(uint8_t *subelempayload, return QDF_STATUS_E_PROTO; } - qdf_mem_copy(&pa_link_info->edca, subelempayload, - sizeof(struct edca_ie)); - subelempayload += sizeof(struct edca_ie); - parsed_payload_len += sizeof(struct edca_ie); + pa_link_info->edca_ie_present = false; + pa_link_info->ven_wme_ie_present = false; + pa_link_info->muedca_ie_present = false; - qdf_mem_copy(&pa_link_info->muedca, subelempayload, - sizeof(struct muedca_ie)); - subelempayload += sizeof(struct muedca_ie); - parsed_payload_len += sizeof(struct muedca_ie); + do { + if (subelempayloadlen < + (parsed_payload_len + + sizeof(struct ie_header))) { + mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain min ie length %zu after parsed payload length of %zu octets", + subelempayloadlen, + sizeof(struct ie_header), + parsed_payload_len); + return QDF_STATUS_E_PROTO; + } + + ie = (struct ie_header *)subelempayload; + + if (subelempayloadlen < + (parsed_payload_len + + (sizeof(struct ie_header) + ie->ie_len))) { + mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain ie length %zu after parsed payload length of %zu octets", + subelempayloadlen, + sizeof(struct ie_header) + ie->ie_len, + parsed_payload_len); + return QDF_STATUS_E_PROTO; + } + + switch (ie->ie_id) { + case WLAN_ELEMID_EDCAPARMS: + if (pa_link_info->ven_wme_ie_present) { + /* WME parameters already present + * use that one instead of EDCA */ + break; + } + if (ie->ie_len == (sizeof(struct edca_ie) - + sizeof(struct ie_header))) { + pa_link_info->edca_ie_present = true; + qdf_mem_copy(&pa_link_info->edca, + subelempayload, + sizeof(struct edca_ie)); + } else { + epcs_debug("Invalid edca length %d in PAV IE", + ie->ie_len); + } + break; + case WLAN_ELEMID_VENDOR: + if (is_wme_param((uint8_t *)ie) && + (ie->ie_len == WLAN_VENDOR_WME_IE_LEN)) { + pa_link_info->ven_wme_ie_present = true; + qdf_mem_copy(&pa_link_info->ven_wme_ie_bytes, + subelempayload, + sizeof(WLAN_VENDOR_WME_IE_LEN + + sizeof(struct ie_header))); + pa_link_info->edca_ie_present = false; + } else { + epcs_debug("Unrelated Venfor IE reecived ie_id %d ie_len %d", + ie->ie_id, + ie->ie_len); + } + break; + case WLAN_ELEMID_EXTN_ELEM: + extn_ie = (struct extn_ie_header *)ie; + switch (extn_ie->ie_extn_id) { + case WLAN_EXTN_ELEMID_MUEDCA: + if (extn_ie->ie_len == WLAN_MAX_MUEDCA_IE_LEN) { + pa_link_info->muedca_ie_present = true; + qdf_mem_copy(&pa_link_info->muedca, + subelempayload, + sizeof(struct muedca_ie)); + } else { + epcs_debug("Invalid muedca length %d in PAV IE", + ie->ie_len); + } + break; + default: + epcs_debug("Unrelated Extn IE reecived ie_id %d ie_len %d extid %d IN PAV IE", + ie->ie_id, + ie->ie_len, + extn_ie->ie_extn_id); + break; + } + break; + default: + epcs_debug("Unrelated IE reecived ie_id %d ie_len %d in PAV IE", + ie->ie_id, + ie->ie_len); + break; + } + subelempayload += ie->ie_len + sizeof(struct ie_header); + parsed_payload_len += ie->ie_len + sizeof(struct ie_header); + } while (parsed_payload_len < subelempayloadlen); if (parsed_payload_len != subelempayloadlen) - epcs_debug("Error in processing per sta profile of PA ML IE %zu %zu", parsed_payload_len, subelempayloadlen); + epcs_debug("Error in processing per sta profile of PA ML IE %zu %zu", + parsed_payload_len, + subelempayloadlen); + + epcs_debug("Link id %d presence of edca %d muedca %d wme %d", + pa_link_info->link_id, + pa_link_info->edca_ie_present, + pa_link_info->muedca_ie_present, + pa_link_info->ven_wme_ie_present); return QDF_STATUS_SUCCESS; }