qcacmn: Add priority access ML IE support
Add support to parse priority access multi link IE. Change-Id: I7a226e0fd1a4d229d721244aeb675e1c09cc5ed3 CRs-Fixed: 3490404
This commit is contained in:

committed by
Rahul Choudhary

parent
6fdf8a4a53
commit
3e0b45fc11
@@ -1466,6 +1466,65 @@ struct erp_ie {
|
|||||||
uint8_t value;
|
uint8_t value;
|
||||||
} qdf_packed;
|
} qdf_packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ac_param_record: AC Parameter Record
|
||||||
|
* @aci_aifsn: ACI/AIFSN field
|
||||||
|
* @ecw_min_max: ECWmin/ECWmax field
|
||||||
|
* @txop_limit: TXOP Limit
|
||||||
|
*/
|
||||||
|
struct ac_param_record {
|
||||||
|
uint8_t aci_aifsn;
|
||||||
|
uint8_t ecw_min_max;
|
||||||
|
uint16_t txop_limit;
|
||||||
|
} qdf_packed;
|
||||||
|
|
||||||
|
/* Max number of access catogeries */
|
||||||
|
#define MAX_NUM_AC 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct edca_ie: EDCA Parameter Set element
|
||||||
|
* @ie: EDCA Element id
|
||||||
|
* @len: EDCA IE length
|
||||||
|
* @qos_info: QOS information
|
||||||
|
* @update_edca_info: Update EDCA Info
|
||||||
|
* @ac_record: AC Parameter Record
|
||||||
|
*/
|
||||||
|
struct edca_ie {
|
||||||
|
uint8_t ie;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t qos_info;
|
||||||
|
uint8_t update_edca_info;
|
||||||
|
struct ac_param_record ac_record[MAX_NUM_AC];
|
||||||
|
} qdf_packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct muac_param_record: MU AC Parameter Record
|
||||||
|
* @aci_aifsn: ACI/AIFSN field
|
||||||
|
* @ecw_min_max: ECWmin/ECWmax field
|
||||||
|
* @mu_edca_timer: MU EDCA Timer
|
||||||
|
*/
|
||||||
|
struct muac_param_record {
|
||||||
|
uint8_t aci_aifsn;
|
||||||
|
uint8_t ecw_min_max;
|
||||||
|
uint8_t mu_edca_timer;
|
||||||
|
} qdf_packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct muedca_ie: MU EDCA Parameter Set element
|
||||||
|
* @elem_id: MU EDCA Element id
|
||||||
|
* @elem_len: MU EDCA IE length
|
||||||
|
* @elem_id_extn: MU EDCA extension element id
|
||||||
|
* @qos_info: QoS Info
|
||||||
|
* @mu_record: MU AC Parameter Record
|
||||||
|
*/
|
||||||
|
struct muedca_ie {
|
||||||
|
uint8_t elem_id;
|
||||||
|
uint8_t elem_len;
|
||||||
|
uint8_t elem_id_extn;
|
||||||
|
uint8_t qos_info;
|
||||||
|
struct muac_param_record mu_record[MAX_NUM_AC];
|
||||||
|
} qdf_packed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct htcap_cmn_ie: HT common IE info
|
* struct htcap_cmn_ie: HT common IE info
|
||||||
* @hc_cap: HT capabilities
|
* @hc_cap: HT capabilities
|
||||||
@@ -2852,6 +2911,67 @@ struct wlan_ml_rv_linfo_perstaprof_stainfo_opparams {
|
|||||||
* End of definitions related to MLO specific aspects of Reduced Neighbor Report
|
* End of definitions related to MLO specific aspects of Reduced Neighbor Report
|
||||||
* element.
|
* element.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Definitions related to Priority access variant Multi-Link element
|
||||||
|
* Common Info field
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Size in octets of Common Info Length subfield of Common Info field in
|
||||||
|
* Priority access variant Multi-Link element.
|
||||||
|
*/
|
||||||
|
/* Common Info Length */
|
||||||
|
#define WLAN_ML_PAV_CINFO_LENGTH_SIZE 1
|
||||||
|
|
||||||
|
/* Max value in octets of Common Info Length subfield of Common Info field in
|
||||||
|
* Priority access variant Multi-Link element
|
||||||
|
*/
|
||||||
|
#define WLAN_ML_PAV_CINFO_LENGTH_MAX \
|
||||||
|
(WLAN_ML_PAV_CINFO_LENGTH_SIZE + \
|
||||||
|
QDF_MAC_ADDR_SIZE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct wlan_ml_pav_linfo_perstaprof - Fixed fields of Per-STA Profile
|
||||||
|
* subelement in Priority access variant Multi-Link element Link Info field
|
||||||
|
* @subelem_id: Subelement ID
|
||||||
|
* @subelem_len: Subelement length
|
||||||
|
* @stacontrol: STA Control
|
||||||
|
*/
|
||||||
|
struct wlan_ml_pav_linfo_perstaprof {
|
||||||
|
uint8_t subelem_id;
|
||||||
|
uint8_t subelem_len;
|
||||||
|
uint16_t stacontrol;
|
||||||
|
} qdf_packed;
|
||||||
|
|
||||||
|
/* The above fixed fields may be followed by:
|
||||||
|
* STA profile (variable size)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Size in octets of STA Control field of Per-STA Profile subelement in
|
||||||
|
* Priority access variant Multi-Link element Link Info field.
|
||||||
|
*/
|
||||||
|
#define WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE 2
|
||||||
|
|
||||||
|
/* Definitions for subfields in STA Control field of Per-STA Profile subelement
|
||||||
|
* in Priority access variant Multi-Link element Link Info field. Any unused
|
||||||
|
* bits are reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Link ID */
|
||||||
|
#define WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX 0
|
||||||
|
#define WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS 4
|
||||||
|
|
||||||
|
/* End of definitions related to priority access variant Multi-Link element Link
|
||||||
|
* Info field.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Maximum size of IEs present in sta profile for a link
|
||||||
|
* EDCA IE and MU EDCA IE are part of this.
|
||||||
|
*/
|
||||||
|
#define WLAN_ML_PAV_LINFO_STAPROF_MAXSIZE \
|
||||||
|
(sizeof(struct edca_ie) + sizeof(struct muedca_ie))
|
||||||
|
|
||||||
|
/* End of definitions related to priority access variant Multi-Link element. */
|
||||||
|
|
||||||
#endif /* WLAN_FEATURE_11BE_MLO */
|
#endif /* WLAN_FEATURE_11BE_MLO */
|
||||||
#endif /* WLAN_FEATURE_11BE */
|
#endif /* WLAN_FEATURE_11BE */
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include "wlan_mlo_mgr_public_structs.h"
|
#include "wlan_mlo_mgr_public_structs.h"
|
||||||
#include <wlan_cm_ucfg_api.h>
|
#include <wlan_cm_ucfg_api.h>
|
||||||
#include <wlan_objmgr_vdev_obj.h>
|
#include <wlan_objmgr_vdev_obj.h>
|
||||||
|
#include <wlan_mlo_epcs.h>
|
||||||
|
|
||||||
#ifdef WLAN_FEATURE_11BE_MLO
|
#ifdef WLAN_FEATURE_11BE_MLO
|
||||||
|
|
||||||
@@ -517,6 +518,24 @@ util_get_rvmlie_persta_link_info(uint8_t *mlieseq,
|
|||||||
qdf_size_t mlieseqlen,
|
qdf_size_t mlieseqlen,
|
||||||
struct ml_rv_info *reconfig_info);
|
struct ml_rv_info *reconfig_info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* util_get_pav_mlie_link_info() - Get priority access link information
|
||||||
|
*
|
||||||
|
* @mlieseq: Starting address of the Multi-Link element or Multi-Link element
|
||||||
|
* fragment sequence
|
||||||
|
* @mlieseqlen: Total length of the Multi-Link element or Multi-Link element
|
||||||
|
* fragment sequence
|
||||||
|
* @pa_info: Pointer to the location where the priority access multi link
|
||||||
|
* information is stored.
|
||||||
|
*
|
||||||
|
* Get EPCS priority access information from Priority Access Multi-Link element.
|
||||||
|
*
|
||||||
|
* Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving
|
||||||
|
* the reason for error in the case of failure.
|
||||||
|
*/
|
||||||
|
QDF_STATUS util_get_pav_mlie_link_info(uint8_t *mlieseq,
|
||||||
|
qdf_size_t mlieseqlen,
|
||||||
|
struct ml_pa_info *pa_info);
|
||||||
#else
|
#else
|
||||||
static inline QDF_STATUS
|
static inline QDF_STATUS
|
||||||
util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
|
util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
|
||||||
@@ -644,5 +663,14 @@ util_get_rvmlie_persta_link_info(uint8_t *mlieseq,
|
|||||||
{
|
{
|
||||||
return QDF_STATUS_E_NOSUPPORT;
|
return QDF_STATUS_E_NOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
QDF_STATUS util_get_pav_mlie_link_info(uint8_t *mlieseq,
|
||||||
|
qdf_size_t mlieseqlen,
|
||||||
|
struct ml_pa_info *pa_info)
|
||||||
|
{
|
||||||
|
return QDF_STATUS_E_NOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* WLAN_FEATURE_11BE_MLO */
|
#endif /* WLAN_FEATURE_11BE_MLO */
|
||||||
#endif /* _WLAN_UTILS_MLO_H_ */
|
#endif /* _WLAN_UTILS_MLO_H_ */
|
||||||
|
@@ -46,16 +46,42 @@ enum wlan_epcs_category {
|
|||||||
WLAN_EPCS_CATEGORY_INVALID,
|
WLAN_EPCS_CATEGORY_INVALID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ml_pa_partner_link_info - Priority Access ML partner information
|
||||||
|
* @link_id: Link ID
|
||||||
|
* @edca: EDCA IE
|
||||||
|
* @muedca: MU EDCA IE
|
||||||
|
*/
|
||||||
|
struct ml_pa_partner_link_info {
|
||||||
|
uint8_t link_id;
|
||||||
|
struct edca_ie edca;
|
||||||
|
struct muedca_ie muedca;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ml_pa_info - priority access ML info
|
||||||
|
* @mld_mac_addr: MLD mac address
|
||||||
|
* @num_links: Number of Links
|
||||||
|
* @link_info: Partner link information
|
||||||
|
*/
|
||||||
|
struct ml_pa_info {
|
||||||
|
struct qdf_mac_addr mld_mac_addr;
|
||||||
|
uint8_t num_links;
|
||||||
|
struct ml_pa_partner_link_info link_info[WLAN_UMAC_MLO_MAX_VDEVS];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct wlan_epcs_info - EPCS information of frame
|
* struct wlan_epcs_info - EPCS information of frame
|
||||||
* @cat: frame category
|
* @cat: frame category
|
||||||
* @dialog_token: dialog token
|
* @dialog_token: dialog token
|
||||||
* @status: status
|
* @status: status
|
||||||
|
* @pa_info: Priority access ML info
|
||||||
*/
|
*/
|
||||||
struct wlan_epcs_info {
|
struct wlan_epcs_info {
|
||||||
enum wlan_epcs_category cat;
|
enum wlan_epcs_category cat;
|
||||||
uint8_t dialog_token;
|
uint8_t dialog_token;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
struct ml_pa_info pa_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,6 +135,12 @@ struct epcs_frm {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* MIN EPCS request frame length */
|
||||||
|
#define EPCS_REQ_MIN_LENGTH 3
|
||||||
|
|
||||||
|
/* MIN EPCS response frame length */
|
||||||
|
#define EPCS_RESP_MIN_LENGTH 5
|
||||||
|
|
||||||
#define epcs_alert(format, args...) \
|
#define epcs_alert(format, args...) \
|
||||||
QDF_TRACE_FATAL(QDF_MODULE_ID_EPCS, format, ## args)
|
QDF_TRACE_FATAL(QDF_MODULE_ID_EPCS, format, ## args)
|
||||||
|
|
||||||
|
@@ -4683,6 +4683,462 @@ QDF_STATUS util_get_rvmlie_persta_link_info(uint8_t *mlieseq,
|
|||||||
return QDF_STATUS_SUCCESS;
|
return QDF_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QDF_STATUS
|
||||||
|
util_parse_pa_multi_link_ctrl(uint8_t *mlieseqpayload,
|
||||||
|
qdf_size_t mlieseqpayloadlen,
|
||||||
|
uint8_t **link_info,
|
||||||
|
qdf_size_t *link_info_len)
|
||||||
|
{
|
||||||
|
qdf_size_t parsed_payload_len;
|
||||||
|
|
||||||
|
/* This helper returns the location(s) and length(s) of (sub)field(s)
|
||||||
|
* inferable after parsing the Multi Link element Control field. These
|
||||||
|
* location(s) and length(s) is/are in reference to the payload section
|
||||||
|
* of the Multi Link element (after defragmentation, if applicable).
|
||||||
|
* Here, the payload is the point after the element ID extension of the
|
||||||
|
* Multi Link element, and includes the payloads of all subsequent
|
||||||
|
* fragments (if any) but not the headers of those fragments.
|
||||||
|
*
|
||||||
|
* Currently, the helper returns the location and length of the Link
|
||||||
|
* Info field in the Multi Link element sequence. Other (sub)field(s)
|
||||||
|
* can be added later as required.
|
||||||
|
*/
|
||||||
|
if (!mlieseqpayload) {
|
||||||
|
mlo_err("ML seq payload pointer is NULL");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mlieseqpayloadlen) {
|
||||||
|
mlo_err("ML seq payload len is 0");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
|
||||||
|
mlo_err_rl("ML seq payload len %zu < ML Control size %u",
|
||||||
|
mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
|
||||||
|
return QDF_STATUS_E_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed_payload_len = 0;
|
||||||
|
|
||||||
|
parsed_payload_len += WLAN_ML_CTRL_SIZE;
|
||||||
|
|
||||||
|
if (mlieseqpayloadlen <
|
||||||
|
(parsed_payload_len +
|
||||||
|
WLAN_ML_PAV_CINFO_LENGTH_MAX)) {
|
||||||
|
mlo_err_rl("ML seq payload len %zu insufficient for MLD cmn size %u after parsed payload len %zu.",
|
||||||
|
mlieseqpayloadlen,
|
||||||
|
WLAN_ML_PAV_CINFO_LENGTH_MAX,
|
||||||
|
parsed_payload_len);
|
||||||
|
return QDF_STATUS_E_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed_payload_len += QDF_MAC_ADDR_SIZE + WLAN_ML_PAV_CINFO_LENGTH_SIZE;
|
||||||
|
|
||||||
|
if (link_info_len) {
|
||||||
|
*link_info_len = mlieseqpayloadlen - parsed_payload_len;
|
||||||
|
mlo_debug("link_info_len:%zu, parsed_payload_len:%zu",
|
||||||
|
*link_info_len, parsed_payload_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mlieseqpayloadlen == parsed_payload_len) {
|
||||||
|
mlo_debug("No Link Info field present");
|
||||||
|
if (link_info)
|
||||||
|
*link_info = NULL;
|
||||||
|
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (link_info)
|
||||||
|
*link_info = mlieseqpayload + parsed_payload_len;
|
||||||
|
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QDF_STATUS
|
||||||
|
util_parse_pamlie_perstaprofile_stactrl(uint8_t *subelempayload,
|
||||||
|
qdf_size_t subelempayloadlen,
|
||||||
|
struct ml_pa_partner_link_info *pa_link_info)
|
||||||
|
{
|
||||||
|
qdf_size_t parsed_payload_len = 0;
|
||||||
|
uint16_t stacontrol;
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
* per-STA profile subelement. These location(s) and length(s) is/are in
|
||||||
|
* reference to the payload section of the per-STA profile subelement
|
||||||
|
* (after defragmentation, if applicable). Here, the payload is the
|
||||||
|
* point after the subelement length in the subelement, and includes the
|
||||||
|
* payloads of all subsequent fragments (if any) but not the headers of
|
||||||
|
* those fragments.
|
||||||
|
*
|
||||||
|
* Currently, the helper returns the priority access link information
|
||||||
|
* for all parner links.
|
||||||
|
*/
|
||||||
|
if (!subelempayload) {
|
||||||
|
mlo_err("Pointer to subelement payload is NULL");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subelempayloadlen) {
|
||||||
|
mlo_err("Length of subelement payload is zero");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subelempayloadlen < WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE) {
|
||||||
|
mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
|
||||||
|
subelempayloadlen,
|
||||||
|
WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE);
|
||||||
|
return QDF_STATUS_E_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed_payload_len = 0;
|
||||||
|
qdf_mem_copy(&stacontrol,
|
||||||
|
subelempayload,
|
||||||
|
WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE);
|
||||||
|
|
||||||
|
stacontrol = qdf_le16_to_cpu(stacontrol);
|
||||||
|
parsed_payload_len += WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE;
|
||||||
|
|
||||||
|
subelempayload += WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE;
|
||||||
|
|
||||||
|
pa_link_info->link_id =
|
||||||
|
QDF_GET_BITS(stacontrol,
|
||||||
|
WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
|
||||||
|
WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
|
||||||
|
|
||||||
|
if (subelempayloadlen <
|
||||||
|
(parsed_payload_len +
|
||||||
|
WLAN_ML_PAV_LINFO_STAPROF_MAXSIZE)) {
|
||||||
|
mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain edca params of size %zu octets after parsed payload length of %zu octets.",
|
||||||
|
subelempayloadlen,
|
||||||
|
WLAN_ML_PAV_LINFO_STAPROF_MAXSIZE,
|
||||||
|
parsed_payload_len);
|
||||||
|
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);
|
||||||
|
|
||||||
|
qdf_mem_copy(&pa_link_info->muedca, subelempayload,
|
||||||
|
sizeof(struct muedca_ie));
|
||||||
|
subelempayload += sizeof(struct muedca_ie);
|
||||||
|
parsed_payload_len += sizeof(struct muedca_ie);
|
||||||
|
|
||||||
|
if (parsed_payload_len != subelempayloadlen)
|
||||||
|
epcs_debug("Error in processing per sta profile of PA ML IE %zu %zu", parsed_payload_len, subelempayloadlen);
|
||||||
|
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QDF_STATUS
|
||||||
|
util_parse_pa_info_from_linkinfo(uint8_t *linkinfo,
|
||||||
|
qdf_size_t linkinfo_len,
|
||||||
|
struct ml_pa_info *pa_info)
|
||||||
|
{
|
||||||
|
uint8_t *linkinfo_currpos;
|
||||||
|
qdf_size_t linkinfo_remlen;
|
||||||
|
bool is_subelemfragseq;
|
||||||
|
uint8_t subelemid;
|
||||||
|
qdf_size_t subelemseqtotallen;
|
||||||
|
qdf_size_t subelemseqpayloadlen;
|
||||||
|
qdf_size_t defragpayload_len;
|
||||||
|
QDF_STATUS ret;
|
||||||
|
|
||||||
|
/* This helper function parses priority access info from the per-STA
|
||||||
|
* prof present (if any) in the Link Info field in the payload of a
|
||||||
|
* Multi Link element (after defragmentation if required). The caller
|
||||||
|
* should pass a copy of the payload so that inline defragmentation of
|
||||||
|
* subelements can be carried out if required. The subelement
|
||||||
|
* defragmentation (if applicable) in this Control Path helper is
|
||||||
|
* required for maintainability, accuracy and eliminating current and
|
||||||
|
* future per-field-access multi-level fragment boundary checks and
|
||||||
|
* adjustments, given the complex format of Multi Link elements. It is
|
||||||
|
* also most likely to be required mainly at the client side.
|
||||||
|
* Fragmentation is currently unlikely to be required for subelements
|
||||||
|
* in Reconfiguration variant Multi-Link elements, but it should be
|
||||||
|
* handled in order to be future ready.
|
||||||
|
*/
|
||||||
|
if (!linkinfo) {
|
||||||
|
mlo_err("linkinfo is NULL");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!linkinfo_len) {
|
||||||
|
mlo_err("linkinfo_len is zero");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pa_info) {
|
||||||
|
mlo_err("ML pa info is NULL");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_info->num_links = 0;
|
||||||
|
linkinfo_currpos = linkinfo;
|
||||||
|
linkinfo_remlen = linkinfo_len;
|
||||||
|
|
||||||
|
while (linkinfo_remlen) {
|
||||||
|
if (linkinfo_remlen < sizeof(struct subelem_header)) {
|
||||||
|
mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
|
||||||
|
linkinfo_remlen,
|
||||||
|
sizeof(struct subelem_header));
|
||||||
|
return QDF_STATUS_E_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
subelemid = linkinfo_currpos[ID_POS];
|
||||||
|
is_subelemfragseq = false;
|
||||||
|
subelemseqtotallen = 0;
|
||||||
|
subelemseqpayloadlen = 0;
|
||||||
|
|
||||||
|
ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
|
||||||
|
linkinfo_currpos,
|
||||||
|
linkinfo_remlen,
|
||||||
|
&is_subelemfragseq,
|
||||||
|
&subelemseqtotallen,
|
||||||
|
&subelemseqpayloadlen);
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (qdf_unlikely(is_subelemfragseq)) {
|
||||||
|
if (!subelemseqpayloadlen) {
|
||||||
|
mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlo_debug("Subelement fragment sequence found with payload len %zu",
|
||||||
|
subelemseqpayloadlen);
|
||||||
|
|
||||||
|
ret = wlan_defrag_subelem_fragseq(true,
|
||||||
|
WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
|
||||||
|
linkinfo_currpos,
|
||||||
|
linkinfo_remlen,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
&defragpayload_len);
|
||||||
|
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (defragpayload_len != subelemseqpayloadlen) {
|
||||||
|
mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
|
||||||
|
defragpayload_len,
|
||||||
|
subelemseqpayloadlen);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust linkinfo_remlen to reflect removal of all
|
||||||
|
* subelement headers except the header of the lead
|
||||||
|
* subelement.
|
||||||
|
*/
|
||||||
|
linkinfo_remlen -= (subelemseqtotallen -
|
||||||
|
subelemseqpayloadlen -
|
||||||
|
sizeof(struct subelem_header));
|
||||||
|
} else {
|
||||||
|
if (linkinfo_remlen <
|
||||||
|
(sizeof(struct subelem_header) +
|
||||||
|
linkinfo_currpos[TAG_LEN_POS])) {
|
||||||
|
mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
|
||||||
|
linkinfo_remlen,
|
||||||
|
sizeof(struct subelem_header) +
|
||||||
|
linkinfo_currpos[TAG_LEN_POS]);
|
||||||
|
return QDF_STATUS_E_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
|
||||||
|
struct ml_pa_partner_link_info *link_info =
|
||||||
|
&pa_info->link_info[pa_info->num_links];
|
||||||
|
ret = util_parse_pamlie_perstaprofile_stactrl(linkinfo_currpos +
|
||||||
|
sizeof(struct subelem_header),
|
||||||
|
subelemseqpayloadlen,
|
||||||
|
link_info);
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret))
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_info->num_links++;
|
||||||
|
|
||||||
|
linkinfo_remlen -= (sizeof(struct subelem_header) +
|
||||||
|
subelemseqpayloadlen);
|
||||||
|
linkinfo_currpos += (sizeof(struct subelem_header) +
|
||||||
|
subelemseqpayloadlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
mlo_debug("Number of ML probe request links found=%u",
|
||||||
|
pa_info->num_links);
|
||||||
|
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDF_STATUS
|
||||||
|
util_get_pav_mlie_link_info(uint8_t *mlieseq,
|
||||||
|
qdf_size_t mlieseqlen,
|
||||||
|
struct ml_pa_info *pa_info)
|
||||||
|
{
|
||||||
|
struct wlan_ie_multilink *mlie_fixed;
|
||||||
|
uint16_t mlcontrol;
|
||||||
|
enum wlan_ml_variant variant;
|
||||||
|
uint8_t *linkinfo;
|
||||||
|
qdf_size_t linkinfo_len;
|
||||||
|
struct ml_pa_info painfo = {0};
|
||||||
|
qdf_size_t mlieseqpayloadlen;
|
||||||
|
uint8_t *mlieseqpayload_copy;
|
||||||
|
bool is_elemfragseq;
|
||||||
|
qdf_size_t defragpayload_len;
|
||||||
|
qdf_size_t tmplen;
|
||||||
|
QDF_STATUS ret;
|
||||||
|
|
||||||
|
if (!mlieseq) {
|
||||||
|
mlo_err("Pointer to Multi-Link element sequence is NULL");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mlieseqlen) {
|
||||||
|
mlo_err("Length of Multi-Link element sequence is zero");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pa_info) {
|
||||||
|
mlo_err("pa_info is NULL");
|
||||||
|
return QDF_STATUS_E_NULL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_info->num_links = 0;
|
||||||
|
|
||||||
|
if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
|
||||||
|
mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
|
||||||
|
mlieseqlen, sizeof(struct wlan_ie_multilink));
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
|
||||||
|
if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
|
||||||
|
mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) {
|
||||||
|
mlo_err("The element is not a Multi-Link element");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
|
||||||
|
|
||||||
|
variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
|
||||||
|
WLAN_ML_CTRL_TYPE_BITS);
|
||||||
|
|
||||||
|
if (variant != WLAN_ML_VARIANT_PRIORITYACCESS) {
|
||||||
|
mlo_err("The variant value %u does not correspond to priority access Variant value %u",
|
||||||
|
variant, WLAN_ML_VARIANT_PRIORITYACCESS);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlieseqpayloadlen = 0;
|
||||||
|
tmplen = 0;
|
||||||
|
is_elemfragseq = false;
|
||||||
|
|
||||||
|
ret = wlan_get_elem_fragseq_info(mlieseq,
|
||||||
|
mlieseqlen,
|
||||||
|
&is_elemfragseq,
|
||||||
|
&tmplen,
|
||||||
|
&mlieseqpayloadlen);
|
||||||
|
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (qdf_unlikely(is_elemfragseq)) {
|
||||||
|
if (tmplen != mlieseqlen) {
|
||||||
|
mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets",
|
||||||
|
tmplen, mlieseqlen);
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mlieseqpayloadlen) {
|
||||||
|
mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
|
||||||
|
mlieseqpayloadlen);
|
||||||
|
} else {
|
||||||
|
if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
|
||||||
|
mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found",
|
||||||
|
mlieseqlen,
|
||||||
|
sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
|
||||||
|
|
||||||
|
if (!mlieseqpayload_copy) {
|
||||||
|
mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
|
||||||
|
return QDF_STATUS_E_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qdf_unlikely(is_elemfragseq)) {
|
||||||
|
ret = wlan_defrag_elem_fragseq(false,
|
||||||
|
mlieseq,
|
||||||
|
mlieseqlen,
|
||||||
|
mlieseqpayload_copy,
|
||||||
|
mlieseqpayloadlen,
|
||||||
|
&defragpayload_len);
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||||
|
qdf_mem_free(mlieseqpayload_copy);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defragpayload_len != mlieseqpayloadlen) {
|
||||||
|
mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
|
||||||
|
defragpayload_len, mlieseqpayloadlen);
|
||||||
|
qdf_mem_free(mlieseqpayload_copy);
|
||||||
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qdf_mem_copy(mlieseqpayload_copy,
|
||||||
|
mlieseq + sizeof(struct ie_header) + 1,
|
||||||
|
mlieseqpayloadlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
linkinfo = NULL;
|
||||||
|
linkinfo_len = 0;
|
||||||
|
|
||||||
|
ret = util_parse_pa_multi_link_ctrl(mlieseqpayload_copy,
|
||||||
|
mlieseqpayloadlen,
|
||||||
|
&linkinfo,
|
||||||
|
&linkinfo_len);
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||||
|
qdf_mem_free(mlieseqpayload_copy);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case Link Info is absent, the number of links will remain
|
||||||
|
* zero.
|
||||||
|
*/
|
||||||
|
if (!linkinfo) {
|
||||||
|
qdf_mem_free(mlieseqpayload_copy);
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlo_debug("Dumping hex of link info after parsing Multi-Link element control");
|
||||||
|
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_ERROR,
|
||||||
|
linkinfo, linkinfo_len);
|
||||||
|
|
||||||
|
ret = util_parse_pa_info_from_linkinfo(linkinfo, linkinfo_len, &painfo);
|
||||||
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||||
|
qdf_mem_free(mlieseqpayload_copy);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdf_mem_copy(pa_info, &painfo, sizeof(painfo));
|
||||||
|
qdf_mem_free(mlieseqpayload_copy);
|
||||||
|
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLAN_FEATURE_11BE
|
#ifdef WLAN_FEATURE_11BE
|
||||||
|
@@ -28,6 +28,53 @@
|
|||||||
#include <utils_mlo.h>
|
#include <utils_mlo.h>
|
||||||
#include <wlan_mlo_epcs.h>
|
#include <wlan_mlo_epcs.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mlo_process_ml_priorityaccess_ie() - API to parse Priority access ML IE
|
||||||
|
* @ml_ie: Pointer to start of ML IE
|
||||||
|
* @ml_ie_len: Length of ML IE
|
||||||
|
* @priority_access_info: pointer to fill multi link priority access information
|
||||||
|
*
|
||||||
|
* Return: QDF_STATUS
|
||||||
|
*/
|
||||||
|
static QDF_STATUS
|
||||||
|
mlo_process_ml_priorityaccess_ie(uint8_t *ml_ie, qdf_size_t ml_ie_len,
|
||||||
|
struct ml_pa_info *priority_access_info)
|
||||||
|
{
|
||||||
|
uint8_t *ml_pa_ie = NULL;
|
||||||
|
qdf_size_t ml_pa_ie_len = 0;
|
||||||
|
QDF_STATUS status;
|
||||||
|
|
||||||
|
if (!ml_ie) {
|
||||||
|
mlo_err("NULL ml_ie");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!priority_access_info) {
|
||||||
|
mlo_err("NULL priority_access_info");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = util_find_mlie_by_variant(ml_ie,
|
||||||
|
ml_ie_len,
|
||||||
|
&ml_pa_ie,
|
||||||
|
&ml_pa_ie_len,
|
||||||
|
WLAN_ML_VARIANT_PRIORITYACCESS);
|
||||||
|
|
||||||
|
if (QDF_IS_STATUS_ERROR(status) || !ml_pa_ie) {
|
||||||
|
mlo_debug("ML IE for reconfig variant not found");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
epcs_debug("PAV ML IE with length %zu is present", ml_pa_ie_len);
|
||||||
|
|
||||||
|
status = util_get_pav_mlie_link_info(ml_pa_ie, ml_pa_ie_len,
|
||||||
|
priority_access_info);
|
||||||
|
if (QDF_IS_STATUS_ERROR(status)) {
|
||||||
|
mlo_err("Unable to get sta link info from ML PAV IE");
|
||||||
|
return QDF_STATUS_E_INVAL;
|
||||||
|
}
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_mlo_parse_epcs_request_action_frame() - API to parse EPCS request action
|
* wlan_mlo_parse_epcs_request_action_frame() - API to parse EPCS request action
|
||||||
* frame.
|
* frame.
|
||||||
@@ -43,6 +90,9 @@ wlan_mlo_parse_epcs_request_action_frame(struct wlan_epcs_info *epcs,
|
|||||||
uint32_t frm_len)
|
uint32_t frm_len)
|
||||||
{
|
{
|
||||||
struct epcs_frm *epcs_action_frm;
|
struct epcs_frm *epcs_action_frm;
|
||||||
|
struct ml_pa_info *priority_access_info = &epcs->pa_info;
|
||||||
|
uint8_t *pa_ie;
|
||||||
|
uint16_t pa_ie_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EPCS request action frame
|
* EPCS request action frame
|
||||||
@@ -65,7 +115,15 @@ wlan_mlo_parse_epcs_request_action_frame(struct wlan_epcs_info *epcs,
|
|||||||
epcs_action_frm->protected_eht_action,
|
epcs_action_frm->protected_eht_action,
|
||||||
epcs_action_frm->dialog_token, frm_len);
|
epcs_action_frm->dialog_token, frm_len);
|
||||||
|
|
||||||
return QDF_STATUS_SUCCESS;
|
if (frm_len > EPCS_REQ_MIN_LENGTH) {
|
||||||
|
pa_ie = (uint8_t *)epcs_action_frm + EPCS_REQ_MIN_LENGTH;
|
||||||
|
pa_ie_len = frm_len - EPCS_REQ_MIN_LENGTH;
|
||||||
|
return mlo_process_ml_priorityaccess_ie(pa_ie,
|
||||||
|
pa_ie_len,
|
||||||
|
priority_access_info);
|
||||||
|
} else {
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +141,9 @@ wlan_mlo_parse_epcs_response_action_frame(struct wlan_epcs_info *epcs,
|
|||||||
uint32_t frm_len)
|
uint32_t frm_len)
|
||||||
{
|
{
|
||||||
struct epcs_frm *epcs_action_frm;
|
struct epcs_frm *epcs_action_frm;
|
||||||
|
struct ml_pa_info *priority_access_info = &epcs->pa_info;
|
||||||
|
uint8_t *pa_ie;
|
||||||
|
uint16_t pa_ie_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EPCS response action frame
|
* EPCS response action frame
|
||||||
@@ -109,7 +170,15 @@ wlan_mlo_parse_epcs_response_action_frame(struct wlan_epcs_info *epcs,
|
|||||||
epcs_action_frm->resp.status_code[0],
|
epcs_action_frm->resp.status_code[0],
|
||||||
epcs_action_frm->resp.status_code[1], frm_len);
|
epcs_action_frm->resp.status_code[1], frm_len);
|
||||||
|
|
||||||
return QDF_STATUS_SUCCESS;
|
if (frm_len > EPCS_RESP_MIN_LENGTH) {
|
||||||
|
pa_ie = (uint8_t *)epcs_action_frm + EPCS_RESP_MIN_LENGTH;
|
||||||
|
pa_ie_len = frm_len - EPCS_RESP_MIN_LENGTH;
|
||||||
|
return mlo_process_ml_priorityaccess_ie(pa_ie,
|
||||||
|
pa_ie_len,
|
||||||
|
priority_access_info);
|
||||||
|
} else {
|
||||||
|
return QDF_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user