瀏覽代碼

qcacmn: Add os_if changes for tdls management

Add os interface changes to send tdls management
frames to tdls component

Change-Id: Ib675e4b089a88ad618f918d9992a777c7221b34c
CRs-Fixed: 2034220
Kabilan Kannan 8 年之前
父節點
當前提交
e81cb8eac8

+ 68 - 0
os_if/linux/tdls/inc/wlan_cfg80211_tdls.h

@@ -33,6 +33,9 @@
 #include <qdf_types.h>
 #include <wlan_tdls_ucfg_api.h>
 
+
+#define TDLS_VDEV_MAGIC 0x54444c53       /* "TDLS" */
+
 /**
  * struct osif_tdls_vdev - OS tdls vdev private structure
  * @tdls_add_peer_comp: Completion to add tdls peer
@@ -52,6 +55,26 @@ struct osif_tdls_vdev {
 	uint32_t mgmt_tx_completion_status;
 };
 
+/**
+ * enum qca_wlan_vendor_tdls_trigger_mode_vdev_map: Maps the user space TDLS
+ *	trigger mode in the host driver.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and
+ *	disconnection handled by user space.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and
+ *	disconnection controlled by host driver based on data traffic.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and
+ *	disconnection jointly controlled by user space and host driver.
+ */
+enum qca_wlan_vendor_tdls_trigger_mode_vdev_map {
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT =
+		QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT,
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT =
+		QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT,
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL =
+		((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT |
+		  QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1),
+};
+
 /**
  * wlan_cfg80211_tdls_priv_init() - API to initialize tdls os private
  * @osif_priv: vdev os private
@@ -96,6 +119,17 @@ int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_pdev *pdev,
 				   struct net_device *dev,
 				   const uint8_t *mac,
 				   struct station_parameters *params);
+
+/**
+ * wlan_cfg80211_tdls_configure_mode() - configure tdls mode
+ * @vdev: vdev obj manager
+ * @trigger_mode: tdls trgger mode
+ *
+ * Return: 0 for success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode);
+
 /**
  * wlan_cfg80211_tdls_oper() - process cfg80211 operation on an TDLS peer
  * @pdev: pdev object
@@ -110,6 +144,27 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev,
 			    const uint8_t *peer,
 			    enum nl80211_tdls_operation oper);
 
+/**
+ * wlan_cfg80211_tdls_mgmt() - process tdls management frames from the supplicant
+ * @pdev: pdev object
+ * @dev: net device
+ * @peer: MAC address of the TDLS peer
+ * @action_code: type of TDLS mgmt frame to be sent
+ * @dialog_token: dialog token used in the frame
+ * @status_code: status to be incuded in the frame
+ * @peer_capability: peer capability information
+ * @buf: additional IEs to be included
+ * @len: lenght of additional Ies
+ * @oper: cfg80211 TDLS operation
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev,
+				struct net_device *dev, const uint8_t *peer,
+				uint8_t action_code, uint8_t dialog_token,
+				uint16_t status_code, uint32_t peer_capability,
+				const uint8_t *buf, size_t len);
+
 /**
  * wlan_cfg80211_tdls_event_callback() - callback for tdls module
  * @userdata: user data
@@ -123,4 +178,17 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev,
 void wlan_cfg80211_tdls_event_callback(void *userdata,
 				       enum tdls_event_type type,
 				       struct tdls_osif_indication *param);
+
+/**
+ * wlan_cfg80211_tdls_rx_callback() - Callback for rx mgmt frame
+ * @user_data: pointer to soc object
+ * @rx_frame: RX mgmt frame information
+ *
+ * This callback will be used to rx frames in os interface.
+ *
+ * Return: None
+ */
+void wlan_cfg80211_tdls_rx_callback(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame);
+
 #endif

+ 232 - 0
os_if/linux/tdls/src/wlan_cfg80211_tdls.c

@@ -36,6 +36,9 @@
 
 #define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS)
 
+
+#define TDLS_MAX_NO_OF_2_4_CHANNELS 14
+
 QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv)
 {
 	struct osif_tdls_vdev *tdls_priv;
@@ -370,6 +373,41 @@ static enum tdls_command_type tdls_oper_to_cmd(enum nl80211_tdls_operation oper)
 		return 0;
 }
 
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode)
+{
+	enum tdls_feature_mode tdls_mode;
+	struct tdls_set_mode_params set_mode_params;
+	int status;
+
+	if (!vdev)
+		return -EINVAL;
+
+	switch (trigger_mode) {
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT:
+		tdls_mode = TDLS_SUPPORT_IMP_MODE;
+		break;
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL:
+		tdls_mode = TDLS_SUPPORT_EXT_CONTROL;
+		break;
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT:
+		tdls_mode = TDLS_SUPPORT_IMP_MODE;
+		break;
+	default:
+		cfg80211_err("Invalid TDLS trigger mode");
+		return -EINVAL;
+	}
+
+	cfg80211_notice("cfg80211 tdls trigger mode %d", trigger_mode);
+	set_mode_params.source = TDLS_SET_MODE_SOURCE_USER;
+	set_mode_params.tdls_mode = tdls_mode;
+	set_mode_params.update_last = false;
+	set_mode_params.vdev = vdev;
+
+	status = ucfg_tdls_set_operating_mode(&set_mode_params);
+	return status;
+}
+
 int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev,
 			    struct net_device *dev,
 			    const uint8_t *peer,
@@ -442,6 +480,196 @@ error:
 	return status;
 }
 
