Browse Source

qcacmn: Add TDLS management frames

Add TDLS management frames implementaion in TDLS
umac component

Change-Id: I46943f7df119894e0d54df2c6edb08ed4546a389
CRs-Fixed: 2034220
Kabilan Kannan 8 years ago
parent
commit
97bc1c725a

+ 1 - 0
umac/tdls/core/src/wlan_tdls_cmds_process.c

@@ -26,6 +26,7 @@
 #include "wlan_tdls_main.h"
 #include "wlan_tdls_peer.h"
 #include "wlan_tdls_ct.h"
+#include "wlan_tdls_mgmt.h"
 #include "wlan_tdls_cmds_process.h"
 #include "wlan_tdls_tgt_api.h"
 

+ 9 - 0
umac/tdls/core/src/wlan_tdls_cmds_process.h

@@ -250,4 +250,13 @@ QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev,
  */
 QDF_STATUS tdls_process_connection_tracker_notify(struct wlan_objmgr_vdev *vdev,
 						  struct tdls_event_info *evt);
+
+/**
+ * tdls_validate_mgmt_request() -validate mgmt request
+ * @tdls_validate: action frame request
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+int tdls_validate_mgmt_request(struct tdls_validate_action_req *tdls_validate);
+
 #endif

+ 2 - 0
umac/tdls/core/src/wlan_tdls_main.c

@@ -26,6 +26,7 @@
 #include "wlan_tdls_cmds_process.h"
 #include "wlan_tdls_peer.h"
 #include "wlan_tdls_ct.h"
+#include "wlan_tdls_mgmt.h"
 
 QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc,
 					     void *arg_list)
@@ -212,6 +213,7 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
 
 	switch (msg->type) {
 	case TDLS_CMD_TX_ACTION:
+		tdls_process_mgmt_req(msg->bodyptr);
 		break;
 	case TDLS_CMD_ADD_STA:
 		tdls_process_add_peer(msg->bodyptr);

+ 407 - 0
umac/tdls/core/src/wlan_tdls_mgmt.c

@@ -21,3 +21,410 @@
  *
  * TDLS management frames implementation
  */
