Browse Source

qcacld-3.0: Handle OWE info update from hostapd

Handle OWE info update from hostapd in the following path:
HDD->SAP->SME->CSR

Change-Id: I7584fb5db036d1643bd7d56076d30a0c75008a98
CRs-Fixed: 2397009
Min Liu 6 years ago
parent
commit
0daa098737

+ 75 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -19663,6 +19663,78 @@ wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy,
 }
 #endif
 
+#ifdef CFG80211_EXTERNAL_DH_UPDATE_SUPPORT
+/**
+ * __wlan_hdd_cfg80211_update_owe_info() - update OWE info
+ * @wiphy: Pointer to wiphy
+ * @dev: Pointer to network device
+ * @owe_info: Pointer to OWE info
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+static int
+__wlan_hdd_cfg80211_update_owe_info(struct wiphy *wiphy,
+				    struct net_device *dev,
+				    struct cfg80211_update_owe_info *owe_info)
+{
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	QDF_STATUS status;
+	int errno = 0;
+
+	hdd_enter_dev(dev);
+
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return errno;
+
+	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EINVAL;
+	}
+
+	if (wlan_hdd_validate_session_id(adapter->vdev_id)) {
+		hdd_err("invalid session id: %d", adapter->vdev_id);
+		return -EINVAL;
+	}
+
+	hdd_debug("owe_status %d", owe_info->status);
+
+	status = wlansap_update_owe_info(WLAN_HDD_GET_SAP_CTX_PTR(adapter),
+					 owe_info->bssid, owe_info->ie,
+					 owe_info->ie_len, owe_info->status);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to update OWE info");
+		errno = qdf_status_to_os_return(status);
+	}
+
+	hdd_exit();
+	return errno;
+}
+
+/**
+ * wlan_hdd_cfg80211_update_owe_info() - update OWE info
+ * @wiphy: Pointer to wiphy
+ * @dev: Pointer to network device
+ * @owe_info: Pointer to OWE info
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+static int
+wlan_hdd_cfg80211_update_owe_info(struct wiphy *wiphy,
+				  struct net_device *dev,
+				  struct cfg80211_update_owe_info *owe_info)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_cfg80211_update_owe_info(wiphy, dev, owe_info);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+#endif
+
 void wlan_hdd_cfg80211_update_replay_counter_cb(
 		void *cb_ctx, struct pmo_gtk_rsp_params *gtk_rsp_param)
 
@@ -21113,6 +21185,9 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
 #if defined(KERNEL_SUPPORT_11R_CFG80211)
 	.update_ft_ies = wlan_hdd_cfg80211_update_ft_ies,
 #endif
+#ifdef CFG80211_EXTERNAL_DH_UPDATE_SUPPORT
+	.update_owe_info = wlan_hdd_cfg80211_update_owe_info,
+#endif
 #ifdef FEATURE_WLAN_TDLS
 	.tdls_mgmt = wlan_hdd_cfg80211_tdls_mgmt,
 	.tdls_oper = wlan_hdd_cfg80211_tdls_oper,

+ 5 - 0
core/mac/inc/sir_api.h

@@ -1118,6 +1118,9 @@ struct assoc_ind {
 	tDot11fIEVHTCaps VHTCaps;
 	tSirMacCapabilityInfo capability_info;
 	bool is_sae_authenticated;
+	const uint8_t *owe_ie;
+	uint32_t owe_ie_len;
+	uint16_t owe_status;
 };
 
 /**
@@ -1140,6 +1143,8 @@ struct assoc_cnf {
 	struct qdf_mac_addr peer_macaddr;
 	uint16_t aid;
 	tSirMacStatusCodes mac_status_code;
+	uint8_t *owe_ie;
+	uint32_t owe_ie_len;
 };
 
 /* / Enum definition for  Wireless medium status change codes */

+ 2 - 0
core/mac/src/pe/include/lim_global.h

@@ -260,6 +260,8 @@ typedef struct sLimMlmStaContext {
 #ifdef WLAN_FEATURE_11AX
 	bool he_capable;
 #endif
+	uint8_t *owe_ie;
+	uint32_t owe_ie_len;
 } tLimMlmStaContext, *tpLimMlmStaContext;
 
 /* Structure definition to hold deferred messages queue parameters */