+void wlan_cfg80211_tdls_rx_callback(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+	uint16_t freq;
+
+	cfg80211_debug("user data:%p, vdev id:%d, rssi:%d, buf:%p, len:%d",
+		user_data, rx_frame->vdev_id, rx_frame->rx_rssi,
+		rx_frame->buf, rx_frame->frame_len);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		rx_frame->vdev_id, WLAN_TDLS_NB_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	wlan_vdev_obj_lock(vdev);
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	wlan_vdev_obj_unlock(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wdev is null");
+		goto fail;
+	}
+
+	if (rx_frame->rx_chan <= TDLS_MAX_NO_OF_2_4_CHANNELS)
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_2GHZ);
+	else
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_5GHZ);
+
+	cfg80211_notice("Indicate frame over nl80211, vdev id:%d, idx:%d",
+		   rx_frame->vdev_id, wdev->netdev->ifindex);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
+#else
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC);
+#endif /* LINUX_VERSION_CODE */
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+}
+
+int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev,
+				struct net_device *dev, const uint8_t *peer_mac,
+				uint8_t action_code, uint8_t dialog_token,
+				uint16_t status_code, uint32_t peer_capability,
+				const uint8_t *buf, size_t len)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_action_frame_request mgmt_req;
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	int status;
+	unsigned long rc;
+	int max_sta_failed = 0;
+	struct tdls_validate_action_req chk_frame;
+	struct tdls_set_responder_req set_responder;
+
+	vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev,
+							 dev->dev_addr,
+							 WLAN_OSIF_ID);
+	if (vdev == NULL) {
+		cfg80211_err("vdev object is NULL");
+		return -EIO;
+	}
+
+	wlan_vdev_obj_lock(vdev);
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	tdls_priv = osif_priv->osif_tdls;
+
+	/* make sure doesn't call send_mgmt() while it is pending */
+	if (TDLS_VDEV_MAGIC == tdls_priv->mgmt_tx_completion_status) {
+		cfg80211_err(QDF_MAC_ADDRESS_STR " action %d couldn't sent, as one is pending. return EBUSY",
+			     QDF_MAC_ADDR_ARRAY(peer_mac), action_code);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
+		return -EBUSY;
+	}
+
+	/* Reset TDLS VDEV magic */
+	tdls_priv->mgmt_tx_completion_status = TDLS_VDEV_MAGIC;
+
+
+	/*prepare the request */
+
+	/* Validate the management Request */
+	chk_frame.vdev = vdev;
+	chk_frame.action_code = action_code;
+	qdf_mem_copy(chk_frame.peer_mac, peer_mac, QDF_MAC_ADDR_SIZE);
+	chk_frame.dialog_token = dialog_token;
+	chk_frame.action_code = action_code;
+	chk_frame.status_code = status_code;
+	chk_frame.len = len;
+	chk_frame.max_sta_failed = max_sta_failed;
+
+	mgmt_req.chk_frame = &chk_frame;
+
+	mgmt_req.vdev = vdev;
+	mgmt_req.vdev_id = wlan_vdev_get_id(vdev);
+	mgmt_req.session_id = mgmt_req.vdev_id;
+	/* populate management req params */
+	qdf_mem_copy(mgmt_req.tdls_mgmt.peer_mac.bytes,
+		     peer_mac, QDF_MAC_ADDR_SIZE);
+	mgmt_req.tdls_mgmt.dialog = dialog_token;
+	mgmt_req.tdls_mgmt.frame_type = action_code;
+	mgmt_req.tdls_mgmt.len = len;
+	mgmt_req.tdls_mgmt.peer_capability = peer_capability;
+	mgmt_req.tdls_mgmt.status_code = chk_frame.status_code;
+
+	/*populate the additional IE's */
+	mgmt_req.cmd_buf = buf;
+	mgmt_req.len = len;
+
+	reinit_completion(&tdls_priv->tdls_mgmt_comp);
+	status = ucfg_tdls_send_mgmt_frame(&mgmt_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_send_mgmt failed err %d", status);
+		status = -EIO;
+		tdls_priv->mgmt_tx_completion_status = false;
+		goto error_mgmt_req;
+	}
+
+	cfg80211_info("Wait for tdls_mgmt_comp. Timeout %u ms",
+		WAIT_TIME_FOR_TDLS_MGMT);
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_mgmt_comp,
+		msecs_to_jiffies(WAIT_TIME_FOR_TDLS_MGMT));
+
+	if ((0 == rc) || (true != tdls_priv->mgmt_tx_completion_status)) {
+		cfg80211_err("%s rc %ld mgmtTxCompletionStatus %u",
+			     !rc ? "Mgmt Tx Completion timed out" :
+			     "Mgmt Tx Completion failed",
+			     rc, tdls_priv->mgmt_tx_completion_status);
+
+		tdls_priv->mgmt_tx_completion_status = false;
+		status = -EINVAL;
+		goto error_mgmt_req;
+	}
+
+	cfg80211_info("Mgmt Tx Completion status %ld TxCompletion %u",
+		rc, tdls_priv->mgmt_tx_completion_status);
+
+	if (chk_frame.max_sta_failed) {
+		status = max_sta_failed;
+		goto error_mgmt_req;
+	}
+
+	if (TDLS_SETUP_RESPONSE == action_code ||
+	    TDLS_SETUP_CONFIRM == action_code) {
+		qdf_mem_copy(set_responder.peer_mac, peer_mac,
+			     QDF_MAC_ADDR_SIZE);
+		set_responder.vdev = vdev;
+		if (TDLS_SETUP_RESPONSE == action_code)
+			set_responder.responder = false;
+		if (TDLS_SETUP_CONFIRM == action_code)
+			set_responder.responder = true;
+		ucfg_tdls_responder(&set_responder);
+	}
+
+error_mgmt_req:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
+	return status;
+}
+
 static void
 wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind)
 {
@@ -504,6 +732,10 @@ void wlan_cfg80211_tdls_event_callback(void *user_data,
 	wlan_vdev_obj_unlock(ind->vdev);
 
 	switch (type) {
+	case TDLS_EVENT_MGMT_TX_ACK_CNF:
+		tdls_priv->mgmt_tx_completion_status = ind->status;
+		complete(&tdls_priv->tdls_mgmt_comp);
+		break;
 	case TDLS_EVENT_ADD_PEER:
 		tdls_priv->tdls_add_peer_status = ind->status;
 		complete(&tdls_priv->tdls_add_peer_comp);

+ 12 - 11
umac/cmn_services/mgmt_txrx/dispatcher/inc/wlan_mgmt_txrx_utils_api.h

@@ -309,17 +309,18 @@ enum wnm_actioncode {
  * @TDLS_DISCOVERY_REQUEST: tdls discovery request frame
  */
 enum tdls_actioncode {
-	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_SETUP_REQUEST = 0,
+	TDLS_SETUP_RESPONSE = 1,
+	TDLS_SETUP_CONFIRM = 2,
+	TDLS_TEARDOWN = 3,
+	TDLS_PEER_TRAFFIC_INDICATION = 4,
+	TDLS_CHANNEL_SWITCH_REQUEST = 5,
+	TDLS_CHANNEL_SWITCH_RESPONSE = 6,
+	TDLS_PEER_PSM_REQUEST = 7,
+	TDLS_PEER_PSM_RESPONSE = 8,
+	TDLS_PEER_TRAFFIC_RESPONSE = 9,
+	TDLS_DISCOVERY_REQUEST = 10,
+	TDLS_DISCOVERY_RESPONSE = 14,
 };
 
 /**

+ 37 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_peer_obj.h

@@ -133,6 +133,7 @@ struct wlan_objmgr_peer_mlme {
 	uint32_t max_rate;
 	uint16_t seq_num;
 	enum wlan_peer_state state;
+	bool is_authenticated;
 };
 
 /**
@@ -732,6 +733,25 @@ static inline void wlan_peer_mlme_set_state(
 	peer->peer_mlme.state = state;
 }
 
+/**
+ * wlan_peer_mlme_set_auth_state() - peer mlme auth state
+ * @peer: PEER object
+ * @is_authenticated: true or false
+ *
+ * API to update the current peer auth state
+ *
+ * Caller need to acquire lock with wlan_peer_obj_lock()
+ *
+ * Return: void
+ */
+static inline void wlan_peer_mlme_set_auth_state(
+				struct wlan_objmgr_peer *peer,
+				bool is_authenticated)
+{
+	/* This API is invoked with lock acquired, do not add log prints */
+	peer->peer_mlme.is_authenticated = is_authenticated;
+}
+
 /**
  * wlan_peer_mlme_get_state() - peer mlme state
  * @peer: PEER object
@@ -749,6 +769,23 @@ static inline enum wlan_peer_state wlan_peer_mlme_get_state(
 	return peer->peer_mlme.state;
 }
 
+/**
+ * wlan_peer_mlme_get_auth_state() - peer mlme auth state
+ * @peer: PEER object
+ *
+ * API to get peer auth state
+ *
+ * Caller need to acquire lock with wlan_peer_obj_lock()
+ *
+ * Return: auth state true/false
+ */
+static inline bool wlan_peer_mlme_get_auth_state(
+				struct wlan_objmgr_peer *peer)
+{
+	/* This API is invoked with lock acquired, do not add log prints */
+	return peer->peer_mlme.is_authenticated;
+}
+
 /**
  * wlan_peer_mlme_get_next_seq_num() - get peer mlme next sequence number
  * @peer: PEER object

+ 347 - 2
umac/tdls/core/src/wlan_tdls_cmds_process.c

@@ -569,6 +569,244 @@ tdls_add_peer_serialize_callback(struct wlan_serialization_command *cmd,
 	return status;
 }
 
+void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
+				  uint8_t action_code)
+{
+	if (!tdls_soc)
+		return;
+
+	if (TDLS_TEARDOWN != action_code ||
+		tdls_soc->tdls_nss_switch_in_progress)
+		return;
+
+	if (tdls_soc->tdls_teardown_peers_cnt != 0)
+		tdls_soc->tdls_teardown_peers_cnt--;
+	if (tdls_soc->tdls_teardown_peers_cnt == 0) {
+		if (tdls_soc->tdls_nss_transition_mode ==
+		    TDLS_NSS_TRANSITION_S_1x1_to_2x2) {
+			/* TDLS NSS switch is fully completed, so
+			 * reset the flags.
+			 */
+			tdls_notice("TDLS NSS switch is fully completed");
+			tdls_soc->tdls_nss_switch_in_progress = false;
+			tdls_soc->tdls_nss_teardown_complete = false;
+		} else {
+			/* TDLS NSS switch is not yet completed, but
+			 * tdls teardown is completed for all the
+			 * peers.
+			 */
+			tdls_notice("teardown done & NSS switch in progress");
+			tdls_soc->tdls_nss_teardown_complete = true;
+		}
+	}
+
+}
+
+/**
+ * tdls_set_cap() - set TDLS capability type
+ * @tdls_vdev: tdls vdev object
+ * @mac: peer mac address
+ * @cap: TDLS capability type
+ *
+ * Return: 0 if successful or negative errno otherwise
+ */
+int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac,
+			  enum tdls_peer_capab cap)
+{
+	struct tdls_peer *curr_peer;
+
+	curr_peer = tdls_get_peer(tdls_vdev, mac);
+	if (curr_peer == NULL) {
+		tdls_err("curr_peer is NULL");
+		return -EINVAL;
+	}
+
+	curr_peer->tdls_support = cap;
+	return 0;
+}
+
+static int tdls_validate_setup_frames(struct tdls_soc_priv_obj *tdls_soc,
+				struct tdls_validate_action_req *tdls_validate)
+{
+	/* supplicant still sends tdls_mgmt(SETUP_REQ)
+	 * even after we return error code at
+	 * 'add_station()'. Hence we have this check
+	 * again in addition to add_station().	Anyway,
+	 * there is no harm to double-check.
+	 */
+	if (TDLS_SETUP_REQUEST == tdls_validate->action_code) {
+		tdls_err(QDF_MAC_ADDRESS_STR " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).",
+			 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+			 tdls_validate->action_code,
+			 tdls_soc->connected_peer_count,
+			 tdls_soc->max_num_tdls_sta);
+		return -EINVAL;
+	}
+	/* maximum reached. tweak to send
+	 * error code to peer and return error
+	 * code to supplicant
+	 */
+	tdls_validate->status_code = QDF_STATUS_E_RESOURCES;
+	tdls_err(QDF_MAC_ADDRESS_STR " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).",
+		 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+		 tdls_validate->action_code,
+		 tdls_soc->connected_peer_count,
+		 tdls_soc->max_num_tdls_sta);
+
+	tdls_validate->max_sta_failed = -EPERM;
+	return 0;
+}
+
+int tdls_validate_mgmt_request(struct tdls_validate_action_req *tdls_validate)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc;
+	struct tdls_peer *curr_peer;
+	struct tdls_peer *temp_peer;
+	QDF_STATUS status;
+
+
+	if (!tdls_validate || !tdls_validate->vdev)
+		return -EINVAL;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(tdls_validate->vdev,
+							&tdls_vdev,
+							&tdls_soc))
+		return -ENOTSUPP;
+
+	/*
+	 * STA or P2P client should be connected and authenticated before
+	 *  sending any TDLS frames
+	 */
+	if (!tdls_is_vdev_connected(tdls_validate->vdev) ||
+	    !tdls_is_vdev_authenticated(tdls_validate->vdev)) {
+		tdls_err("STA is not connected or not authenticated.");
+		return -EAGAIN;
+	}
+
+	/* other than teardown frame, mgmt frames are not sent if disabled */
+	if (TDLS_TEARDOWN != tdls_validate->action_code) {
+		if (!tdls_check_is_tdls_allowed(tdls_validate->vdev)) {
+			tdls_err("TDLS not allowed, reject MGMT, action = %d",
+				tdls_validate->action_code);
+			return -EPERM;
+		}
+		/* if tdls_mode is disabled, then decline the peer's request */
+		if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode ||
+		    TDLS_SUPPORT_SUSPENDED == tdls_soc->tdls_current_mode) {
+			tdls_notice(QDF_MAC_ADDRESS_STR
+				" TDLS mode is disabled. action %d declined.",
+				QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+				tdls_validate->action_code);
+			return -ENOTSUPP;
+		}
+		if (tdls_soc->tdls_nss_switch_in_progress) {
+			tdls_err("nss switch in progress, action %d declined "
+				QDF_MAC_ADDRESS_STR,
+				tdls_validate->action_code,
+				QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac));
+			return -EAGAIN;
+		}
+	}
+
+	if (TDLS_IS_SETUP_ACTION(tdls_validate->action_code)) {
+		if (NULL != tdls_is_progress(tdls_vdev,
+			tdls_validate->peer_mac, true)) {
+			tdls_err("setup is ongoing. action %d declined for "
+				 QDF_MAC_ADDRESS_STR,
+				 tdls_validate->action_code,
+				 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac));
+			return -EPERM;
+		}
+	}
+
+	/*
+	 * Discard TDLS Discovery request and setup confirm if violates
+	 * ACM rules
+	 */
+	if ((TDLS_DISCOVERY_REQUEST == tdls_validate->action_code ||
+		TDLS_SETUP_CONFIRM == tdls_validate->action_code)) {
+		/*  call hdd_wmm_is_acm_allowed() */
+		if (!tdls_soc->tdls_wmm_cb(&tdls_vdev->vdev)) {
+			tdls_err("admission ctrl set to VI, action %d declined",
+				 tdls_validate->action_code);
+			return -EPERM;
+		}
+	}
+
+
+	if (TDLS_SETUP_REQUEST == tdls_validate->action_code ||
+	    TDLS_SETUP_RESPONSE == tdls_validate->action_code) {
+		if (tdls_soc->max_num_tdls_sta <=
+			tdls_soc->connected_peer_count) {
+			status = tdls_validate_setup_frames(tdls_soc,
+							    tdls_validate);
+			if (QDF_STATUS_SUCCESS != status)
+				return status;
+			/* fall through to send setup resp
+			 * with failure status code
+			 */
+		} else {
+			curr_peer =
+				tdls_find_peer(tdls_vdev,
+					       tdls_validate->peer_mac);
+			if (curr_peer) {
+				if (TDLS_IS_LINK_CONNECTED(curr_peer)) {
+					tdls_err(QDF_MAC_ADDRESS_STR " already connected action %d declined.",
+						QDF_MAC_ADDR_ARRAY(
+						tdls_validate->peer_mac),
+						tdls_validate->action_code);
+
+					return -EPERM;
+				}
+			}
+		}
+	}
+
+	tdls_notice("tdls_mgmt" QDF_MAC_ADDRESS_STR " action %d, dialog_token %d status %d, len = %zu",
+		   QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+		   tdls_validate->action_code, tdls_validate->dialog_token,
+		   tdls_validate->status_code, tdls_validate->len);
+
+	/*Except teardown responder will not be used so just make 0 */
+	tdls_validate->responder = 0;
+	if (TDLS_TEARDOWN == tdls_validate->action_code) {
+		temp_peer = tdls_find_peer(tdls_vdev, tdls_validate->peer_mac);
+		if (!temp_peer) {
+			tdls_err(QDF_MAC_ADDRESS_STR " peer doesn't exist",
+				     QDF_MAC_ADDR_ARRAY(
+				     tdls_validate->peer_mac));
+			return -EPERM;
+		}
+
+		if (TDLS_IS_LINK_CONNECTED(temp_peer))
+			tdls_validate->responder = temp_peer->is_responder;
+		else {
+			tdls_err(QDF_MAC_ADDRESS_STR " peer doesn't exist or not connected %d dialog_token %d status %d, tdls_validate->len = %zu",
+				 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+				 temp_peer->link_status,
+				 tdls_validate->dialog_token,
+				 tdls_validate->status_code,
+				 tdls_validate->len);
+			return -EPERM;
+		}
+	}
+
+	/* For explicit trigger of DIS_REQ come out of BMPS for
+	 * successfully receiving DIS_RSP from peer.
+	 */
+	if ((TDLS_SETUP_RESPONSE == tdls_validate->action_code) ||
+	    (TDLS_SETUP_CONFIRM == tdls_validate->action_code) ||
+	    (TDLS_DISCOVERY_RESPONSE == tdls_validate->action_code) ||
+	    (TDLS_DISCOVERY_REQUEST == tdls_validate->action_code)) {
+		/* Fw will take care if PS offload is enabled. */
+		if (TDLS_DISCOVERY_REQUEST != tdls_validate->action_code)
+			tdls_set_cap(tdls_vdev, tdls_validate->peer_mac,
+					      TDLS_CAP_SUPPORTED);
+	}
+	return 0;
+}
+
 QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req)
 {
 	struct wlan_serialization_command cmd = {0,};
@@ -1000,6 +1238,105 @@ error:
 	return status;
 }
 