+
+#include "wlan_tdls_main.h"
+#include "wlan_tdls_tgt_api.h"
+#include <wlan_serialization_api.h>
+#include "wlan_mgmt_txrx_utils_api.h"
+#include "wlan_tdls_peer.h"
+#include "wlan_tdls_ct.h"
+#include "wlan_tdls_cmds_process.h"
+#include "wlan_tdls_mgmt.h"
+
+static
+const char *const tdls_action_frames_type[] = { "TDLS Setup Request",
+					 "TDLS Setup Response",
+					 "TDLS Setup Confirm",
+					 "TDLS Teardown",
+					 "TDLS Peer Traffic Indication",
+					 "TDLS Channel Switch Request",
+					 "TDLS Channel Switch Response",
+					 "TDLS Peer PSM Request",
+					 "TDLS Peer PSM Response",
+					 "TDLS Peer Traffic Response",
+					 "TDLS Discovery Request"};
+
+/**
+ * tdls_set_rssi() - Set TDLS RSSI on peer given by mac
+ * @tdls_vdev: tdls vdev object
+ * @mac: MAC address of Peer
+ * @rx_rssi: rssi value
+ *
+ * Set RSSI on TDSL peer
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+static int tdls_set_rssi(struct tdls_vdev_priv_obj *tdls_vdev,
+		  const uint8_t *mac,
+		  int8_t rx_rssi)
+{
+	struct tdls_peer *curr_peer;
+
+	curr_peer = tdls_find_peer(tdls_vdev, mac);
+	if (curr_peer == NULL) {
+		tdls_err("curr_peer is NULL");
+		return -EINVAL;
+	}
+
+	curr_peer->rssi = rx_rssi;
+
+	return 0;
+}
+
+/**
+ * tdls_process_rx_mgmt() - process tdls rx mgmt frames
+ * @rx_mgmt_event: tdls rx mgmt event
+ * @tdls_vdev: tdls vdev object
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS tdls_process_rx_mgmt(
+	struct tdls_rx_mgmt_event *rx_mgmt_event,
+	struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	struct tdls_rx_mgmt_frame *rx_mgmt;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	uint8_t *mac;
+	enum tdls_actioncode action_frame_type;
+
+	if (!rx_mgmt_event)
+		return QDF_STATUS_E_INVAL;
+
+	tdls_soc_obj = rx_mgmt_event->tdls_soc_obj;
+	rx_mgmt = rx_mgmt_event->rx_mgmt;
+
+	if (!tdls_soc_obj || !rx_mgmt) {
+		tdls_err("invalid psoc object or rx mgmt");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tdls_debug("soc:%p, frame_len:%d, rx_chan:%d, vdev_id:%d, frm_type:%d, rx_rssi:%d, buf:%p",
+		tdls_soc_obj->soc, rx_mgmt->frame_len,
+		rx_mgmt->rx_chan, rx_mgmt->vdev_id, rx_mgmt->frm_type,
+		rx_mgmt->rx_rssi, rx_mgmt->buf);
+
+	if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET + 1] ==
+						TDLS_PUBLIC_ACTION_DISC_RESP) {
+		mac = &rx_mgmt->buf[TDLS_80211_PEER_ADDR_OFFSET];
+		tdls_notice("[TDLS] TDLS Discovery Response,"
+		       QDF_MAC_ADDRESS_STR " RSSI[%d] <--- OTA",
+		       QDF_MAC_ADDR_ARRAY(mac), rx_mgmt->rx_rssi);
+			tdls_recv_discovery_resp(tdls_vdev, mac);
+			tdls_set_rssi(tdls_vdev, mac, rx_mgmt->rx_rssi);
+	}
+
+
+	if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET] ==
+	    TDLS_ACTION_FRAME) {
+		action_frame_type =
+			rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET + 1];
+		if (action_frame_type >= TDLS_ACTION_FRAME_TYPE_MAX) {
+			tdls_debug("[TDLS] unknown[%d] <--- OTA",
+				   action_frame_type);
+		} else {
+			tdls_notice("[TDLS] %s <--- OTA",
+				   tdls_action_frames_type[action_frame_type]);
+		}
+	}
+
+	/* tdls_soc_obj->tdls_rx_cb ==> wlan_tdls_rx_callback() */
+	if (tdls_soc_obj && tdls_soc_obj->tdls_rx_cb)
+		tdls_soc_obj->tdls_rx_cb(tdls_soc_obj->tdls_rx_cb_data,
+					 rx_mgmt);
+	else
+		tdls_debug("rx mgmt, but no valid up layer callback");
+
+	qdf_mem_free(rx_mgmt);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_rx_mgmt_event *tdls_rx;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	if (!(msg->bodyptr)) {
+		tdls_err("invalid message body");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tdls_rx = (struct tdls_rx_mgmt_event *) msg->bodyptr;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(tdls_rx->tdls_soc_obj->soc,
+				tdls_rx->rx_mgmt->vdev_id, WLAN_TDLS_NB_ID);
+
+	if (vdev) {
+		tdls_debug("tdls rx mgmt frame received");
+
+		tdls_vdev = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+							WLAN_UMAC_COMP_TDLS);
+		if (tdls_vdev)
+			status = tdls_process_rx_mgmt(tdls_rx, tdls_vdev);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	}
+
+	qdf_mem_free(msg->bodyptr);
+	msg->bodyptr = NULL;
+
+	return status;
+}
+
+QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister)
+{
+	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info[3];
+	QDF_STATUS status;
+	int num_of_entries;
+
+	tdls_debug("psoc:%p, is register rx:%d", psoc, isregister);
+
+	frm_cb_info[0].frm_type = MGMT_PROBE_REQ;
+	frm_cb_info[0].mgmt_rx_cb = tgt_tdls_mgmt_frame_rx_cb;
+	frm_cb_info[1].frm_type = MGMT_ACTION_TDLS_DISCRESP;
+	frm_cb_info[1].mgmt_rx_cb = tgt_tdls_mgmt_frame_rx_cb;
+	frm_cb_info[2].frm_type = MGMT_ACTION_VENDOR_SPECIFIC;
+	frm_cb_info[2].mgmt_rx_cb = tgt_tdls_mgmt_frame_rx_cb;
+	num_of_entries = 3;
+
+	if (isregister)
+		status = wlan_mgmt_txrx_register_rx_cb(psoc,
+				WLAN_UMAC_COMP_TDLS, frm_cb_info,
+				num_of_entries);
+	else
+		status = wlan_mgmt_txrx_deregister_rx_cb(psoc,
+				WLAN_UMAC_COMP_TDLS, frm_cb_info,
+				num_of_entries);
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_internal_send_mgmt_tx_done(struct tdls_action_frame_request *req,
+				QDF_STATUS status)
+{
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct tdls_osif_indication indication;
+
+	if (!req || !req->vdev)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	indication.status = status;
+	indication.vdev = req->vdev;
+
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
+	if (tdls_soc_obj && tdls_soc_obj->tdls_event_cb)
+		tdls_soc_obj->tdls_event_cb(tdls_soc_obj->tdls_evt_cb_data,
+			TDLS_EVENT_MGMT_TX_ACK_CNF, &indication);
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_activate_send_mgmt_request(
+				struct tdls_action_frame_request *action_req)
+{
+	struct wlan_objmgr_peer *peer;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	struct scheduler_msg msg;
+	struct tdls_send_mgmt_request *tdls_mgmt_req;
+
+	if (!action_req || !action_req->vdev)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(action_req->vdev,
+						WLAN_TDLS_SB_ID))
+		return QDF_STATUS_E_NULL_VALUE;
+
+
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(action_req->vdev);
+	if (!tdls_soc_obj) {
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto release_mgmt_ref;
+	}
+
+	tdls_mgmt_req = qdf_mem_malloc(sizeof(struct tdls_send_mgmt_request) +
+				action_req->tdls_mgmt.len);
+	if (NULL == tdls_mgmt_req) {
+		status = QDF_STATUS_E_NOMEM;
+		tdls_err("mem alloc failed ");
+		QDF_ASSERT(0);
+		goto release_mgmt_ref;
+	}
+
+	tdls_debug("session_id %d "
+		   "tdls_mgmt.dialog %d "
+		   "tdls_mgmt.frame_type %d "
+		   "tdls_mgmt.status_code %d "
+		   "tdls_mgmt.responder %d "
+		   "tdls_mgmt.peer_capability %d",
+		   action_req->session_id,
+		   action_req->tdls_mgmt.dialog,
+		   action_req->tdls_mgmt.frame_type,
+		   action_req->tdls_mgmt.status_code,
+		   action_req->tdls_mgmt.responder,
+		   action_req->tdls_mgmt.peer_capability);
+
+	tdls_mgmt_req->session_id = action_req->session_id;
+	/* Using dialog as transactionId. This can be used to
+	 * match response with request
+	 */
+	tdls_mgmt_req->transaction_id = action_req->tdls_mgmt.dialog;
+	tdls_mgmt_req->req_type = action_req->tdls_mgmt.frame_type;
+	tdls_mgmt_req->dialog = action_req->tdls_mgmt.dialog;
+	tdls_mgmt_req->status_code = action_req->tdls_mgmt.status_code;
+	tdls_mgmt_req->responder = action_req->tdls_mgmt.responder;
+	tdls_mgmt_req->peer_capability = action_req->tdls_mgmt.peer_capability;
+
+	peer = wlan_vdev_get_bsspeer(action_req->vdev);
+
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_peer_try_get_ref(peer,
+							WLAN_TDLS_SB_ID)) {
+		qdf_mem_free(tdls_mgmt_req);
+		goto release_mgmt_ref;
+	}
+
+	qdf_mem_copy(tdls_mgmt_req->bssid.bytes,
+		     wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
+
+	qdf_mem_copy(tdls_mgmt_req->peer_mac.bytes,
+		     action_req->tdls_mgmt.peer_mac.bytes, QDF_MAC_ADDR_SIZE);
+
+	if (action_req->tdls_mgmt.len && action_req->tdls_mgmt.buf) {
+		qdf_mem_copy(tdls_mgmt_req->add_ie, action_req->tdls_mgmt.buf,
+			     action_req->tdls_mgmt.len);
+	}
+
+	tdls_mgmt_req->length = sizeof(struct tdls_send_mgmt_request) +
+				action_req->tdls_mgmt.len;
+
+	/* Send the request to PE. */
+	qdf_mem_zero(&msg, sizeof(msg));
+
+	tdls_debug("sending TDLS Mgmt Frame req to PE ");
+	tdls_mgmt_req->message_type = tdls_soc_obj->tdls_send_mgmt_req;
+
+	msg.type = tdls_soc_obj->tdls_send_mgmt_req;
+	msg.bodyptr = tdls_mgmt_req;
+
+	status = scheduler_post_msg(QDF_MODULE_ID_PE, &msg);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
+release_mgmt_ref:
+	wlan_objmgr_vdev_release_ref(action_req->vdev, WLAN_TDLS_SB_ID);
+
+	/*update tdls nss infornation based on action code */
+	tdls_reset_nss(tdls_soc_obj, action_req->chk_frame->action_code);
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd,
+	 enum wlan_serialization_cb_reason reason)
+{
+	struct tdls_action_frame_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!cmd || !cmd->umac_cmd) {
+		tdls_err("invalid params cmd: %p, ", cmd);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = cmd->umac_cmd;
+
+	tdls_debug("reason: %d, vdev_id: %d",
+		reason, req->vdev_id);
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		/* command moved to active list */
+		status = tdls_activate_send_mgmt_request(req);
+		break;
+
+	case WLAN_SER_CB_CANCEL_CMD:
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		/* command removed from pending list.
+		 * notify status complete with failure
+		 */
+		status = tdls_internal_send_mgmt_tx_done(req,
+				QDF_STATUS_E_FAILURE);
+		qdf_mem_free(req);
+		break;
+
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		/* command successfully completed.
+		 * release tdls_action_frame_request memory
+		 */
+		qdf_mem_free(req);
+		break;
+
+	default:
+		/* Do nothing but logging */
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS tdls_process_mgmt_req(
+			struct tdls_action_frame_request *tdls_mgmt_req)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_serialization_command cmd = {0, };
+	enum wlan_serialization_status ser_cmd_status;
+
+	/* If connected and in Infra. Only then allow this */
+	status = tdls_validate_mgmt_request(tdls_mgmt_req->chk_frame);
+	if (status != QDF_STATUS_SUCCESS) {
+		status = tdls_internal_send_mgmt_tx_done(tdls_mgmt_req,
+							 status);
+		qdf_mem_free(tdls_mgmt_req);
+		return status;
+	}
+
+	/* update the responder, status code information
+	 * after the  cmd validation
+	 */
+	tdls_mgmt_req->tdls_mgmt.responder =
+			tdls_mgmt_req->chk_frame->responder;
+	tdls_mgmt_req->tdls_mgmt.status_code =
+			tdls_mgmt_req->chk_frame->status_code;
+
+	cmd.cmd_type = WLAN_SER_CMD_TDLS_SEND_MGMT;
+	/* Cmd Id not applicable for non scan cmds */
+	cmd.cmd_id = 0;
+	cmd.cmd_cb = (wlan_serialization_cmd_callback)
+		tdls_send_mgmt_serialize_callback;
+	cmd.umac_cmd = tdls_mgmt_req;
+	cmd.source = WLAN_UMAC_COMP_TDLS;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
+
+	cmd.vdev = tdls_mgmt_req->vdev;
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	tdls_debug("wlan_serialization_request status:%d", ser_cmd_status);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list.Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	case WLAN_SER_CMD_DENIED_LIST_FULL:
+	case WLAN_SER_CMD_DENIED_RULES_FAILED:
+	case WLAN_SER_CMD_DENIED_UNSPECIFIED:
+		/* free the request */
+		qdf_mem_free(tdls_mgmt_req);
+
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+	return status;
+}

+ 51 - 0
umac/tdls/core/src/wlan_tdls_mgmt.h

@@ -21,3 +21,54 @@
  *
  * TDLS management frames include file
  */
+
+#ifndef _WLAN_TDLS_MGMT_H_
+#define _WLAN_TDLS_MGMT_H_
+
+/* default tdls serialize timeout is set to 10 secs */
+#define TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT  10000
+
+/*
+ * struct tdls_send_mgmt_request - tdls management request
+ * @message_type: type of pe message
+ * @length: length of the frame.
+ * @session_id: session id
+ * @transaction_id: transaction ID for cmd
+ * @req_type: type of action frame
+ * @dialog: dialog token used in the frame.
+ * @status_code: status to be incuded in the frame.
+ * @responder: tdls request type
+ * @peer_capability: peer capability information
+ * @bssid: bssid
+ * @peer_mac: mac address of the peer
+ * @add_ie: additional ie's to be included
+ */
+struct tdls_send_mgmt_request {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t transaction_id;
+	uint8_t req_type;
+	uint8_t dialog;
+	uint16_t status_code;
+	uint8_t responder;
+	uint32_t peer_capability;
+	struct qdf_mac_addr bssid;
+	struct qdf_mac_addr peer_mac;
+	/* Variable length. Dont add any field after this. */
+	uint8_t add_ie[1];
+};
+
+/**
+ * tdls_process_mgmt_req() - send a TDLS mgmt request to serialize module
+ * @tdls_mgmt_req: tdls management request
+ *
+ * TDLS request API, called from cfg80211 to send a TDLS frame in
+ * serialized manner to PE
+ *
+ *Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_mgmt_req(
+			struct tdls_action_frame_request *tdls_mgmt_req);
+#endif
+

+ 40 - 0
umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h

@@ -824,4 +824,44 @@ struct tdls_event_notify {
 	struct wlan_objmgr_vdev *vdev;
 	struct tdls_event_info event;
 };
+
+/**
+ * struct tdls_event_notify - tdls event notify
+ * @peer_mac: peer's mac address
+ * @frame_type: Type of TDLS mgmt frame to be sent
+ * @dialog: dialog token used in the frame.
+ * @status_code: status to be incuded in the frame
+ * @responder: Tdls request type
+ * @peer_capability: peer cpabilities
+ * @len: lenght of additional Ies
+ * @buf: additional IEs to be included
+ */
+struct tdls_send_mgmt {
+	struct qdf_mac_addr peer_mac;
+	uint8_t frame_type;
+	uint8_t dialog;
+	uint16_t status_code;
+	uint8_t responder;
+	uint32_t peer_capability;
+	uint8_t len;
+	/* Variable length, do not add anything after this */
+	uint8_t *buf;
+};
+
+/**
+ * struct tdls_send_action_frame_request - tdls send mgmt request
+ * @vdev: vdev object
+ * @session_id: session id
+ * @vdev_id: vdev id
+ * @tdls_mgmt: tdls managment
+ */
+struct tdls_action_frame_request {
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t session_id;
+	uint8_t vdev_id;
+	const uint8_t *cmd_buf;
+	uint8_t len;
+	struct tdls_send_mgmt tdls_mgmt;
+};
+
 #endif

+ 12 - 0
umac/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h

@@ -118,4 +118,16 @@ QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
  */
 QDF_STATUS ucfg_tdls_oper(struct wlan_objmgr_vdev *vdev,
 			  const uint8_t *macaddr, enum tdls_command_type cmd);
+
+/**
+ * ucfg_tdls_send_mgmt_frame() - send TDLS mgmt frame
+ * @mgmt_req: pointer to TDLS action frame request struct
+ *
+ * This will TDLS action frames to peer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_send_mgmt_frame(
+				struct tdls_action_frame_request *mgmt_req);
+
 #endif

+ 39 - 0
umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c

@@ -436,3 +436,42 @@ error:
 	qdf_mem_free(req);
 	return status;
 }
+
+QDF_STATUS ucfg_tdls_send_mgmt_frame(
+				struct tdls_action_frame_request *req)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_action_frame_request *mgmt_req;
+
+	if (!req || !req->vdev) {
+		tdls_err("Invalid mgmt req params %p", req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	mgmt_req = qdf_mem_malloc(sizeof(*mgmt_req) +
+					req->len);
+	if (!mgmt_req) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_mem_copy(mgmt_req, req, sizeof(*req));
+
+	/*populate the additional IE's */
+	if ((0 != req->len) && (NULL != req->cmd_buf)) {
+		qdf_mem_copy(mgmt_req->tdls_mgmt.buf, req->cmd_buf,
+				req->len);
+		mgmt_req->tdls_mgmt.len = req->len;
+	} else {
+		mgmt_req->tdls_mgmt.len = 0;
+	}
+
+	tdls_notice("vdev id: %d, session id : %d", mgmt_req->vdev_id,
+		    mgmt_req->session_id);
+	msg.bodyptr = mgmt_req;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_TX_ACTION;
+	scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+
+	return QDF_STATUS_SUCCESS;
+}