qcacmn: Converge FTM feature

Support for FTM to make it common between WIN and MCL.

Change-Id: I4a65ca6d73d83e71f6a04405b5c41cdddb0a3c71
CRs-fixed: 2148283
diff --git a/ftm/core/src/wlan_ftm_svc.c b/ftm/core/src/wlan_ftm_svc.c
new file mode 100644
index 0000000..a055642
--- /dev/null
+++ b/ftm/core/src/wlan_ftm_svc.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: This implementation of init/deint functions for FTM services.
+ */
+
+#include "wlan_ftm_svc_i.h"
+#include <wlan_lmac_if_def.h>
+#include <wlan_ftm_ucfg_api.h>
+
+static inline struct wlan_lmac_if_ftm_tx_ops *
+wlan_psoc_get_ftm_txops(struct wlan_objmgr_psoc *psoc)
+{
+	return &((psoc->soc_cb.tx_ops.ftm_tx_ops));
+}
+
+static QDF_STATUS
+ftm_pdev_obj_init(struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj)
+{
+	ftm_pdev_obj->data = qdf_mem_malloc(FTM_CMD_MAX_BUF_LENGTH);
+	if (!ftm_pdev_obj->data) {
+		ftm_err("Memory alloc failed for ftm pdev obj data");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	ftm_pdev_obj->length = 0;
+
+	ftm_pdev_obj->cmd_type = WIFI_FTM_CMD_UNKNOWN;
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_ftm_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
+					void *arg_list)
+{
+	QDF_STATUS status;
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj;
+
+	ftm_pdev_obj = qdf_mem_malloc(sizeof(*ftm_pdev_obj));
+
+	if (!ftm_pdev_obj) {
+		ftm_err("Memory alloc failed for ftm pdev obj");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	ftm_pdev_obj->pdev = pdev;
+	status = ftm_pdev_obj_init(ftm_pdev_obj);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ftm_err("ftm pdev obj init failed");
+		qdf_mem_free(ftm_pdev_obj);
+		return status;
+	}
+
+	status = wlan_objmgr_pdev_component_obj_attach(pdev,
+						WLAN_UMAC_COMP_FTM,
+						ftm_pdev_obj,
+						QDF_STATUS_SUCCESS);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ftm_err("ftm pdev obj attach failed");
+		qdf_mem_free(ftm_pdev_obj);
+		return status;
+	}
+
+	return status;
+}
+
+static QDF_STATUS
+ftm_pdev_obj_deinit(struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj)
+{
+	if (ftm_pdev_obj->data) {
+		qdf_mem_free(ftm_pdev_obj->data);
+
+		ftm_pdev_obj->data = NULL;
+		ftm_pdev_obj->length = 0;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_ftm_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev,
+					void *arg_list)
+{
+	QDF_STATUS status;
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj =
+		wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_FTM);
+
+	if (NULL == ftm_pdev_obj) {
+		ftm_err("invalid wifi ftm obj");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	status = wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_FTM,
+							ftm_pdev_obj);
+
+	status = ftm_pdev_obj_deinit(ftm_pdev_obj);
+	ftm_pdev_obj->pdev = NULL;
+
+	qdf_mem_free(ftm_pdev_obj);
+
+	return status;
+}
+
+QDF_STATUS
+wlan_ftm_testmode_attach(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_ftm_tx_ops *ftm_tx_ops;
+
+	ftm_tx_ops = wlan_psoc_get_ftm_txops(psoc);
+
+	if (ftm_tx_ops->ftm_attach)
+		return ftm_tx_ops->ftm_attach(psoc);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_ftm_testmode_detach(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_ftm_tx_ops *ftm_tx_ops;
+
+	ftm_tx_ops = wlan_psoc_get_ftm_txops(psoc);
+
+	if (ftm_tx_ops->ftm_detach)
+		return ftm_tx_ops->ftm_detach(psoc);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_ftm_cmd_send(struct wlan_objmgr_pdev *pdev, uint8_t *buf,
+			uint32_t len, uint8_t pdev_id)
+{
+	struct wlan_lmac_if_ftm_tx_ops *ftm_tx_ops;
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc)
+		return QDF_STATUS_E_NOENT;
+
+	ftm_tx_ops = wlan_psoc_get_ftm_txops(psoc);
+
+	if (ftm_tx_ops->ftm_cmd_send)
+		return ftm_tx_ops->ftm_cmd_send(pdev, buf, len, pdev_id);
+
+	return QDF_STATUS_SUCCESS;
+}
diff --git a/ftm/core/src/wlan_ftm_svc_i.h b/ftm/core/src/wlan_ftm_svc_i.h
new file mode 100644
index 0000000..bd8be91
--- /dev/null
+++ b/ftm/core/src/wlan_ftm_svc_i.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declare the ftm service data structure and apis
+ */
+#ifndef _WLAN_FTM_SVC_H_
+#define _WLAN_FTM_SVC_H_
+
+#include <qdf_types.h>
+#include <qdf_status.h>
+#include <wlan_objmgr_pdev_obj.h>
+
+/**
+ * struct ftm_seg_hdr_info - the segment header for the event from FW
+ * @len: length of the segment header
+ * @msgref: message reference
+ * @segment_info: segment information
+ * @pad: padding
+ *
+ */
+struct ftm_seg_hdr_info {
+	uint32_t len;
+	uint32_t msgref;
+	uint32_t segment_info;
+	uint32_t pad;
+};
+
+/**
+ * wlan_ftm_pdev_obj_create_notification() - ftm pdev create handler
+ * @pdev: pdev pointer
+ * @arg_list: argument list
+ *
+ * return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS wlan_ftm_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
+							void *arg_list);
+
+/**
+ * wlan_ftm_pdev_obj_destroy_notification() - ftm pdev destroy handler
+ * @pdev: pdev pointer
+ * @arg_list: argument list
+ *
+ * return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS wlan_ftm_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev,
+							void *arg_list);
+
+/**
+ * wlan_ftm_cmd_send() - send ftm command to target_if layer
+ * @pdev: pdev pointer
+ * @buf: data buffer
+ * @len: event length
+ *
+ * return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS wlan_ftm_cmd_send(struct wlan_objmgr_pdev *pdev, uint8_t *buf,
+				uint32_t len, uint8_t pdev_id);
+
+/**
+ * wlan_ftm_testmode_attach() - Attach FTM UTF handle
+ * @psoc: psoc pointer
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS wlan_ftm_testmode_attach(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_ftm_testmode_detach() - Attach FTM UTF handle
+ * @psoc: psoc pointer
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS wlan_ftm_testmode_detach(struct wlan_objmgr_psoc *psoc);
+#endif /* _WLAN_FTM_SVC_H_ */
diff --git a/ftm/dispatcher/inc/wlan_ftm_init_deinit_api.h b/ftm/dispatcher/inc/wlan_ftm_init_deinit_api.h
new file mode 100644
index 0000000..0487af6
--- /dev/null
+++ b/ftm/dispatcher/inc/wlan_ftm_init_deinit_api.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declare the ftm service data structure and apis
+ */
+#ifndef _WLAN_FTM_UCFG_API_H_
+#define _WLAN_FTM_UCFG_API_H_
+
+#include <qdf_types.h>
+#include <qdf_status.h>
+#include <wlan_objmgr_cmn.h>
+
+/**
+ * dispatcher_ftm_init() - FTM testmode initialization API
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS dispatcher_ftm_init(void);
+
+/**
+ * dispatcher_ftm_deinit() - FTM testmode deinitialization API
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS dispatcher_ftm_deinit(void);
+
+/**
+ * dispatcher_ftm_psoc_open() - FTM module open API
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS dispatcher_ftm_psoc_open(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * dispatcher_ftm_psoc_close() - FTM module close API
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS dispatcher_ftm_psoc_close(struct wlan_objmgr_psoc *psoc);
+#endif /* _WLAN_FTM_UCFG_API_H_ */
diff --git a/ftm/dispatcher/inc/wlan_ftm_ucfg_api.h b/ftm/dispatcher/inc/wlan_ftm_ucfg_api.h
new file mode 100644
index 0000000..34a6489
--- /dev/null
+++ b/ftm/dispatcher/inc/wlan_ftm_ucfg_api.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declare the ftm service data structure and apis
+ */
+#ifndef _WLAN_FTM_UCFG_API_H_
+#define _WLAN_FTM_UCFG_API_H_
+
+#include <qdf_types.h>
+#include <qdf_status.h>
+#include <wlan_objmgr_cmn.h>
+
+#define FTM_DEBUG       0
+
+#if FTM_DEBUG
+#define ftm_log(level, args...) \
+	QDF_TRACE(QDF_MODULE_ID_FTM, level, ## args)
+#define ftm_logfl(level, format, args...) \
+	ftm_log(level, FL(format), ## args)
+
+#define ftm_alert(format, args...) \
+	ftm_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args)
+#define ftm_err(format, args...) \
+	ftm_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args)
+#define ftm_warn(format, args...) \
+	ftm_logfl(QDF_TRACE_LEVEL_WARN, format, ## args)
+#define ftm_notice(format, args...) \
+	ftm_logfl(QDF_TRACE_LEVEL_INFO, format, ## args)
+#define ftm_debug(format, args...) \
+	ftm_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args)
+#else
+#define ftm_alert(format, args...)
+#define ftm_err(format, args...)
+#define ftm_warn(format, args...)
+#define ftm_notice(format, args...)
+#define ftm_debug(format, args...)
+#endif
+
+#define FTM_IOCTL_UNIFIED_UTF_CMD		0x1000
+#define FTM_IOCTL_UNIFIED_UTF_RSP		0x1001
+#define FTM_CMD_MAX_BUF_LENGTH		    2048
+
+/**
+ * enum wifi_ftm_cmd_type - the enumeration of the command source per pdev
+ * @WIFI_FTM_CMD_IOCTL: command from ioctl on the pdev
+ * @WIFI_FTM_CMD_NL80211: command from nl80211 on the pdev
+ *
+ */
+enum wifi_ftm_pdev_cmd_type {
+	WIFI_FTM_CMD_IOCTL = 1,
+	WIFI_FTM_CMD_NL80211,
+
+	/* command should be added above */
+	WIFI_FTM_CMD_UNKNOWN,
+};
+
+/**
+ * struct wifi_ftm_pdev_priv_obj - wifi ftm pdev utf event info
+ * @pdev: pointer to pdev
+ * @data: data ptr
+ * @current_seq: curent squence
+ * @expected_seq: expected sequence
+ * @length: length
+ * @offset: offset
+ * @cmd_type: command type from either ioctl or nl80211
+ */
+struct wifi_ftm_pdev_priv_obj {
+	struct wlan_objmgr_pdev *pdev;
+	uint8_t *data;
+	uint8_t current_seq;
+	uint8_t expected_seq;
+	qdf_size_t length;
+	qdf_size_t offset;
+	enum wifi_ftm_pdev_cmd_type cmd_type;
+};
+
+/**
+ * wlan_ftm_testmode_cmd() - handle FTM testmode command
+ * @pdev: pdev pointer
+ * @data: data
+ * @len: data length
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS ucfg_wlan_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev,
+					uint8_t *data, uint32_t len);
+
+/**
+ * wlan_ftm_testmode_rsp() - handle FTM testmode command
+ * @pdev: pdev pointer
+ * @data: data
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS ucfg_wlan_ftm_testmode_rsp(struct wlan_objmgr_pdev *pdev,
+					uint8_t *data);
+
+/**
+ * wlan_ftm_process_utf_event() - process ftm UTF event
+ * @scn_handle: scn handle
+ * @event: event buffer
+ * @len: event length
+ *
+ * return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS wlan_ftm_process_utf_event(struct wlan_objmgr_pdev *pdev,
+					uint8_t *event_buf, uint32_t len);
+#endif /* _WLAN_FTM_UCFG_API_H_ */
diff --git a/ftm/dispatcher/src/wlan_ftm_init_deinit.c b/ftm/dispatcher/src/wlan_ftm_init_deinit.c
new file mode 100644
index 0000000..47364e0
--- /dev/null
+++ b/ftm/dispatcher/src/wlan_ftm_init_deinit.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: This implementation of init/deint functions for FTM services.
+ */
+
+#include <wlan_ftm_init_deinit_api.h>
+#include <wlan_ftm_ucfg_api.h>
+#include <wlan_objmgr_global_obj.h>
+#include "../../core/src/wlan_ftm_svc_i.h"
+#include <wlan_cmn.h>
+#include <qdf_module.h>
+
+QDF_STATUS dispatcher_ftm_init(void)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_FTM,
+			wlan_ftm_pdev_obj_create_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		goto err_pdev_create;
+
+	status = wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_FTM,
+			wlan_ftm_pdev_obj_destroy_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		goto err_pdev_delete;
+
+	return QDF_STATUS_SUCCESS;
+
+err_pdev_delete:
+	wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_FTM,
+			wlan_ftm_pdev_obj_create_notification, NULL);
+err_pdev_create:
+	return status;
+}
+
+QDF_STATUS dispatcher_ftm_deinit(void)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status = wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_FTM,
+			wlan_ftm_pdev_obj_create_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_FAILURE;
+
+	status = wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_FTM,
+			wlan_ftm_pdev_obj_destroy_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS dispatcher_ftm_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+	/* calling the wmi event handler registration */
+	return wlan_ftm_testmode_attach(psoc);
+}
+
+QDF_STATUS dispatcher_ftm_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+	/* calling the wmi event handler de-registration */
+	return wlan_ftm_testmode_detach(psoc);
+}
diff --git a/ftm/dispatcher/src/wlan_ftm_ucfg_api.c b/ftm/dispatcher/src/wlan_ftm_ucfg_api.c
new file mode 100644
index 0000000..8a737be
--- /dev/null
+++ b/ftm/dispatcher/src/wlan_ftm_ucfg_api.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: This implementation of init/deint functions for FTM services.
+ */
+
+#include <wlan_ftm_ucfg_api.h>
+#include <wlan_cfg80211_ftm.h>
+#include "../../core/src/wlan_ftm_svc_i.h"
+#include <wlan_cmn.h>
+#include <qdf_module.h>
+
+QDF_STATUS ucfg_wlan_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev,
+					uint8_t *data, uint32_t len)
+{
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj;
+	uint8_t pdev_id;
+
+	ftm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+							WLAN_UMAC_COMP_FTM);
+	if (!ftm_pdev_obj) {
+		ftm_err("Failed to get ftm pdev component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ftm_pdev_obj->length = 0;
+	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+
+	return wlan_ftm_cmd_send(pdev, data, len, pdev_id);
+}
+
+QDF_STATUS ucfg_wlan_ftm_testmode_rsp(struct wlan_objmgr_pdev *pdev,
+					uint8_t *data)
+{
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj;
+	uint32_t *len;
+
+	ftm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+							WLAN_UMAC_COMP_FTM);
+	if (!ftm_pdev_obj) {
+		ftm_err("Failed to get ftm pdev component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (ftm_pdev_obj->length) {
+		len = (uint32_t *)data;
+		*len = ftm_pdev_obj->length;
+		qdf_mem_copy((data + 4), ftm_pdev_obj->data,
+					ftm_pdev_obj->length);
+
+		ftm_pdev_obj->length = 0;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS
+wlan_ftm_process_utf_event(struct wlan_objmgr_pdev *pdev,
+			    uint8_t *event_buf, uint32_t len)
+{
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj;
+	u_int16_t utf_datalen;
+	uint8_t *utf_data;
+	struct ftm_seg_hdr_info seghdr_info;
+	u_int8_t total_segments, current_seq;
+
+	ftm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+			WLAN_UMAC_COMP_FTM);
+	if (!ftm_pdev_obj) {
+		ftm_err("Failed to get ftm pdev component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	utf_data = event_buf;
+	seghdr_info = *(struct ftm_seg_hdr_info *)(event_buf);
+	ftm_pdev_obj->current_seq = (seghdr_info.segment_info & 0xF);
+
+	current_seq = (seghdr_info.segment_info & 0xF);
+	total_segments = (seghdr_info.segment_info >> 4) & 0xF;
+
+	utf_datalen = len - sizeof(seghdr_info);
+
+	if (current_seq == 0) {
+		ftm_pdev_obj->expected_seq = 0;
+		ftm_pdev_obj->offset = 0;
+	} else {
+		if (ftm_pdev_obj->expected_seq != current_seq) {
+			ftm_debug("seq mismatch exp Seq %d got seq %d\n",
+				ftm_pdev_obj->expected_seq, current_seq);
+		}
+	}
+
+	qdf_mem_copy(&ftm_pdev_obj->data[ftm_pdev_obj->offset],
+			&utf_data[sizeof(seghdr_info)], utf_datalen);
+
+	ftm_pdev_obj->offset = ftm_pdev_obj->offset + utf_datalen;
+	ftm_pdev_obj->expected_seq++;
+
+	if (ftm_pdev_obj->expected_seq == total_segments) {
+		if (ftm_pdev_obj->offset != seghdr_info.len) {
+			ftm_debug("len mismatch len %zu total len %d\n",
+				ftm_pdev_obj->offset, seghdr_info.len);
+		}
+
+		ftm_pdev_obj->length = ftm_pdev_obj->offset;
+
+		/**
+		 * If the repsonse is for a command from FTM daemon,
+		 * send this repsonse data to cfg80211
+		 */
+		if (ftm_pdev_obj->cmd_type == WIFI_FTM_CMD_NL80211) {
+			if (wlan_cfg80211_ftm_rx_event(pdev, ftm_pdev_obj->data,
+				ftm_pdev_obj->length) != QDF_STATUS_SUCCESS) {
+				return QDF_STATUS_E_FAILURE;
+			}
+			ftm_pdev_obj->cmd_type = WIFI_FTM_CMD_UNKNOWN;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
diff --git a/init_deinit/dispatcher/src/dispatcher_init_deinit.c b/init_deinit/dispatcher/src/dispatcher_init_deinit.c
index 306239c..258996b 100644
--- a/init_deinit/dispatcher/src/dispatcher_init_deinit.c
+++ b/init_deinit/dispatcher/src/dispatcher_init_deinit.c
@@ -22,6 +22,7 @@
 #include <dispatcher_init_deinit.h>
 #include <scheduler_api.h>
 #include <wlan_scan_ucfg_api.h>
+#include <wlan_ftm_init_deinit_api.h>
 #include <wlan_mgmt_txrx_utils_api.h>
 #include <wlan_serialization_api.h>
 #ifdef WLAN_POLICY_MGR_ENABLE
@@ -774,6 +775,9 @@
 	if (QDF_STATUS_SUCCESS != dispatcher_green_ap_init())
 		goto green_ap_init_fail;
 
+	if (QDF_STATUS_SUCCESS != dispatcher_ftm_init())
+		goto ftm_init_fail;
+
 	/*
 	 * scheduler INIT has to be the last as each component's
 	 * initialization has to happen first and then at the end
@@ -785,6 +789,8 @@
 	return QDF_STATUS_SUCCESS;
 
 scheduler_init_fail:
+	dispatcher_ftm_deinit();
+ftm_init_fail:
 	dispatcher_green_ap_deinit();
 green_ap_init_fail:
 	dispatcher_spectral_deinit();
@@ -832,6 +838,8 @@
 {
 	QDF_BUG(QDF_STATUS_SUCCESS == scheduler_deinit());
 
+	QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_ftm_deinit());
+
 	QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_green_ap_deinit());
 
 	QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_spectral_deinit());
@@ -921,7 +929,13 @@
 	if (QDF_STATUS_SUCCESS != son_psoc_open(psoc))
 		goto psoc_son_fail;
 
+	if (QDF_STATUS_SUCCESS != dispatcher_ftm_psoc_open(psoc))
+		goto ftm_psoc_open_fail;
+
 	return QDF_STATUS_SUCCESS;
+
+ftm_psoc_open_fail:
+	son_psoc_close(psoc);
 psoc_son_fail:
 	regulatory_psoc_close(psoc);
 regulatory_psoc_open_fail:
@@ -946,6 +960,8 @@
 
 QDF_STATUS dispatcher_psoc_close(struct wlan_objmgr_psoc *psoc)
 {
+	QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_ftm_psoc_close(psoc));
+
 	QDF_BUG(QDF_STATUS_SUCCESS == son_psoc_close(psoc));
 
 	QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_regulatory_psoc_close(psoc));
diff --git a/os_if/linux/ftm/inc/wlan_cfg80211_ftm.h b/os_if/linux/ftm/inc/wlan_cfg80211_ftm.h
new file mode 100644
index 0000000..3bb497e
--- /dev/null
+++ b/os_if/linux/ftm/inc/wlan_cfg80211_ftm.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declares driver FTM functions interfacing with linux kernel
+ */
+
+#ifndef _WLAN_CFG80211_FTM_H_
+#define _WLAN_CFG80211_FTM_H_
+
+/**
+ * enum wlan_cfg80211_ftm_attr - FTM Netlink attributes
+ * @WLAN_CFG80211_FTM_ATTR_INVALID: attribute is invalid
+ * @WLAN_CFG80211_FTM_ATTR_CMD: attribute type is FTM command
+ * @WLAN_CFG80211_FTM_ATTR_DATA: attribute type is data
+ *
+ * @WLAN_CFG80211_FTM_ATTR_MAX: Max number of attributes
+ */
+enum wlan_cfg80211_ftm_attr {
+	WLAN_CFG80211_FTM_ATTR_INVALID = 0,
+	WLAN_CFG80211_FTM_ATTR_CMD = 1,
+	WLAN_CFG80211_FTM_ATTR_DATA = 2,
+
+	/* keep last */
+	WLAN_CFG80211_FTM_ATTR_MAX,
+};
+
+/**
+ * enum wlan_cfg80211_ftm_cmd - FTM command types
+ * @WLAN_CFG80211_FTM_CMD_WLAN_FTM: command is of type FTM
+ */
+enum wlan_cfg80211_ftm_cmd {
+	WLAN_CFG80211_FTM_CMD_WLAN_FTM = 0,
+};
+
+#define WLAN_FTM_DATA_MAX_LEN 2048
+
+/**
+ * wlan_cfg80211_ftm_testmode_cmd() - process cfg80211 testmode command
+ * @pdev: pdev object
+ * @data: ftm testmode command data of type void
+ * @len: length of the data
+ *
+ * Return: 0 on success or -Eerrno otherwise
+ */
+int wlan_cfg80211_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev,
+				void *data, uint32_t len);
+
+/**
+ * wlan_cfg80211_ftm_rx_event() - handle the received ftm event
+ * @pdev: pdev object
+ * @data: ftm event data
+ * @len: length of the data
+ *
+ * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E errno otherwise
+ */
+QDF_STATUS wlan_cfg80211_ftm_rx_event(struct wlan_objmgr_pdev *pdev,
+					uint8_t *data, uint32_t len);
+
+#endif
diff --git a/os_if/linux/ftm/inc/wlan_ioctl_ftm.h b/os_if/linux/ftm/inc/wlan_ioctl_ftm.h
new file mode 100644
index 0000000..7a94c3f
--- /dev/null
+++ b/os_if/linux/ftm/inc/wlan_ioctl_ftm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declares driver FTM functions interfacing with linux kernel
+ */
+
+#ifndef _WLAN_IOCTL_FTM_H_
+#define _WLAN_IOCTL_FTM_H_
+
+/**
+ * wlan_ioctl_ftm_testmode_cmd() - handle the ftm ioctl command
+ * @pdev: pdev object
+ * @cmd: ftm command
+ * @userdata: the content of the command
+ * @length: the length of the userdata
+ *
+ * Return: 0 on success, otherwise the error code.
+ */
+int wlan_ioctl_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev, int cmd,
+				uint8_t *userdata, uint32_t length);
+
+#endif
diff --git a/os_if/linux/ftm/src/wlan_cfg80211_ftm.c b/os_if/linux/ftm/src/wlan_cfg80211_ftm.c
new file mode 100644
index 0000000..1401002
--- /dev/null
+++ b/os_if/linux/ftm/src/wlan_cfg80211_ftm.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: implementation of the driver FTM functions interfacing with linux kernel
+ */
+
+#include <net/cfg80211.h>
+#include <qdf_util.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_cfg80211_ftm.h>
+#include <wlan_ftm_ucfg_api.h>
+#include <wlan_osif_priv.h>
+#include <qdf_types.h>
+#include <qdf_module.h>
+
+static const struct nla_policy
+wlan_cfg80211_ftm_policy[WLAN_CFG80211_FTM_ATTR_MAX + 1] = {
+	[WLAN_CFG80211_FTM_ATTR_CMD] = {.type = NLA_U32},
+	[WLAN_CFG80211_FTM_ATTR_DATA] = {.type = NLA_BINARY,
+		.len = WLAN_FTM_DATA_MAX_LEN},
+};
+
+static int
+wlan_cfg80211_process_ftm_cmd(struct wlan_objmgr_pdev *pdev,
+				struct nlattr *tb[])
+{
+	int buf_len;
+	void *buf;
+	QDF_STATUS status;
+
+	if (!tb[WLAN_CFG80211_FTM_ATTR_DATA]) {
+		ftm_err("WLAN_CFG80211_FTM_ATTR_DATA attribute is invalid");
+		return -EINVAL;
+	}
+
+	buf = nla_data(tb[WLAN_CFG80211_FTM_ATTR_DATA]);
+	buf_len = nla_len(tb[WLAN_CFG80211_FTM_ATTR_DATA]);
+
+	if (buf_len > WLAN_FTM_DATA_MAX_LEN)
+		return -EINVAL;
+
+	ftm_debug("****FTM Tx cmd len = %d*****", buf_len);
+
+	status = ucfg_wlan_ftm_testmode_cmd(pdev, buf, buf_len);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		status = QDF_STATUS_E_BUSY;
+
+	return qdf_status_to_os_return(status);
+}
+
+int
+wlan_cfg80211_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev,
+				void *data, uint32_t len)
+{
+	struct nlattr *tb[WLAN_CFG80211_FTM_ATTR_MAX + 1];
+	int err = 0, cmd;
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj;
+
+	ftm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+							WLAN_UMAC_COMP_FTM);
+	if (!ftm_pdev_obj) {
+		ftm_err("Failed to get ftm pdev component");
+		return -EINVAL;
+	}
+
+	ftm_pdev_obj->cmd_type = WIFI_FTM_CMD_NL80211;
+
+	err = nla_parse(tb, WLAN_CFG80211_FTM_ATTR_MAX - 1, data,
+			len, wlan_cfg80211_ftm_policy);
+	if (err) {
+		ftm_err("Testmode INV ATTR");
+		return err;
+	}
+
+	if (!tb[WLAN_CFG80211_FTM_ATTR_CMD]) {
+		ftm_err("Testmode INV CMD");
+		return -EINVAL;
+	}
+	cmd = nla_get_u32(tb[WLAN_CFG80211_FTM_ATTR_CMD]);
+
+	switch (cmd) {
+	case WLAN_CFG80211_FTM_CMD_WLAN_FTM:
+		err = wlan_cfg80211_process_ftm_cmd(pdev, tb);
+		break;
+
+	default:
+		ftm_err("unknown command: %d", cmd);
+		return -ENOENT;
+	}
+
+	return err;
+}
+
+qdf_export_symbol(wlan_cfg80211_ftm_testmode_cmd);
+
+QDF_STATUS
+wlan_cfg80211_ftm_rx_event(struct wlan_objmgr_pdev *pdev,
+				uint8_t *data, uint32_t len)
+{
+	struct pdev_osif_priv *pdev_ospriv;
+	qdf_nbuf_t skb = NULL;
+
+	if (!data || !len) {
+		ftm_err("Null data or invalid length");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev_ospriv = wlan_pdev_get_ospriv(pdev);
+	if (!pdev_ospriv) {
+		ftm_err("pdev_ospriv is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	ftm_debug("Testmode response event generated");
+
+	skb = cfg80211_testmode_alloc_event_skb(pdev_ospriv->wiphy,
+						len, GFP_ATOMIC);
+
+	if (!skb)
+		return QDF_STATUS_E_NOMEM;
+
+	if (nla_put_u32(skb, WLAN_CFG80211_FTM_ATTR_CMD,
+			WLAN_CFG80211_FTM_CMD_WLAN_FTM) ||
+		nla_put(skb, WLAN_CFG80211_FTM_ATTR_DATA, len, data)) {
+		goto nla_put_failure;
+	}
+
+	cfg80211_testmode_event(skb, GFP_ATOMIC);
+
+	return QDF_STATUS_SUCCESS;
+
+nla_put_failure:
+	qdf_nbuf_free(skb);
+	ftm_err("nla_put failed on testmode rx skb!");
+
+	return QDF_STATUS_E_INVAL;
+}
diff --git a/os_if/linux/ftm/src/wlan_ioctl_ftm.c b/os_if/linux/ftm/src/wlan_ioctl_ftm.c
new file mode 100644
index 0000000..952b9f7
--- /dev/null
+++ b/os_if/linux/ftm/src/wlan_ioctl_ftm.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: implementation of the driver FTM functions interfacing with linux kernel
+ */
+
+#include <qdf_util.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_ftm_ucfg_api.h>
+#include <qdf_types.h>
+#include <qdf_module.h>
+#include <wlan_cfg80211_ftm.h>
+#include <wlan_ioctl_ftm.h>
+
+static QDF_STATUS
+wlan_process_ftm_ioctl_cmd(struct wlan_objmgr_pdev *pdev,
+		uint8_t *userdata, uint32_t length)
+{
+	uint8_t *buffer;
+	QDF_STATUS error;
+
+	if (get_user(length, (uint32_t *)userdata) != 0)
+		return QDF_STATUS_E_FAILURE;
+
+	if (length > WLAN_FTM_DATA_MAX_LEN)
+		return QDF_STATUS_E_FAILURE;
+
+	buffer = qdf_mem_malloc(length);
+	if (!buffer)
+		return QDF_STATUS_E_NOMEM;
+
+	if (copy_from_user(buffer, &userdata[sizeof(length)], length))
+		error = QDF_STATUS_E_FAILURE;
+	else
+		error = ucfg_wlan_ftm_testmode_cmd(pdev, buffer, length);
+
+	qdf_mem_free(buffer);
+
+	return error;
+}
+
+static QDF_STATUS
+wlan_process_ftm_ioctl_rsp(struct wlan_objmgr_pdev *pdev,
+		uint8_t *userdata, uint32_t length)
+{
+	uint8_t *buffer;
+	QDF_STATUS error;
+
+	length = WLAN_FTM_DATA_MAX_LEN + sizeof(u_int32_t);
+
+	buffer = qdf_mem_malloc(length);
+	if (!buffer)
+		return QDF_STATUS_E_NOMEM;
+
+	error = ucfg_wlan_ftm_testmode_rsp(pdev, buffer);
+	if (!error)
+		error = copy_to_user((userdata - sizeof(int)), buffer, length);
+	else
+		error = QDF_STATUS_E_AGAIN;
+
+	qdf_mem_free(buffer);
+
+	return error;
+}
+
+int
+wlan_ioctl_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev, int cmd,
+		uint8_t *userdata, uint32_t length)
+{
+	QDF_STATUS error;
+	struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj;
+
+	ftm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
+			WLAN_UMAC_COMP_FTM);
+	if (!ftm_pdev_obj) {
+		ftm_err("Failed to get ftm pdev component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ftm_pdev_obj->cmd_type = WIFI_FTM_CMD_IOCTL;
+
+	switch (cmd) {
+	case FTM_IOCTL_UNIFIED_UTF_CMD:
+		error = wlan_process_ftm_ioctl_cmd(pdev,
+				userdata, length);
+		break;
+	case FTM_IOCTL_UNIFIED_UTF_RSP:
+		error = wlan_process_ftm_ioctl_rsp(pdev,
+				userdata, length);
+		break;
+	default:
+		ftm_err("FTM Unknown cmd - not supported");
+		error = QDF_STATUS_E_NOSUPPORT;
+	}
+
+	return qdf_status_to_os_return(error);
+}
+
+qdf_export_symbol(wlan_ioctl_ftm_testmode_cmd);
diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h
index 9a18c0d..c5a65d6 100644
--- a/qdf/inc/qdf_types.h
+++ b/qdf/inc/qdf_types.h
@@ -325,6 +325,7 @@
  * @QDF_MODULE_ID_DIRECT_BUF_RX: Direct Buffer Receive module ID
  * @QDF_MODULE_ID_DISA: DISA (encryption test) module ID
  * @QDF_MODULE_ID_GREEN_AP: Green AP related logging
+ * @QDF_MODULE_ID_FTM: FTM module ID
  * @QDF_MODULE_ID_ANY: anything
  * @QDF_MODULE_ID_MAX: Max place holder module ID
  */
@@ -422,6 +423,7 @@
 	QDF_MODULE_ID_DIRECT_BUF_RX,
 	QDF_MODULE_ID_DISA,
 	QDF_MODULE_ID_GREEN_AP,
+	QDF_MODULE_ID_FTM,
 	QDF_MODULE_ID_ANY,
 	QDF_MODULE_ID_MAX,
 } QDF_MODULE_ID;
diff --git a/target_if/core/src/target_if_main.c b/target_if/core/src/target_if_main.c
index 92743ea..1f90f2d 100644
--- a/target_if/core/src/target_if_main.c
+++ b/target_if/core/src/target_if_main.c
@@ -34,6 +34,7 @@
 #endif
 #include <target_if_reg.h>
 #include <target_if_scan.h>
+#include <target_if_ftm.h>
 #ifdef DFS_COMPONENT_ENABLE
 #include <target_if_dfs.h>
 #endif
@@ -302,6 +303,12 @@
 }
 
 static
+void target_if_ftm_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	target_if_ftm_register_tx_ops(tx_ops);
+}
+
+static
 QDF_STATUS target_if_register_umac_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 {
 	/* call regulatory callback to register tx ops */
@@ -333,6 +340,8 @@
 
 	target_if_green_ap_tx_ops_register(tx_ops);
 
+	target_if_ftm_tx_ops_register(tx_ops);
+
 	/* Converged UMAC components to register their TX-ops here */
 	return QDF_STATUS_SUCCESS;
 }
diff --git a/target_if/ftm/inc/target_if_ftm.h b/target_if/ftm/inc/target_if_ftm.h
new file mode 100644
index 0000000..97ca6f5
--- /dev/null
+++ b/target_if/ftm/inc/target_if_ftm.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: declare the ftm service data structure and apis
+ */
+#ifndef _TARGET_IF_FTM_H_
+#define _TARGET_IF_FTM_H_
+
+#include <qdf_types.h>
+#include <qdf_status.h>
+#include <wlan_objmgr_psoc_obj.h>
+
+/**
+ * target_if_ftm_register_tx_ops() - register ftm tx ops
+ * @tx_ops: tx ops pointer
+ *
+ * Register ftm tx ops
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS target_if_ftm_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops);
+
+/**
+ * target_if_ftm_attach() - Register FW event handler
+ * @psoc: psoc pointer
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS
+target_if_ftm_attach(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_ftm_detach() - De-Register FW event handler
+ * @psoc: psoc pointer
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS
+target_if_ftm_detach(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_ftm_cmd_send() - Send WMI command for FTM requests
+ * @pdev: pdev pointer
+ * buf: data to be sent to FW
+ * len: length of the data
+ * pdev_id: pdev id
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS
+target_if_ftm_cmd_send(struct wlan_objmgr_pdev *pdev,
+				uint8_t *buf, uint32_t len, uint8_t pdev_id);
+#endif /* _TARGET_IF_FTM_H_ */
diff --git a/target_if/ftm/src/target_if_ftm.c b/target_if/ftm/src/target_if_ftm.c
new file mode 100644
index 0000000..6d02d6d
--- /dev/null
+++ b/target_if/ftm/src/target_if_ftm.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: offload lmac interface APIs definitions for FTM
+ */
+
+#include <qdf_status.h>
+#include <target_if_ftm.h>
+#include <wmi_unified_priv.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <target_if.h>
+#include <wlan_lmac_if_def.h>
+#include <wlan_ftm_ucfg_api.h>
+
+static inline struct wlan_lmac_if_ftm_rx_ops *
+target_if_ftm_get_rx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &psoc->soc_cb.rx_ops.ftm_rx_ops;
+}
+
+static int
+target_if_ftm_process_utf_event(ol_scn_t sc, uint8_t *event_buf, uint32_t len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_pdev *pdev;
+	struct wmi_host_pdev_utf_event event;
+	struct wlan_lmac_if_ftm_rx_ops *ftm_rx_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	psoc = target_if_get_psoc_from_scn_hdl(sc);
+	if (!psoc) {
+		ftm_err("null psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FTM_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ftm_err("unable to get psoc reference");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	event.datalen = len;
+	if (wmi_extract_pdev_utf_event(GET_WMI_HDL_FROM_PSOC(psoc),
+				event_buf, &event) != QDF_STATUS_SUCCESS) {
+		ftm_err("Extracting utf event failed");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, event.pdev_id, WLAN_FTM_ID);
+	if (!pdev) {
+		ftm_err("null pdev");
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	ftm_rx_ops = target_if_ftm_get_rx_ops(psoc);
+
+	if (ftm_rx_ops->ftm_ev_handler) {
+		status = ftm_rx_ops->ftm_ev_handler(pdev,
+				event.data, event.datalen);
+		if (QDF_IS_STATUS_ERROR(status))
+			status = QDF_STATUS_E_INVAL;
+	} else {
+		status = QDF_STATUS_E_INVAL;
+	}
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_FTM_ID);
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
+
+	return status;
+}
+
+QDF_STATUS target_if_ftm_cmd_send(struct wlan_objmgr_pdev *pdev,
+				uint8_t *buf, uint32_t len, uint8_t pdev_id)
+{
+	QDF_STATUS ret;
+	wmi_unified_t handle = GET_WMI_HDL_FROM_PDEV(pdev);
+	struct pdev_utf_params param;
+
+	param.utf_payload = buf;
+	param.len = len;
+
+	ret = wmi_unified_pdev_utf_cmd_send(handle, &param, pdev_id);
+	if (ret) {
+		ftm_err("wmi utf cmd send failed, ret: %d", ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return ret;
+}
+
+QDF_STATUS target_if_ftm_attach(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS ret;
+	wmi_unified_t handle = GET_WMI_HDL_FROM_PSOC(psoc);
+
+	ret = wmi_unified_register_event_handler(handle, wmi_pdev_utf_event_id,
+						target_if_ftm_process_utf_event,
+						WMI_RX_UMAC_CTX);
+	if (ret) {
+		ftm_err("wmi event registration failed, ret: %d", ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return ret;
+}
+
+QDF_STATUS target_if_ftm_detach(struct wlan_objmgr_psoc *psoc)
+
+{
+	int ret;
+	wmi_unified_t handle = GET_WMI_HDL_FROM_PSOC(psoc);
+
+	ret = wmi_unified_unregister_event_handler(handle,
+							wmi_pdev_utf_event_id);
+
+	if (ret) {
+		ftm_err("wmi event deregistration failed, ret: %d", ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS target_if_ftm_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	struct wlan_lmac_if_ftm_tx_ops *ftm_tx_ops;
+
+	if (!tx_ops) {
+		ftm_err("invalid tx_ops");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ftm_tx_ops = &tx_ops->ftm_tx_ops;
+	ftm_tx_ops->ftm_attach = target_if_ftm_attach;
+	ftm_tx_ops->ftm_detach = target_if_ftm_detach;
+	ftm_tx_ops->ftm_cmd_send = target_if_ftm_cmd_send;
+
+	return QDF_STATUS_SUCCESS;
+}
diff --git a/umac/cmn_services/inc/wlan_cmn.h b/umac/cmn_services/inc/wlan_cmn.h
index 73d487a..062d9be 100644
--- a/umac/cmn_services/inc/wlan_cmn.h
+++ b/umac/cmn_services/inc/wlan_cmn.h
@@ -118,11 +118,13 @@
  * @WLAN_UMAC_COMP_NAN:           Neighbor Aware Networking
  * @WLAN_UMAC_COMP_DFS:           DFS
  * @WLAN_UMAC_COMP_SPECTRAL:      Spectral
- * @WLAN_UMAC_COMP_ID_MAX:        Maximum components in UMAC
  * @WLAN_UMAC_COMP_OFFCHAN_TXRX:  Offchan TxRx
  * @WLAN_UMAC_COMP_SPLITMAC:      SplitMAC
  * @WLAN_UMAC_COMP_DISA:          DISA encryption test
  * @WLAN_UMAC_COMP_GREEN_AP:      Green AP
+ * @WLAN_UMAC_COMP_FTM:           FTM component
+ *
+ * @WLAN_UMAC_COMP_ID_MAX:        Maximum components in UMAC
  *
  * This id is static.
  * On Adding new component, new id has to be assigned
@@ -151,6 +153,7 @@
 	WLAN_UMAC_COMP_SPLITMAC,
 	WLAN_UMAC_COMP_DISA,
 	WLAN_UMAC_COMP_GREEN_AP,
+	WLAN_UMAC_COMP_FTM,
 	WLAN_UMAC_COMP_ID_MAX,
 };
 
diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h
index 1fb88b5..3c3da3a 100644
--- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h
+++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h
@@ -203,6 +203,7 @@
  * @WLAN_DEBUG_ID:              Debug operations
  * @WLAN_DIRECT_BUF_RX_ID:      Direct Buffer Receive operations
  * @WLAN_DISA_ID:               DISA (encryption test) operations
+ * @WLAN_FTM_ID:                FTM module
  * @WLAN_REF_ID_MAX:            Max id used to generate ref count tracking array
  */
  /* New value added to the enum must also be reflected in function
@@ -241,6 +242,7 @@
 	WLAN_DEBUG_ID         = 29,
 	WLAN_DIRECT_BUF_RX_ID = 30,
 	WLAN_DISA_ID          = 31,
+	WLAN_FTM_ID           = 31,
 	WLAN_REF_ID_MAX,
 } wlan_objmgr_ref_dbgid;
 
@@ -286,6 +288,7 @@
 					"WLAN_DEBUG_ID",
 					"WLAN_DIRECT_BUF_RX_ID",
 					"WLAN_DISA_ID",
+					"WLAN_FTM_ID",
 					"WLAN_REF_ID_MAX" };
 
 	return (char *)strings[id];
diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
index f5d9305..98ca158 100644
--- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
+++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
@@ -112,6 +112,21 @@
 	QDF_STATUS (*set_chan_list)(struct wlan_objmgr_pdev *pdev, void *arg);
 };
 
+/**
+ * struct wlan_lmac_if_ftm_tx_ops - south bound tx function pointers for ftm
+ * @ftm_attach: function to register event handlers with FW
+ * @ftm_detach: function to de-register event handlers with FW
+ * @ftm_cmd_send: function to send FTM commands to FW
+ *
+ * ftm module uses these functions to avail ol/da lmac services
+ */
+struct wlan_lmac_if_ftm_tx_ops {
+	QDF_STATUS (*ftm_attach)(struct wlan_objmgr_psoc *psoc);
+	QDF_STATUS (*ftm_detach)(struct wlan_objmgr_psoc *psoc);
+	QDF_STATUS (*ftm_cmd_send)(struct wlan_objmgr_pdev *pdev,
+				uint8_t *buf, uint32_t len, uint8_t mac_id);
+};
+
 
 struct wlan_lmac_if_mlme_tx_ops {
 	void (*scan_sta_power_events)(struct wlan_objmgr_pdev *pdev,
@@ -420,6 +435,17 @@
 #endif
 
 /**
+ * struct wlan_lmac_if_ftm_rx_ops  - south bound rx function pointers for FTM
+ * @ftm_ev_handler: function to handle FTM event
+ *
+ * lmac modules uses this API to post FTM events to FTM module
+ */
+struct wlan_lmac_if_ftm_rx_ops {
+	QDF_STATUS (*ftm_ev_handler)(struct wlan_objmgr_pdev *pdev,
+					uint8_t *event_buf, uint32_t len);
+};
+
+/**
  * struct wlan_lmac_reg_if_tx_ops - structure of tx function
  *                  pointers for regulatory component
  * @register_master_handler: pointer to register event handler
@@ -614,15 +640,20 @@
 #endif
 	 struct wlan_lmac_if_mlme_tx_ops mops;
 	 struct wlan_lmac_if_target_tx_ops target_tx_ops;
+
 #ifdef WLAN_OFFCHAN_TXRX_ENABLE
 	struct wlan_lmac_if_offchan_txrx_ops offchan_txrx_ops;
 #endif
+
 #ifdef DIRECT_BUF_RX_ENABLE
 	struct wlan_lmac_if_direct_buf_rx_tx_ops dbr_tx_ops;
 #endif
+
 #ifdef WLAN_SUPPORT_GREEN_AP
 	 struct wlan_lmac_if_green_ap_tx_ops green_ap_tx_ops;
 #endif
+
+	struct wlan_lmac_if_ftm_tx_ops ftm_tx_ops;
 };
 
 /**
@@ -1066,9 +1097,12 @@
 	struct wlan_lmac_if_tdls_rx_ops tdls_rx_ops;
 #endif
 	struct wlan_lmac_if_mlme_rx_ops mops;
+
 #ifdef WLAN_SUPPORT_GREEN_AP
 	struct wlan_lmac_if_green_ap_rx_ops green_ap_rx_ops;
 #endif
+
+	struct wlan_lmac_if_ftm_rx_ops ftm_rx_ops;
 };
 
 /* Function pointer to call legacy tx_ops registration in OL/WMA.
diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
index 01bad79..b2670b8 100644
--- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
+++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
@@ -51,10 +51,12 @@
 #include <wlan_dfs_tgt_api.h>
 #include <wlan_dfs_utils_api.h>
 #endif
+
 #ifdef WLAN_SUPPORT_GREEN_AP
 #include <wlan_green_ap_api.h>
 #include <wlan_green_ap_ucfg_api.h>
 #endif
+#include <wlan_ftm_ucfg_api.h>
 
 /* Function pointer for OL/WMA specific UMAC tx_ops
  * registration.
@@ -324,6 +326,18 @@
 }
 #endif
 
+static QDF_STATUS
+wlan_lmac_if_umac_ftm_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops)
+{
+	struct wlan_lmac_if_ftm_rx_ops *ftm_rx_ops;
+
+	ftm_rx_ops = &rx_ops->ftm_rx_ops;
+
+	ftm_rx_ops->ftm_ev_handler = wlan_ftm_process_utf_event;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * wlan_lmac_if_umac_rx_ops_register() - UMAC rx handler register
  * @rx_ops: Pointer to rx_ops structure to be populated
@@ -389,6 +403,9 @@
 
 	wlan_lmac_if_umac_green_ap_rx_ops_register(rx_ops);
 
+	/* FTM rx_ops */
+	wlan_lmac_if_umac_ftm_rx_ops_register(rx_ops);
+
 	return QDF_STATUS_SUCCESS;
 }