+/**
+ * tdls_process_send_mgmt_rsp() - handle response for send mgmt
+ * @rsp: TDLS send mgmt response
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_osif_indication ind;
+
+	psoc = rsp->psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
+						    WLAN_TDLS_SB_ID);
+	if (!vdev) {
+		tdls_err("invalid vdev");
+		status =  QDF_STATUS_E_INVAL;
+		qdf_mem_free(rsp);
+		return status;
+	}
+	tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!tdls_soc || !tdls_vdev) {
+		tdls_err("soc object:%p, vdev object:%p", tdls_soc, tdls_vdev);
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_SEND_MGMT);
+
+	if (legacy_result_success == rsp->status_code)
+		goto free_rsp;
+	tdls_err("send mgmt failed. status code(=%d)", rsp->status_code);
+	status = QDF_STATUS_E_FAILURE;
+
+	if (tdls_soc && tdls_soc->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = rsp->status_code;
+		tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+				       TDLS_EVENT_MGMT_TX_ACK_CNF, &ind);
+	}
+
+free_rsp:
+	qdf_mem_free(rsp);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+	return status;
+}
+
+/**
+ * tdls_send_mgmt_tx_completion() - process tx completion
+ * @tx_complete: TDLS mgmt completion info
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_send_mgmt_tx_completion(
+			struct tdls_mgmt_tx_completion_ind *tx_complete)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_osif_indication ind;
+
+	psoc = tx_complete->psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    tx_complete->session_id,
+						    WLAN_TDLS_SB_ID);
+
+	if (!vdev) {
+		tdls_err("invalid vdev");
+		status =  QDF_STATUS_E_INVAL;
+		goto free_tx_complete;
+	}
+
+	tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+
+	if (!tdls_soc || !tdls_vdev) {
+		tdls_err("soc object:%p, vdev object:%p", tdls_soc, tdls_vdev);
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	if (tdls_soc && tdls_soc->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = tx_complete->tx_complete_status;
+		tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+			       TDLS_EVENT_MGMT_TX_ACK_CNF, &ind);
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+free_tx_complete:
+	qdf_mem_free(tx_complete);
+	return status;
+}
+
 /**
  * tdls_add_peer_rsp() - handle response for add TDLS peer
  * @rsp: TDLS add peer response
@@ -1139,10 +1476,12 @@ QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp)
 			tdls_debug(QDF_MAC_ADDRESS_STR " status is %d",
 				   QDF_MAC_ADDR_ARRAY(macaddr),
 				   curr_peer->link_status);
+
 			wlan_vdev_obj_lock(vdev);
 			id = wlan_vdev_get_id(vdev);
 			wlan_vdev_obj_unlock(vdev);
-			if (TDLS_IS_CONNECTED(curr_peer)) {
+
+			if (TDLS_IS_LINK_CONNECTED(curr_peer)) {
 				soc_obj->tdls_dereg_tl_peer(
 					soc_obj->tdls_tl_peer_data,
 					id, curr_peer->sta_id);
@@ -1464,6 +1803,10 @@ static QDF_STATUS tdls_config_force_peer(
 
 	tdls_set_callback(peer, req->callback);
 
+	tdls_set_ct_mode(soc_obj->soc);
+	if (soc_obj->enable_tdls_connection_tracker)
+		tdls_implicit_enable(vdev_obj);
+
 	return status;
 error:
 	qdf_mem_free(peer_update_param);
@@ -1605,8 +1948,10 @@ QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req)
 		qdf_mem_free(peer_update_param);
 		goto error;
 	}
+	tdls_set_ct_mode(soc_obj->soc);
+	if (!soc_obj->enable_tdls_connection_tracker)
+		tdls_implicit_disable(vdev_obj);
 
-	/*TODO set tdls connection tracker state*/
 error:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
 	qdf_mem_free(req);

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

