瀏覽代碼

qcacld-3.0: Add TWT setup support to componentization

Add TWT setup support to TWT componentization
i.e to setup TWT session.

Change-Id: Ic79be278b264634d1d54759950167547d0daf1ef
CRs-Fixed: 3085483
Srinivas Girigowda 3 年之前
父節點
當前提交
5fd6f2b7d8

+ 9 - 1
components/target_if/twt/src/target_if_ext_twt_cmd.c

@@ -28,7 +28,15 @@ QDF_STATUS
 target_if_twt_setup_req(struct wlan_objmgr_psoc *psoc,
 			struct twt_add_dialog_param *req)
 {
-	return QDF_STATUS_SUCCESS;
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return wmi_unified_twt_add_dialog_cmd(wmi_handle, req);
 }
 
 QDF_STATUS

+ 93 - 2
components/target_if/twt/src/target_if_ext_twt_evt.c

@@ -30,7 +30,57 @@ static int
 target_if_twt_setup_complete_event_handler(ol_scn_t scn, uint8_t *event,
 					   uint32_t len)
 {
-	return 0;
+	QDF_STATUS qdf_status;
+	struct wmi_unified *wmi_handle;
+	struct wlan_objmgr_psoc *psoc;
+	struct twt_add_dialog_complete_event *data;
+	struct wlan_lmac_if_twt_rx_ops *twt_rx_ops;
+
+	TARGET_IF_ENTER();
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	twt_rx_ops = wlan_twt_get_rx_ops(psoc);
+	if (!twt_rx_ops || !twt_rx_ops->twt_setup_comp_cb) {
+		target_if_err("No valid twt setup complete rx ops");
+		return -EINVAL;
+	}
+
+	data = qdf_mem_malloc(sizeof(*data));
+	if (!data)
+		return -ENOMEM;
+
+	qdf_status = wmi_extract_twt_add_dialog_comp_event(wmi_handle,
+						event, &data->params);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		target_if_err("extract twt add dialog event failed (status=%d)",
+			      qdf_status);
+		goto done;
+	}
+
+	if (data->params.num_additional_twt_params) {
+		qdf_status = wmi_extract_twt_add_dialog_comp_additional_params(
+						wmi_handle, event, len, 0,
+						&data->additional_params);
+		if (QDF_IS_STATUS_ERROR(qdf_status))
+			goto done;
+	}
+
+	qdf_status = twt_rx_ops->twt_setup_comp_cb(psoc, data);
+
+done:
+	qdf_mem_free(data);
+	return qdf_status_to_os_return(qdf_status);
 }
 
 static int
@@ -72,7 +122,48 @@ static int
 target_if_twt_ack_complete_event_handler(ol_scn_t scn, uint8_t *event,
 					 uint32_t len)
 {
-	return 0;
+	QDF_STATUS qdf_status;
+	struct wmi_unified *wmi_handle;
+	struct wlan_objmgr_psoc *psoc;
+	struct twt_ack_complete_event_param *data;
+	struct wlan_lmac_if_twt_rx_ops *twt_rx_ops;
+
+	TARGET_IF_ENTER();
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	twt_rx_ops = wlan_twt_get_rx_ops(psoc);
+	if (!twt_rx_ops || !twt_rx_ops->twt_ack_comp_cb) {
+		target_if_err("No valid twt ack rx ops");
+		return -EINVAL;
+	}
+
+	data = qdf_mem_malloc(sizeof(*data));
+	if (!data)
+		return -ENOMEM;
+
+	qdf_status = wmi_extract_twt_ack_comp_event(wmi_handle, event, data);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		target_if_err("extract twt ack event failed (status=%d)",
+			      qdf_status);
+		goto done;
+	}
+
+	qdf_status = twt_rx_ops->twt_ack_comp_cb(psoc, data);
+
+done:
+	qdf_mem_free(data);
+	return qdf_status_to_os_return(qdf_status);
 }
 
 QDF_STATUS

+ 581 - 6
components/umac/twt/core/src/wlan_twt_main.c

@@ -15,6 +15,7 @@
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
+#include "include/wlan_mlme_cmn.h"
 #include <wlan_objmgr_psoc_obj.h>
 #include <wlan_objmgr_peer_obj.h>
 #include <wlan_twt_api.h>
@@ -23,6 +24,7 @@
 #include <wlan_mlme_main.h>
 #include "wlan_twt_main.h"
 #include "twt/core/src/wlan_twt_priv.h"
