|
@@ -2373,9 +2373,163 @@ static void util_parse_noninheritance_list(uint8_t *extn_elem,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef WLAN_FEATURE_11BE_MLO
|
|
|
|
+/**
|
|
|
|
+ * util_handle_rnr_ie_for_mbssid() - parse and modify RNR IE for MBSSID feature
|
|
|
|
+ * @rnr: The pointer to RNR IE
|
|
|
|
+ * @bssid_index: BSSID index from MBSSID index IE
|
|
|
|
+ * @pos: The buffer pointer to save the transformed RNR IE, caller is expected
|
|
|
|
+ * to supply a buffer that is at least as big as @rnr
|
|
|
|
+ *
|
|
|
|
+ * Per the description about Neighbor AP Information field about MLD
|
|
|
|
+ * parameters subfield in section 9.4.2.170.2 of Draft P802.11be_D1.4.
|
|
|
|
+ * If the reported AP is affiliated with the same MLD of the reporting AP,
|
|
|
|
+ * the TBTT information is skipped; If the reported AP is affiliated with
|
|
|
|
+ * the same MLD of the nontransmitted BSSID, the TBTT information is
|
|
|
|
+ * copied and the MLD ID is changed to 0.
|
|
|
|
+ *
|
|
|
|
+ * Return: Length of the element written to @pos
|
|
|
|
+ */
|
|
|
|
+static int util_handle_rnr_ie_for_mbssid(const uint8_t *rnr,
|
|
|
|
+ uint8_t bssid_index, uint8_t *pos)
|
|
|
|
+{
|
|
|
|
+ size_t rnr_len;
|
|
|
|
+ const uint8_t *data, *rnr_end;
|
|
|
|
+ uint8_t *rnr_new;
|
|
|
|
+ struct neighbor_ap_info_field *neighbor_ap_info;
|
|
|
|
+ struct rnr_mld_info *mld_param;
|
|
|
|
+ uint8_t tbtt_type, tbtt_len, tbtt_count;
|
|
|
|
+ uint8_t mld_pos, mld_id;
|
|
|
|
+ int32_t i, copy_len;
|
|
|
|
+ /* The count of TBTT info field whose MLD ID equals to 0 in a neighbor
|
|
|
|
+ * AP information field.
|
|
|
|
+ */
|
|
|
|
+ uint32_t tbtt_info_field_count;
|
|
|
|
+ /* The total bytes of TBTT info fields whose MLD ID equals to 0 in
|
|
|
|
+ * current RNR IE.
|
|
|
|
+ */
|
|
|
|
+ uint32_t tbtt_info_field_len = 0;
|
|
|
|
+ uint8_t nbr_ap_info_len = sizeof(struct neighbor_ap_info_field);
|
|
|
|
+
|
|
|
|
+ rnr_len = rnr[TAG_LEN_POS];
|
|
|
|
+ rnr_end = rnr + rnr_len + MIN_IE_LEN;
|
|
|
|
+ rnr_new = pos;
|
|
|
|
+ qdf_mem_copy(pos, rnr, MIN_IE_LEN);
|
|
|
|
+ pos += MIN_IE_LEN;
|
|
|
|
+
|
|
|
|
+ data = rnr + PAYLOAD_START_POS;
|
|
|
|
+ while (data < rnr_end) {
|
|
|
|
+ neighbor_ap_info = (struct neighbor_ap_info_field *)data;
|
|
|
|
+ tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count;
|
|
|
|
+ tbtt_len = neighbor_ap_info->tbtt_header.tbtt_info_length;
|
|
|
|
+ tbtt_type = neighbor_ap_info->tbtt_header.tbbt_info_fieldtype;
|
|
|
|
+ scm_debug("channel number %d, op class %d, bssid_index %d",
|
|
|
|
+ neighbor_ap_info->channel_number,
|
|
|
|
+ neighbor_ap_info->operting_class, bssid_index);
|
|
|
|
+ scm_debug("tbtt_count %d, tbtt_length %d, tbtt_type %d",
|
|
|
|
+ tbtt_count, tbtt_len, tbtt_type);
|
|
|
|
+
|
|
|
|
+ copy_len = tbtt_len * (tbtt_count + 1) +
|
|
|
|
+ nbr_ap_info_len;
|
|
|
|
+ if (data + copy_len > rnr_end)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (tbtt_len >=
|
|
|
|
+ TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM)
|
|
|
|
+ mld_pos =
|
|
|
|
+ TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD;
|
|
|
|
+ else
|
|
|
|
+ mld_pos = 0;
|
|
|
|
+
|
|
|
|
+ /* If MLD params do not exist, copy this neighbor AP
|
|
|
|
+ * information field.
|
|
|
|
+ * Per Draft P802.11be_D1.4, tbtt_type value 1, 2 and 3
|
|
|
|
+ * are reserved,
|
|
|
|
+ */
|
|
|
|
+ if (mld_pos == 0 || tbtt_type != 0) {
|
|
|
|
+ scm_debug("no MLD params, tbtt_type %d", tbtt_type);
|
|
|
|
+ qdf_mem_copy(pos, data, copy_len);
|
|
|
|
+ pos += copy_len;
|
|
|
|
+ data += copy_len;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ qdf_mem_copy(pos, data, nbr_ap_info_len);
|
|
|
|
+ neighbor_ap_info = (struct neighbor_ap_info_field *)pos;
|
|
|
|
+ pos += nbr_ap_info_len;
|
|
|
|
+ data += nbr_ap_info_len;
|
|
|
|
+
|
|
|
|
+ tbtt_info_field_count = 0;
|
|
|
|
+ for (i = 0; i < tbtt_count + 1; i++) {
|
|
|
|
+ mld_param = (struct rnr_mld_info *)&data[mld_pos];
|
|
|
|
+ mld_id = mld_param->mld_id;
|
|
|
|
+
|
|
|
|
+ /* Refer to Draft P802.11be_D1.4
|
|
|
|
+ * 9.4.2.170.2 Neighbor AP Information field about
|
|
|
|
+ * MLD parameters subfield
|
|
|
|
+ */
|
|
|
|
+ if (mld_id == 0) {
|
|
|
|
+ /* Skip this TBTT information since this
|
|
|
|
+ * reported AP is affiliated with the same MLD
|
|
|
|
+ * of the reporting AP who sending the frame
|
|
|
|
+ * carrying this element.
|
|
|
|
+ */
|
|
|
|
+ tbtt_info_field_len += tbtt_len;
|
|
|
|
+ data += tbtt_len;
|
|
|
|
+ tbtt_info_field_count++;
|
|
|
|
+ } else if (mld_id == bssid_index) {
|
|
|
|
+ /* Copy this TBTT information and change MLD
|
|
|
|
+ * to 0 as this reported AP is affiliated with
|
|
|
|
+ * the same MLD of the nontransmitted BSSID.
|
|
|
|
+ */
|
|
|
|
+ qdf_mem_copy(pos, data, tbtt_len);
|
|
|
|
+ mld_param =
|
|
|
|
+ (struct rnr_mld_info *)&pos[mld_pos];
|
|
|
|
+ scm_debug("change MLD ID from %d to 0",
|
|
|
|
+ mld_param->mld_id);
|
|
|
|
+ mld_param->mld_id = 0;
|
|
|
|
+ data += tbtt_len;
|
|
|
|
+ pos += tbtt_len;
|
|
|
|
+ } else {
|
|
|
|
+ qdf_mem_copy(pos, data, tbtt_len);
|
|
|
|
+ data += tbtt_len;
|
|
|
|
+ pos += tbtt_len;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ scm_debug("skip %d neighbor info", tbtt_info_field_count);
|
|
|
|
+ if (tbtt_info_field_count == (tbtt_count + 1)) {
|
|
|
|
+ /* If all the TBTT information are skipped, then also
|
|
|
|
+ * revert the neighbor AP info which has been copied.
|
|
|
|
+ */
|
|
|
|
+ pos -= nbr_ap_info_len;
|
|
|
|
+ tbtt_info_field_len += nbr_ap_info_len;
|
|
|
|
+ } else {
|
|
|
|
+ neighbor_ap_info->tbtt_header.tbtt_info_count -=
|
|
|
|
+ tbtt_info_field_count;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rnr_new[TAG_LEN_POS] = rnr_len - tbtt_info_field_len;
|
|
|
|
+ if (rnr_new[TAG_LEN_POS] > 0)
|
|
|
|
+ rnr_len = rnr_new[TAG_LEN_POS] + MIN_IE_LEN;
|
|
|
|
+ else
|
|
|
|
+ rnr_len = 0;
|
|
|
|
+
|
|
|
|
+ return rnr_len;
|
|
|
|
+}
|
|
|
|
+#else
|
|
|
|
+static int util_handle_rnr_ie_for_mbssid(const uint8_t *rnr,
|
|
|
|
+ uint8_t bssid_index, uint8_t *pos)
|
|
|
|
+{
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
|
|
static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
|
|
uint8_t *subelement,
|
|
uint8_t *subelement,
|
|
- size_t subie_len, uint8_t *new_ie)
|
|
|
|
|
|
+ size_t subie_len, uint8_t *new_ie,
|
|
|
|
+ uint8_t bssid_index)
|
|
{
|
|
{
|
|
uint8_t *pos, *tmp;
|
|
uint8_t *pos, *tmp;
|
|
const uint8_t *tmp_old, *tmp_new;
|
|
const uint8_t *tmp_old, *tmp_new;
|
|
@@ -2450,7 +2604,13 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
|
|
subie_len);
|
|
subie_len);
|
|
if (!tmp) {
|
|
if (!tmp) {
|
|
/* ie in old ie but not in subelement */
|
|
/* ie in old ie but not in subelement */
|
|
- if (tmp_old[0] != WLAN_ELEMID_MULTIPLE_BSSID) {
|
|
|
|
|
|
+ if (tmp_old[0] == WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT) {
|
|
|
|
+ /* handle rnr ie for mbssid*/
|
|
|
|
+ pos +=
|
|
|
|
+ util_handle_rnr_ie_for_mbssid(tmp_old,
|
|
|
|
+ bssid_index,
|
|
|
|
+ pos);
|
|
|
|
+ } else if (tmp_old[0] != WLAN_ELEMID_MULTIPLE_BSSID) {
|
|
if ((pos + tmp_old[1] + MIN_IE_LEN) <=
|
|
if ((pos + tmp_old[1] + MIN_IE_LEN) <=
|
|
(new_ie + ielen)) {
|
|
(new_ie + ielen)) {
|
|
qdf_mem_copy(pos, tmp_old,
|
|
qdf_mem_copy(pos, tmp_old,
|
|
@@ -2901,7 +3061,8 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
|
|
util_gen_new_ie(ie, ielen,
|
|
util_gen_new_ie(ie, ielen,
|
|
(nontx_profile +
|
|
(nontx_profile +
|
|
PAYLOAD_START_POS),
|
|
PAYLOAD_START_POS),
|
|
- subie_len, new_ie);
|
|
|
|
|
|
+ subie_len, new_ie,
|
|
|
|
+ mbssid_info.profile_num);
|
|
|
|
|
|
if (!new_ie_len) {
|
|
if (!new_ie_len) {
|
|
if (mbssid_info.split_prof_continue) {
|
|
if (mbssid_info.split_prof_continue) {
|