@@ -25,6 +25,11 @@
 #ifndef _WLAN_TDLS_CMDS_PROCESS_H_
 #define _WLAN_TDLS_CMDS_PROCESS_H_
 
+#define TDLS_IS_SETUP_ACTION(action) \
+	((TDLS_SETUP_REQUEST <= action) && \
+	(TDLS_SETUP_CONFIRM >= action))
+
+
 /**
  * enum tdls_add_oper - add peer type
  * @TDLS_OPER_NONE: none
@@ -37,6 +42,53 @@ enum tdls_add_oper {
 	TDLS_OPER_UPDATE
 };
 
+/**
+ * enum legacy_result_code - defined to comply with tSirResultCodes, need refine
+ *                           when mlme converged.
+ * @legacy_result_success: success
+ * @legacy_result_max: max result value
+ */
+enum legacy_result_code {
+	legacy_result_success,
+	legacy_result_max = 0x7FFFFFFF
+};
+
+/**
+ * struct tdls_send_mgmt_rsp - TDLS Response struct PE --> TDLS module
+ *                           same as struct tSirSmeRsp
+ * @message_type: message type eWNI_SME_TDLS_SEND_MGMT_RSP
+ * @length: message length
+ * @session_id: session id
+ * @transaction_id: transaction id
+ * @status_code: status code as tSirResultCodes
+ * @psoc: soc object
+ */
+struct tdls_send_mgmt_rsp {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t transaction_id;
+	enum legacy_result_code status_code;
+	struct wlan_objmgr_psoc *psoc;
+};
+
+/**
+ * struct tdls_mgmt_tx_completion_ind - TDLS TX completion PE --> TDLS module
+ *                           same as struct sSirMgmtTxCompletionInd
+ * @message_type: message type eWNI_SME_MGMT_FRM_TX_COMPLETION_IND
+ * @length: message length
+ * @session_id: session id
+ * @tx_complete_status: tx complete status
+ * @psoc: soc object
+ */
+struct tdls_mgmt_tx_completion_ind {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;      /* Session ID */
+	uint32_t tx_complete_status;
+	struct wlan_objmgr_psoc *psoc;
+};
+
 /**
  * struct tdls_add_sta_req - TDLS request struct TDLS module --> PE
  *                           same as struct tSirTdlsAddStaReq;
@@ -213,6 +265,52 @@ QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req);
  */
 QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp);
 