+#include <wlan_twt_tgt_if_ext_tx_api.h>
 
 /**
  * wlan_twt_add_session()  - Add TWT session entry in the TWT context
@@ -39,6 +41,38 @@ wlan_twt_add_session(struct wlan_objmgr_psoc *psoc,
 		     uint8_t dialog_id,
 		     void *context)
 {
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer twt component object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		if (peer_priv->session_info[i].dialog_id ==
+			TWT_ALL_SESSIONS_DIALOG_ID) {
+			peer_priv->session_info[i].dialog_id = dialog_id;
+			peer_priv->session_info[i].twt_ack_ctx = context;
+			break;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -57,6 +91,38 @@ wlan_twt_set_command_in_progress(struct wlan_objmgr_psoc *psoc,
 				 uint8_t dialog_id,
 				 enum wlan_twt_commands cmd)
 {
+	struct wlan_objmgr_peer *peer;
+	struct twt_peer_priv_obj *peer_priv;
+	uint8_t i = 0;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err(" peer twt component object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		if (peer_priv->session_info[i].dialog_id == dialog_id ||
+			dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			peer_priv->session_info[i].active_cmd = cmd;
+			if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)
+				break;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -65,6 +131,43 @@ wlan_twt_init_context(struct wlan_objmgr_psoc *psoc,
 		      struct qdf_mac_addr *peer_mac,
 		      uint8_t dialog_id)
 {
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer twt component object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	peer_priv->num_twt_sessions = WLAN_MAX_TWT_SESSIONS_PER_PEER;
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		if (peer_priv->session_info[i].dialog_id == dialog_id ||
+			dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			peer_priv->session_info[i].setup_done = false;
+			peer_priv->session_info[i].dialog_id =
+					TWT_ALL_SESSIONS_DIALOG_ID;
+			peer_priv->session_info[i].active_cmd =
+					WLAN_TWT_NONE;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	twt_debug("init done");
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -360,20 +463,131 @@ static
 bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc,
 			    struct qdf_mac_addr *peer_mac, uint8_t dialog_id)
 {
-	return false;
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	bool is_setup_done = false;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return false;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer mlme component object is NULL");
+		return false;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		if (peer_priv->session_info[i].dialog_id == dialog_id ||
+		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			is_setup_done =
+				peer_priv->session_info[i].setup_done;
+
+			if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID ||
+			    is_setup_done)
+				break;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+
+	return is_setup_done;
 }
 
 bool wlan_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc,
 				      struct qdf_mac_addr *peer_mac,
 				      uint8_t dialog_id)
 {
-	return false;
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i, num_twt_sessions = 0, max_twt_sessions;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return true;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer twt component object is NULL");
+		return true;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+
+	max_twt_sessions = peer_priv->num_twt_sessions;
+	for (i = 0; i < max_twt_sessions; i++) {
+		uint8_t existing_session_dialog_id =
+				peer_priv->session_info[i].dialog_id;
+
+		if (existing_session_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID &&
+			existing_session_dialog_id != dialog_id)
+			num_twt_sessions++;
+	}
+
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+
+	twt_debug("num_twt_sessions:%d max_twt_sessions:%d",
+			  num_twt_sessions, max_twt_sessions);
+	return num_twt_sessions == max_twt_sessions;
 }
 
 bool wlan_twt_is_setup_in_progress(struct wlan_objmgr_psoc *psoc,
 				   struct qdf_mac_addr *peer_mac,
 				   uint8_t dialog_id)
 {
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return false;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer twt component object is NULL");
+		return false;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		bool setup_done = peer_priv->session_info[i].setup_done;
+		uint8_t existing_session_dialog_id;
+
+		existing_session_dialog_id =
+			peer_priv->session_info[i].dialog_id;
+		if (existing_session_dialog_id == dialog_id &&
+		    existing_session_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID &&
+		    !setup_done) {
+			qdf_mutex_release(&peer_priv->twt_peer_lock);
+			wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+			return true;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+
 	return false;
 }
 
@@ -392,6 +606,43 @@ wlan_twt_set_ack_context(struct wlan_objmgr_psoc *psoc,
 			 uint8_t dialog_id,
 			 void *context)
 {
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer twt component object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		uint8_t existing_session_dialog_id;
+
+		existing_session_dialog_id =
+			peer_priv->session_info[i].dialog_id;
+		if (existing_session_dialog_id == dialog_id ||
+		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			peer_priv->session_info[i].twt_ack_ctx = context;
+
+			if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)
+				break;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -410,7 +661,46 @@ wlan_twt_get_ack_context(struct wlan_objmgr_psoc *psoc,
 			 uint8_t dialog_id,
 			 void **context)
 {
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		goto err;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("peer twt component object is NULL");
+		goto err;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		uint8_t existing_session_dialog_id;
+
+		existing_session_dialog_id =
+			peer_priv->session_info[i].dialog_id;
+		if (existing_session_dialog_id == dialog_id ||
+		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			*context = peer_priv->session_info[i].twt_ack_ctx;
+			break;
+		}
+	}
+
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
 	return QDF_STATUS_SUCCESS;
+
+err:
+	*context = NULL;
+	return QDF_STATUS_E_FAILURE;
 }
 
 /**
@@ -430,14 +720,117 @@ bool wlan_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc,
 				     enum wlan_twt_commands cmd,
 				     enum wlan_twt_commands *pactive_cmd)
 {
-	return false;
+	struct wlan_objmgr_peer *peer;
+	struct twt_peer_priv_obj *peer_priv;
+	enum wlan_twt_commands active_cmd;
+	uint8_t i = 0;
+	bool is_command_in_progress = false;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return false;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err(" peer twt component object is NULL");
+		return false;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		active_cmd = peer_priv->session_info[i].active_cmd;
+
+		if (pactive_cmd)
+			*pactive_cmd = active_cmd;
+
+		if (peer_priv->session_info[i].dialog_id == dialog_id ||
+			dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			if (cmd == WLAN_TWT_ANY) {
+				is_command_in_progress =
+					(active_cmd != WLAN_TWT_NONE);
+
+				if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID ||
+					is_command_in_progress)
+					break;
+			} else {
+				is_command_in_progress = (active_cmd == cmd);
+
+				if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID ||
+					is_command_in_progress)
+					break;
+			}
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+
+	return is_command_in_progress;
 }
 
 QDF_STATUS wlan_twt_setup_req(struct wlan_objmgr_psoc *psoc,
 			      struct twt_add_dialog_param *req,
 			      void *context)
 {
-	return QDF_STATUS_SUCCESS;
+	QDF_STATUS status;
+	bool cmd_in_progress, notify_in_progress;
+	enum wlan_twt_commands active_cmd = WLAN_TWT_NONE;
+
+	if (wlan_twt_is_max_sessions_reached(psoc, &req->peer_macaddr,
+					     req->dialog_id)) {
+		twt_err("TWT add failed(dialog_id:%d), another TWT already exists (max reached)",
+			req->dialog_id);
+		return QDF_STATUS_E_AGAIN;
+	}
+
+	if (wlan_twt_is_setup_in_progress(psoc, &req->peer_macaddr,
+					  req->dialog_id)) {
+		twt_err("TWT setup is in progress for dialog_id:%d",
+			req->dialog_id);
+		return QDF_STATUS_E_ALREADY;
+	}
+
+	if (!mlme_get_user_ps(psoc, req->vdev_id)) {
+		twt_warn("Power save mode disable");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	notify_in_progress = wlan_is_twt_notify_in_progress(psoc, req->vdev_id);
+	if (notify_in_progress) {
+		twt_warn("Waiting for TWT Notify");
+		return QDF_STATUS_E_BUSY;
+	}
+
+	cmd_in_progress = wlan_twt_is_command_in_progress(
+					psoc, &req->peer_macaddr, req->dialog_id,
+					WLAN_TWT_ANY, &active_cmd);
+	if (cmd_in_progress) {
+		twt_debug("Already TWT command:%d is in progress", active_cmd);
+		return QDF_STATUS_E_PENDING;
+	}
+
+	/*
+	 * Add the dialog id to TWT context to drop back to back
+	 * commands
+	 */
+	wlan_twt_add_session(psoc, &req->peer_macaddr, req->dialog_id, context);
+	wlan_twt_set_ack_context(psoc, &req->peer_macaddr, req->dialog_id,
+				 context);
+	wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr,
+					 req->dialog_id, WLAN_TWT_SETUP);
+
+	status = tgt_twt_setup_req_send(psoc, req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		twt_err("tgt_twt_setup_req_send failed (status=%d)", status);
+		wlan_twt_init_context(psoc, &req->peer_macaddr, req->dialog_id);
+	}
+
+	return status;
 }
 
 /**
@@ -483,7 +876,29 @@ QDF_STATUS
 wlan_twt_ack_event_handler(struct wlan_objmgr_psoc *psoc,
 			   struct twt_ack_complete_event_param *event)
 {
-	return QDF_STATUS_SUCCESS;
+	void *ack_context = NULL;
+	QDF_STATUS qdf_status;
+
+	twt_debug("TWT ack status: %d", event->status);
+	/* If the ack status is other than 0 (SUCCESS) then its a error.
+	 * that means there won't be following TWT add/del/pause/resume/nudge
+	 * event, hence clear the command in progress to NONE
+	 */
+	if (event->status) {
+		qdf_status = wlan_twt_set_command_in_progress(psoc,
+					 &event->peer_macaddr,
+					 event->dialog_id, WLAN_TWT_NONE);
+		if (QDF_IS_STATUS_ERROR(qdf_status))
+			return qdf_status;
+	}
+	qdf_status = wlan_twt_get_ack_context(psoc, &event->peer_macaddr,
+					      event->dialog_id, &ack_context);
+	if (QDF_IS_STATUS_ERROR(qdf_status))
+		return qdf_status;
+
+	qdf_status = mlme_twt_osif_ack_complete_ind(psoc, event, ack_context);
+
+	return qdf_status;
 }
 
 /**
@@ -500,6 +915,37 @@ wlan_twt_set_setup_done(struct wlan_objmgr_psoc *psoc,
 			struct qdf_mac_addr *peer_mac,
 			uint8_t dialog_id, bool is_set)
 {
+	struct twt_peer_priv_obj *peer_priv;
+	struct wlan_objmgr_peer *peer;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err(" peer twt component object is NULL");
+		return;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		if (peer_priv->session_info[i].dialog_id == dialog_id) {
+			peer_priv->session_info[i].setup_done = is_set;
+			twt_debug("setup done:%d dialog:%d", is_set, dialog_id);
+			break;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
 }
 
 /**
@@ -518,6 +964,37 @@ wlan_twt_set_session_state(struct wlan_objmgr_psoc *psoc,
 			   uint8_t dialog_id,
 			   enum wlan_twt_session_state state)
 {
+	struct wlan_objmgr_peer *peer;
+	struct twt_peer_priv_obj *peer_priv;
+	uint8_t i;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err(" peer twt component object is NULL");
+		return;
+	}
+
+	twt_debug("set_state:%d for dialog_id:%d", state, dialog_id);
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		if (peer_priv->session_info[i].dialog_id == dialog_id ||
+		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			peer_priv->session_info[i].state = state;
+			break;
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
 }
 
 /**
@@ -531,6 +1008,13 @@ static void
 wlan_twt_process_renego_failure(struct wlan_objmgr_psoc *psoc,
 				struct twt_add_dialog_complete_event *event)
 {
+	/* Reset the active TWT command to none */
+	wlan_twt_set_command_in_progress(psoc,
+					 &event->params.peer_macaddr,
+					 event->params.dialog_id,
+					 WLAN_TWT_NONE);
+
+	mlme_twt_osif_setup_complete_ind(psoc, event, true);
 }
 
 /**
@@ -545,13 +1029,104 @@ static void
 wlan_twt_process_add_initial_nego(struct wlan_objmgr_psoc *psoc,
 				  struct twt_add_dialog_complete_event *event)
 {
+	mlme_twt_osif_setup_complete_ind(psoc, event, false);
+
+	/* Reset the active TWT command to none */
+	wlan_twt_set_command_in_progress(psoc,
+					 &event->params.peer_macaddr,
+					 event->params.dialog_id,
+					 WLAN_TWT_NONE);
+
+	if (event->params.status) {
+		/* Clear the stored TWT dialog ID as TWT setup failed */
+		wlan_twt_init_context(psoc, &event->params.peer_macaddr,
+				      event->params.dialog_id);
+		return;
+	}
+
+	wlan_twt_set_setup_done(psoc, &event->params.peer_macaddr,
+				event->params.dialog_id, true);
+
+	wlan_twt_set_session_state(psoc, &event->params.peer_macaddr,
+				   event->params.dialog_id,
+				   WLAN_TWT_SETUP_STATE_ACTIVE);
 }
 
 QDF_STATUS
 wlan_twt_setup_complete_event_handler(struct wlan_objmgr_psoc *psoc,
 				    struct twt_add_dialog_complete_event *event)
 {
-	return QDF_STATUS_SUCCESS;
+	bool is_evt_allowed;
+	bool setup_done;
+	enum HOST_TWT_ADD_STATUS status = event->params.status;
+	enum wlan_twt_commands active_cmd = WLAN_TWT_NONE;
+	enum QDF_OPMODE opmode;
+	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
+	uint32_t pdev_id, vdev_id;
+	struct wlan_objmgr_pdev *pdev;
+
+	vdev_id = event->params.vdev_id;
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
+	if (pdev_id == WLAN_INVALID_PDEV_ID) {
+		twt_err("Invalid pdev id");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID);
+	if (!pdev) {
+		twt_err("Invalid pdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id);
+
+	switch (opmode) {
+	case QDF_SAP_MODE:
+		mlme_twt_osif_setup_complete_ind(psoc, event, false);
+		break;
+	case QDF_STA_MODE:
+		is_evt_allowed = wlan_twt_is_command_in_progress(
+						psoc,
+						&event->params.peer_macaddr,
+						event->params.dialog_id,
+						WLAN_TWT_SETUP, &active_cmd);
+
+		if (!is_evt_allowed) {
+			twt_debug("Drop TWT add dialog event for dialog_id:%d status:%d active_cmd:%d",
+				  event->params.dialog_id, status,
+				  active_cmd);
+			qdf_status = QDF_STATUS_E_INVAL;
+			goto cleanup;
+		}
+
+		setup_done = wlan_twt_is_setup_done(psoc,
+						    &event->params.peer_macaddr,
+						    event->params.dialog_id);
+		twt_debug("setup_done:%d status:%d", setup_done, status);
+
+		if (setup_done && status) {
+			/*This is re-negotiation failure case */
+			wlan_twt_process_renego_failure(psoc, event);
+		} else {
+			wlan_twt_process_add_initial_nego(psoc, event);
+		}
+
+		break;
+	default:
+		twt_debug("TWT Setup is not supported on %s",
+			  qdf_opmode_str(opmode));
+		break;
+	}
+
+	qdf_status = wlan_twt_set_command_in_progress(psoc,
+					&event->params.peer_macaddr,
+					event->params.dialog_id, WLAN_TWT_NONE);
+	if (QDF_IS_STATUS_ERROR(qdf_status))
+		return qdf_status;
+
+cleanup:
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID);
+	return qdf_status;
 }
 
 static bool

+ 3 - 2
components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_rx_api.c

@@ -24,12 +24,13 @@
 #include <wlan_objmgr_psoc_obj.h>
 #include <wlan_twt_public_structs.h>
 #include <wlan_twt_tgt_if_ext_rx_ops.h>
+#include "twt/core/src/wlan_twt_main.h"
 
 static QDF_STATUS
 tgt_twt_setup_complete_resp_handler(struct wlan_objmgr_psoc *psoc,
 			     struct twt_add_dialog_complete_event *event)
 {
-	return QDF_STATUS_SUCCESS;
+	return wlan_twt_setup_complete_event_handler(psoc, event);
 }
 
 static QDF_STATUS
@@ -71,7 +72,7 @@ static QDF_STATUS
 tgt_twt_ack_complete_resp_handler(struct wlan_objmgr_psoc *psoc,
 			    struct twt_ack_complete_event_param *event)
 {
-	return QDF_STATUS_SUCCESS;
+	return wlan_twt_ack_event_handler(psoc, event);
 }
 
 void tgt_twt_register_ext_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)

