Bläddra i källkod

qcacmn: Add Non-inheritance IE support on STA

If there is any non-inheritance element present as part of the
nontransmitted BSSID profile then while generating scan entry
for that profile, driver need not inherit those list of
element IDs and list of element ID extensions from the
transmitted BSSID profile.

Since non-inheritance element is an element ID extension, it
should be part of extension element. So the logic we use over
here is to find if there are any extension element present in
the nontransmitted BSSID profile. if yes, then only go ahead
with below logic or else go with the normal flow.

Logic:
Mark and store the start of the list of element IDs and
list of Element ID extension.
While generating the new ie for the non transmitted BSSID
profile, do not inherit the IEs present in the above
mentioned lists.

Change-Id: I466afa8273e841b6f7656b1dc59342bc2d4f13bc
CRs-Fixed: 2883389
Adwait Nayak 4 år sedan
förälder
incheckning
4eea90754c

+ 2 - 0
umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h

@@ -461,6 +461,7 @@ enum element_ie {
  * @WLAN_EXTN_ELEMID_MUEDCA: MU-EDCA IE
  * @WLAN_EXTN_ELEMID_HE_6G_CAP: HE 6GHz Band Capabilities IE
  * @WLAN_EXTN_ELEMID_SRP:    spatial reuse parameter IE
+ * @WLAN_EXTN_ELEMID_NONINHERITANCE: Non inheritance IE
  */
 enum extn_element_ie {
 	WLAN_EXTN_ELEMID_MAX_CHAN_SWITCH_TIME = 34,
@@ -468,6 +469,7 @@ enum extn_element_ie {
 	WLAN_EXTN_ELEMID_HEOP        = 36,
 	WLAN_EXTN_ELEMID_MUEDCA      = 38,
 	WLAN_EXTN_ELEMID_SRP         = 39,
+	WLAN_EXTN_ELEMID_NONINHERITANCE = 56,
 	WLAN_EXTN_ELEMID_HE_6G_CAP   = 59,
 	WLAN_EXTN_ELEMID_ESP         = 11,
 };

+ 29 - 2
umac/scan/dispatcher/inc/wlan_scan_public_structs.h

@@ -63,7 +63,7 @@ typedef uint32_t wlan_scan_id;
 /**
  * IE Field nomenclature
  * @MBSSID_INDICATOR_POS: Position of MaxBSSID indicator inside MBSSID tag
- * @UPTO_TAG_LEN: 2bytes, which includes Tag Number and Tag length field
+ * @MIN_IE_LEN: 2bytes, which includes Tag Number and Tag length field
  * @TAG_LEN_POS: Position of tag length field in MBSSID tag
  * @VALID_ELEM_LEAST_LEN: Minimum fields required after tag length to call
  * a MBSSID tag valid. (MaxBSSID Indicator + subelement ID + Subelement length
@@ -87,9 +87,14 @@ typedef uint32_t wlan_scan_id;
  * profile, which includes at least one tag, which may have tag number + tag
  * length + atleast 1 byte of datai
  * @BSS_INDEX_POS: Position of BSSID index field in Multiple BSSID index tag
+ * @MIN_VENDOR_TAG_LEN: Minimum length of a vendor specific tag
+ * @OUI_LEN: OUI + OUI Type + Min DATA
+ * @ELEM_ID_EXTN_POS: Position of element ID extension in an extension element
+ * @ELEM_ID_LIST_LEN_POS: Position of length field in list of element IDs
+ * @ELEM_ID_LIST_POS: Position to the start of element ID list
  */
 #define MBSSID_INDICATOR_POS 2
-#define UPTO_TAG_LEN 2
+#define MIN_IE_LEN 2
 #define TAG_LEN_POS 1
 #define VALID_ELEM_LEAST_LEN 4
 #define SUBELEMENT_START_POS 3
@@ -104,6 +109,11 @@ typedef uint32_t wlan_scan_id;
 #define VALID_BSS_PROF_LEAST_LEN 4
 #define SPLIT_PROF_DATA_LEAST_LEN 3
 #define BSS_INDEX_POS 2
+#define MIN_VENDOR_TAG_LEN 7
+#define OUI_LEN 5
+#define ELEM_ID_EXTN_POS 2
+#define ELEM_ID_LIST_LEN_POS 3
+#define ELEM_ID_LIST_POS 4
 
 /* forward declaration */
 struct wlan_objmgr_vdev;
@@ -340,6 +350,23 @@ enum nontx_profile_reasoncode {
 	INVALID_NONTX_PROF = 0x2
 };
 
+/**
+ * struct non_inheritance_ie - Non inheritance tag information
+ * @list_len: Length of element ID list
+ * @extn_len: Length of element ID extension list
+ * @non_inherit: Flag to indicate if any noninheritance tag present
+ *              in the non tx BSSID profile
+ * @non_inh_ie_found: Flag to indicate if the noninheritance tag found
+ *                   from non tx BSSID profile present in the tx profile
+ *                   so that the copy of that IE can be skipped.
+ */
+struct non_inheritance_ie {
+	uint8_t list_len;
+	uint8_t extn_len;
+	bool non_inherit;
+	bool non_inh_ie_found;
+};
+
 /**
  * struct rnr_bss_info - Reduced Neighbor Report BSS information
  * @neighbor_ap_tbtt_offset: Neighbor AP TBTT offset

+ 244 - 49
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -1751,7 +1751,33 @@ util_scan_gen_scan_entry(struct wlan_objmgr_pdev *pdev,
 	return status;
 }
 
-/**
+/*
+ * util_is_noninh_ie() - find the noninhertance information element
+ * in the received frame's IE list, so that we can stop inheriting that IE
+ * in the caller function.
+ *
+ * @elem_id: Element ID in the received frame's IE, which is being processed.
+ * @non_inh_list: pointer to the non inherited list of element IDs or
+ *                list of extension element IDs.
+ * @len: Length of non inheritance IE list
+ *
+ * Return: False if the element ID is not found or else return true
+ */
+static bool util_is_noninh_ie(uint8_t elem_id,
+			      uint8_t *non_inh_list,
+			      int8_t len)
+{
+	int count;
+
+	for (count = 0; count < len; count++) {
+		if (elem_id == non_inh_list[count])
+			return true;
+	}
+
+	return false;
+}
+
+/*
  * util_scan_find_ie() - find information element
  * @eid: element id
  * @ies: pointer consisting of IEs
@@ -1793,13 +1819,132 @@ static void util_gen_new_bssid(uint8_t *bssid, uint8_t max_bssid,
 	new_bssid_addr[5] |= (lsb_n + mbssid_index) % (1 << max_bssid);
 }
 
+/*
+ * util_scan_noninheritance() - This block of code is to identify if
+ * there is any non-inheritance element present as part of the nontransmitted
+ * BSSID profile. If it is found then Host need not inherit those list of
+ * element IDs and list of element ID extensions from the transmitted BSSID
+ * profile.
+ * Since non-inheritance element is an element ID extension, it should
+ * be part of extension element. So first we need to find if there are
+ * any extension element present in the nontransmitted BSSID profile.
+ * @extn_elem: If valid, it points to the element ID field of
+ * extension element tag in the nontransmitted BSSID profile.
+ * It may or may not have non inheritance tag present.
+ *      _____________________________________________
+ *     |         |       |       |List of|List of    |
+ *     | Element |Length |Element|Element|Element ID |
+ *     |  ID     |       |ID extn| IDs   |Extension  |
+ *     |_________|_______|_______|_______|___________|
+ * List of Element IDs:
+ *      __________________
+ *     |         |        |
+ *     |  Length |Element |
+ *     |         |ID List |
+ *     |_________|________|
+ * List of Element ID Extensions:
+ *      __________________________
+ *     |         |                |
+ *     |  Length |Element ID      |
+ *     |         |extension List  |
+ *     |_________|________________|
+ * @elem_list: Element ID list
+ * @extn_elem_list: Element ID exiension list
+ * @non_inheritance_ie: Non inheritance IE information
+ */
+
+static void util_scan_noninheritance(uint8_t *extn_elem,
+				     uint8_t **elem_list,
+				     uint8_t **extn_elem_list,
+				     struct non_inheritance_ie *ninh)
+{
+	int8_t extn_rem_len = 0;
+
+	if ((extn_elem[ELEM_ID_EXTN_POS] == WLAN_EXTN_ELEMID_NONINHERITANCE) &&
+	    (extn_elem[ELEM_ID_LIST_LEN_POS] < extn_elem[TAG_LEN_POS])) {
+		/*
+		 * extn_rem_len represents the number of bytes after
+		 * the length subfield of list of Element IDs.
+		 * So here, extn_rem_len should be equal to
+		 * Element ID list + Length subfield of Element ID
+		 * extension list + Element ID extension list.
+		 *
+		 * Here we have taken two pointers pointing to the
+		 * element ID list and element ID extension list
+		 * which we will use to detect the same elements
+		 * in the transmitted BSSID profile and choose not
+		 * to inherit those elements while constructing the
+		 * frame for nontransmitted BSSID profile.
+		 */
+		extn_rem_len = extn_elem[TAG_LEN_POS] - MIN_IE_LEN;
+		ninh->non_inherit = true;
+
+		if (extn_rem_len && extn_elem[ELEM_ID_LIST_LEN_POS]) {
+			if (extn_rem_len >= extn_elem[ELEM_ID_LIST_LEN_POS]) {
+				ninh->list_len =
+					extn_elem[ELEM_ID_LIST_LEN_POS];
+				*elem_list = extn_elem + ELEM_ID_LIST_POS;
+				extn_rem_len -= ninh->list_len;
+			} else {
+				/*
+				 * Corrupt frame. length subfield of
+				 * element ID list is greater than
+				 * what it should be. Go ahead with
+				 * frame generation but do not honour
+				 * the non inheritance part. Also, mark
+				 * the element ID in subcopy as 0, so
+				 * that this element info will not
+				 * be copied.
+				 */
+				ninh->non_inherit = false;
+				extn_elem[0] = 0;
+			}
+		}
+
+		extn_rem_len--;
+		if (extn_rem_len > 0) {
+			if (!ninh->list_len) {
+				ninh->extn_len =
+					extn_elem[ELEM_ID_LIST_LEN_POS + 1];
+			} else {
+				ninh->extn_len =
+					extn_elem[ELEM_ID_LIST_POS +
+					ninh->list_len];
+			}
+
+			if (extn_rem_len != ninh->extn_len) {
+				/*
+				 * Corrupt frame. length subfield of
+				 * element ID extn list is not
+				 * what it should be. Go ahead with
+				 * frame generation but do not honour
+				 * the non inheritance part. Also, mark
+				 * the element ID in subcopy as 0, so
+				 * that this element info will not
+				 * be copied.
+				 */
+				ninh->non_inherit = false;
+				extn_elem[0] = 0;
+			}
+
+			if (ninh->extn_len) {
+				*extn_elem_list =
+					(extn_elem + ninh->list_len +
+					 ELEM_ID_LIST_POS + 1);
+			}
+		}
+	}
+}
+
 static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 				uint8_t *subelement,
 				size_t subie_len, uint8_t *new_ie)
 {
 	uint8_t *pos, *tmp;
 	const uint8_t *tmp_old, *tmp_new;
-	uint8_t *sub_copy;
+	uint8_t *sub_copy, *extn_elem = NULL;
+	struct non_inheritance_ie ninh = {0};
+	uint8_t *elem_list = NULL, *extn_elem_list = NULL;
 	size_t tmp_rem_len;
 
 	/* copy subelement as we need to change its content to
@@ -1815,22 +1960,52 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 	/* new ssid */
 	tmp_new = util_scan_find_ie(WLAN_ELEMID_SSID, sub_copy, subie_len);
 	if (tmp_new) {
-		scm_debug(" SSID %.*s", tmp_new[1], &tmp_new[2]);
-		if ((pos + tmp_new[1] + 2) <= (new_ie + ielen)) {
-			qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
-			pos += (tmp_new[1] + 2);
+		scm_debug(" SSID %.*s", tmp_new[1],
+			  &tmp_new[PAYLOAD_START_POS]);
+		if ((pos + tmp_new[1] + MIN_IE_LEN) <=
+		    (new_ie + ielen)) {
+			qdf_mem_copy(pos, tmp_new,
+				     (tmp_new[1] + MIN_IE_LEN));
+			pos += (tmp_new[1] + MIN_IE_LEN);
 		}
 	}
 
+	extn_elem = util_scan_find_ie(WLAN_ELEMID_EXTN_ELEM,
+				      sub_copy, subie_len);
+
+	if (extn_elem && extn_elem[TAG_LEN_POS]) {
+		util_scan_noninheritance(extn_elem, &elem_list,
+					 &extn_elem_list, &ninh);
+	}
+
 	/* go through IEs in ie (skip SSID) and subelement,
 	 * merge them into new_ie
 	 */
 	tmp_old = util_scan_find_ie(WLAN_ELEMID_SSID, ie, ielen);
-	tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
+	tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + MIN_IE_LEN : ie;
+
+	while (((tmp_old + tmp_old[1] + MIN_IE_LEN) - ie) <= ielen) {
+		ninh.non_inh_ie_found = 0;
+		if (ninh.non_inherit) {
+			if (ninh.list_len) {
+				ninh.non_inh_ie_found =
+					util_is_noninh_ie(tmp_old[0],
+							  elem_list,
+							  ninh.list_len);
+			}
+
+			if (!ninh.non_inh_ie_found &&
+			    ninh.extn_len &&
+			    (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM)) {
+				ninh.non_inh_ie_found =
+					util_is_noninh_ie(tmp_old[2],
+							  extn_elem_list,
+							  ninh.extn_len);
+			}
+		}
 
-	while (((tmp_old + tmp_old[1] + 2) - ie) <= ielen) {
-		if (tmp_old[0] == 0) {
-			tmp_old += tmp_old[1] + 2;
+		if (ninh.non_inh_ie_found || (tmp_old[0] == 0)) {
+			tmp_old += tmp_old[1] + MIN_IE_LEN;
 			continue;
 		}
 
@@ -1839,11 +2014,12 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 		if (!tmp) {
 			/* ie in old ie but not in subelement */
 			if (tmp_old[0] != WLAN_ELEMID_MULTIPLE_BSSID) {
-				if ((pos + tmp_old[1] + 2) <=
+				if ((pos + tmp_old[1] + MIN_IE_LEN) <=
 				    (new_ie + ielen)) {
 					qdf_mem_copy(pos, tmp_old,
-						     tmp_old[1] + 2);
-					pos += tmp_old[1] + 2;
+						     (tmp_old[1] +
+						      MIN_IE_LEN));
+					pos += tmp_old[1] + MIN_IE_LEN;
 				}
 			}
 		} else {
@@ -1855,76 +2031,95 @@ static uint32_t util_gen_new_ie(uint8_t *ie, uint32_t ielen,
 			 */
 			tmp_rem_len = subie_len - (tmp - sub_copy);
 			if (tmp_old[0] == WLAN_ELEMID_VENDOR &&
-			    tmp_rem_len >= 7) {
-				if (!qdf_mem_cmp(tmp_old + 2, tmp + 2, 5)) {
+			    tmp_rem_len >= MIN_VENDOR_TAG_LEN) {
+				if (!qdf_mem_cmp(tmp_old + PAYLOAD_START_POS,
+						 tmp + PAYLOAD_START_POS,
+						 OUI_LEN)) {
 					/* same vendor ie, copy from
 					 * subelement
 					 */
-					if ((pos + tmp[1] + 2) <=
+					if ((pos + tmp[1] + MIN_IE_LEN) <=
 					    (new_ie + ielen)) {
 						qdf_mem_copy(pos, tmp,
-							     tmp[1] + 2);
-						pos += tmp[1] + 2;
+							     tmp[1] +
+							     MIN_IE_LEN);
+						pos += tmp[1] + MIN_IE_LEN;
 						tmp[0] = 0;
 					}
 				} else {
-					if ((pos + tmp_old[1] + 2) <=
+					if ((pos + tmp_old[1] +
+					     MIN_IE_LEN) <=
 					    (new_ie + ielen)) {
 						qdf_mem_copy(pos, tmp_old,
-							     tmp_old[1] + 2);
-						pos += tmp_old[1] + 2;
+							     tmp_old[1] +
+							     MIN_IE_LEN);
+						pos += tmp_old[1] +
+							MIN_IE_LEN;
 					}
 				}
 			} else if (tmp_old[0] == WLAN_ELEMID_EXTN_ELEM) {
-				if (tmp_old[2] == tmp[2]) {
+				if (tmp_old[PAYLOAD_START_POS] ==
+				    tmp[PAYLOAD_START_POS]) {
 					/* same ie, copy from subelement */
-					if ((pos + tmp[1] + 2) <=
+					if ((pos + tmp[1] + MIN_IE_LEN) <=
 					    (new_ie + ielen)) {
 						qdf_mem_copy(pos, tmp,
-							     tmp[1] + 2);
-						pos += tmp[1] + 2;
+							     tmp[1] +
+							     MIN_IE_LEN);
+						pos += tmp[1] + MIN_IE_LEN;
 						tmp[0] = 0;
 					}
 				} else {
-					if ((pos + tmp_old[1] + 2) <=
+					if ((pos + tmp_old[1] + MIN_IE_LEN) <=
 					    (new_ie + ielen)) {
 						qdf_mem_copy(pos, tmp_old,
-							     tmp_old[1] + 2);
-						pos += tmp_old[1] + 2;
+							     tmp_old[1] +
+							     MIN_IE_LEN);
+						pos += tmp_old[1] +
+							MIN_IE_LEN;
 					}
 				}
+
 			} else {
 				/* copy ie from subelement into new ie */
-				if ((pos + tmp[1] + 2) <= (new_ie + ielen)) {
-					qdf_mem_copy(pos, tmp, tmp[1] + 2);
-					pos += tmp[1] + 2;
+				if ((pos + tmp[1] + MIN_IE_LEN) <=
+				    (new_ie + ielen)) {
+					qdf_mem_copy(pos, tmp,
+						     tmp[1] + MIN_IE_LEN);
+					pos += tmp[1] + MIN_IE_LEN;
 					tmp[0] = 0;
 				}
 			}
 		}
 
-		if (((tmp_old + tmp_old[1] + 2) - ie) >= ielen)
+		if (((tmp_old + tmp_old[1] + MIN_IE_LEN) - ie) >= ielen)
 			break;
 
-		tmp_old += tmp_old[1] + 2;
+		tmp_old += tmp_old[1] + MIN_IE_LEN;
 	}
 
 	/* go through subelement again to check if there is any ie not
 	 * copied to new ie, skip ssid, capability, bssid-index ie
 	 */
 	tmp_new = sub_copy;
-	while (((tmp_new + tmp_new[1] + 2) - sub_copy) <= subie_len) {
+	while (((tmp_new + tmp_new[1] + MIN_IE_LEN) - sub_copy) <=
+	       subie_len) {
 		if (!(tmp_new[0] == WLAN_ELEMID_NONTX_BSSID_CAP ||
 		      tmp_new[0] == WLAN_ELEMID_SSID ||
-		      tmp_new[0] == WLAN_ELEMID_MULTI_BSSID_IDX)) {
-			if ((pos + tmp_new[1] + 2) <= (new_ie + ielen)) {
-				qdf_mem_copy(pos, tmp_new, tmp_new[1] + 2);
-				pos += tmp_new[1] + 2;
+		      tmp_new[0] == WLAN_ELEMID_MULTI_BSSID_IDX ||
+		      ((tmp_new[0] == WLAN_ELEMID_EXTN_ELEM) &&
+		       (tmp_new[2] == WLAN_EXTN_ELEMID_NONINHERITANCE)))) {
+			if ((pos + tmp_new[1] + MIN_IE_LEN) <=
+			    (new_ie + ielen)) {
+				qdf_mem_copy(pos, tmp_new,
+					     tmp_new[1] + MIN_IE_LEN);
+				pos += tmp_new[1] + MIN_IE_LEN;
 			}
 		}
-		if (((tmp_new + tmp_new[1] + 2) - sub_copy) >= subie_len)
+		if (((tmp_new + tmp_new[1] + MIN_IE_LEN) - sub_copy) >=
+		    subie_len)
 			break;
-		tmp_new += tmp_new[1] + 2;
+		tmp_new += tmp_new[1] + MIN_IE_LEN;
 	}
 
 	qdf_mem_free(sub_copy);
@@ -2100,7 +2295,7 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 	if (!new_ie)
 		return QDF_STATUS_E_NOMEM;
 
-	while (pos < (ie + ielen + UPTO_TAG_LEN)) {
+	while (pos < (ie + ielen + MIN_IE_LEN)) {
 		mbssid_elem =
 			util_scan_find_ie(WLAN_ELEMID_MULTIPLE_BSSID, pos,
 					  ielen - (pos - ie));
@@ -2111,7 +2306,7 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 			(1 << mbssid_elem[MBSSID_INDICATOR_POS]);
 
 		next_elem =
-			mbssid_elem + mbssid_elem[TAG_LEN_POS] + UPTO_TAG_LEN;
+			mbssid_elem + mbssid_elem[TAG_LEN_POS] + MIN_IE_LEN;
 
 		/* Skip Element ID, Len, MaxBSSID Indicator */
 		if (!mbssid_info.split_profile &&
@@ -2132,7 +2327,7 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 		mbssid_info.skip_bssid_copy = false;
 		for (subelement = mbssid_elem + SUBELEMENT_START_POS;
 		     subelement < (next_elem - 1);
-		     subelement += UPTO_TAG_LEN + subelement[TAG_LEN_POS]) {
+		     subelement += MIN_IE_LEN + subelement[TAG_LEN_POS]) {
 			subie_len = subelement[TAG_LEN_POS];
 
 			if (subie_len > MAX_SUBELEM_LEN) {
@@ -2144,10 +2339,10 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 			}
 
 			if ((next_elem - subelement) <
-			    (UPTO_TAG_LEN + subie_len))
+			    (MIN_IE_LEN + subie_len))
 				break;
 
-			next_subelement = subelement + subie_len + UPTO_TAG_LEN;
+			next_subelement = subelement + subie_len + MIN_IE_LEN;
 			retval = util_handle_nontx_prof(mbssid_elem, subelement,
 							next_subelement,
 							&mbssid_info,
@@ -2195,10 +2390,10 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 					qdf_mem_copy(split_prof_start,
 						     subelement,
 						     (subie_len +
-						      UPTO_TAG_LEN));
+						      MIN_IE_LEN));
 					split_prof_end = (split_prof_start +
 							  subie_len +
-							  UPTO_TAG_LEN);
+							  MIN_IE_LEN);
 					break;
 				}
 
@@ -2212,7 +2407,7 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 				 */
 
 				qdf_mem_copy(split_prof_end,
-					     (subelement + UPTO_TAG_LEN),
+					     (subelement + MIN_IE_LEN),
 					     subie_len);
 				split_prof_end =
 					(split_prof_end + subie_len);
@@ -2249,7 +2444,7 @@ static QDF_STATUS util_scan_parse_mbssid(struct wlan_objmgr_pdev *pdev,
 
 				split_prof_len =
 					(split_prof_end -
-					 split_prof_start - UPTO_TAG_LEN);
+					 split_prof_start - MIN_IE_LEN);
 			}
 
 			if (mbssid_info.split_prof_continue) {