Merge "qcacmn: Use only partner links with valid scan entry" into wlan-cmn.driver.lnx.2.0.14
This commit is contained in:

committad av
Gerrit - the friendly Code Review server

incheckning
4004081535
@@ -1439,6 +1439,67 @@ static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev,
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static QDF_STATUS cm_remove_mbssid_links_without_scan_entry(
|
||||
qdf_list_t *candidate_list)
|
||||
{
|
||||
struct scan_cache_node *scan_node = NULL;
|
||||
struct scan_cache_entry *partner_entry = NULL, *scan_entry = NULL;
|
||||
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
|
||||
struct partner_link_info *partner_info;
|
||||
struct qdf_mac_addr *mld_addr;
|
||||
uint8_t i = 0;
|
||||
|
||||
if (qdf_list_peek_front(candidate_list,
|
||||
&cur_node) != QDF_STATUS_SUCCESS) {
|
||||
mlme_err("Failed to dequeue");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
while (cur_node) {
|
||||
qdf_list_peek_next(candidate_list, cur_node, &next_node);
|
||||
scan_node = qdf_container_of(cur_node, struct scan_cache_node,
|
||||
node);
|
||||
scan_entry = scan_node->entry;
|
||||
mld_addr = util_scan_entry_mldaddr(scan_entry);
|
||||
|
||||
if (!scan_entry->mbssid_info.profile_num || !mld_addr)
|
||||
goto next_entry;
|
||||
|
||||
/*
|
||||
* Mark the links of an MBSSID partner as invalid if there
|
||||
* is no scan entry for the link at the time of the candidate
|
||||
* selection.
|
||||
*
|
||||
* For MBSSID candidates, ML-probe request would not be sent,
|
||||
* during join phase, therefore the scan entry would not be
|
||||
* created anytime before the association.
|
||||
*
|
||||
*/
|
||||
for (i = 0; i < scan_entry->ml_info.num_links; i++) {
|
||||
if (!scan_entry->ml_info.link_info[i].is_valid_link)
|
||||
continue;
|
||||
|
||||
partner_info = &scan_entry->ml_info.link_info[i];
|
||||
partner_entry = cm_get_entry(candidate_list,
|
||||
&partner_info->link_addr);
|
||||
|
||||
if (!partner_entry ||
|
||||
!qdf_is_macaddr_equal(mld_addr,
|
||||
&partner_entry->ml_info.mld_mac_addr)) {
|
||||
scan_entry->ml_info.link_info[i].is_valid_link = false;
|
||||
mlme_debug("Scan entry is not present for link idx %d, drop the link",
|
||||
scan_entry->ml_info.link_info[i].link_id);
|
||||
}
|
||||
}
|
||||
next_entry:
|
||||
cur_node = next_node;
|
||||
next_node = NULL;
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev,
|
||||
struct cm_connect_req *cm_req,
|
||||
@@ -1446,6 +1507,12 @@ static QDF_STATUS cm_update_mlo_filter(struct wlan_objmgr_pdev *pdev,
|
||||
{
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static QDF_STATUS cm_remove_mbssid_links_without_scan_entry(
|
||||
qdf_list_t *candidate_list)
|
||||
{
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static QDF_STATUS
|
||||
@@ -1500,6 +1567,10 @@ cm_connect_fetch_candidates(struct wlan_objmgr_pdev *pdev,
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
|
||||
}
|
||||
*num_bss_found = num_bss;
|
||||
|
||||
if (num_bss && !wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev))
|
||||
cm_remove_mbssid_links_without_scan_entry(candidate_list);
|
||||
|
||||
op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
|
||||
if (num_bss && op_mode == QDF_STA_MODE &&
|
||||
!cm_req->req.is_non_assoc_link)
|
||||
|
@@ -106,47 +106,6 @@ util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
|
||||
qdf_size_t link_frame_maxsize,
|
||||
qdf_size_t *link_frame_len);
|
||||
|
||||
/**
|
||||
* util_gen_link_probe_rsp_from_assoc_rsp() - Generate link specific
|
||||
* probe response from assoc response.
|
||||
* @frame: Pointer to original association response. This should not contain the
|
||||
* 802.11 header, and must start from the fixed fields in the association
|
||||
* response. This is required due to some caller semantics built into the end to
|
||||
* end design.
|
||||
* @frame_len: Length of original association response
|
||||
* @link_id: Link ID for secondary links
|
||||
* @link_addr: Secondary link's MAC address
|
||||
* @link_frame: Generated secondary link specific association response. Note
|
||||
* that this will start from the 802.11 header (unlike the original association
|
||||
* response). This should be ignored in the case of failure.
|
||||
* @link_frame_maxsize: Maximum size of generated secondary link specific
|
||||
* association response
|
||||
* @link_frame_len: Pointer to location where populated length of generated
|
||||
* secondary link specific association response should be written. This should
|
||||
* be ignored in the case of failure.
|
||||
* @bcn_prb_ptr: Pointer to probe response of the current link on which assoc
|
||||
* response is received, This should not contain the 802.11 header, and must
|
||||
* start from the fixed fields in the probe response.
|
||||
* @bcn_prb_len: Length of probe response of @bcn_prb_ptr.
|
||||
*
|
||||
* Generate a link specific logically equivalent probe response for the
|
||||
* secondary link from the original association response containing a Multi-Link
|
||||
* element.
|
||||
* Currently, only two link MLO is supported.
|
||||
*
|
||||
* 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_gen_link_probe_rsp_from_assoc_rsp(uint8_t *frame, qdf_size_t frame_len,
|
||||
uint8_t link_id,
|
||||
struct qdf_mac_addr link_addr,
|
||||
uint8_t *link_frame,
|
||||
qdf_size_t link_frame_maxsize,
|
||||
qdf_size_t *link_frame_len,
|
||||
uint8_t *bcn_prb_ptr,
|
||||
qdf_size_t bcn_prb_len);
|
||||
|
||||
/**
|
||||
* util_gen_link_probe_rsp() - Generate link specific probe response
|
||||
* @frame: Pointer to original probe response. This should not contain the
|
||||
@@ -639,19 +598,6 @@ util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
|
||||
return QDF_STATUS_E_NOSUPPORT;
|
||||
}
|
||||
|
||||
static inline QDF_STATUS
|
||||
util_gen_link_probe_rsp_from_assoc_rsp(uint8_t *frame, qdf_size_t frame_len,
|
||||
uint8_t link_id,
|
||||
struct qdf_mac_addr link_addr,
|
||||
uint8_t *link_frame,
|
||||
qdf_size_t link_frame_maxsize,
|
||||
qdf_size_t *link_frame_len,
|
||||
uint8_t *bcn_prb_ptr,
|
||||
qdf_size_t bcn_prb_len)
|
||||
{
|
||||
return QDF_STATUS_E_NOSUPPORT;
|
||||
}
|
||||
|
||||
static inline QDF_STATUS
|
||||
util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq,
|
||||
qdf_size_t *mlieseqlen)
|
||||
|
@@ -1850,972 +1850,6 @@ util_find_bvmlie_persta_prof_for_linkid(uint8_t req_link_id,
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
|
||||
static
|
||||
QDF_STATUS util_gen_link_prb_rsp_from_assoc_rsp_cmn(uint8_t *frame,
|
||||
qdf_size_t frame_len,
|
||||
uint8_t orig_subtype,
|
||||
uint8_t gen_subtype,
|
||||
uint8_t req_link_id,
|
||||
struct qdf_mac_addr link_addr,
|
||||
uint8_t *link_frame,
|
||||
qdf_size_t link_frame_maxsize,
|
||||
qdf_size_t *link_frame_len,
|
||||
uint8_t *bcn_prb_ptr,
|
||||
qdf_size_t bcn_prb_len)
|
||||
{
|
||||
/* Pointer to Multi-Link element/Multi-Link element fragment sequence */
|
||||
uint8_t *mlieseq;
|
||||
/* Total length of Multi-Link element sequence (including fragments if
|
||||
* any)
|
||||
*/
|
||||
qdf_size_t mlieseqlen;
|
||||
/* Variant (i.e. type) of the Multi-Link element */
|
||||
enum wlan_ml_variant variant;
|
||||
|
||||
/* Length of the payload of the Multi-Link element (inclusive of
|
||||
* fragment payloads if any) without IE headers and element ID extension
|
||||
*/
|
||||
qdf_size_t mlieseqpayloadlen;
|
||||
/* Pointer to copy of the payload of the Multi-Link element (inclusive
|
||||
* of fragment payloads if any) without IE headers and element ID
|
||||
* extension
|
||||
*/
|
||||
uint8_t *mlieseqpayload_copy;
|
||||
|
||||
/* Pointer to start of Link Info within the copy of the payload of the
|
||||
* Multi-Link element
|
||||
*/
|
||||
uint8_t *link_info;
|
||||
/* Length of the Link Info */
|
||||
qdf_size_t link_info_len;
|
||||
|
||||
/* Pointer to the IE section that occurs after the fixed fields in the
|
||||
* original frame for the reporting STA.
|
||||
*/
|
||||
uint8_t *frame_iesection;
|
||||
/* Offset to the start of the IE section in the original frame for the
|
||||
* reporting STA.
|
||||
*/
|
||||
qdf_size_t frame_iesection_offset;
|
||||
/* Total length of the IE section in the original frame for the
|
||||
* reporting STA.
|
||||
*/
|
||||
qdf_size_t frame_iesection_len;
|
||||
|
||||
/* Pointer to the IEEE802.11 frame header in the link specific frame
|
||||
* being generated for the reported STA.
|
||||
*/
|
||||
struct wlan_frame_hdr *link_frame_hdr;
|
||||
/* Current position in the link specific frame being generated for the
|
||||
* reported STA.
|
||||
*/
|
||||
uint8_t *link_frame_currpos;
|
||||
/* Current length of the link specific frame being generated for the
|
||||
* reported STA.
|
||||
*/
|
||||
qdf_size_t link_frame_currlen;
|
||||
|
||||
/* Pointer to IE for reporting STA */
|
||||
const uint8_t *reportingsta_ie;
|
||||
/* Total size of IE for reporting STA, inclusive of the element header
|
||||
*/
|
||||
qdf_size_t reportingsta_ie_size;
|
||||
|
||||
/* Pointer to current position in STA profile */
|
||||
uint8_t *sta_prof_currpos;
|
||||
/* Remaining length of STA profile */
|
||||
qdf_size_t sta_prof_remlen;
|
||||
/* Pointer to start of IE section in STA profile that occurs after fixed
|
||||
* fields.
|
||||
*/
|
||||
uint8_t *sta_prof_iesection;
|
||||
/* Total length of IE section in STA profile */
|
||||
qdf_size_t sta_prof_iesection_len;
|
||||
/* Pointer to current position being processed in IE section in STA
|
||||
* profile.
|
||||
*/
|
||||
uint8_t *sta_prof_iesection_currpos;
|
||||
/* Remaining length of IE section in STA profile */
|
||||
qdf_size_t sta_prof_iesection_remlen;
|
||||
|
||||
/* Pointer to IE in STA profile, that occurs within IE section */
|
||||
uint8_t *sta_prof_ie;
|
||||
/* Total size of IE in STA profile, inclusive of the element header */
|
||||
qdf_size_t sta_prof_ie_size;
|
||||
|
||||
/* Pointer to element ID list in Non-Inheritance IE */
|
||||
uint8_t *ninherit_elemlist;
|
||||
/* Length of element ID list in Non-Inheritance IE */
|
||||
qdf_size_t ninherit_elemlist_len;
|
||||
/* Pointer to element ID extension list in Non-Inheritance IE */
|
||||
uint8_t *ninherit_elemextlist;
|
||||
/* Length of element ID extension list in Non-Inheritance IE */
|
||||
qdf_size_t ninherit_elemextlist_len;
|
||||
/* Whether a given IE is in a non-inheritance list */
|
||||
bool is_in_noninheritlist;
|
||||
|
||||
/* Whether MAC address of reported STA is valid */
|
||||
bool is_reportedmacaddr_valid;
|
||||
/* MAC address of reported STA */
|
||||
struct qdf_mac_addr reportedmacaddr;
|
||||
|
||||
/* Pointer to per-STA profile */
|
||||
uint8_t *persta_prof;
|
||||
/* Length of the containing buffer which starts with the per-STA profile
|
||||
*/
|
||||
qdf_size_t persta_prof_bufflen;
|
||||
|
||||
/* Other variables for temporary purposes */
|
||||
|
||||
/* Variable into which API for determining fragment information will
|
||||
* indicate whether the element is the start of a fragment sequence or
|
||||
* not.
|
||||
*/
|
||||
bool is_elemfragseq;
|
||||
/* De-fragmented payload length returned by API for element
|
||||
* defragmentation.
|
||||
*/
|
||||
qdf_size_t defragpayload_len;
|
||||
/* Pointer to Beacon interval in STA info field */
|
||||
uint16_t beaconinterval;
|
||||
/* Whether Beacon interval value valid */
|
||||
bool is_beaconinterval_valid;
|
||||
/* TSF offset of the reproted AP */
|
||||
uint64_t tsfoffset;
|
||||
/* TSF offset value valid */
|
||||
bool is_tsfoffset_valid;
|
||||
/* If Complete Profile or not*/
|
||||
bool is_completeprofile;
|
||||
qdf_size_t tmplen;
|
||||
QDF_STATUS ret;
|
||||
uint8_t ie_idx, linkid = 0xFF;
|
||||
/* List of IEs to add from @bcn_prb_ptr */
|
||||
uint8_t missing_ie_list[] = {WLAN_ELEMID_SSID, WLAN_ELEMID_RSN};
|
||||
/* No.of IEs in @missing_ie_list array */
|
||||
uint8_t missing_ie_len = sizeof(missing_ie_list);
|
||||
/* List of Extn IEs to add from @bcn_prb_ptr */
|
||||
uint8_t *missing_ext_ie_list = NULL;
|
||||
/* No.of IEs in @missing_ext_ie_list array */
|
||||
uint8_t missing_ext_ie_len = 0x0;
|
||||
uint8_t *bcn_prb_ies_ptr, *secondary_ie;
|
||||
qdf_size_t bcn_prb_ies_len;
|
||||
|
||||
if (!frame) {
|
||||
mlo_err("Pointer to original frame is NULL");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
if (!frame_len) {
|
||||
mlo_err("Length of original frame is zero");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
if (!link_frame) {
|
||||
mlo_err("Pointer to secondary link specific frame is NULL");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
if (!link_frame_maxsize) {
|
||||
mlo_err("Maximum size of secondary link specific frame is zero");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
if (!link_frame_len) {
|
||||
mlo_err("Pointer to populated length of secondary link specific frame is NULL");
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
frame_iesection_offset = 0;
|
||||
|
||||
/* This is a (re)association response */
|
||||
frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET;
|
||||
|
||||
if (frame_len < frame_iesection_offset) {
|
||||
/* The caller is supposed to have confirmed that this is a valid
|
||||
* frame containing a Multi-Link element. Hence we treat this as
|
||||
* a case of invalid argument being passed to us.
|
||||
*/
|
||||
mlo_err("Frame length %zu is smaller than the IE section offset %zu for orig_subtype %u",
|
||||
frame_len, frame_iesection_offset, orig_subtype);
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
frame_iesection_len = frame_len - frame_iesection_offset;
|
||||
|
||||
if (frame_iesection_len == 0) {
|
||||
/* The caller is supposed to have confirmed that this is a valid
|
||||
* frame containing a Multi-Link element. Hence we treat this as
|
||||
* a case of invalid argument being passed to us.
|
||||
*/
|
||||
mlo_err("No space left in frame for IE section");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
frame_iesection = frame + frame_iesection_offset;
|
||||
|
||||
bcn_prb_ies_ptr = bcn_prb_ptr + WLAN_PROBE_RESP_IES_OFFSET;
|
||||
bcn_prb_ies_len = bcn_prb_len - WLAN_PROBE_RESP_IES_OFFSET;
|
||||
|
||||
mlieseq = NULL;
|
||||
mlieseqlen = 0;
|
||||
|
||||
ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq,
|
||||
&mlieseqlen);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
return ret;
|
||||
|
||||
if (!mlieseq) {
|
||||
/* The caller is supposed to have confirmed that a Multi-Link
|
||||
* element is present in the frame. Hence we treat this as a
|
||||
* case of invalid argument being passed to us.
|
||||
*/
|
||||
mlo_err("Invalid original frame since no Multi-Link element found");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
/* Sanity check the Multi-Link element sequence length */
|
||||
if (!mlieseqlen) {
|
||||
mlo_err("Length of Multi-Link element sequence is zero. Investigate.");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
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_PROTO;
|
||||
}
|
||||
|
||||
ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
return ret;
|
||||
|
||||
if (variant != WLAN_ML_VARIANT_BASIC) {
|
||||
mlo_err_rl("Unexpected variant %u of Multi-Link element.",
|
||||
variant);
|
||||
return QDF_STATUS_E_PROTO;
|
||||
}
|
||||
|
||||
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 (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 per Multi-Link element search: %zu octets",
|
||||
tmplen, mlieseqlen);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
if (!mlieseqpayloadlen) {
|
||||
mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
mlo_debug("ML IE 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 (is_elemfragseq) {
|
||||
ret = wlan_defrag_elem_fragseq(false,
|
||||
mlieseq,
|
||||
mlieseqlen,
|
||||
mlieseqpayload_copy,
|
||||
mlieseqpayloadlen,
|
||||
&defragpayload_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
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);
|
||||
ret = QDF_STATUS_E_FAILURE;
|
||||
goto mem_free;
|
||||
}
|
||||
} else {
|
||||
qdf_mem_copy(mlieseqpayload_copy,
|
||||
mlieseq + sizeof(struct ie_header) + 1,
|
||||
mlieseqpayloadlen);
|
||||
}
|
||||
|
||||
link_info = NULL;
|
||||
link_info_len = 0;
|
||||
|
||||
ret = util_parse_multi_link_ctrl(mlieseqpayload_copy,
|
||||
mlieseqpayloadlen,
|
||||
&link_info,
|
||||
&link_info_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
/* As per the standard, the sender must include Link Info for
|
||||
* association request/response. Throw an error if we are unable to
|
||||
* obtain this.
|
||||
*/
|
||||
if (!link_info) {
|
||||
mlo_err_rl("Unable to successfully obtain Link Info");
|
||||
ret = QDF_STATUS_E_PROTO;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
/* Note: We may have a future change to skip subelements which are not
|
||||
* Per-STA Profile, handle more than two links in MLO, handle cases
|
||||
* where we unexpectedly find more Per-STA Profiles than expected, etc.
|
||||
*/
|
||||
|
||||
persta_prof = NULL;
|
||||
persta_prof_bufflen = 0;
|
||||
|
||||
ret = util_find_bvmlie_persta_prof_for_linkid(req_link_id,
|
||||
link_info,
|
||||
link_info_len,
|
||||
&persta_prof,
|
||||
&persta_prof_bufflen);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||
mlo_err_rl("Per STA profile not found for link id %d",
|
||||
req_link_id);
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
sta_prof_remlen = 0;
|
||||
sta_prof_currpos = NULL;
|
||||
is_reportedmacaddr_valid = false;
|
||||
is_beaconinterval_valid = false;
|
||||
is_completeprofile = false;
|
||||
is_tsfoffset_valid = false;
|
||||
|
||||
/* Parse per-STA profile */
|
||||
ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof +
|
||||
sizeof(struct subelem_header),
|
||||
persta_prof_bufflen,
|
||||
&linkid,
|
||||
&beaconinterval,
|
||||
&is_beaconinterval_valid,
|
||||
&tsfoffset,
|
||||
&is_tsfoffset_valid,
|
||||
&is_completeprofile,
|
||||
&is_reportedmacaddr_valid,
|
||||
&reportedmacaddr,
|
||||
true,
|
||||
&sta_prof_currpos,
|
||||
&sta_prof_remlen,
|
||||
NULL,
|
||||
NULL);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
if (!is_completeprofile) {
|
||||
mlo_err("Complete profile information is not present in per-STA profile");
|
||||
ret = QDF_STATUS_E_NOSUPPORT;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
/* We double check for a NULL STA Profile, though the helper function
|
||||
* above would have taken care of this. We need to get a non-NULL STA
|
||||
* profile, because we need to get at least the expected fixed fields,
|
||||
* even if there is an (improbable) total inheritance.
|
||||
*/
|
||||
if (!sta_prof_currpos) {
|
||||
mlo_err_rl("STA profile is NULL");
|
||||
ret = QDF_STATUS_E_PROTO;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
/* As per the standard, the sender sets the MAC address in the per-STA
|
||||
* profile in association request/response. Without this, we cannot
|
||||
* generate the link specific frame.
|
||||
*/
|
||||
if (!is_reportedmacaddr_valid) {
|
||||
mlo_err_rl("Unable to get MAC address from per-STA profile");
|
||||
ret = QDF_STATUS_E_PROTO;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
link_frame_currpos = link_frame;
|
||||
*link_frame_len = 0;
|
||||
link_frame_currlen = 0;
|
||||
|
||||
if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) {
|
||||
mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets",
|
||||
WLAN_MAC_HDR_LEN_3A, link_frame_maxsize);
|
||||
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
link_frame_currpos += WLAN_MAC_HDR_LEN_3A;
|
||||
link_frame_currlen += WLAN_MAC_HDR_LEN_3A;
|
||||
|
||||
/* This is a (re)association response */
|
||||
mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame");
|
||||
if (sta_prof_remlen < (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
|
||||
mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u",
|
||||
sta_prof_remlen,
|
||||
WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN);
|
||||
|
||||
ret = QDF_STATUS_E_PROTO;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
/* TODO: */
|
||||
qdf_mem_copy(link_frame_currpos, bcn_prb_ptr, WLAN_TIMESTAMP_LEN);
|
||||
link_frame_currpos += WLAN_TIMESTAMP_LEN;
|
||||
link_frame_currlen += WLAN_TIMESTAMP_LEN;
|
||||
|
||||
if (is_beaconinterval_valid) {
|
||||
qdf_mem_copy(link_frame_currpos, &beaconinterval,
|
||||
WLAN_BEACONINTERVAL_LEN);
|
||||
} else {
|
||||
/* Use the BI from input frame if per-STA doesn't have valid
|
||||
* BI
|
||||
*/
|
||||
qdf_mem_copy(link_frame_currpos,
|
||||
bcn_prb_ptr + WLAN_TIMESTAMP_LEN,
|
||||
WLAN_BEACONINTERVAL_LEN);
|
||||
}
|
||||
link_frame_currpos += WLAN_BEACONINTERVAL_LEN;
|
||||
link_frame_currlen += WLAN_BEACONINTERVAL_LEN;
|
||||
|
||||
/* Capability information and Status Code are specific to the
|
||||
* link. Copy these from the STA profile.
|
||||
*/
|
||||
|
||||
if ((link_frame_maxsize - link_frame_currlen) <
|
||||
WLAN_CAPABILITYINFO_LEN) {
|
||||
mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets",
|
||||
WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN,
|
||||
(link_frame_maxsize - link_frame_currlen));
|
||||
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
|
||||
WLAN_CAPABILITYINFO_LEN);
|
||||
link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
|
||||
link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
|
||||
mlo_debug("Added Capability Info (%u octets) to link specific frame",
|
||||
WLAN_CAPABILITYINFO_LEN);
|
||||
|
||||
sta_prof_currpos += WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN;
|
||||
sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN;
|
||||
|
||||
sta_prof_iesection = sta_prof_currpos;
|
||||
sta_prof_iesection_len = sta_prof_remlen;
|
||||
|
||||
/* Populate non-inheritance lists if applicable */
|
||||
ninherit_elemlist_len = 0;
|
||||
ninherit_elemlist = NULL;
|
||||
ninherit_elemextlist_len = 0;
|
||||
ninherit_elemextlist = NULL;
|
||||
|
||||
ret = util_get_noninheritlists(sta_prof_iesection,
|
||||
sta_prof_iesection_len,
|
||||
&ninherit_elemlist,
|
||||
&ninherit_elemlist_len,
|
||||
&ninherit_elemextlist,
|
||||
&ninherit_elemextlist_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
/* Go through IEs of the reporting STA, and those in STA profile, merge
|
||||
* them into link_frame (except for elements in the Non-Inheritance
|
||||
* list).
|
||||
*
|
||||
* Note: Currently, only 2-link MLO is supported here. We may have a
|
||||
* future change to expand to more links.
|
||||
*/
|
||||
reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection,
|
||||
frame_iesection_len);
|
||||
|
||||
/* This is a (re)association response. Sanity check that the
|
||||
* SSID element is present neither for the reporting STA nor in
|
||||
* the STA profile.
|
||||
*/
|
||||
if (reportingsta_ie) {
|
||||
mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present.");
|
||||
ret = QDF_STATUS_E_PROTO;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID,
|
||||
sta_prof_iesection,
|
||||
sta_prof_iesection_len);
|
||||
|
||||
if (sta_prof_ie) {
|
||||
mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present.");
|
||||
ret = QDF_STATUS_E_PROTO;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection;
|
||||
|
||||
ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection,
|
||||
frame_iesection_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
|
||||
|
||||
while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection)
|
||||
<= frame_iesection_len) {
|
||||
if (reportingsta_ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
|
||||
for (ie_idx = 0; ie_idx < missing_ie_len; ie_idx++) {
|
||||
if (missing_ie_list[ie_idx] ==
|
||||
reportingsta_ie[ID_POS]) {
|
||||
missing_ie_list[ie_idx] =
|
||||
WLAN_ELEMID_EXTN_ELEM;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ie_idx = 0; ie_idx < missing_ext_ie_len; ie_idx++) {
|
||||
if (missing_ext_ie_list[ie_idx] ==
|
||||
reportingsta_ie[IDEXT_POS]) {
|
||||
missing_ext_ie_list[ie_idx] =
|
||||
WLAN_ELEMID_EXTN_ELEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip Multi-Link element */
|
||||
if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
|
||||
(reportingsta_ie[IDEXT_POS] ==
|
||||
WLAN_EXTN_ELEMID_MULTI_LINK)) {
|
||||
if (((reportingsta_ie + reportingsta_ie_size) -
|
||||
frame_iesection) == frame_iesection_len)
|
||||
break;
|
||||
|
||||
/* Add BV ML IE for link specific probe response */
|
||||
ret = util_add_mlie_for_prb_rsp_gen(
|
||||
reportingsta_ie,
|
||||
reportingsta_ie[TAG_LEN_POS],
|
||||
&link_frame_currpos,
|
||||
&link_frame_currlen,
|
||||
link_frame_maxsize,
|
||||
linkid);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
reportingsta_ie += reportingsta_ie_size;
|
||||
|
||||
ret = util_validate_reportingsta_ie(reportingsta_ie,
|
||||
frame_iesection,
|
||||
frame_iesection_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
|
||||
MIN_IE_LEN;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
sta_prof_ie = NULL;
|
||||
sta_prof_ie_size = 0;
|
||||
|
||||
if (sta_prof_iesection_len) {
|
||||
if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
|
||||
sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS],
|
||||
reportingsta_ie[IDEXT_POS],
|
||||
sta_prof_iesection,
|
||||
sta_prof_iesection_len);
|
||||
} else {
|
||||
sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS],
|
||||
sta_prof_iesection,
|
||||
sta_prof_iesection_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sta_prof_ie) {
|
||||
/* IE is present for reporting STA, but not in STA
|
||||
* profile.
|
||||
*/
|
||||
|
||||
is_in_noninheritlist = false;
|
||||
|
||||
ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie,
|
||||
reportingsta_ie_size,
|
||||
ninherit_elemlist,
|
||||
ninherit_elemlist_len,
|
||||
ninherit_elemextlist,
|
||||
ninherit_elemextlist_len,
|
||||
&is_in_noninheritlist);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
if (!is_in_noninheritlist) {
|
||||
if ((link_frame_currpos +
|
||||
reportingsta_ie_size) <=
|
||||
(link_frame + link_frame_maxsize)) {
|
||||
qdf_mem_copy(link_frame_currpos,
|
||||
reportingsta_ie,
|
||||
reportingsta_ie_size);
|
||||
|
||||
link_frame_currpos +=
|
||||
reportingsta_ie_size;
|
||||
link_frame_currlen +=
|
||||
reportingsta_ie_size;
|
||||
|
||||
if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) present for reporting STA but not in STA profile. Copied IE from reporting frame to link specific frame",
|
||||
reportingsta_ie[ID_POS],
|
||||
reportingsta_ie[IDEXT_POS],
|
||||
reportingsta_ie_size);
|
||||
} else {
|
||||
mlo_etrace_debug("IE with element ID : %u (%zu octets) present for reporting STA but not in STA profile. Copied IE from reporting frame to link specific frame",
|
||||
reportingsta_ie[ID_POS],
|
||||
reportingsta_ie_size);
|
||||
}
|
||||
} else {
|
||||
if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
reportingsta_ie[ID_POS],
|
||||
reportingsta_ie[IDEXT_POS],
|
||||
reportingsta_ie_size,
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
} else {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
reportingsta_ie[ID_POS],
|
||||
reportingsta_ie_size,
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
}
|
||||
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto mem_free;
|
||||
}
|
||||
} else {
|
||||
if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) present for reporting STA but not in STA profile. However it is in Non-Inheritance list, hence ignoring.",
|
||||
reportingsta_ie[ID_POS],
|
||||
reportingsta_ie[IDEXT_POS],
|
||||
reportingsta_ie_size);
|
||||
} else {
|
||||
mlo_etrace_debug("IE with element ID : %u (%zu octets) present for reporting STA but not in STA profile. However it is in Non-Inheritance list, hence ignoring.",
|
||||
reportingsta_ie[ID_POS],
|
||||
reportingsta_ie_size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* IE is present for reporting STA and also in STA
|
||||
* profile, copy from STA profile and flag the IE in STA
|
||||
* profile as copied (by setting EID field to 0). The
|
||||
* SSID element (with EID 0) is processed first to
|
||||
* enable this. For vendor IE, compare OUI + type +
|
||||
* subType to determine if they are the same IE.
|
||||
*/
|
||||
/* Note: This may be revisited in a future change, to
|
||||
* adhere to provisions in the standard for multiple
|
||||
* occurrences of a given element ID/extension element
|
||||
* ID.
|
||||
*/
|
||||
|
||||
ret = util_validate_sta_prof_ie(sta_prof_ie,
|
||||
sta_prof_iesection,
|
||||
sta_prof_iesection_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] +
|
||||
MIN_IE_LEN;
|
||||
|
||||
sta_prof_iesection_remlen =
|
||||
sta_prof_iesection_len -
|
||||
(sta_prof_ie - sta_prof_iesection);
|
||||
|
||||
if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
|
||||
(sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) {
|
||||
/* If Vendor IE also presents in STA profile,
|
||||
* then ignore the Vendor IE which is for
|
||||
* reporting STA. It only needs to copy Vendor
|
||||
* IE from STA profile to link specific frame.
|
||||
* The copy happens when going through the
|
||||
* remaining IEs.
|
||||
*/
|
||||
;
|
||||
} else {
|
||||
/* Copy IE from STA profile into link specific
|
||||
* frame.
|
||||
*/
|
||||
if ((link_frame_currpos + sta_prof_ie_size) <=
|
||||
(link_frame + link_frame_maxsize)) {
|
||||
qdf_mem_copy(link_frame_currpos,
|
||||
sta_prof_ie,
|
||||
sta_prof_ie_size);
|
||||
|
||||
link_frame_currpos += sta_prof_ie_size;
|
||||
link_frame_currlen +=
|
||||
sta_prof_ie_size;
|
||||
|
||||
if (reportingsta_ie[ID_POS] ==
|
||||
WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie[IDEXT_POS],
|
||||
sta_prof_ie_size);
|
||||
} else {
|
||||
mlo_etrace_debug("IE with element ID : %u (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie_size);
|
||||
}
|
||||
|
||||
sta_prof_ie[0] = 0;
|
||||
} else {
|
||||
if (sta_prof_ie[ID_POS] ==
|
||||
WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie[IDEXT_POS],
|
||||
sta_prof_ie_size,
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
} else {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie_size,
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
}
|
||||
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto mem_free;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((reportingsta_ie + reportingsta_ie_size) -
|
||||
frame_iesection) == frame_iesection_len)
|
||||
break;
|
||||
|
||||
reportingsta_ie += reportingsta_ie_size;
|
||||
|
||||
ret = util_validate_reportingsta_ie(reportingsta_ie,
|
||||
frame_iesection,
|
||||
frame_iesection_len);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
|
||||
MIN_IE_LEN;
|
||||
}
|
||||
|
||||
/* Go through the remaining unprocessed IEs in STA profile and copy them
|
||||
* to the link specific frame. The processed ones are marked with 0 in
|
||||
* the first octet. The first octet corresponds to the element ID. In
|
||||
* the case of (re)association request, the element with actual ID
|
||||
* WLAN_ELEMID_SSID(0) has already been copied to the link specific
|
||||
* frame. In the case of (re)association response, it has been verified
|
||||
* that the element with actual ID WLAN_ELEMID_SSID(0) is present
|
||||
* neither for the reporting STA nor in the STA profile.
|
||||
*/
|
||||
sta_prof_iesection_currpos = sta_prof_iesection;
|
||||
sta_prof_iesection_remlen = sta_prof_iesection_len;
|
||||
|
||||
while (sta_prof_iesection_remlen > 0) {
|
||||
sta_prof_ie = sta_prof_iesection_currpos;
|
||||
ret = util_validate_sta_prof_ie(sta_prof_ie,
|
||||
sta_prof_iesection_currpos,
|
||||
sta_prof_iesection_remlen);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
goto mem_free;
|
||||
|
||||
sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
|
||||
|
||||
if (!sta_prof_ie[0] || (sta_prof_ie[0] == 0xff && sta_prof_ie[1] > 0 && sta_prof_ie[2] == 0x38)) {
|
||||
/* Skip this, since it has already been processed
|
||||
* or it is non inheritance IE which is not required
|
||||
*/
|
||||
sta_prof_iesection_currpos += sta_prof_ie_size;
|
||||
sta_prof_iesection_remlen -= sta_prof_ie_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Copy IE from STA profile into link specific frame. */
|
||||
if ((link_frame_currpos + sta_prof_ie_size) <=
|
||||
(link_frame + link_frame_maxsize)) {
|
||||
if (sta_prof_ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
|
||||
for (ie_idx = 0; ie_idx < missing_ie_len; ie_idx++) {
|
||||
if (missing_ie_list[ie_idx] ==
|
||||
sta_prof_ie[ID_POS]) {
|
||||
missing_ie_list[ie_idx] =
|
||||
WLAN_ELEMID_EXTN_ELEM;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ie_idx = 0; ie_idx < missing_ext_ie_len; ie_idx++) {
|
||||
if (missing_ext_ie_list[ie_idx] ==
|
||||
sta_prof_ie[IDEXT_POS]) {
|
||||
missing_ext_ie_list[ie_idx] =
|
||||
WLAN_ELEMID_EXTN_ELEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qdf_mem_copy(link_frame_currpos,
|
||||
sta_prof_ie,
|
||||
sta_prof_ie_size);
|
||||
|
||||
link_frame_currpos += sta_prof_ie_size;
|
||||
link_frame_currlen +=
|
||||
sta_prof_ie_size;
|
||||
|
||||
if (reportingsta_ie[ID_POS] ==
|
||||
WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_debug("IE with element ID : %u extension element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie[IDEXT_POS],
|
||||
sta_prof_ie_size);
|
||||
} else {
|
||||
mlo_etrace_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie_size);
|
||||
}
|
||||
|
||||
sta_prof_ie[0] = 0;
|
||||
} else {
|
||||
if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie[IDEXT_POS],
|
||||
sta_prof_ie_size,
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
} else {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
sta_prof_ie[ID_POS],
|
||||
sta_prof_ie_size,
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
}
|
||||
|
||||
ret = QDF_STATUS_E_NOMEM;
|
||||
goto mem_free;
|
||||
}
|
||||
|
||||
sta_prof_iesection_currpos += sta_prof_ie_size;
|
||||
sta_prof_iesection_remlen -= sta_prof_ie_size;
|
||||
}
|
||||
|
||||
/* Copy missing IEs from probe resp of original link */
|
||||
for (ie_idx = 0; ie_idx < missing_ie_len; ie_idx++) {
|
||||
if (missing_ie_list[ie_idx] == WLAN_ELEMID_EXTN_ELEM)
|
||||
continue;
|
||||
|
||||
secondary_ie = util_find_eid(missing_ie_list[ie_idx],
|
||||
bcn_prb_ies_ptr, bcn_prb_ies_len);
|
||||
if (!secondary_ie) {
|
||||
mlo_etrace_err_rl("IE %u not found in secondary probe resp buffer",
|
||||
missing_ie_list[ie_idx]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((link_frame_currpos + secondary_ie[TAG_LEN_POS]) >
|
||||
(link_frame + link_frame_maxsize)) {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
secondary_ie[ID_POS],
|
||||
secondary_ie[TAG_LEN_POS],
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
qdf_mem_copy(link_frame_currpos, secondary_ie,
|
||||
secondary_ie[TAG_LEN_POS] + MIN_IE_LEN);
|
||||
link_frame_currpos += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
|
||||
link_frame_currlen += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
|
||||
}
|
||||
|
||||
/* Copy missing extn IEs from probe resp of original link */
|
||||
for (ie_idx = 0; ie_idx < missing_ext_ie_len; ie_idx++) {
|
||||
if (missing_ext_ie_list[ie_idx] == WLAN_ELEMID_EXTN_ELEM)
|
||||
continue;
|
||||
|
||||
secondary_ie = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
|
||||
missing_ext_ie_list[ie_idx],
|
||||
bcn_prb_ies_ptr,
|
||||
bcn_prb_ies_len);
|
||||
if (!secondary_ie) {
|
||||
mlo_etrace_err_rl("Extn IE %u not found in secondary probe resp buffer",
|
||||
missing_iext_ie_list[ie_idx]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((link_frame_currpos + secondary_ie[TAG_LEN_POS]) >
|
||||
(link_frame + link_frame_maxsize)) {
|
||||
mlo_etrace_err_rl("Insufficient space in link specific frame for IE with extn element ID : %u. Required: %zu octets, available: %zu octets",
|
||||
secondary_ie[IDEXT_POS],
|
||||
secondary_ie[TAG_LEN_POS],
|
||||
link_frame_maxsize -
|
||||
link_frame_currlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
qdf_mem_copy(link_frame_currpos, secondary_ie,
|
||||
secondary_ie[TAG_LEN_POS] + MIN_IE_LEN);
|
||||
link_frame_currpos += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
|
||||
link_frame_currlen += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
|
||||
}
|
||||
|
||||
/* Copy the link MAC addr */
|
||||
link_frame_hdr = (struct wlan_frame_hdr *)link_frame;
|
||||
|
||||
qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
|
||||
QDF_MAC_ADDR_SIZE);
|
||||
qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
|
||||
QDF_MAC_ADDR_SIZE);
|
||||
qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, QDF_MAC_ADDR_SIZE);
|
||||
|
||||
link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0;
|
||||
link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1;
|
||||
|
||||
mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:"
|
||||
QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT,
|
||||
gen_subtype,
|
||||
QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3),
|
||||
QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2),
|
||||
QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1));
|
||||
|
||||
/* Seq num not used so not populated */
|
||||
|
||||
*link_frame_len = link_frame_currlen;
|
||||
|
||||
qdf_err("Generated ML Probe from assoc resp");
|
||||
qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
|
||||
link_frame, link_frame_currlen);
|
||||
|
||||
ret = QDF_STATUS_SUCCESS;
|
||||
|
||||
mem_free:
|
||||
qdf_mem_free(mlieseqpayload_copy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len,
|
||||
uint8_t subtype,
|
||||
@@ -3927,25 +2961,6 @@ util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
|
||||
link_frame_maxsize, link_frame_len);
|
||||
}
|
||||
|
||||
QDF_STATUS
|
||||
util_gen_link_probe_rsp_from_assoc_rsp(uint8_t *frame, qdf_size_t frame_len,
|
||||
uint8_t link_id, struct qdf_mac_addr link_addr,
|
||||
uint8_t *link_frame, qdf_size_t link_frame_maxsize,
|
||||
qdf_size_t *link_frame_len,
|
||||
uint8_t *bcn_prb_ptr,
|
||||
qdf_size_t bcn_prb_len)
|
||||
{
|
||||
return util_gen_link_prb_rsp_from_assoc_rsp_cmn(frame, frame_len,
|
||||
WLAN_FC0_STYPE_ASSOC_RESP,
|
||||
WLAN_FC0_STYPE_PROBE_RESP,
|
||||
link_id, link_addr,
|
||||
link_frame,
|
||||
link_frame_maxsize,
|
||||
link_frame_len,
|
||||
bcn_prb_ptr,
|
||||
bcn_prb_len);
|
||||
}
|
||||
|
||||
QDF_STATUS
|
||||
util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
|
||||
uint8_t link_id,
|
||||
|
@@ -529,8 +529,6 @@ struct reduced_neighbor_report {
|
||||
* @ecsa_ie: Pointer to eCSA IE
|
||||
* @max_cst_ie: Pointer to Max Channel Switch Time IE
|
||||
* @is_valid_link: The partner link can be used if true
|
||||
* @is_scan_entry_not_found: If set to true, the partner link scan entry is
|
||||
* not present in scan DB (currently using for non-TxMBSSID MLO AP)
|
||||
* @op_class: Operating class
|
||||
*/
|
||||
struct partner_link_info {
|
||||
@@ -542,7 +540,6 @@ struct partner_link_info {
|
||||
const uint8_t *ecsa_ie;
|
||||
const uint8_t *max_cst_ie;
|
||||
bool is_valid_link;
|
||||
bool is_scan_entry_not_found;
|
||||
uint8_t op_class;
|
||||
};
|
||||
|
||||
|
Referens i nytt ärende
Block a user