+ 23 - 1
components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_tx_api.c

@@ -32,7 +32,29 @@ QDF_STATUS
 tgt_twt_setup_req_send(struct wlan_objmgr_psoc *psoc,
 		       struct twt_add_dialog_param *req)
 {
-	return QDF_STATUS_SUCCESS;
+	struct wlan_lmac_if_twt_tx_ops *tx_ops;
+	QDF_STATUS status;
+
+	if (!psoc) {
+		twt_err("psoc is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!req) {
+		twt_err("Invalid input");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tx_ops = wlan_twt_get_tx_ops(psoc);
+	if (!tx_ops || !tx_ops->setup_req) {
+		twt_err("setup_req tx_ops is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		return status;
+	}
+
+	status = tx_ops->setup_req(psoc, req);
+
+	return status;
 }
 
 QDF_STATUS

+ 3 - 2
core/hdd/src/wlan_hdd_cfg80211.c

@@ -4228,8 +4228,9 @@ __wlan_hdd_cfg80211_get_features(struct wiphy *wiphy,
 					  QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R);
 	}
 
-	ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &twt_req);
-	ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &twt_res);
+	hdd_get_twt_requestor(hdd_ctx->psoc, &twt_req);
+	hdd_get_twt_responder(hdd_ctx->psoc, &twt_res);
+	hdd_debug("twt_req:%d twt_res:%d", twt_req, twt_res);
 
 	if (twt_req || twt_res) {
 		wlan_hdd_cfg80211_set_feature(feature_flags,

+ 5 - 0
core/hdd/src/wlan_hdd_cm_connect.c

@@ -50,6 +50,8 @@
 #include "wlan_roam_debug.h"
 #include <wlan_hdd_regulatory.h>
 #include "wlan_hdd_hostapd.h"
+#include <wlan_twt_ucfg_ext_api.h>
+#include <osif_twt_internal.h>
 
 bool hdd_cm_is_vdev_associated(struct hdd_adapter *adapter)
 {
@@ -1305,6 +1307,9 @@ hdd_cm_connect_success_post_user_update(struct wlan_objmgr_vdev *vdev,
 		ucfg_mlme_init_twt_context(hdd_ctx->psoc,
 					   &rsp->bssid,
 					   TWT_ALL_SESSIONS_DIALOG_ID);
+		ucfg_twt_init_context(hdd_ctx->psoc,
+				      &rsp->bssid,
+				      TWT_ALL_SESSIONS_DIALOG_ID);
 	}
 	hdd_periodic_sta_stats_start(adapter);
 	wlan_twt_concurrency_update(hdd_ctx);

+ 169 - 78
core/hdd/src/wlan_hdd_twt.c

@@ -45,6 +45,15 @@
 #include "wlan_twt_ucfg_ext_cfg.h"
 #include "osif_twt_internal.h"
 
+const struct nla_policy
+wlan_hdd_wifi_twt_config_policy[
+	QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = {
+		[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION] = {
+			.type = NLA_U8},
+		[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS] = {
+			.type = NLA_NESTED},
+};
+
 #if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED)
 QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val)
 {
@@ -86,6 +95,27 @@ void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx,
 	osif_twt_send_responder_disable_cmd(hdd_ctx->psoc, pdev_id);
 }
 
+int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter,
+				      struct nlattr **tb)
+{
+	return 0;
+}
+
+void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)
+{
+}
+
+void
+hdd_send_twt_del_all_sessions_to_userspace(struct hdd_adapter *adapter)
+{
+}
+
+int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter,
+					  struct nlattr **tb)
+{
+	return 0;
+}
+
 QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx)
 {
 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
@@ -94,6 +124,73 @@ QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx)
 	return QDF_STATUS_SUCCESS;
 }
 
