qcacld-3.0: Update Assoc IEs to firmware after STA connects

As part of MBO(Multiband Operations), the Assoc IE's including
MBO IE need to be sent to FW as part of Roam Scan Offload command
so that these IE's can be used later in firmware initiated roams

Change-Id: Ia873c65a7813ae63d8e53d7445095990b0c2fed7
CRs-Fixed: 1039969
(cherry picked from commit 0af3520421400b65002604e0a3a9c7c714cc1e21)
diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h
index 8d23b42..68707c0 100644
--- a/core/hdd/inc/wlan_hdd_wext.h
+++ b/core/hdd/inc/wlan_hdd_wext.h
@@ -215,6 +215,9 @@
 #define WFD_OUI_TYPE_SIZE  4
 #endif
 
+#define MBO_OUI_TYPE   "\x50\x6f\x9a\x16"
+#define MBO_OUI_TYPE_SIZE  4
+
 typedef enum {
 	eWEXT_WPS_OFF = 0,
 	eWEXT_WPS_ON = 1,
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 4b4773e..4e17321 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -10921,6 +10921,37 @@
 }
 
 /**
+ * wlan_hdd_add_assoc_ie() - Add Assoc IE to roamProfile
+ * @wext_state: Pointer to wext state
+ * @gen_ie: Pointer to IE data
+ * @len: length of IE data
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+static int wlan_hdd_add_assoc_ie(hdd_wext_state_t *wext_state,
+				const uint8_t *gen_ie, uint16_t len)
+{
+	uint16_t cur_add_ie_len =
+		wext_state->assocAddIE.length;
+
+	if (SIR_MAC_MAX_ADD_IE_LENGTH <
+			(wext_state->assocAddIE.length + len)) {
+		hdd_err("Cannot accommodate assocAddIE Need bigger buffer space");
+		QDF_ASSERT(0);
+		return -ENOMEM;
+	}
+	memcpy(wext_state->assocAddIE.addIEdata +
+			cur_add_ie_len, gen_ie, len);
+	wext_state->assocAddIE.length += len;
+
+	wext_state->roamProfile.pAddIEAssoc =
+		wext_state->assocAddIE.addIEdata;
+	wext_state->roamProfile.nAddIEAssocLength =
+		wext_state->assocAddIE.length;
+	return 0;
+}
+
+/**
  * wlan_hdd_cfg80211_set_ie() - set IEs
  * @pAdapter: Pointer to adapter
  * @ie: Pointer ot ie
@@ -10940,6 +10971,7 @@
 	uint16_t akmsuiteCount;
 	int *akmlist;
 #endif
+	int status;
 
 	/* clear previous assocAddIE */
 	pWextState->assocAddIE.length = 0;
@@ -11086,6 +11118,13 @@
 					pWextState->assocAddIE.addIEdata;
 				pWextState->roamProfile.nAddIEAssocLength =
 					pWextState->assocAddIE.length;
+			} else if ((0 == memcmp(&genie[0], MBO_OUI_TYPE,
+							MBO_OUI_TYPE_SIZE))){
+				hdd_info("Set MBO IE(len %d)", eLen + 2);
+				status = wlan_hdd_add_assoc_ie(pWextState,
+							genie - 2, eLen + 2);
+				if (status)
+					return status;
 			} else {
 				uint16_t add_ie_len =
 					pWextState->assocAddIE.length;
@@ -11181,6 +11220,15 @@
 			}
 			break;
 #endif
