qcacld-3.0: Fix supported operating classes IE order in assoc request

Strip supported operating classes IE from additional IE’s sent by user
and update the same to rearrange along with other IE’s in ascending
order.

Change-Id: I198e8e3aa8e0f977d916d7f3a6fc0e5951032769
CRs-Fixed: 2006920
diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c
index 167b802..6a01564 100644
--- a/core/mac/src/pe/lim/lim_send_management_frames.c
+++ b/core/mac/src/pe/lim/lim_send_management_frames.c
@@ -1942,6 +1942,11 @@
 		}
 	}
 
+	if (eSIR_SUCCESS != lim_strip_supp_op_class_update_struct(mac_ctx,
+			add_ie, &add_ie_len, &frm->SuppOperatingClasses))
+		lim_log(mac_ctx, LOG1,
+		FL("Unable to Stripoff supp op classes IE from Assoc Req"));
+
 	status = dot11f_get_packed_assoc_request_size(mac_ctx, frm, &payload);
 	if (DOT11F_FAILED(status)) {
 		lim_log(mac_ctx, LOGP,
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index 5cc00df..005cfbe 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/core/mac/src/pe/lim/lim_utils.c
@@ -6705,7 +6705,8 @@
 tSirRetStatus lim_strip_ie(tpAniSirGlobal mac_ctx,
 		uint8_t *addn_ie, uint16_t *addn_ielen,
 		uint8_t eid, eSizeOfLenField size_of_len_field,
-		uint8_t *oui, uint8_t oui_length, uint8_t *extracted_ie)
+		uint8_t *oui, uint8_t oui_length, uint8_t *extracted_ie,
+		uint32_t eid_max_len)
 {
 	uint8_t *tempbuf = NULL;
 	uint16_t templen = 0;
@@ -6757,12 +6758,11 @@
 			 */
 			if (NULL != extracted_ie) {
 				qdf_mem_set(extracted_ie,
-					DOT11F_IE_EXTCAP_MAX_LEN +
-						size_of_len_field + 1, 0);
-				if (elem_len <= DOT11F_IE_EXTCAP_MAX_LEN)
+					    eid_max_len + size_of_len_field + 1,
+					    0);
+				if (elem_len <= eid_max_len)
 					qdf_mem_copy(extracted_ie, &ptr[0],
-						elem_len +
-						size_of_len_field + 1);
+					elem_len + size_of_len_field + 1);
 			}
 		}
 		left -= elem_len;
@@ -6776,6 +6776,44 @@
 	return eSIR_SUCCESS;
 }
 
+tSirRetStatus lim_strip_supp_op_class_update_struct(tpAniSirGlobal mac_ctx,
+		uint8_t *addn_ie, uint16_t *addn_ielen,
+		tDot11fIESuppOperatingClasses *dst)
+{
+	uint8_t extracted_buff[DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN + 2];
+	tSirRetStatus status;
+
+	qdf_mem_set((uint8_t *)&extracted_buff[0],
+		    DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN + 2,
+		    0);
+	status = lim_strip_ie(mac_ctx, addn_ie, addn_ielen,
+			      DOT11F_EID_SUPPOPERATINGCLASSES, ONE_BYTE,
+			      NULL, 0, extracted_buff,
+			      DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN);
+	if (eSIR_SUCCESS != status) {
+		lim_log(mac_ctx, LOG1,
+		       FL("Failed to strip supp_op_mode IE status = (%d)."),
+		       status);
+		return status;
+	}
+
+	if (DOT11F_EID_SUPPOPERATINGCLASSES != extracted_buff[0] ||
+	    extracted_buff[1] > DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN) {
+		lim_log(mac_ctx, LOG1, FL("Invalid IEs eid = %d elem_len=%d "),
+			extracted_buff[0], extracted_buff[1]);
+		return eSIR_FAILURE;
+	}
+
+	/* update the extracted supp op class to struct*/
+	if (DOT11F_PARSE_SUCCESS != dot11f_unpack_ie_supp_operating_classes(
+	    mac_ctx, &extracted_buff[2], extracted_buff[1], dst)) {
+		lim_log(mac_ctx, LOGE, FL("dot11f_unpack Parse Error "));
+		return eSIR_FAILURE;
+	}
+
+	return eSIR_SUCCESS;
+}
+
 /**
  * lim_update_extcap_struct() - poputlate the dot11f structure
  * @mac_ctx: global MAC context
@@ -6839,7 +6877,8 @@
 		     0);
 	status = lim_strip_ie(mac_ctx, addn_ie, addn_ielen,
 			      DOT11F_EID_EXTCAP, ONE_BYTE,
-			      NULL, 0, extracted_buff);
+			      NULL, 0, extracted_buff,
+			      DOT11F_IE_EXTCAP_MAX_LEN);
 	if (eSIR_SUCCESS != status) {
 		lim_log(mac_ctx, LOG1,
 		       FL("Failed to strip extcap IE status = (%d)."), status);
diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h
index 9978fb8..70da5a5 100644
--- a/core/mac/src/pe/lim/lim_utils.h
+++ b/core/mac/src/pe/lim/lim_utils.h
@@ -613,6 +613,23 @@
 void lim_merge_extcap_struct(tDot11fIEExtCap *dst, tDot11fIEExtCap *src,
 		bool add);
 
+/**
+ * lim_strip_op_class_update_struct - strip sup op class IE and populate
+ *				  the dot11f structure
+ * @mac_ctx: global MAC context
+ * @addn_ie: Additional IE buffer
+ * @addn_ielen: Length of additional IE
+ * @dst: Supp operating class IE structure to be updated
+ *
+ * This function is used to strip supp op class IE from IE buffer and
+ * update the passed structure.
+ *
+ * Return: tSirRetStatus
+ */
+tSirRetStatus lim_strip_supp_op_class_update_struct(tpAniSirGlobal mac_ctx,
+		uint8_t *addn_ie, uint16_t *addn_ielen,
+		tDot11fIESuppOperatingClasses *dst);
+
 uint8_t lim_get_80Mhz_center_channel(uint8_t primary_channel);
 void lim_update_obss_scanparams(tpPESession session,
 			tDot11fIEOBSSScanParameters *scan_params);
@@ -658,5 +675,6 @@
 tSirRetStatus lim_strip_ie(tpAniSirGlobal mac_ctx,
 		uint8_t *addn_ie, uint16_t *addn_ielen,
 		uint8_t eid, eSizeOfLenField size_of_len_field,
-		uint8_t *oui, uint8_t out_len, uint8_t *extracted_ie);
+		uint8_t *oui, uint8_t out_len, uint8_t *extracted_ie,
+		uint32_t eid_max_len);
 #endif /* __LIM_UTILS_H */