+static int hdd_twt_configure(struct hdd_adapter *adapter,
+			     struct nlattr **tb)
+{
+	enum qca_wlan_twt_operation twt_oper;
+	struct nlattr *twt_oper_attr;
+	struct nlattr *twt_param_attr;
+	uint32_t id;
+	int ret = 0;
+	struct wlan_objmgr_vdev *vdev;
+
+	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION;
+	twt_oper_attr = tb[id];
+
+	if (!twt_oper_attr) {
+		hdd_err("TWT operation NOT specified");
+		return -EINVAL;
+	}
+
+	twt_oper = nla_get_u8(twt_oper_attr);
+
+	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS;
+	twt_param_attr = tb[id];
+
+	if (!twt_param_attr &&
+	    twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES &&
+	    twt_oper != QCA_WLAN_TWT_SUSPEND) {
+		hdd_err("TWT parameters NOT specified");
+		return -EINVAL;
+	}
+
+	hdd_debug("TWT Operation 0x%x", twt_oper);
+
+	vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_TWT_ID);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return -EINVAL;
+	}
+
+	switch (twt_oper) {
+	case QCA_WLAN_TWT_SET:
+		ret = osif_twt_setup_req(vdev, twt_param_attr);
+		break;
+	case QCA_WLAN_TWT_GET:
+		break;
+	case QCA_WLAN_TWT_TERMINATE:
+		break;
+	case QCA_WLAN_TWT_SUSPEND:
+		break;
+	case QCA_WLAN_TWT_RESUME:
+		break;
+	case QCA_WLAN_TWT_NUDGE:
+		break;
+	case QCA_WLAN_TWT_GET_CAPABILITIES:
+		break;
+	case QCA_WLAN_TWT_GET_STATS:
+		break;
+	case QCA_WLAN_TWT_CLEAR_STATS:
+		break;
+	default:
+		hdd_err("Invalid TWT Operation");
+		ret = -EINVAL;
+		break;
+	}
+
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_TWT_ID);
+	return ret;
+}
 #elif defined(WLAN_SUPPORT_TWT)
 
 #define TWT_DISABLE_COMPLETE_TIMEOUT 1000
@@ -150,15 +247,6 @@ qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1]
 	[QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 },
 };
 
-const struct nla_policy
-wlan_hdd_wifi_twt_config_policy[
-	QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = {
-		[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION] = {
-			.type = NLA_U8},
-		[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS] = {
-			.type = NLA_NESTED},
-};
-
 static const struct nla_policy
 qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 },
@@ -4098,75 +4186,6 @@ static int hdd_twt_configure(struct hdd_adapter *adapter,
 	return ret;
 }
 
-/**
- * __wlan_hdd_cfg80211_wifi_twt_config() - Wifi TWT configuration
- * vendor command
- * @wiphy: wiphy device pointer
- * @wdev: wireless device pointer
- * @data: Vendor command data buffer
- * @data_len: Buffer length
- *
- * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX.
- *
- * Return: 0 for Success and negative value for failure
- */
-static int
-__wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
-				    struct wireless_dev *wdev,
-				    const void *data, int data_len)
-{
-	struct net_device *dev = wdev->netdev;
-	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
-	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
-	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1];
-	int errno;
-
-	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
-		hdd_err("Command not allowed in FTM mode");
-		return -EPERM;
-	}
-
-	errno = wlan_hdd_validate_context(hdd_ctx);
-	if (errno)
-		return errno;
-
-	errno = hdd_validate_adapter(adapter);
-	if (errno)
-		return errno;
-
-	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX,
-				    data,
-				    data_len,
-				    wlan_hdd_wifi_twt_config_policy)) {
-		hdd_err("invalid twt attr");
-		return -EINVAL;
-	}
-
-	errno = hdd_twt_configure(adapter, tb);
-
-	return errno;
-}
-
-int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
-				      struct wireless_dev *wdev,
-				      const void *data,
-				      int data_len)
-{
-	int errno;
-	struct osif_vdev_sync *vdev_sync;
-
-	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
-	if (errno)
-		return errno;
-
-	errno = __wlan_hdd_cfg80211_wifi_twt_config(wiphy, wdev, data,
-						    data_len);
-
-	osif_vdev_sync_op_stop(vdev_sync);
-
-	return errno;
-}
-
 void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
 			    struct wma_tgt_cfg *cfg)
 {
@@ -4293,6 +4312,7 @@ QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx)
 
 		ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, true);
 		qdf_event_reset(&hdd_ctx->twt_enable_comp_evt);
+
 		wma_send_twt_enable_cmd(pdev_id, &twt_en_dis);
 		status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt,
 					       TWT_ENABLE_COMPLETE_TIMEOUT);
@@ -4377,6 +4397,7 @@ QDF_STATUS hdd_send_twt_requestor_disable_cmd(struct hdd_context *hdd_ctx)
 	hdd_ctx->twt_state = TWT_DISABLE_REQUESTED;
 	twt_en_dis.ext_conf_present = true;
 	qdf_event_reset(&hdd_ctx->twt_disable_comp_evt);
+
 	wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
 
 	status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt,
@@ -4795,3 +4816,73 @@ QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val)
 }
 
 #endif