+ 5 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -3084,12 +3084,16 @@ void __lim_process_sme_assoc_cnf_new(struct mac_context *mac_ctx, uint32_t msg_t
 		 */
 		sta_ds->mlmStaContext.mlmState =
 			eLIM_MLM_LINK_ESTABLISHED_STATE;
+		sta_ds->mlmStaContext.owe_ie = assoc_cnf.owe_ie;
+		sta_ds->mlmStaContext.owe_ie_len = assoc_cnf.owe_ie_len;
 		pe_debug("sending Assoc Rsp frame to STA (assoc id=%d)",
 			sta_ds->assocId);
 		lim_send_assoc_rsp_mgmt_frame(mac_ctx, QDF_STATUS_SUCCESS,
 					sta_ds->assocId, sta_ds->staAddr,
 					sta_ds->mlmStaContext.subType, sta_ds,
 					session_entry);
+		sta_ds->mlmStaContext.owe_ie = NULL;
+		sta_ds->mlmStaContext.owe_ie_len = 0;
 		goto end;
 	} else {
 		uint8_t add_pre_auth_context = true;
@@ -3134,6 +3138,7 @@ end:
 		qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]);
 		session_entry->parsedAssocReq[sta_ds->assocId] = NULL;
 	}
+	qdf_mem_free(assoc_cnf.owe_ie);
 }
 
 static void __lim_process_sme_addts_req(struct mac_context *mac, uint32_t *pMsgBuf)

+ 9 - 0
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -1307,6 +1307,9 @@ lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx,
 
 	bytes += sizeof(tSirMacMgmtHdr) + payload;
 
+	if (sta)
+		bytes += sta->mlmStaContext.owe_ie_len;
+
 	qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame,
 				      (void **)&packet);
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
@@ -1352,6 +1355,12 @@ lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx,
 		qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload,
 			     &add_ie[0], addn_ie_len);
 
+	if (sta && sta->mlmStaContext.owe_ie_len)
+		qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload
+			     + addn_ie_len,
+			     sta->mlmStaContext.owe_ie,
+			     sta->mlmStaContext.owe_ie_len);
+
 	if ((BAND_5G ==
 		lim_get_rf_band(pe_session->currentOperChannel)) ||
 			(pe_session->pePersona == QDF_P2P_CLIENT_MODE) ||

+ 14 - 0
core/sap/inc/sap_api.h

@@ -1340,6 +1340,20 @@ void sap_dfs_set_current_channel(void *sap_ctx);
  */
 void wlansap_cleanup_cac_timer(struct sap_context *sap_ctx);
 
+/**
+ * wlansap_update_owe_info() - Update OWE info
+ * @sap_ctx: sap context
+ * @peer: peer mac
+ * @ie: IE from hostapd
+ * @ie_len: IE length
+ * @owe_status: status from hostapd
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlansap_update_owe_info(struct sap_context *sap_ctx,
+				   uint8_t *peer, const uint8_t *ie,
+				   uint32_t ie_len, uint16_t owe_status);
+
 #ifdef __cplusplus
 }
 #endif

+ 162 - 1
core/sap/src/sap_module.c

@@ -287,7 +287,10 @@ static void wlansap_owe_cleanup(struct sap_context *sap_ctx)
 		if (status == QDF_STATUS_SUCCESS) {
 			assoc_ind = owe_assoc_ind->assoc_ind;
 			qdf_mem_free(owe_assoc_ind);
-			/* TODO: disassoc OWE STA */
+			assoc_ind->owe_ie = NULL;
+			assoc_ind->owe_ie_len = 0;
+			assoc_ind->owe_status = eSIR_MAC_UNSPEC_FAILURE_STATUS;
+			status = sme_update_owe_info(mac, assoc_ind);
 			qdf_mem_free(assoc_ind);
 		} else {
 			QDF_TRACE_ERROR(QDF_MODULE_ID_SAP,
@@ -2471,3 +2474,161 @@ void wlansap_cleanup_cac_timer(struct sap_context *sap_ctx)
 			FL("sapdfs, force cleanup running dfs cac timer"));
 	}
 }