+/**
+ * tdls_reset_nss() - reset tdls nss parameters
+ * @tdls_soc: TDLS soc object
+ * @action_code: action code
+ *
+ * Return: None
+ */
+void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
+				  uint8_t action_code);
+
+/**
+ * tdls_set_cap() - set TDLS capability type
+ * @tdls_vdev: tdls vdev object
+ * @mac: peer mac address
+ * @cap: TDLS capability type
+ *
+ * Return: 0 if successful or negative errno otherwise
+ */
+int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac,
+			  enum tdls_peer_capab cap);
+
+/**
+ * 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);
+
+/**
+ * tdls_process_send_mgmt_rsp() - handle response for send mgmt
+ * @rsp: TDLS send mgmt response
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp);
+
+/**
+ * tdls_send_mgmt_tx_completion() - process tx completion
+ * @tx_complete: TDLS mgmt completion info
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_send_mgmt_tx_completion(
+			struct tdls_mgmt_tx_completion_ind *tx_complete);
+
 /**
  * tdls_process_add_peer_rsp() - handle response for delete TDLS peer
  * @rsp: TDLS delete peer response

+ 21 - 0
umac/tdls/core/src/wlan_tdls_ct.c

@@ -52,6 +52,27 @@ bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev)
 	return true;
 }
 
+bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_peer *peer;
+	bool is_authenticated = false;
+
+	wlan_vdev_obj_lock(vdev);
+	peer = wlan_vdev_get_bsspeer(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	if (!peer) {
+		tdls_err("peer is null");
+		return false;
+	}
+
+	wlan_peer_obj_lock(peer);
+	is_authenticated = wlan_peer_mlme_get_auth_state(peer);
+	wlan_peer_obj_unlock(peer);
+
+	return is_authenticated;
+}
+
 /**
  * tdls_peer_reset_discovery_processed() - reset discovery status
  * @tdls_vdev: TDLS vdev object

+ 17 - 0
umac/tdls/core/src/wlan_tdls_ct.h

@@ -155,4 +155,21 @@ void tdls_discovery_timeout_peer_cb(void *user_data);
  * Return: Void
  */
 void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev);
