qcacld-3.0: Implementation of NDI Create/Delete

Add MCL changes for NDI create and NDI delete commands.

Change-Id: I270cd213d89224f73ff2ce9fad784cec3e0f8fa3
CRs-Fixed: 2014795
diff --git a/core/hdd/src/wlan_hdd_nan_datapath.c b/core/hdd/src/wlan_hdd_nan_datapath.c
index 50d4ae2..947a86b 100644
--- a/core/hdd/src/wlan_hdd_nan_datapath.c
+++ b/core/hdd/src/wlan_hdd_nan_datapath.c
@@ -36,6 +36,8 @@
 #include "wlan_hdd_object_manager.h"
 #include <qca_vendor.h>
 #include "os_if_nan.h"
+#include "wlan_nan_api.h"
+#include "nan_public_structs.h"
 
 #ifndef WLAN_FEATURE_NAN_CONVERGENCE
 /* NLA policy */
@@ -103,7 +105,10 @@
 	hdd_ctx->nan_datapath_enabled =
 		hdd_ctx->config->enable_nan_datapath &&
 			cfg->nan_datapath_enabled;
-	hdd_info("enable_nan_datapath: %d", hdd_ctx->nan_datapath_enabled);
+	hdd_info("enable_nan_datapath: final: %d, host: %d, fw: %d",
+		hdd_ctx->nan_datapath_enabled,
+		hdd_ctx->config->enable_nan_datapath,
+		cfg->nan_datapath_enabled);
 }
 
 /**
@@ -1820,6 +1825,35 @@
 	tCsrRoamInfo *roam_info, uint32_t roam_id, eRoamCmdStatus roam_status,
 	eCsrRoamResult roam_result)
 {
+	bool success;
+	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(adapter->hdd_vdev);
+
+	if (roam_status == eCSR_ROAM_NDP_STATUS_UPDATE) {
+		switch (roam_result) {
+		case eCSR_ROAM_RESULT_NDI_CREATE_RSP:
+			success = (roam_info->ndp.ndi_create_params.status ==
+					NAN_DATAPATH_RSP_STATUS_SUCCESS);
+			hdd_debug("posting ndi create status: %d to umac",
+				success);
+			os_if_nan_post_ndi_create_rsp(psoc, adapter->sessionId,
+							success);
+			return;
+		case eCSR_ROAM_RESULT_NDI_DELETE_RSP:
+			success = (roam_info->ndp.ndi_create_params.status ==
+					NAN_DATAPATH_RSP_STATUS_SUCCESS);
+			hdd_debug("posting ndi delete status: %d to umac",
+				success);
+			os_if_nan_post_ndi_delete_rsp(psoc, adapter->sessionId,
+							success);
+			return;
+		default:
+			hdd_err("in correct roam_result: %d", roam_result);
+			return;
+		}
+	} else {
+		hdd_err("in correct roam_status: %d", roam_status);
+		return;
+	}
 }
 #endif
 
@@ -1976,6 +2010,21 @@
 	return ret;
 }
 
+#ifndef WLAN_FEATURE_NAN_CONVERGENCE
+static int update_ndi_state(struct hdd_adapter_s *adapter, uint32_t state)
+{
+	struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter);
+
+	ndp_ctx->state = state;
+	return 0;
+}
+#else
+static int update_ndi_state(struct hdd_adapter_s *adapter, uint32_t state)
+{
+	return os_if_nan_set_ndi_state(adapter->hdd_vdev, state);
+}
+#endif
+
 /**
  * hdd_init_nan_data_mode() - initialize nan data mode
  * @adapter: adapter context
@@ -1985,7 +2034,6 @@
 int hdd_init_nan_data_mode(struct hdd_adapter_s *adapter)
 {
 	struct net_device *wlan_dev = adapter->dev;
-	struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter);
 	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	QDF_STATUS status;
 	int32_t ret_val = 0;
@@ -2033,7 +2081,7 @@
 		hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", ret_val);
 	}
 
-	ndp_ctx->state = NAN_DATA_NDI_CREATING_STATE;
+	update_ndi_state(adapter, NAN_DATA_NDI_CREATING_STATE);
 	return ret_val;
 
 error_wmm_init:
@@ -2048,3 +2096,155 @@
 
 	return ret_val;
 }
+
+#ifdef WLAN_FEATURE_NAN_CONVERGENCE
+struct wlan_objmgr_vdev *hdd_ndi_open(char *iface_name)
+{
+	hdd_adapter_t *adapter;
+	hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+
+	ENTER();
+	/* Check for an existing interface of NDI type */
+	adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE);
+	if (adapter) {
+		hdd_err("Cannot support more than one NDI");
+		return NULL;
+	}
+
+	adapter = hdd_open_adapter(hdd_ctx, QDF_NDI_MODE, iface_name,
+			wlan_hdd_get_intf_addr(hdd_ctx), NET_NAME_UNKNOWN,
+			true);
+	if (!adapter) {
+		hdd_err("hdd_open_adapter failed");
+		return NULL;
+	}
+
+	EXIT();
+	return adapter->hdd_vdev;
+}
+
+int hdd_ndi_start(uint8_t vdev_id)
+{
+	hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	uint8_t op_channel = hdd_ctx->config->nan_datapath_ndi_channel;
+	hdd_adapter_t *adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+
+	ENTER();
+	/*
+	 * The NAN data interface has been created at this point.
+	 * Unlike traditional device modes, where the higher application
+	 * layer initiates connect / join / start, the NAN data
+	 * interface does not have any such formal requests. The NDI
+	 * create request is responsible for starting the BSS as well.
+	 */
+	if (op_channel != NAN_SOCIAL_CHANNEL_2_4GHZ ||
+		op_channel != NAN_SOCIAL_CHANNEL_5GHZ_LOWER_BAND ||
+		op_channel != NAN_SOCIAL_CHANNEL_5GHZ_UPPER_BAND) {
+		/* start NDI on the default 2.4 GHz social channel */
+		op_channel = NAN_SOCIAL_CHANNEL_2_4GHZ;
+	}
+	if (hdd_ndi_start_bss(adapter, op_channel)) {
+		hdd_err("NDI start bss failed");
+		/* Start BSS failed, delete the interface */
+		hdd_close_ndi(adapter);
+		EXIT();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int hdd_ndi_delete(uint8_t vdev_id, char *iface_name, uint16_t transaction_id)
+{
+	int ret;
+	hdd_adapter_t *adapter;
+	hdd_station_ctx_t *sta_ctx;
+	hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+
+	/* Check if there is already an existing inteface with the same name */
+	adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+	if (!adapter || !WLAN_HDD_IS_NDI(adapter)) {
+		hdd_err("NAN data interface %s is not available", iface_name);
+		return -EINVAL;
+	}
+
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (!sta_ctx) {
+		hdd_err("sta_ctx is NULL");
+		return -EINVAL;
+	}
+
+	/* Since, the interface is being deleted, remove the broadcast id. */
+	hdd_ctx->sta_to_adapter[sta_ctx->broadcast_staid] = 0;
+	sta_ctx->broadcast_staid = HDD_WLAN_INVALID_STA_ID;
+
+	os_if_nan_set_ndp_delete_transaction_id(adapter->hdd_vdev,
+						transaction_id);
+	os_if_nan_set_ndi_state(adapter->hdd_vdev, NAN_DATA_NDI_DELETING_STATE);
+
+	/* Delete the interface */
+	ret = __wlan_hdd_del_virtual_intf(hdd_ctx->wiphy, &adapter->wdev);
+	if (ret)
+		hdd_err("NDI delete request failed");
+	else
+		hdd_err("NDI delete request successfully issued");
+
+	return ret;
+}
+
+void hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id,
+				struct nan_datapath_inf_create_rsp *ndi_rsp)
+{
+	tCsrRoamInfo roam_info = {0};
+	tSirBssDescription tmp_bss_descp = {0};
+	hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	hdd_adapter_t *adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+	struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
+	hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+
+	if (ndi_rsp->status == QDF_STATUS_SUCCESS) {
+		hdd_alert("NDI interface successfully created");
+		os_if_nan_set_ndp_create_transaction_id(adapter->hdd_vdev, 0);
+		os_if_nan_set_ndi_state(adapter->hdd_vdev,
+					NAN_DATA_NDI_CREATED_STATE);
+		wlan_hdd_netif_queue_control(adapter,
+					WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
+					WLAN_CONTROL_PATH);
+	} else {
+		hdd_alert("NDI interface creation failed with reason %d",
+			ndi_rsp->reason /* create_reason */);
+	}
+
+	sta_ctx->broadcast_staid = ndi_rsp->sta_id;
+	hdd_save_peer(sta_ctx, sta_ctx->broadcast_staid, &bc_mac_addr);
+	hdd_roam_register_sta(adapter, &roam_info,
+				sta_ctx->broadcast_staid,
+				&bc_mac_addr, &tmp_bss_descp);
+	hdd_ctx->sta_to_adapter[sta_ctx->broadcast_staid] = adapter;
+}
+
+void hdd_ndi_close(uint8_t vdev_id)
+{
+	hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	hdd_adapter_t *adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+	hdd_close_ndi(adapter);
+}
+
+void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id)
+{
+	hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	hdd_adapter_t *adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
+
+	wlan_hdd_netif_queue_control(adapter,
+				     WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
+				     WLAN_CONTROL_PATH);
+
+	complete(&adapter->disconnect_comp_var);
+}
+
+void hdd_ndp_session_end_handler(hdd_adapter_t *adapter)
+{
+	os_if_nan_ndi_session_end(adapter->hdd_vdev);
+}
+
+#endif