+
+#define DH_OUI_TYPE	(0x20)
+/**
+ * wlansap_validate_owe_ie() - validate OWE IE
+ * @ie: IE buffer
+ * @remaining_ie_len: remaining IE length
+ *
+ * Return: validated IE length, negative for failure
+ */
+static int wlansap_validate_owe_ie(const uint8_t *ie, uint32_t remaining_ie_len)
+{
+	uint8_t ie_id, ie_len, ie_ext_id = 0;
+
+	if (remaining_ie_len < 2) {
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, "IE too short");
+		return -EINVAL;
+	}
+
+	ie_id = ie[0];
+	ie_len = ie[1];
+
+	/* IEs that we are expecting in OWE IEs
+	 * - RSN IE
+	 * - DH IE
+	 */
+	switch (ie_id) {
+	case DOT11F_EID_RSN:
+		if (ie_len < DOT11F_IE_RSN_MIN_LEN ||
+		    ie_len > DOT11F_IE_RSN_MAX_LEN) {
+			QDF_TRACE_ERROR(QDF_MODULE_ID_SAP,
+					"Invalid RSN IE len %d", ie_len);
+			return -EINVAL;
+		}
+		ie_len += 2;
+		break;
+	case DOT11F_EID_DH_PARAMETER_ELEMENT:
+		ie_ext_id = ie[2];
+		if (ie_ext_id != DH_OUI_TYPE) {
+			QDF_TRACE_ERROR(QDF_MODULE_ID_SAP,
+					"Invalid DH IE ID %d", ie_ext_id);
+			return -EINVAL;
+		}
+		if (ie_len < DOT11F_IE_DH_PARAMETER_ELEMENT_MIN_LEN ||
+		    ie_len > DOT11F_IE_DH_PARAMETER_ELEMENT_MAX_LEN) {
+			QDF_TRACE_ERROR(QDF_MODULE_ID_SAP,
+					"Invalid DH IE len %d", ie_len);
+			return -EINVAL;
+		}
+		ie_len += 2;
+		break;
+	default:
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, "Invalid IE %d", ie_id);
+		return -EINVAL;
+	}
+
+	if (ie_len > remaining_ie_len) {
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, "Invalid IE len");
+		return -EINVAL;
+	}
+
+	return ie_len;
+}
+
+/**
+ * wlansap_validate_owe_ies() - validate OWE IEs
+ * @ie: IE buffer
+ * @ie_len: IE length
+ *
+ * Return: true if validated
+ */
+static bool wlansap_validate_owe_ies(const uint8_t *ie, uint32_t ie_len)
+{
+	const uint8_t *remaining_ie = ie;
+	uint32_t remaining_ie_len = ie_len;
+	int validated_len;
+	bool validated = true;
+
+	while (remaining_ie_len) {
+		validated_len = wlansap_validate_owe_ie(remaining_ie,
+							remaining_ie_len);
+		if (validated_len < 0) {
+			validated = false;
+			break;
+		}
+		remaining_ie += validated_len;
+		remaining_ie_len -= validated_len;
+	}
+
+	return validated;
+}
+
+QDF_STATUS wlansap_update_owe_info(struct sap_context *sap_ctx,
+				   uint8_t *peer, const uint8_t *ie,
+				   uint32_t ie_len, uint16_t owe_status)
+{
+	struct mac_context *mac;
+	struct owe_assoc_ind *owe_assoc_ind;
+	struct assoc_ind *assoc_ind = NULL;
+	qdf_list_node_t *node = NULL, *next_node = NULL;
+	QDF_STATUS status;
+
+	if (!wlansap_validate_owe_ies(ie, ie_len)) {
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, "Invalid OWE IE");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	if (!sap_ctx) {
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, "Invalid SAP context");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	mac = sap_get_mac_context();
+	if (!mac) {
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, "Invalid MAC context");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	if (QDF_STATUS_SUCCESS !=
+		qdf_list_peek_front(&sap_ctx->owe_pending_assoc_ind_list,
+				    &next_node)) {
+		QDF_TRACE_ERROR(QDF_MODULE_ID_SAP,
+				"Failed to find assoc ind list");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	do {
+		node = next_node;
+		owe_assoc_ind = qdf_container_of(node, struct owe_assoc_ind,
+						 node);
+		if (qdf_mem_cmp(peer,
+				owe_assoc_ind->assoc_ind->peerMacAddr,
+				QDF_MAC_ADDR_SIZE) == 0) {
+			status = qdf_list_remove_node(
+					   &sap_ctx->owe_pending_assoc_ind_list,
+					   node);
+			if (status != QDF_STATUS_SUCCESS) {
+				QDF_TRACE_ERROR(QDF_MODULE_ID_SAP,
+						"Failed to remove assoc ind");
+				return status;
+			}
+			assoc_ind = owe_assoc_ind->assoc_ind;
+			qdf_mem_free(owe_assoc_ind);
+			break;
+		}
+	} while (QDF_STATUS_SUCCESS ==
+		 qdf_list_peek_next(&sap_ctx->owe_pending_assoc_ind_list,
+				    node, &next_node));
+
+	if (assoc_ind) {
+		assoc_ind->owe_ie = ie;
+		assoc_ind->owe_ie_len = ie_len;
+		assoc_ind->owe_status = owe_status;
+		status = sme_update_owe_info(mac, assoc_ind);
+		qdf_mem_free(assoc_ind);
+	}
+
+	return status;
+}

+ 10 - 0
core/sme/inc/csr_api.h

@@ -1466,4 +1466,14 @@ csr_get_channel_status(struct mac_context *mac, uint32_t channel_id);
  * Return: none
  */
 void csr_clear_channel_status(struct mac_context *mac);
+
+/**
+ * csr_update_owe_info() - Update OWE info
+ * @mac: mac context
+ * @assoc_ind: assoc ind
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS csr_update_owe_info(struct mac_context *mac,
+			       struct assoc_ind *assoc_ind);
 #endif

+ 9 - 0
core/sme/inc/sme_api.h

@@ -3260,4 +3260,13 @@ QDF_STATUS sme_set_thermal_mgmt(mac_handle_t mac_handle,
 QDF_STATUS sme_update_hidden_ssid_status_cb(mac_handle_t mac_handle,
 					    hidden_ssid_cb cb);
 
+/**
+ * sme_update_owe_info() - Update OWE info
+ * @mac: mac context
+ * @assoc_ind: assoc ind
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_update_owe_info(struct mac_context *mac,
+			       struct assoc_ind *assoc_ind);
 #endif /* #if !defined( __SME_API_H ) */

+ 14 - 0
core/sme/src/common/sme_api.c

@@ -15022,3 +15022,17 @@ QDF_STATUS sme_update_hidden_ssid_status_cb(mac_handle_t mac_handle,
 
 	return status;
 }
+
+QDF_STATUS sme_update_owe_info(struct mac_context *mac,
+			       struct assoc_ind *assoc_ind)
+{
+	QDF_STATUS status;
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		status = csr_update_owe_info(mac, assoc_ind);
+		sme_release_global_lock(&mac->sme);
+	}
+
+	return status;
+}