+
+/**
+ * tdls_is_vdev_connected() -check the vdev connection
+ * @vdev: vdev oobject
+ *
+ * Return: true or false
+ */
+bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_is_vdev_authenticated() -check the vdev authentication state
+ * @vdev: vdev oobject
+ *
+ * Return: true or false
+ */
+bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev);
+
 #endif

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

@@ -30,6 +30,8 @@
 #include "wlan_tdls_tgt_api.h"
 #include "wlan_policy_mgr_public_struct.h"
 #include "wlan_policy_mgr_api.h"
+#include "wlan_scan_ucfg_api.h"
+
 
 /* Global tdls soc pvt object
  * this is useful for some functions which does not receive either vdev or psoc

+ 6 - 1
umac/tdls/core/src/wlan_tdls_main.h

@@ -34,6 +34,7 @@
 #include <wlan_tdls_public_structs.h>
 #include <scheduler_api.h>
 #include "wlan_serialization_api.h"
+#include "wlan_tdls_mgmt.h"
 
 /* Bit mask flag for tdls_option to FW */
 #define ENA_TDLS_OFFCHAN      (1 << 0)  /* TDLS Off Channel support */
@@ -74,7 +75,7 @@
 #define tdls_alert(format, args...) \
 	tdls_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args)
 
-#define TDLS_IS_CONNECTED(peer)  \
+#define TDLS_IS_LINK_CONNECTED(peer)  \
 	((TDLS_LINK_CONNECTED == (peer)->link_status) || \
 	 (TDLS_LINK_TEARING == (peer)->link_status))
 