+
+/**
+ * __wlan_hdd_cfg80211_wifi_twt_config() - Wifi TWT configuration
+ * vendor command
+ * @wiphy: wiphy device pointer
+ * @wdev: wireless device pointer
+ * @data: Vendor command data buffer
+ * @data_len: Buffer length
+ *
+ * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX.
+ *
+ * Return: 0 for Success and negative value for failure
+ */
+static int
+__wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
+				    struct wireless_dev *wdev,
+				    const void *data, int data_len)
+{
+	struct net_device *dev = wdev->netdev;
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1];
+	int errno;
+
+	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EPERM;
+	}
+
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return errno;
+
+	errno = hdd_validate_adapter(adapter);
+	if (errno)
+		return errno;
+
+	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX,
+				    data,
+				    data_len,
+				    wlan_hdd_wifi_twt_config_policy)) {
+		hdd_err("invalid twt attr");
+		return -EINVAL;
+	}
+
+	errno = hdd_twt_configure(adapter, tb);
+
+	return errno;
+}
+
+int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
+				      struct wireless_dev *wdev,
+				      const void *data,
+				      int data_len)
+{
+	int errno;
+	struct osif_vdev_sync *vdev_sync;
+
+	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_wifi_twt_config(wiphy, wdev, data,
+						    data_len);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return errno;
+}
+

+ 549 - 1
os_if/twt/src/osif_twt_ext_req.c

@@ -21,6 +21,7 @@
 #include <wlan_objmgr_vdev_obj.h>
 #include <wlan_twt_ucfg_api.h>
 #include <wlan_twt_ucfg_ext_api.h>
+#include <wlan_twt_ucfg_ext_cfg.h>
 #include <osif_twt_req.h>
 #include <osif_twt_ext_req.h>
 #include <wlan_policy_mgr_api.h>
@@ -41,6 +42,433 @@
 #define TWT_SETUP_WAKE_INTVL_EXP_MAX            31
 #define TWT_MAX_NEXT_TWT_SIZE                   3
 