+ 43 - 1
core/sme/src/csr/csr_api_roam.c

@@ -15748,7 +15748,8 @@ QDF_STATUS csr_send_assoc_cnf_msg(struct mac_context *mac,
 	struct assoc_cnf *pMsg;
 	struct scheduler_msg msg = { 0 };
 
-	sme_debug("Posting eWNI_SME_ASSOC_CNF to LIM.HalStatus: %d", Halstatus);
+	sme_debug("HalStatus: %d, mac_status_code %d",
+		  Halstatus, mac_status_code);
 	do {
 		pMsg = qdf_mem_malloc(sizeof(*pMsg));
 		if (!pMsg)
@@ -15769,6 +15770,15 @@ QDF_STATUS csr_send_assoc_cnf_msg(struct mac_context *mac,
 			     QDF_MAC_ADDR_SIZE);
 		/* aid */
 		pMsg->aid = pAssocInd->aid;
+		/* OWE IE */
+		if (pAssocInd->owe_ie_len) {
+			pMsg->owe_ie = qdf_mem_malloc(pAssocInd->owe_ie_len);
+			if (!pMsg->owe_ie)
+				return QDF_STATUS_E_NOMEM;
+			qdf_mem_copy(pMsg->owe_ie, pAssocInd->owe_ie,
+				     pAssocInd->owe_ie_len);
+			pMsg->owe_ie_len = pAssocInd->owe_ie_len;
+		}
 
 		msg.type = pMsg->messageType;
 		msg.bodyval = 0;
@@ -21295,3 +21305,35 @@ QDF_STATUS csr_roam_synch_callback(struct mac_context *mac_ctx,
 	return status;
 }
 #endif
+
+QDF_STATUS csr_update_owe_info(struct mac_context *mac,
+			       struct assoc_ind *assoc_ind)
+{
+	uint32_t session_id = CSR_SESSION_ID_INVALID;
+	QDF_STATUS status;
+
+	status = csr_roam_get_session_id_from_bssid(mac,
+					(struct qdf_mac_addr *)assoc_ind->bssId,
+					&session_id);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_debug("Couldn't find session_id for given BSSID");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Send Association completion message to PE */
+	if (assoc_ind->owe_status)
+		status = QDF_STATUS_E_INVAL;
+	status = csr_send_assoc_cnf_msg(mac, assoc_ind, status,
+					assoc_ind->owe_status);
+	/*
+	 * send a message to CSR itself just to avoid the EAPOL frames
+	 * going OTA before association response
+	 */
+	if (assoc_ind->owe_status == 0)
+		status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac,
+								   assoc_ind,
+								   status,
+								   session_id);
+
+	return status;
+}