@@ -203,6 +204,10 @@ struct tdls_soc_priv_obj {
 	enum tdls_nss_transition_state tdls_nss_transition_mode;
 	int32_t tdls_teardown_peers_cnt;
 	struct tdls_set_state_info set_state_info;
+	tdls_rx_callback tdls_rx_cb;
+	void *tdls_rx_cb_data;
+	tdls_wmm_check tdls_wmm_cb;
+	void *tdls_wmm_cb_data;
 	tdls_tx_ack_cnf_callback tdls_tx_cnf_cb;
 	void *tx_ack_cnf_cb_data;
 	tdls_evt_callback tdls_event_cb;

+ 2 - 3
umac/tdls/core/src/wlan_tdls_mgmt.c

@@ -113,7 +113,6 @@ static QDF_STATUS tdls_process_rx_mgmt(
 			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 =
@@ -127,7 +126,7 @@ static QDF_STATUS tdls_process_rx_mgmt(
 		}
 	}
 
-	/* tdls_soc_obj->tdls_rx_cb ==> wlan_tdls_rx_callback() */
+	/* tdls_soc_obj->tdls_rx_cb ==> wlan_cfg80211_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);
@@ -157,7 +156,6 @@ QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg)
 
 	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)
@@ -175,6 +173,7 @@ 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;
 

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

@@ -28,6 +28,24 @@
 /* default tdls serialize timeout is set to 10 secs */
 #define TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT  10000
 
+#define TDLS_PUBLIC_ACTION_FRAME_OFFSET 24
+#define TDLS_PUBLIC_ACTION_FRAME 4
+#define TDLS_PUBLIC_ACTION_DISC_RESP 14
+#define TDLS_ACTION_FRAME 12
+#define TDLS_80211_PEER_ADDR_OFFSET (TDLS_PUBLIC_ACTION_FRAME + \
+				     QDF_MAC_ADDR_SIZE)
+#define TDLS_ACTION_FRAME_TYPE_MAX 11
+
+/**
+ * struct tdls_rx_mgmt_event - tdls rx mgmt frame event
+ * @tdls_soc_obj: tdls soc private object
+ * @rx_mgmt: tdls rx mgmt frame structure
+ */
+struct tdls_rx_mgmt_event {
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct tdls_rx_mgmt_frame *rx_mgmt;
+};
+
 /*
  * struct tdls_send_mgmt_request - tdls management request
  * @message_type: type of pe message
@@ -70,5 +88,26 @@ struct tdls_send_mgmt_request {
  */
 QDF_STATUS tdls_process_mgmt_req(
 			struct tdls_action_frame_request *tdls_mgmt_req);
+
+/**
+ * tdls_mgmt_rx_ops() - register or unregister rx callback
+ * @psoc: psoc object
+ * @isregister: register if true, unregister if false
+ *
+ * This function registers or unregisters rx callback to mgmt txrx
+ * component.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister);
+
+/**
+ * tdls_process_rx_frame() - process tdls rx frames
+ * @msg: scheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg);
 #endif
 

+ 4 - 2
umac/tdls/dispatcher/inc/wlan_tdls_public_structs.h

@@ -29,6 +29,8 @@
 #include <qdf_mc_timer.h>
 #include <wlan_cmn.h>
 #include <wlan_cmn_ieee80211.h>
+#include <wlan_objmgr_psoc_obj.h>
+
 
 #define WLAN_TDLS_STA_MAX_NUM                        8
 #define WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM        1
@@ -59,7 +61,7 @@
 #define WAIT_TIME_TDLS_LINK_ESTABLISH_REQ      1500
 
 /** Maximum time(ms) to wait for tdls mgmt to complete **/
-#define WAIT_TIME_TDLS_MGMT         11000
+#define WAIT_TIME_FOR_TDLS_MGMT         11000
 
 #define TDLS_TEARDOWN_PEER_UNREACHABLE   25
 #define TDLS_TEARDOWN_PEER_UNSPEC_REASON 26