+static const struct nla_policy
+qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION] = {
+							.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF] = {.type = NLA_U64 },
+};
+
+static int osif_is_twt_command_allowed(struct wlan_objmgr_vdev *vdev,
+				       uint8_t vdev_id,
+				       struct wlan_objmgr_psoc *psoc)
+{
+	enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev);
+
+	if (mode != QDF_STA_MODE &&
+	    mode != QDF_P2P_CLIENT_MODE)
+		return -EOPNOTSUPP;
+
+	if (!wlan_cm_is_vdev_connected(vdev)) {
+		osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode);
+		return -EAGAIN;
+	}
+
+	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
+		return -EBUSY;
+
+	if (wlan_get_vdev_status(vdev)) {
+		osif_err_rl("Scan in progress");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static bool osif_twt_setup_conc_allowed(struct wlan_objmgr_psoc *psoc,
+					uint8_t vdev_id)
+{
+	return policy_mgr_current_concurrency_is_mcc(psoc) ||
+	       policy_mgr_is_scc_with_this_vdev_id(psoc, vdev_id);
+}
+
+/**
+ * osif_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd
+ * @req_type: twt setup request type
+ * @twt_cmd: pointer to store twt command
+ *
+ * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
+ */
+static QDF_STATUS
+osif_twt_setup_req_type_to_cmd(u8 req_type, enum HOST_TWT_COMMAND *twt_cmd)
+{
+	if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST) {
+		*twt_cmd = HOST_TWT_COMMAND_REQUEST_TWT;
+	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST) {
+		*twt_cmd = HOST_TWT_COMMAND_SUGGEST_TWT;
+	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND) {
+		*twt_cmd = HOST_TWT_COMMAND_DEMAND_TWT;
+	} else {
+		osif_err_rl("Invalid TWT_SETUP_REQ_TYPE %d", req_type);
+		return QDF_STATUS_E_INVAL;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * osif_twt_parse_add_dialog_attrs() - Get TWT add dialog parameter
+ * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
+ * @tb: nl attributes
+ * @params: wmi twt add dialog parameters
+ *
+ * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX
+ *
+ * Return: 0 or -EINVAL.
+ */
+static int
+osif_twt_parse_add_dialog_attrs(struct nlattr **tb,
+				struct twt_add_dialog_param *params)
+{
+	uint32_t wake_intvl_exp, result;
+	int cmd_id;
+	QDF_STATUS qdf_status;
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+	if (tb[cmd_id]) {
+		params->dialog_id = nla_get_u8(tb[cmd_id]);
+		if (params->dialog_id > TWT_MAX_DIALOG_ID) {
+			osif_err_rl("Flow id (%u) invalid", params->dialog_id);
+			return -EINVAL;
+		}
+	} else {
+		params->dialog_id = 0;
+		osif_debug("TWT_SETUP_FLOW_ID not specified. set to zero");
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
+	if (!tb[cmd_id]) {
+		osif_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must");
+		return -EINVAL;
+	}
+	wake_intvl_exp = nla_get_u8(tb[cmd_id]);
+	if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) {
+		osif_err_rl("Invalid wake_intvl_exp %u > %u",
+			   wake_intvl_exp,
+			   TWT_SETUP_WAKE_INTVL_EXP_MAX);
+		return -EINVAL;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
+	params->flag_bcast = nla_get_flag(tb[cmd_id]);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
+	if (tb[cmd_id]) {
+		params->dialog_id = nla_get_u8(tb[cmd_id]);
+		osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id);
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION;
+	if (tb[cmd_id]) {
+		params->b_twt_recommendation = nla_get_u8(tb[cmd_id]);
+		osif_debug("TWT_SETUP_BCAST_RECOMM %d",
+			  params->b_twt_recommendation);
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE;
+	if (tb[cmd_id]) {
+		params->b_twt_persistence = nla_get_u8(tb[cmd_id]);
+		osif_debug("TWT_SETUP_BCAST_PERSIS %d",
+			  params->b_twt_persistence);
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE;
+	if (!tb[cmd_id]) {
+		osif_err_rl("TWT_SETUP_REQ_TYPE is must");
+		return -EINVAL;
+	}
+	qdf_status = osif_twt_setup_req_type_to_cmd(nla_get_u8(tb[cmd_id]),
+						   &params->twt_cmd);
+	if (QDF_IS_STATUS_ERROR(qdf_status))
+		return qdf_status_to_os_return(qdf_status);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
+	params->flag_trigger = nla_get_flag(tb[cmd_id]);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
+	if (!tb[cmd_id]) {
+		osif_err_rl("TWT_SETUP_FLOW_TYPE is must");
+		return -EINVAL;
+	}
+	params->flag_flow_type = nla_get_u8(tb[cmd_id]);
+	if (params->flag_flow_type != TWT_FLOW_TYPE_ANNOUNCED &&
+	    params->flag_flow_type != TWT_FLOW_TYPE_UNANNOUNCED)
+		return -EINVAL;
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
+	params->flag_protection = nla_get_flag(tb[cmd_id]);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
+	if (tb[cmd_id])
+		params->sp_offset_us = nla_get_u32(tb[cmd_id]);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
+	if (!tb[cmd_id]) {
+		osif_err_rl("TWT_SETUP_WAKE_DURATION is must");
+		return -EINVAL;
+	}
+	params->wake_dura_us = TWT_WAKE_DURATION_MULTIPLICATION_FACTOR *
+			       nla_get_u32(tb[cmd_id]);
+	if (params->wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) {
+		osif_err_rl("Invalid wake_dura_us %u",
+			   params->wake_dura_us);
+		return -EINVAL;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION;
+	if (tb[cmd_id])
+		params->min_wake_dura_us = nla_get_u32(tb[cmd_id]);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION;
+	if (tb[cmd_id])
+		params->max_wake_dura_us = nla_get_u32(tb[cmd_id]);
+
+	if (params->min_wake_dura_us > params->max_wake_dura_us) {
+		osif_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero",
+			   params->min_wake_dura_us, params->max_wake_dura_us);
+		params->min_wake_dura_us = 0;
+		params->max_wake_dura_us = 0;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
+	if (!tb[cmd_id]) {
+		osif_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
+		return -EINVAL;
+	}
+	params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
+
+	/*
+	 * If mantissa in microsecond is present then take precedence over
+	 * mantissa in TU. And send mantissa in microsecond to firmware.
+	 */
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
+	if (tb[cmd_id])
+		params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
+
+	if (params->wake_intvl_mantis >
+	    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
+		osif_err_rl("Invalid wake_intvl_mantis %u",
+			   params->wake_intvl_mantis);
+		return -EINVAL;
+	}
+
+	if (wake_intvl_exp && params->wake_intvl_mantis) {
+		result = 2 << (wake_intvl_exp - 1);
+		if (result >
+		    (UINT_MAX / params->wake_intvl_mantis)) {
+			osif_err_rl("Invalid exp %d mantissa %d",
+				   wake_intvl_exp,
+				   params->wake_intvl_mantis);
+			return -EINVAL;
+		}
+		params->wake_intvl_us =
+			params->wake_intvl_mantis * result;
+	} else {
+		params->wake_intvl_us = params->wake_intvl_mantis;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL;
+	if (tb[cmd_id])
+		params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]);
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL;
+	if (tb[cmd_id])
+		params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]);
+
+	if (params->min_wake_intvl_us > params->max_wake_intvl_us) {
+		osif_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero",
+			   params->min_wake_intvl_us,
+			   params->max_wake_intvl_us);
+		params->min_wake_dura_us = 0;
+		params->max_wake_dura_us = 0;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
+	if (tb[cmd_id])
+		params->wake_time_tsf = nla_get_u64(tb[cmd_id]);
+	else
+		params->wake_time_tsf = 0;
+
+	osif_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d",
+		  params->dialog_id, params->vdev_id, params->wake_intvl_us,
+		  params->min_wake_intvl_us, params->max_wake_intvl_us,
+		  params->wake_intvl_mantis);
+
+	osif_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d",
+		  params->wake_dura_us, params->min_wake_dura_us,
+		  params->max_wake_dura_us, params->sp_offset_us,
+		  params->twt_cmd);
+	osif_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d wake_tsf 0x%llx",
+		  params->flag_bcast, params->flag_trigger,
+		  params->flag_flow_type,
+		  params->flag_protection,
+		  params->wake_time_tsf);
+	osif_debug("twt: peer mac_addr "
+		  QDF_MAC_ADDR_FMT,
+		  QDF_MAC_ADDR_REF(params->peer_macaddr.bytes));
+
+	return 0;
+}
+
+static int osif_fill_peer_macaddr(struct wlan_objmgr_vdev *vdev,
+				  uint8_t *mac_addr)
+{
+	struct wlan_objmgr_peer *peer;
+
+	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TWT_ID);
+	if (!peer) {
+		osif_err("peer is null");
+		return -EINVAL;
+	}
+	wlan_peer_obj_lock(peer);
+	qdf_mem_copy(mac_addr, wlan_peer_get_macaddr(peer),
+				 QDF_MAC_ADDR_SIZE);
+	wlan_peer_obj_unlock(peer);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+	return 0;
+}
+
+/**
+ * osif_twt_ack_wait_response: TWT wait for ack event if it's supported
+ * @psoc: psoc context
+ * @request: OSIF request cookie
+ * @twt_cmd: TWT command for which ack event come
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+osif_twt_ack_wait_response(struct wlan_objmgr_psoc *psoc,
+			   struct osif_request *request, int twt_cmd)
+{
+	struct twt_ack_context *ack_priv;
+	int ret = 0;
+	bool twt_ack_cap;
+
+	ucfg_twt_get_twt_ack_supported(psoc, &twt_ack_cap);
+
+	if (!twt_ack_cap) {
+		osif_err("TWT ack is not supported. No need to wait");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	ack_priv = osif_request_priv(request);
+	ack_priv->twt_cmd_ack = twt_cmd;
+
+	ret = osif_request_wait_for_response(request);
+	if (ret) {
+		osif_err("TWT ack response timed out");
+		return QDF_STATUS_E_TIMEOUT;
+	}
+
+	osif_debug("TWT ack info: vdev_id %d dialog_id %d twt_cmd %d status %d peer_macaddr "
+			  QDF_MAC_ADDR_FMT, ack_priv->vdev_id, ack_priv->dialog_id,
+			  ack_priv->twt_cmd_ack, ack_priv->status,
+			  QDF_MAC_ADDR_REF(ack_priv->peer_macaddr.bytes));
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static int
+osif_send_twt_setup_req(struct wlan_objmgr_vdev *vdev,
+			struct wlan_objmgr_psoc *psoc,
+			struct twt_add_dialog_param *twt_params)
+{
+	QDF_STATUS status;
+	int twt_cmd, ret = 0;
+	struct osif_request *request;
+	struct twt_ack_context *ack_priv;
+	void *context;
+	static const struct osif_request_params params = {
+				.priv_size = sizeof(*ack_priv),
+				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
+	};
+
+	request = osif_request_alloc(&params);
+	if (!request) {
+		osif_err("Request allocation failure");
+		return -ENOMEM;
+	}
+
+	context = osif_request_cookie(request);
+
+	status = ucfg_twt_setup_req(psoc, twt_params, context);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ret = qdf_status_to_os_return(status);
+		osif_err("Failed to send add dialog command");
+		goto cleanup;
+	}
+
+	twt_cmd = HOST_TWT_ADD_DIALOG_CMDID;
+	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		/*
+		 * If the TWT ack event comes after the timeout or
+		 * if the event is not received from the firmware, then
+		 * initialize the context (reset the active command),
+		 * otherwise future commands shall be blocked.
+		 */
+		ucfg_twt_init_context(psoc, &twt_params->peer_macaddr,
+				      twt_params->dialog_id);
+		ret = qdf_status_to_os_return(status);
+		goto cleanup;
+	}
+
+	ack_priv = osif_request_priv(request);
+	if (ack_priv->status) {
+		osif_err("Received TWT ack error: %d. Reset twt command",
+			 ack_priv->status);
+		ucfg_twt_init_context(psoc, &twt_params->peer_macaddr,
+				      twt_params->dialog_id);
+
+		switch (ack_priv->status) {
+		case HOST_ADD_TWT_STATUS_INVALID_PARAM:
+		case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
+		case HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
+			ret = -EINVAL;
+			break;
+		case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
+		case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
+		case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
+			ret = -EBUSY;
+			break;
+		case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
+			ret = -EOPNOTSUPP;
+			break;
+		case HOST_ADD_TWT_STATUS_NOT_READY:
+			ret = -EAGAIN;
+			break;
+		case HOST_ADD_TWT_STATUS_NO_RESOURCE:
+			ret = -ENOMEM;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+cleanup:
+	osif_request_put(request);
+	return ret;
+}
+
 int osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc *psoc,
 				       uint8_t pdev_id)
 {
@@ -88,7 +516,127 @@ int osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc *psoc,
 int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev,
 		       struct nlattr *twt_param_attr)
 {
-	return 0;
+	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
+	struct wlan_objmgr_psoc *psoc;
+	int ret = 0;
+	uint8_t vdev_id, pdev_id;
+	struct twt_add_dialog_param params = {0};
+	uint32_t congestion_timeout = 0;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		osif_err("NULL psoc");
+		return -EINVAL;
+	}
+
+	vdev_id = wlan_vdev_get_id(vdev);
+	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
+	if (ret)
+		return ret;
+
+	if (osif_twt_setup_conc_allowed(psoc, vdev_id)) {
+		osif_err_rl("TWT setup reject: SCC or MCC concurrency exists");
+		return -EAGAIN;
+	}
+
+	ret = wlan_cfg80211_nla_parse_nested(tb2,
+					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
+					 twt_param_attr,
+					 qca_wlan_vendor_twt_add_dialog_policy);
+	if (ret)
+		return ret;
+
+	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
+	if (ret)
+		return ret;
+
+	params.vdev_id = vdev_id;
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
+
+	ret = osif_twt_parse_add_dialog_attrs(tb2, &params);
+	if (ret)
+		return ret;
+
+	ucfg_twt_cfg_get_congestion_timeout(psoc, &congestion_timeout);
+
+	if (congestion_timeout) {
+		ret = osif_twt_send_requestor_disable_cmd(psoc, pdev_id);
+		if (ret) {
+			osif_err("Failed to disable TWT");
+			return ret;
+		}
+	}
+
+	ucfg_twt_cfg_set_congestion_timeout(psoc, 0);
+
+	ret = osif_twt_send_requestor_enable_cmd(psoc, pdev_id);
+	if (ret) {
+		osif_err("Failed to Enable TWT");
+		return ret;
+	}
+
+	return osif_send_twt_setup_req(vdev, psoc, &params);
+}
+
+/**
+ * osif_twt_handle_renego_failure() - Upon re-nego failure send TWT teardown
+ *
+ * @adapter: Adapter pointer
+ * @event: Pointer to Add dialog complete event structure
+ *
+ * Upon re-negotiation failure, this function constructs TWT teardown
+ * message to the target.
+ *
+ * Return: None
+ */
+void
+osif_twt_handle_renego_failure(struct wlan_objmgr_psoc *psoc,
+		       struct twt_add_dialog_complete_event *event)
+{
+	struct twt_del_dialog_param params = {0};
+	uint8_t pdev_id;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t vdev_id;
+
+	if (!event)
+		return;
+
+	vdev_id = event->params.vdev_id;
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id,
+						WLAN_TWT_ID);
+	if (pdev_id == WLAN_INVALID_PDEV_ID) {
+		osif_err("Invalid pdev id");
+		return;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID);
+	if (!pdev) {
+		osif_err("Invalid pdev");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
+						    WLAN_TWT_ID);
+	if (!vdev) {
+		osif_err("vdev object is NULL");
+		goto end;
+	}
+
+	qdf_copy_macaddr(&params.peer_macaddr, &event->params.peer_macaddr);
+	params.vdev_id = vdev_id;
+	params.dialog_id = event->params.dialog_id;
+
+	osif_debug("renego: twt_terminate: vdev_id:%d dialog_id:%d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
+		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
+
+	osif_send_sta_twt_teardown_req(vdev, psoc, &params);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+
+end:
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID);
 }
 
 int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev,