+		case DOT11F_EID_SUPPOPERATINGCLASSES:
+			{
+				hdd_info("Set Supported Operating Classes IE(len %d)", eLen + 2);
+				status = wlan_hdd_add_assoc_ie(pWextState,
+							genie - 2, eLen + 2);
+				if (status)
+					return status;
+				break;
+			}
 		default:
 			hdd_err("Set UNKNOWN IE %X", elementId);
 			/* when Unknown IE is received we should break and continue
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 24704da..aa1f5a3 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -3037,6 +3037,7 @@
 	int8_t early_stop_scan_min_threshold;
 	int8_t early_stop_scan_max_threshold;
 	enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode;
+	tSirAddie assoc_ie;
 } tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq;
 
 typedef struct sSirRoamOffloadScanRsp {
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 6508f21..c1603da 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -17443,6 +17443,16 @@
 			req_buf->hi_rssi_scan_delay,
 			req_buf->hi_rssi_scan_rssi_ub);
 
+	if ((command == ROAM_SCAN_OFFLOAD_START) &&
+				(reason == REASON_CONNECT)) {
+		req_buf->assoc_ie.length = session->nAddIEAssocLength;
+		qdf_mem_copy(req_buf->assoc_ie.addIEdata,
+				session->pAddIEAssoc,
+				session->nAddIEAssocLength);
+	} else {
+		req_buf->assoc_ie.length = 0;
+	}
+
 	msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ;
 	msg.reserved = 0;
 	msg.bodyptr = req_buf;
diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c
index 03e8686..44ca7bc 100644
--- a/core/wma/src/wma_scan_roam.c
+++ b/core/wma/src/wma_scan_roam.c
@@ -744,7 +744,8 @@
 				      uint32_t mode, uint32_t vdev_id)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
-	struct roam_offload_scan_params params = {0};
+	struct roam_offload_scan_params *params =
+				qdf_mem_malloc(sizeof(*params));
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 	int auth_mode = WMI_AUTH_NONE;
@@ -753,46 +754,50 @@
 				    (roam_req->ConnectedNetwork.authentication,
 				    roam_req->ConnectedNetwork.encryption);
 	WMA_LOGD("%s : auth mode = %d", __func__, auth_mode);
-	params.auth_mode = auth_mode;
+	params->auth_mode = auth_mode;
 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
 
-	params.is_roam_req_valid = 0;
-	params.mode = mode;
-	params.vdev_id = vdev_id;
+	params->is_roam_req_valid = 0;
+	params->mode = mode;
+	params->vdev_id = vdev_id;
 	if (roam_req) {
-		params.is_roam_req_valid = 1;
+		params->is_roam_req_valid = 1;
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
-		params.roam_offload_enabled = roam_req->RoamOffloadEnabled;
-		params.prefer_5ghz = roam_req->Prefer5GHz;
-		params.roam_rssi_cat_gap = roam_req->RoamRssiCatGap;
-		params.select_5ghz_margin = roam_req->Select5GHzMargin;
-		params.reassoc_failure_timeout =
+		params->roam_offload_enabled = roam_req->RoamOffloadEnabled;
+		params->prefer_5ghz = roam_req->Prefer5GHz;
+		params->roam_rssi_cat_gap = roam_req->RoamRssiCatGap;
+		params->select_5ghz_margin = roam_req->Select5GHzMargin;
+		params->reassoc_failure_timeout =
 				roam_req->ReassocFailureTimeout;
-		params.rokh_id_length = roam_req->R0KH_ID_Length;
-		qdf_mem_copy(params.rokh_id, roam_req->R0KH_ID,
+		params->rokh_id_length = roam_req->R0KH_ID_Length;
+		qdf_mem_copy(params->rokh_id, roam_req->R0KH_ID,
 				WMI_ROAM_R0KH_ID_MAX_LEN);
-		qdf_mem_copy(params.krk, roam_req->KRK, WMI_KRK_KEY_LEN);
-		qdf_mem_copy(params.btk, roam_req->BTK, WMI_BTK_KEY_LEN);
-		qdf_mem_copy(params.psk_pmk, roam_req->PSK_PMK,
+		qdf_mem_copy(params->krk, roam_req->KRK, WMI_KRK_KEY_LEN);
+		qdf_mem_copy(params->btk, roam_req->BTK, WMI_BTK_KEY_LEN);
+		qdf_mem_copy(params->psk_pmk, roam_req->PSK_PMK,
 				WMI_ROAM_SCAN_PSK_SIZE);
-		params.pmk_len = roam_req->pmk_len;
-		params.roam_key_mgmt_offload_enabled =
+		params->pmk_len = roam_req->pmk_len;
+		params->roam_key_mgmt_offload_enabled =
 				roam_req->RoamKeyMgmtOffloadEnabled;
 		wma_roam_scan_fill_self_caps(wma_handle,
-			&params.roam_offload_params, roam_req);
-		params.okc_enabled = roam_req->okc_enabled;
+			&params->roam_offload_params, roam_req);
+		params->okc_enabled = roam_req->okc_enabled;
 #endif
-		params.is_ese_assoc = roam_req->IsESEAssoc;
-		params.mdid.mdie_present = roam_req->MDID.mdiePresent;
-		params.mdid.mobility_domain = roam_req->MDID.mobilityDomain;
+		params->is_ese_assoc = roam_req->IsESEAssoc;
+		params->mdid.mdie_present = roam_req->MDID.mdiePresent;
+		params->mdid.mobility_domain = roam_req->MDID.mobilityDomain;
+		params->assoc_ie_length = roam_req->assoc_ie.length;
+		qdf_mem_copy(params->assoc_ie, roam_req->assoc_ie.addIEdata,
+						roam_req->assoc_ie.length);
 	}
 
 	status = wmi_unified_roam_scan_offload_mode_cmd(wma_handle->wmi_handle,
-				scan_cmd_fp, &params);
+				scan_cmd_fp, params);
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
 	WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_MODE", __func__);
+	qdf_mem_free(params);
 	return status;
 }