@@ -252,7 +254,7 @@ enum tdls_event_msg_type {
 	TDLS_SHOULD_DISCOVER = 0,
 	TDLS_SHOULD_TEARDOWN,
 	TDLS_PEER_DISCONNECTED,
-	TDLS_CONNECTION_TRACKER_NOTIFY,
+	TDLS_CONNECTION_TRACKER_NOTIFY
 };
 
 /**

+ 35 - 0
umac/tdls/dispatcher/inc/wlan_tdls_tgt_api.h

@@ -67,6 +67,22 @@ QDF_STATUS tgt_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS tgt_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc,
 			      struct sta_uapsd_trig_params *params);
 
+/**
+ * tgt_tdls_send_mgmt_rsp() - process tdls mgmt response
+ * @pmsg: sheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg);
+
+/**
+ * tgt_tdls_send_mgmt_tx_completion() -process tx completion message
+ * @pmsg: sheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg);
+
 /**
  * tgt_tdls_del_peer_rsp() - handle TDLS del peer response
  * @pmsg: sheduler msg
@@ -111,4 +127,23 @@ QDF_STATUS tgt_tdls_unregister_ev_handler(struct wlan_objmgr_psoc *psoc);
 QDF_STATUS
 tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc,
 		       struct tdls_event_info *info);
+
+/**
+ * tgt_tdls_mgmt_frame_rx_cb() - callback for rx mgmt frame
+ * @psoc: soc context
+ * @peer: peer context
+ * @buf: rx buffer
+ * @mgmt_rx_params: mgmt rx parameters
+ * @frm_type: frame type
+ *
+ * This function gets called from mgmt tx/rx component when rx mgmt
+ * received.
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
+QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
+	struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
+	struct mgmt_rx_event_params *mgmt_rx_params,
+	enum mgmt_frame_type frm_type);
+
 #endif

+ 151 - 0
umac/tdls/dispatcher/src/wlan_tdls_tgt_api.c

@@ -87,6 +87,36 @@ QDF_STATUS tgt_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!pmsg || !pmsg->bodyptr) {
+		tdls_err("msg: 0x%p", pmsg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = tdls_send_mgmt_tx_completion(pmsg->bodyptr);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!pmsg || !pmsg->bodyptr) {
+		tdls_err("msg: 0x%p", pmsg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = tdls_process_send_mgmt_rsp(pmsg->bodyptr);
+
+	return status;
+}
+
 QDF_STATUS tgt_tdls_add_peer_rsp(struct scheduler_msg *pmsg)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -183,3 +213,124 @@ tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc,
 
 	return status;
 }
+
+static
+QDF_STATUS tgt_tdls_mgmt_frame_process_rx_cb(
+			struct wlan_objmgr_psoc *psoc,
+			struct wlan_objmgr_peer *peer,
+			qdf_nbuf_t buf,
+			struct mgmt_rx_event_params *mgmt_rx_params,
+			enum mgmt_frame_type frm_type)
+{
+	struct tdls_rx_mgmt_frame *rx_mgmt;
+	struct tdls_rx_mgmt_event *rx_mgmt_event;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct scheduler_msg msg;
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t vdev_id;
+	uint8_t *pdata;
+	QDF_STATUS status;
+
+	tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+			WLAN_UMAC_COMP_TDLS);
+	if (!tdls_soc_obj) {
+		tdls_err("tdls ctx is NULL, drop this frame");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!peer) {
+		vdev = tdls_get_vdev(psoc, WLAN_TDLS_SB_ID);
+		if (!vdev) {
+			tdls_err("current tdls vdev is null, can't get vdev id");
+			return QDF_STATUS_E_FAILURE;
+		}
+		wlan_vdev_obj_lock(vdev);
+		vdev_id = wlan_vdev_get_id(vdev);
+		wlan_vdev_obj_unlock(vdev);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+	} else {
+		wlan_peer_obj_lock(peer);
+		vdev = wlan_peer_get_vdev(peer);
+		wlan_peer_obj_unlock(peer);
+		if (!vdev) {
+			tdls_err("vdev is NULL in peer, drop this frame");
+			return QDF_STATUS_E_FAILURE;
+		}
+		wlan_vdev_obj_lock(vdev);
+		vdev_id = wlan_vdev_get_id(vdev);
+		wlan_vdev_obj_unlock(vdev);
+	}
+
+	rx_mgmt_event = qdf_mem_malloc(sizeof(*rx_mgmt_event));
+	if (!rx_mgmt_event) {
+		tdls_err("Failed to allocate rx mgmt event");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	rx_mgmt = qdf_mem_malloc(sizeof(*rx_mgmt) +
+			mgmt_rx_params->buf_len);
+	if (!rx_mgmt) {
+		tdls_err("Failed to allocate rx mgmt frame");
+		qdf_mem_free(rx_mgmt_event);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	pdata = (uint8_t *)qdf_nbuf_data(buf);
+	rx_mgmt->frame_len = mgmt_rx_params->buf_len;
+	rx_mgmt->rx_chan = mgmt_rx_params->channel;
+	rx_mgmt->vdev_id = vdev_id;
+	rx_mgmt->frm_type = frm_type;
+	rx_mgmt->rx_rssi = mgmt_rx_params->rssi;
+
+	rx_mgmt_event->rx_mgmt = rx_mgmt;
+	rx_mgmt_event->tdls_soc_obj = tdls_soc_obj;
+	qdf_mem_copy(rx_mgmt->buf, pdata, mgmt_rx_params->buf_len);
+	msg.type = TDLS_EVENT_RX_MGMT;
+	msg.bodyptr = rx_mgmt_event;
+	msg.callback = tdls_process_rx_frame;
+	status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
+
+	qdf_nbuf_free(buf);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(
+			struct wlan_objmgr_psoc *psoc,
+			struct wlan_objmgr_peer *peer,
+			qdf_nbuf_t buf,
+			struct mgmt_rx_event_params *mgmt_rx_params,
+			enum mgmt_frame_type frm_type)
+{
+	QDF_STATUS status;
+
+	tdls_debug("psoc:%p, peer:%p, type:%d", psoc, peer, frm_type);
+
+
+	if (!buf) {
+		tdls_err("rx frame buff is null buf:%p", buf);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!mgmt_rx_params || !psoc) {
+		tdls_err("input is NULL mgmt_rx_params:%p psoc:%p, peer:%p",
+			  mgmt_rx_params, psoc, peer);
+		status = QDF_STATUS_E_INVAL;
+		goto release_nbuf;
+	}
+
+	status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_SB_ID);
+	if (QDF_STATUS_SUCCESS != status)
+		goto release_nbuf;
+
+	status = tgt_tdls_mgmt_frame_process_rx_cb(psoc, peer, buf,
+						   mgmt_rx_params, frm_type);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
+
+	if (QDF_STATUS_SUCCESS != status)
+release_nbuf:
+		qdf_nbuf_free(buf);
+	return status;
+}
+

+ 14 - 1
umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c

@@ -194,6 +194,12 @@ QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	soc_obj->tdls_rx_cb = req->tdls_rx_cb;
+	soc_obj->tdls_rx_cb_data = req->tdls_rx_cb_data;
+
+	soc_obj->tdls_wmm_cb = req->tdls_wmm_cb;
+	soc_obj->tdls_wmm_cb_data = req->tdls_wmm_cb_data;
+
 	soc_obj->tdls_event_cb = req->tdls_event_cb;
 	soc_obj->tdls_evt_cb_data = req->tdls_evt_cb_data;
 
@@ -256,9 +262,14 @@ QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc)
 					tdls_scan_serialization_comp_info_cb);
 	if (QDF_STATUS_SUCCESS != status) {
 		tdls_err("Serialize scan cmd register failed ");
-		status = QDF_STATUS_E_FAILURE;
+		return status;
 	}
 
+	/* register callbacks with tx/rx mgmt */
+	status = tdls_mgmt_rx_ops(psoc, true);
+	if (status != QDF_STATUS_SUCCESS)
+		tdls_err("Failed to register mgmt rx callback, status:%d",
+			status);
 	return status;
 }
 
@@ -647,4 +658,6 @@ void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
 	tdls_update_tx_pkt_cnt(vdev, mac_addr);
 
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
 }
+