+ 404 - 0
os_if/twt/src/osif_twt_ext_rsp.c

@@ -26,11 +26,387 @@
 #include <wlan_osif_priv.h>
 #include <wlan_osif_request_manager.h>
 
+/**
+ * osif_twt_get_setup_event_len() - Calculates the length of twt
+ * setup nl response
+ * @additional_params_present: if true, then length required for
+ * fixed and additional parameters is returned. if false,
+ * then length required for fixed parameters is returned.
+ *
+ * Return: Length of twt setup nl response
+ */
+static
+uint32_t osif_twt_get_setup_event_len(bool additional_params_present)
+{
+	uint32_t len = 0;
+
+	len += NLMSG_HDRLEN;
+
+	/* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */
+	len += NLA_HDRLEN;
+
+	/* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */
+	len += nla_total_size(sizeof(u8));
+
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
+	len += nla_total_size(sizeof(u8));
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
+	len += nla_total_size(sizeof(u8));
+
+	if (!additional_params_present)
+		return len;
+
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE */
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE*/
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION*/
+	len += nla_total_size(sizeof(u32));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA*/
+	len += nla_total_size(sizeof(u32));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF*/
+	len += nla_total_size(sizeof(u64));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME*/
+	len += nla_total_size(sizeof(u32));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER*/
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION*/
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST*/
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED*/
+	len += nla_total_size(sizeof(u8));
+	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
+	len += nla_total_size(QDF_MAC_ADDR_SIZE);
+
+	return len;
+}
+
+/**
+ * twt_add_status_to_vendor_twt_status() - convert from
+ * HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status
+ * @status: HOST_ADD_TWT_STATUS value from firmare
+ *
+ * Return: qca_wlan_vendor_twt_status values corresponding
+ * to HOST_ADD_TWT_STATUS.
+ */
+static enum qca_wlan_vendor_twt_status
+twt_add_status_to_vendor_twt_status(enum HOST_ADD_TWT_STATUS status)
+{
+	switch (status) {
+	case HOST_ADD_TWT_STATUS_OK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
+	case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
+		return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED;
+	case HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
+		return QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID;
+	case HOST_ADD_TWT_STATUS_INVALID_PARAM:
+		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
+	case HOST_ADD_TWT_STATUS_NOT_READY:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY;
+	case HOST_ADD_TWT_STATUS_NO_RESOURCE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
+	case HOST_ADD_TWT_STATUS_NO_ACK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
+	case HOST_ADD_TWT_STATUS_NO_RESPONSE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE;
+	case HOST_ADD_TWT_STATUS_DENIED:
+		return QCA_WLAN_VENDOR_TWT_STATUS_DENIED;
+	case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	case HOST_ADD_TWT_STATUS_AP_PARAMS_NOT_IN_RANGE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE;
+	case HOST_ADD_TWT_STATUS_AP_IE_VALIDATION_FAILED:
+		return QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID;
+	case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
+		return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
+	case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
+		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
+	case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
+	default:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	}
+}
+
+/**
+ * twt_add_cmd_to_vendor_twt_resp_type() - convert from
+ * HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type
+ * @status: HOST_TWT_COMMAND value from firmare
+ *
+ * Return: qca_wlan_vendor_twt_setup_resp_type values for valid
+ * HOST_TWT_COMMAND value and -EINVAL for invalid value
+ */
+static
+int twt_add_cmd_to_vendor_twt_resp_type(enum HOST_TWT_COMMAND type)
+{
+	switch (type) {
+	case HOST_TWT_COMMAND_ACCEPT_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_ACCEPT;
+	case HOST_TWT_COMMAND_ALTERNATE_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE;
+	case HOST_TWT_COMMAND_DICTATE_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_DICTATE;
+	case HOST_TWT_COMMAND_REJECT_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_REJECT;
+	default:
+		return -EINVAL;
+	}
+}
+
+/**
+ * osif_twt_setup_pack_resp_nlmsg() - pack nlmsg response for setup
+ * @reply_skb: pointer to the response skb structure
+ * @event: twt event buffer with firmware response
+ *
+ * Pack the nl response with parameters and additional parameters
+ * received from firmware.
+ * Firmware sends additional parameters only for 2 conditions
+ * 1) TWT Negotiation is accepted by AP - Firmware sends
+ * QCA_WLAN_VENDOR_TWT_STATUS_OK with appropriate response type
+ * in additional parameters
+ * 2) AP has proposed Alternate values - In this case firmware sends
+ * QCA_WLAN_VENDOR_TWT_STATUS_DENIED with appropriate response type
+ * in additional parameters
+ *
+ * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
+ * on failure
+ */
+static QDF_STATUS
+osif_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb,
+			       struct twt_add_dialog_complete_event *event)
+{
+	struct nlattr *config_attr;
+	uint64_t sp_offset_tsf;
+	enum qca_wlan_vendor_twt_status vendor_status;
+	int response_type, attr;
+	uint32_t wake_duration;
+	uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu;
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
+		       QCA_WLAN_TWT_SET)) {
+		osif_err("Failed to put TWT operation");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	config_attr = nla_nest_start(reply_skb,
+				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
+	if (!config_attr) {
+		osif_err("nla_nest_start error");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	sp_offset_tsf = event->additional_params.sp_tsf_us_hi;
+	sp_offset_tsf = (sp_offset_tsf << 32) |
+			 event->additional_params.sp_tsf_us_lo;
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+	if (nla_put_u8(reply_skb, attr, event->params.dialog_id)) {
+		osif_err("Failed to put dialog_id");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
+	vendor_status = twt_add_status_to_vendor_twt_status(
+							event->params.status);
+	if (nla_put_u8(reply_skb, attr, vendor_status)) {
+		osif_err("Failed to put setup status");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (event->params.num_additional_twt_params == 0) {
+		nla_nest_end(reply_skb, config_attr);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	response_type = twt_add_cmd_to_vendor_twt_resp_type(
+					event->additional_params.twt_cmd);
+	if (response_type == -EINVAL) {
+		osif_err("Invalid response type from firmware");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE;
+	if (nla_put_u8(reply_skb, attr, response_type)) {
+		osif_err("Failed to put setup response type");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
+	if (nla_put_u8(reply_skb, attr, event->additional_params.announce)) {
+		osif_err("Failed to put setup flow type");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	osif_debug("wake_dur_us %d", event->additional_params.wake_dur_us);
+	wake_duration = (event->additional_params.wake_dur_us /
+			 TWT_WAKE_DURATION_MULTIPLICATION_FACTOR);
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
+	if (nla_put_u32(reply_skb, attr, wake_duration)) {
+		osif_err("Failed to put wake duration");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	wake_intvl_mantis_us = event->additional_params.wake_intvl_us;
+	if (nla_put_u32(reply_skb,
+			QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA,
+			wake_intvl_mantis_us)) {
+		osif_err("Failed to put wake interval mantissa in us");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	wake_intvl_mantis_tu = (event->additional_params.wake_intvl_us /
+				 TWT_WAKE_INTVL_MULTIPLICATION_FACTOR);
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
+	if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) {
+		osif_err("Failed to put wake interval mantissa in tu");
+		return QDF_STATUS_E_FAILURE;
+	}
+	osif_debug("Send mantissa_us:%d, mantissa_tu:%d to userspace",
+		  wake_intvl_mantis_us, wake_intvl_mantis_tu);
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
+	if (nla_put_u8(reply_skb, attr, 0)) {
+		osif_err("Failed to put wake interval exp");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
+	if (wlan_cfg80211_nla_put_u64(reply_skb, attr, sp_offset_tsf)) {
+		osif_err("Failed to put sp_offset_tsf");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
+	if (nla_put_u32(reply_skb, attr,
+			event->additional_params.sp_offset_us)) {
+		osif_err("Failed to put sp_offset_us");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (event->additional_params.trig_en) {
+		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
+		if (nla_put_flag(reply_skb, attr)) {
+			osif_err("Failed to put trig type");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	if (event->additional_params.protection) {
+		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
+		if (nla_put_flag(reply_skb, attr)) {
+			osif_err("Failed to put protection flag");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	if (event->additional_params.bcast) {
+		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
+		if (nla_put_flag(reply_skb, attr)) {
+			osif_err("Failed to put bcast flag");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	if (!event->additional_params.info_frame_disabled) {
+		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED;
+		if (nla_put_flag(reply_skb, attr)) {
+			osif_err("Failed to put twt info enable flag");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
+	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
+		    event->params.peer_macaddr.bytes)) {
+		osif_err("Failed to put mac_addr");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	nla_nest_end(reply_skb, config_attr);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void
+osif_twt_setup_response(struct wlan_objmgr_psoc *psoc,
+			struct twt_add_dialog_complete_event *event)
+{
+	struct sk_buff *twt_vendor_event;
+	struct wireless_dev *wdev;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	size_t data_len;
+	QDF_STATUS status;
+	bool additional_params_present = false;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						event->params.vdev_id,
+						WLAN_TWT_ID);
+	if (!vdev) {
+		osif_err("vdev is null");
+		return;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		osif_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		osif_err("wireless dev is null");
+		goto fail;
+	}
+
+	if (event->params.num_additional_twt_params != 0)
+		additional_params_present = true;
+
+	data_len = osif_twt_get_setup_event_len(additional_params_present);
+	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
+				wdev->wiphy, wdev, data_len,
+				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
+				GFP_KERNEL);
+	if (!twt_vendor_event) {
+		osif_err("TWT: Alloc setup resp skb fail");
+		goto fail;
+	}
+
+	status = osif_twt_setup_pack_resp_nlmsg(twt_vendor_event, event);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		osif_err("Failed to pack nl add dialog response");
+		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
+		goto fail;
+	}
+
+	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
+
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+}
+
 QDF_STATUS
 osif_twt_setup_complete_cb(struct wlan_objmgr_psoc *psoc,
 			   struct twt_add_dialog_complete_event *event,
 			   bool renego_fail)
 {
+	uint32_t vdev_id = event->params.vdev_id;
+
+	osif_debug("TWT: add dialog_id:%d, status:%d vdev_id:%d renego_fail:%d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, event->params.dialog_id,
+		  event->params.status, vdev_id, renego_fail,
+		  QDF_MAC_ADDR_REF(event->params.peer_macaddr.bytes));
+
+	osif_twt_setup_response(psoc, event);
+
+	if (renego_fail)
+		osif_twt_handle_renego_failure(psoc, event);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -74,6 +450,34 @@ osif_twt_ack_complete_cb(struct wlan_objmgr_psoc *psoc,
 			 struct twt_ack_complete_event_param *params,
 			 void *context)
 {
+	struct osif_request *request = NULL;
+	struct twt_ack_context *status_priv;
+
+	request = osif_request_get(context);
+	if (!request) {
+		osif_err("obsolete request");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status_priv = osif_request_priv(request);
+	if (!status_priv) {
+		osif_err("obsolete status_priv");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (status_priv->twt_cmd_ack == params->twt_cmd_ack) {
+		status_priv->vdev_id = params->vdev_id;
+		qdf_copy_macaddr(&status_priv->peer_macaddr,
+				 &params->peer_macaddr);
+		status_priv->dialog_id = params->dialog_id;
+		status_priv->status = params->status;
+		osif_request_complete(request);
+	} else {
+		osif_err("Invalid TWT ack. Expected cmd: %d Actual cmd: %d",
+				status_priv->twt_cmd_ack, params->twt_cmd_ack);
+	}
+
+	osif_request_put(request);
 	return QDF_STATUS_SUCCESS;
 }