Sfoglia il codice sorgente

qcacld-3.0: Add support for TWT Setup vendor command

Add TWT vendor subcommand and TWT operations for
Host triggered TWT. Also add support for TWT Setup command
request and response.

CRs-Fixed: 2735650
Change-Id: I4f52c9fb240714077347ffc5177692de01a6a126
Rajasekaran Kalidoss 4 anni fa
parent
commit
1ca17fe1cf

+ 45 - 3
core/hdd/inc/wlan_hdd_twt.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -28,12 +28,22 @@
 
 #include "qdf_types.h"
 #include "qdf_status.h"
+#include "qca_vendor.h"
+#include <net/cfg80211.h>
 
 struct hdd_context;
+struct hdd_adapter;
 struct wma_tgt_cfg;
-struct wmi_twt_enable_complete_event_param;
+struct wmi_twt_add_dialog_param;
+extern const struct nla_policy qca_wlan_vendor_twt_add_dialog_policy[
+		QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
+
+extern const struct nla_policy
+wlan_hdd_wifi_twt_config_policy[
+	QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1];
 
 #ifdef WLAN_SUPPORT_TWT
+
 /**
  * enum twt_status - TWT target state
  * @TWT_INIT: Init State
@@ -64,6 +74,23 @@ enum twt_status {
 	TWT_CLOSED,
 };
 
+/**
+ * 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_NL80211_VENDOR_SUBCMD_CONFIG_TWT
+ *
+ * Return: 0 for success, negative errno for failure.
+ */
+int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
+				      struct wireless_dev *wdev,
+				      const void *data,
+				      int data_len);
+
 /**
  * hdd_update_tgt_twt_cap() - Update TWT target capabilities
  * @hdd_ctx: HDD Context
@@ -82,7 +109,6 @@ void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
  */
 void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx);
 
-#define TWT_DISABLE_COMPLETE_TIMEOUT 1000
 /**
  * hdd_send_twt_disable_cmd() - Send TWT disable command to target
  * @hdd_ctx: HDD Context
@@ -113,6 +139,19 @@ void wlan_hdd_twt_init(struct hdd_context *hdd_ctx);
  */
 void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx);
 
+#define FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT                            \
+{                                                                        \
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,                         \
+	.info.subcmd =                                                   \
+		QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT,                    \
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |                            \
+		WIPHY_VENDOR_CMD_NEED_NETDEV |                           \
+		WIPHY_VENDOR_CMD_NEED_RUNNING,                           \
+	.doit = wlan_hdd_cfg80211_wifi_twt_config,                       \
+	vendor_command_policy(wlan_hdd_wifi_twt_config_policy,           \
+			      QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX)       \
+},
+
 #else
 static inline void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
 					  struct wma_tgt_cfg *cfg)
@@ -136,5 +175,8 @@ static inline void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)
 {
 }
 
+#define FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT
+
 #endif
+
 #endif /* if !defined(WLAN_HDD_TWT_H)*/

+ 139 - 119
core/hdd/src/wlan_hdd_cfg80211.c

@@ -157,6 +157,10 @@
 #include "wlan_cm_roam_ucfg_api.h"
 #include "hif.h"
 #include "wlan_reg_ucfg_api.h"
+#include "wlan_hdd_twt.h"
+
+#define TWT_FLOW_TYPE_ANNOUNCED 0
+#define TWT_FLOW_TYPE_UNANNOUNCED 1
 
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
@@ -760,6 +764,21 @@ static struct ieee80211_iface_combination
 
 static struct cfg80211_ops wlan_hdd_cfg80211_ops;
 
+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 },
+};
+
 #ifdef WLAN_NL80211_TESTMODE
 enum wlan_hdd_tm_attr {
 	WLAN_HDD_TM_ATTR_INVALID = 0,
@@ -6827,20 +6846,6 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
 
 };
 
-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_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 },
-};
-
 static const struct nla_policy
 qca_wlan_vendor_attr_he_omi_tx_policy [QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS] =       {.type = NLA_U8 },
@@ -9288,6 +9293,121 @@ static void hdd_disable_runtime_pm_for_user(struct hdd_context *hdd_ctx)
 	qdf_runtime_pm_prevent_suspend(&ctx->user);
 }
 
+int hdd_twt_get_add_dialog_values(struct nlattr **tb,
+				  struct wmi_twt_add_dialog_param *params)
+{
+	uint32_t wake_intvl_exp, result;
+	int cmd_id;
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+	if (tb[cmd_id]) {
+		params->dialog_id = nla_get_u8(tb[cmd_id]);
+	} else {
+		params->dialog_id = 0;
+		hdd_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]) {
+		hdd_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) {
+		hdd_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_REQ_TYPE;
+	if (!tb[cmd_id]) {
+		hdd_err_rl("TWT_SETUP_REQ_TYPE is must");
+		return -EINVAL;
+	}
+	params->twt_cmd = nla_get_u8(tb[cmd_id]);
+
+	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]) {
+		hdd_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]) {
+		hdd_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) {
+		hdd_err_rl("Invalid wake_dura_us %u",
+			   params->wake_dura_us);
+		return -EINVAL;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
+	if (!tb[cmd_id]) {
+		hdd_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
+		return -EINVAL;
+	}
+	params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
+	if (params->wake_intvl_mantis >
+	    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
+		hdd_err_rl("Invalid wake_intvl_mantis %u",
+			   params->wake_dura_us);
+		return -EINVAL;
+	}
+
+	if (wake_intvl_exp && params->wake_intvl_mantis) {
+		result = 2 << (wake_intvl_exp - 1);
+		if (result >
+		    (UINT_MAX / params->wake_intvl_mantis)) {
+			hdd_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;
+	}
+
+	hdd_debug("twt: dialod_id %d, vdev %d, wake intvl_us %d, mantis %d",
+		  params->dialog_id, params->vdev_id, params->wake_intvl_us,
+		  params->wake_intvl_mantis);
+	hdd_debug("twt: wake dura %d, sp_offset %d, cmd %d",
+		  params->wake_dura_us, params->sp_offset_us,
+		  params->twt_cmd);
+	hdd_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d",
+		  params->flag_bcast, params->flag_trigger,
+		  params->flag_flow_type,
+		  params->flag_protection);
+	hdd_debug("twt: peer mac_addr "
+		  QDF_MAC_ADDR_STR,
+		  QDF_MAC_ADDR_ARRAY(params->peer_macaddr));
+
+	return 0;
+}
+
 /**
  * __wlan_hdd_cfg80211_set_wifi_test_config() - Wifi test configuration
  * vendor command
@@ -9769,12 +9889,10 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		struct wmi_twt_add_dialog_param params = {0};
 		struct hdd_station_ctx *hdd_sta_ctx =
 			WLAN_HDD_GET_STATION_CTX_PTR(adapter);
-		uint32_t wake_intvl_exp = 0, result = 0;
 		struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
 		struct nlattr *twt_session;
 		int tmp, rc;
 		uint32_t congestion_timeout = 0;
-		uint8_t twt_cmd;
 
 		if ((adapter->device_mode != QDF_STA_MODE &&
 		     adapter->device_mode != QDF_P2P_CLIENT_MODE) ||
@@ -9804,110 +9922,9 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 				goto send_err;
 			}
 
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
-			if (!tb2[cmd_id]) {
-				hdd_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must");
-				goto send_err;
-			}
-			wake_intvl_exp = nla_get_u8(tb2[cmd_id]);
-			if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) {
-				hdd_err_rl("Invalid wake_intvl_exp %u > %u",
-					   wake_intvl_exp,
-					   TWT_SETUP_WAKE_INTVL_EXP_MAX);
-				goto send_err;
-			}
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
-			if (tb2[cmd_id])
-				params.flag_bcast = nla_get_flag(tb2[cmd_id]);
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE;
-			if (!tb2[cmd_id]) {
-				hdd_err_rl("TWT_SETUP_REQ_TYPE is must");
-				goto send_err;
-			}
-			twt_cmd = nla_get_u8(tb2[cmd_id]);
-			if (twt_cmd == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST)
-				params.twt_cmd =
-					WMI_HOST_TWT_COMMAND_REQUEST_TWT;
-			else if (twt_cmd == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST)
-				params.twt_cmd =
-					WMI_HOST_TWT_COMMAND_SUGGEST_TWT;
-			else if (twt_cmd == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND)
-				params.twt_cmd =
-					WMI_HOST_TWT_COMMAND_DEMAND_TWT;
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
-			if (tb2[cmd_id])
-				params.flag_trigger = nla_get_flag(tb2[cmd_id]);
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
-			if (!tb2[cmd_id]) {
-				hdd_err_rl("TWT_SETUP_FLOW_TYPE is must");
-				goto send_err;
-			}
-			params.flag_flow_type = nla_get_u8(tb2[cmd_id]);
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
-			if (tb2[cmd_id])
-				params.flag_protection =
-					nla_get_flag(tb2[cmd_id]);
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
-			if (tb2[cmd_id])
-				params.sp_offset_us = nla_get_u32(tb2[cmd_id]);
-
-			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
-			if (!tb2[cmd_id]) {
-				hdd_err_rl("TWT_SETUP_WAKE_DURATION is must");
-				goto send_err;
-			}
-			params.wake_dura_us = 256 * nla_get_u32(tb2[cmd_id]);
-			if (params.wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) {
-				hdd_err_rl("Invalid wake_dura_us %u",
-					   params.wake_dura_us);
-				goto send_err;
-			}
-
-			cmd_id =
-			QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
-			if (!tb2[cmd_id]) {
-				hdd_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
-				goto send_err;
-			}
-			params.wake_intvl_mantis = nla_get_u32(tb2[cmd_id]);
-			if (params.wake_intvl_mantis >
-			    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
-				hdd_err_rl("Invalid wake_intvl_mantis %u",
-					   params.wake_dura_us);
+			ret_val = hdd_twt_get_add_dialog_values(tb2, &params);
+			if (ret_val)
 				goto send_err;
-			}
-
-			if (wake_intvl_exp && params.wake_intvl_mantis) {
-				result = 2 << (wake_intvl_exp - 1);
-				if (result >
-				    (UINT_MAX / params.wake_intvl_mantis)) {
-					hdd_err_rl("Invalid exp %d mantissa %d",
-						   wake_intvl_exp,
-						   params.wake_intvl_mantis);
-					goto send_err;
-				}
-				params.wake_intvl_us =
-					params.wake_intvl_mantis * result;
-			} else {
-				params.wake_intvl_us = params.wake_intvl_mantis;
-			}
-
-			hdd_debug("twt: vdev %d, intvl_us %d, mantis %d",
-				  params.vdev_id, params.wake_intvl_us,
-				  params.wake_intvl_mantis);
-			hdd_debug("twt: dura %d, offset %d, cmd %d",
-				  params.wake_dura_us, params.sp_offset_us,
-				  params.twt_cmd);
-			hdd_debug("twt: bcast %d, trigger %d, type %d, prot %d",
-				  params.flag_bcast, params.flag_trigger,
-				  params.flag_flow_type,
-				  params.flag_protection);
 
 			ucfg_mlme_get_twt_congestion_timeout(hdd_ctx->psoc,
 							&congestion_timeout);
@@ -15103,6 +15120,9 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	},
 
 	FEATURE_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
+#ifdef WLAN_SUPPORT_TWT
+	FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT
+#endif
 
 	{
 		.info.vendor_id = QCA_NL80211_VENDOR_ID,

+ 16 - 3
core/hdd/src/wlan_hdd_cfg80211.h

@@ -209,9 +209,10 @@ extern const struct nla_policy wlan_hdd_wisa_cmd_policy[
 #define USE_CFG80211_DEL_STA_V2
 #endif
 
-#define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX 0xFFFF
-#define TWT_SETUP_WAKE_DURATION_MAX       0xFFFF
-#define TWT_SETUP_WAKE_INTVL_EXP_MAX      31
+#define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX       0xFFFF
+#define TWT_SETUP_WAKE_DURATION_MAX             0xFFFF
+#define TWT_SETUP_WAKE_INTVL_EXP_MAX            31
+#define TWT_WAKE_DURATION_MULTIPLICATION_FACTOR 256
 
 /**
  * enum eDFS_CAC_STATUS: CAC status
@@ -860,4 +861,16 @@ static inline void hdd_send_update_owe_info_event(struct hdd_adapter *adapter,
  */
 bool hdd_is_legacy_connection(struct hdd_adapter *adapter);
 
+/**
+ * hdd_twt_get_add_dialog_values() - 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.
+ */
+int hdd_twt_get_add_dialog_values(struct nlattr **tb2,
+			       struct wmi_twt_add_dialog_param *params);
 #endif

+ 565 - 9
core/hdd/src/wlan_hdd_twt.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -23,11 +23,570 @@
  *
  */
 
+#include "wmi.h"
+#include "wmi_unified_priv.h"
+#include "wmi_unified_twt_param.h"
 #include "wlan_hdd_twt.h"
 #include "wlan_hdd_main.h"
 #include "wlan_hdd_cfg.h"
 #include "sme_api.h"
 #include "wma_twt.h"
+#include "osif_sync.h"
+#include "wlan_osif_request_manager.h"
+
+#define TWT_SETUP_COMPLETE_TIMEOUT 1000
+#define TWT_DISABLE_COMPLETE_TIMEOUT 1000
+
+/**
+ * struct twt_add_dialog_complete_event - TWT add dialog complete event
+ * @params: Fixed parameters for TWT add dialog complete event
+ * @additional_params: additional parameters for TWT add dialog complete event
+ *
+ * Holds the fixed and additional parameters from add dialog
+ * complete event
+ */
+struct twt_add_dialog_complete_event {
+	struct wmi_twt_add_dialog_complete_event_param params;
+	struct wmi_twt_add_dialog_additional_params additional_params;
+};
+
+/**
+ * struct twt_add_dialog_comp_ev_priv - private struct for twt add dialog
+ * @add_dialog_comp_ev_buf: buffer from TWT add dialog complete_event
+ *
+ * This TWT add dialog private structure is registered with os_if to
+ * retrieve the TWT add dialog response event buffer.
+ */
+struct twt_add_dialog_comp_ev_priv {
+	struct twt_add_dialog_complete_event add_dialog_comp_ev_buf;
+};
+
+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 uint32_t hdd_get_twt_setup_event_len(void)
+{
+	uint32_t len = 0;
+
+	len += NLMSG_HDRLEN;
+	/* 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));
+	/* 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));
+
+	return len;
+}
+
+/**
+ * wmi_twt_add_cmd_to_vendor_twt_resp_type() - convert from
+ * WMI_HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type
+ * @status: WMI_HOST_TWT_COMMAND value from firmare
+ *
+ * Return: qca_wlan_vendor_twt_setup_resp_type values for valid
+ * WMI_HOST_TWT_COMMAND value and -EINVAL for invalid value
+ */
+static
+int wmi_twt_add_cmd_to_vendor_twt_resp_type(enum WMI_HOST_TWT_COMMAND type)
+{
+	switch (type) {
+	case WMI_HOST_TWT_COMMAND_ACCEPT_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_ACCEPT;
+	case WMI_HOST_TWT_COMMAND_ALTERNATE_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE;
+	case WMI_HOST_TWT_COMMAND_DICTATE_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_DICTATE;
+	case WMI_HOST_TWT_COMMAND_REJECT_TWT:
+		return QCA_WLAN_VENDOR_TWT_RESP_REJECT;
+	default:
+		return -EINVAL;
+	}
+}
+
+/**
+ * wmi_twt_add_status_to_vendor_twt_status() - convert from
+ * WMI_HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status
+ * @status: WMI_HOST_ADD_TWT_STATUS value from firmare
+ *
+ * Return: qca_wlan_vendor_twt_status values for valid
+ * WMI_HOST_ADD_TWT_STATUS and -EINVAL for invalid value
+ */
+static
+int wmi_twt_add_status_to_vendor_twt_status(enum WMI_HOST_ADD_TWT_STATUS status)
+{
+	switch (status) {
+	case WMI_HOST_ADD_TWT_STATUS_OK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
+	case WMI_HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
+		return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED;
+	case WMI_HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
+		return QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID;
+	case WMI_HOST_ADD_TWT_STATUS_INVALID_PARAM:
+		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
+	case WMI_HOST_ADD_TWT_STATUS_NOT_READY:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY;
+	case WMI_HOST_ADD_TWT_STATUS_NO_RESOURCE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
+	case WMI_HOST_ADD_TWT_STATUS_NO_ACK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
+	case WMI_HOST_ADD_TWT_STATUS_NO_RESPONSE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE;
+	case WMI_HOST_ADD_TWT_STATUS_DENIED:
+		return QCA_WLAN_VENDOR_TWT_STATUS_DENIED;
+	case WMI_HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	default:
+		return -EINVAL;
+	}
+}
+
+static
+QDF_STATUS hdd_twt_setup_pack_resp_nlmsg(
+	 struct sk_buff *reply_skb,
+	 struct twt_add_dialog_complete_event *event)
+{
+	uint64_t sp_offset_tsf;
+	int vendor_status;
+	int response_type;
+
+	hdd_enter();
+
+	sp_offset_tsf = event->additional_params.sp_tsf_us_hi;
+	sp_offset_tsf = (sp_offset_tsf << 32) |
+			 event->additional_params.sp_tsf_us_lo;
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID,
+		       event->params.dialog_id)) {
+		hdd_debug("TWT: Failed to put dialog_id");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	vendor_status = wmi_twt_add_status_to_vendor_twt_status(event->params.status);
+	if (vendor_status == -EINVAL)
+		return QDF_STATUS_E_FAILURE;
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS,
+		       vendor_status)) {
+		hdd_err("TWT: Failed to put QCA_WLAN_TWT_SET");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	response_type = wmi_twt_add_cmd_to_vendor_twt_resp_type(event->additional_params.twt_cmd);
+	if (response_type == -EINVAL)
+		return QDF_STATUS_E_FAILURE;
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE,
+		       response_type)) {
+		hdd_err("TWT: Failed to put QCA_WLAN_TWT_SET");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE,
+		       event->additional_params.announce)) {
+		hdd_err("TWT: Failed to put QCA_WLAN_TWT_SET");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION,
+			event->additional_params.wake_dur_us)) {
+		hdd_err("TWT: Failed to put wake duration");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (nla_put_u32(reply_skb,
+			QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA,
+			event->additional_params.wake_intvl_us)) {
+		hdd_err("TWT: Failed to put wake interval us");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP,
+		       0)) {
+		hdd_err("TWT: Failed to put wake interval exp");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (wlan_cfg80211_nla_put_u64(reply_skb,
+				      QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF,
+				      sp_offset_tsf)) {
+		hdd_err("TWT: Failed to put sp_offset_tsf");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME,
+			event->additional_params.sp_offset_us)) {
+		hdd_err("TWT: Failed to put sp_offset_us");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (event->additional_params.trig_en) {
+		if (nla_put_flag(reply_skb,
+				 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER)) {
+			hdd_err("TWT: Failed to put trig type");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	if (event->additional_params.protection) {
+		if (nla_put_flag(reply_skb,
+				 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION)) {
+			hdd_err("TWT: Failed to put protection flag");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	if (event->additional_params.bcast) {
+		if (nla_put_flag(reply_skb,
+				 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST)) {
+			hdd_err("TWT: Failed to put bcast flag");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	if (!event->additional_params.info_frame_disabled) {
+		if (nla_put_flag(reply_skb,
+				 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED)) {
+			hdd_err("TWT: Failed to put twt info enable flag");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	hdd_exit();
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void
+hdd_twt_add_dialog_comp_cb(void *context,
+			   struct wmi_twt_add_dialog_complete_event_param *params,
+			   struct wmi_twt_add_dialog_additional_params *additional_params)
+{
+	struct osif_request *request;
+	struct twt_add_dialog_comp_ev_priv *priv;
+
+	hdd_enter();
+
+	request = osif_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete request");
+		return;
+	}
+
+	priv = osif_request_priv(request);
+
+	qdf_mem_copy(&priv->add_dialog_comp_ev_buf.params, params,
+		     sizeof(*params));
+	qdf_mem_copy(&priv->add_dialog_comp_ev_buf.additional_params,
+		     additional_params,
+		     sizeof(*additional_params));
+	osif_request_complete(request);
+	osif_request_put(request);
+
+	hdd_debug("TWT: add dialog_id:%d, status:%d vdev_id %d peer mac_addr"
+		  QDF_MAC_ADDR_STR, params->dialog_id,
+		  params->status, params->vdev_id,
+		  QDF_MAC_ADDR_ARRAY(params->peer_macaddr));
+
+	hdd_exit();
+}
+
+/**
+ * hdd_send_twt_add_dialog_cmd() - Send TWT add dialog command to target
+ * @hdd_ctx: HDD Context
+ * @twt_params: Pointer to Add dialog cmd params structure
+ *
+ * Return: QDF_STATUS
+ */
+static
+int hdd_send_twt_add_dialog_cmd(struct hdd_context *hdd_ctx,
+				struct wmi_twt_add_dialog_param *twt_params)
+{
+	struct twt_add_dialog_complete_event *add_dialog_comp_ev_params;
+	struct twt_add_dialog_comp_ev_priv *priv;
+	static const struct osif_request_params osif_req_params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = TWT_SETUP_COMPLETE_TIMEOUT,
+		.dealloc = NULL,
+	};
+	struct osif_request *request;
+	struct sk_buff *reply_skb = NULL;
+	void *cookie;
+	QDF_STATUS status;
+	int skb_len;
+	int ret;
+
+	request = osif_request_alloc(&osif_req_params);
+	if (!request) {
+		hdd_err("twt osif request allocation failure");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	cookie = osif_request_cookie(request);
+	status = sme_add_dialog_cmd(hdd_ctx->mac_handle,
+				    hdd_twt_add_dialog_comp_cb,
+				    twt_params,
+				    cookie);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to send add dialog command");
+		ret = qdf_status_to_os_return(status);
+		goto err;
+	}
+
+	ret = osif_request_wait_for_response(request);
+	if (ret) {
+		hdd_err("twt: add dialog req timedout");
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	priv = osif_request_priv(request);
+	add_dialog_comp_ev_params = &priv->add_dialog_comp_ev_buf;
+
+	skb_len = hdd_get_twt_setup_event_len();
+
+	reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
+							skb_len);
+	if (!reply_skb) {
+		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	status = hdd_twt_setup_pack_resp_nlmsg(reply_skb,
+					       add_dialog_comp_ev_params);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("Failed to pack nl add dialog response");
+		ret = qdf_status_to_os_return(status);
+		goto err;
+	}
+	ret = cfg80211_vendor_cmd_reply(reply_skb);
+
+err:
+	if (request)
+		osif_request_put(request);
+
+	if (ret && reply_skb)
+		kfree_skb(reply_skb);
+	return ret;
+}
+
+/**
+ * hdd_twt_setup_session() - Process TWT setup operation in the
+ * received vendor command and send it to firmare
+ * @adapter: adapter pointer
+ * @twt_param_attr: nl attributes
+ *
+ * Handles QCA_WLAN_TWT_SET
+ *
+ * Return: 0 for Success and negative value for failure
+ */
+static int hdd_twt_setup_session(struct hdd_adapter *adapter,
+				 struct nlattr *twt_param_attr)
+{
+	struct hdd_station_ctx *hdd_sta_ctx = NULL;
+	struct wmi_twt_add_dialog_param params = {0};
+	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
+	uint32_t congestion_timeout = 0;
+	int ret = 0;
+
+	if (adapter->device_mode != QDF_STA_MODE &&
+	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
+		return -EOPNOTSUPP;
+	}
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (hdd_sta_ctx->conn_info.conn_state != eConnectionState_Associated) {
+		hdd_err_rl("Invalid state, vdev %d mode %d state %d",
+			   adapter->vdev_id, adapter->device_mode,
+			   hdd_sta_ctx->conn_info.conn_state);
+		return -EINVAL;
+	}
+
+	qdf_mem_copy(params.peer_macaddr,
+		     hdd_sta_ctx->conn_info.bssid.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	params.vdev_id = adapter->vdev_id;
+
+	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 = hdd_twt_get_add_dialog_values(tb2, &params);
+	if (ret)
+		return ret;
+
+	ucfg_mlme_get_twt_congestion_timeout(adapter->hdd_ctx->psoc,
+					     &congestion_timeout);
+
+	if (congestion_timeout) {
+		ret = qdf_status_to_os_return(
+			hdd_send_twt_disable_cmd(adapter->hdd_ctx));
+		if (ret) {
+			hdd_err("Failed to disable TWT");
+			return ret;
+		}
+		ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0);
+		hdd_send_twt_enable_cmd(adapter->hdd_ctx);
+	}
+	ret = hdd_send_twt_add_dialog_cmd(adapter->hdd_ctx, &params);
+	return ret;
+}
+
+/**
+ * hdd_twt_configure - Process the TWT
+ * operation in the recevied vendor command
+ * @adapter: adapter pointer
+ * @tb: nl attributes
+ *
+ * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION
+ *
+ * Return: 0 for Success and negative value for failure
+ */
+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;
+
+	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION;
+	twt_oper_attr = tb[id];
+
+	if (!twt_oper_attr) {
+		hdd_err("TWT parameters NOT specified");
+		return -EINVAL;
+	}
+
+	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS;
+	twt_param_attr = tb[id];
+
+	if (!twt_param_attr) {
+		hdd_err("TWT parameters NOT specified");
+		return -EINVAL;
+	}
+
+	twt_oper = nla_get_u8(twt_oper_attr);
+	hdd_debug("twt: TWT Operation 0x%x", twt_oper);
+
+	switch (twt_oper) {
+	case QCA_WLAN_TWT_SET:
+		ret = hdd_twt_setup_session(adapter, 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;
+	default:
+		hdd_err("Invalid TWT Operation");
+		ret = -EINVAL;
+		break;
+	}
+
+	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)
@@ -170,23 +729,20 @@ void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
 	status = sme_register_twt_disable_complete_cb(hdd_ctx->mac_handle,
 						      hdd_twt_disable_comp_cb);
 	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_deregister_twt_enable_complete_cb(hdd_ctx->mac_handle);
 		hdd_err("Register twt disable complete failed");
-		goto twt_init_fail;
+		return;
 	}
 
 	status = qdf_event_create(&hdd_ctx->twt_disable_comp_evt);
 	if (!QDF_IS_STATUS_SUCCESS(status)) {
-		hdd_err("twt_disable_comp_evt init failed");
 		sme_deregister_twt_disable_complete_cb(hdd_ctx->mac_handle);
-		goto twt_init_fail;
+		sme_deregister_twt_enable_complete_cb(hdd_ctx->mac_handle);
+		hdd_err("twt_disable_comp_evt init failed");
+		return;
 	}
 
 	hdd_send_twt_enable_cmd(hdd_ctx);
-	return;
-
-twt_init_fail:
-
-	sme_deregister_twt_enable_complete_cb(hdd_ctx->mac_handle);
 }
 
 void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)

+ 20 - 29
core/sme/inc/sme_api.h

@@ -155,6 +155,8 @@ struct sme_config_params {
 #define BW_160_OFFSET_BIT  3
 #endif /* FEATURE_WLAN_TDLS */
 
+struct wmi_twt_add_dialog_param;
+
 /* Thermal Mitigation*/
 typedef struct {
 	uint16_t smeMinTempThreshold;
@@ -3621,7 +3623,7 @@ QDF_STATUS sme_register_twt_enable_complete_cb(mac_handle_t mac_handle,
 					       twt_enable_cb twt_enable_cb);
 
 /**
- * sme_register_twt_disable_complete_cb - TWT disable registrar
+ * sme_register_twt_disable_complete_cb() - TWT disable registrar
  * @mac_handle: MAC handle
  * @twt_disable_cb: Function callback to handle disable event
  *
@@ -3630,6 +3632,21 @@ QDF_STATUS sme_register_twt_enable_complete_cb(mac_handle_t mac_handle,
 QDF_STATUS sme_register_twt_disable_complete_cb(mac_handle_t mac_handle,
 						twt_disable_cb twt_disable_cb);
 
+/**
+ * sme_add_dialog_cmd() - Register callback and send TWT add dialog
+ * command to firmware
+ * @mac_handle: MAC handle
+ * @twt_add_dialog_cb: Function callback to handle add_dialog event
+ * @twt_params: TWT add dialog parameters
+ * @context: os_if_request cookie
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle,
+			      twt_add_dialog_cb twt_add_dialog_cb,
+			      struct wmi_twt_add_dialog_param *twt_params,
+			      void *context);
+
 /**
  * sme_deregister_twt_enable_complete_cb() - TWT enable deregistrar
  * @mac_handle: Opaque handle to the global MAC context
@@ -3639,40 +3656,14 @@ QDF_STATUS sme_register_twt_disable_complete_cb(mac_handle_t mac_handle,
 QDF_STATUS sme_deregister_twt_enable_complete_cb(mac_handle_t mac_handle);
 
 /**
- * sme_deregister_twt_disable_complete_cb - TWT disable deregistrar
+ * sme_deregister_twt_disable_complete_cb() - TWT disable deregistrar
  * @mac_handle: Opaque handle to the global MAC context
  *
  * Return: QDF Status
  */
 QDF_STATUS sme_deregister_twt_disable_complete_cb(mac_handle_t mac_handle);
-
-#else
-static inline
-QDF_STATUS sme_register_twt_enable_complete_cb(mac_handle_t mac_handle,
-					       twt_enable_cb twt_enable_cb)
-{
-	return QDF_STATUS_SUCCESS;
-}
-
-static inline
-QDF_STATUS sme_register_twt_disable_complete_cb(mac_handle_t mac_handle,
-						twt_disable_cb twt_disable_cb)
-{
-	return QDF_STATUS_SUCCESS;
-}
-
-static inline
-QDF_STATUS sme_deregister_twt_enable_complete_cb(mac_handle_t mac_handle)
-{
-	return QDF_STATUS_SUCCESS;
-}
-
-static inline
-QDF_STATUS sme_deregister_twt_disable_complete_cb(mac_handle_t mac_handle)
-{
-	return QDF_STATUS_SUCCESS;
-}
 #endif
+
 /**
  * sme_get_sta_cxn_info() - This function populates all the connection
  *			    information which is formed by DUT-STA to AP

+ 31 - 2
core/sme/inc/sme_internal.h

@@ -39,6 +39,7 @@
 #include "wmi_unified.h"
 #include "wmi_unified_param.h"
 
+struct wmi_twt_add_dialog_complete_event_param;
 struct wmi_twt_enable_complete_event_param;
 /*--------------------------------------------------------------------------
   Type declarations
@@ -142,10 +143,34 @@ typedef void (*p2p_lo_callback)(void *context,
 typedef void (*sme_send_oem_data_rsp_msg)(struct oem_data_rsp *);
 #endif
 
-typedef void (*twt_enable_cb)(hdd_handle_t hdd_handle,
-			      struct wmi_twt_enable_complete_event_param *params);
+#ifdef WLAN_SUPPORT_TWT
+/**
+ * typedef twt_enable_cb - TWT enable callback signature.
+ * @hdd_handle: Opaque handle to the HDD context
+ * @params: TWT enable complete event parameters.
+ */
+typedef
+void (*twt_enable_cb)(hdd_handle_t hdd_handle,
+		      struct wmi_twt_enable_complete_event_param *params);
+
+/**
+ * typedef twt_disable_cb - TWT enable callback signature.
+ * @hdd_handle: Opaque handle to the HDD context
+ */
 typedef void (*twt_disable_cb)(hdd_handle_t hdd_handle);
 
+/**
+ * typedef twt_add_dialog_cb - TWT add dialog callback signature.
+ * @context: Opaque context that the client can use to associate the
+ *           callback with the request.
+ * @params: TWT add dialog complete event fixed parameters.
+ * @params: TWT add dialog complete event additional parameters.
+ */
+typedef void (*twt_add_dialog_cb)(void *context,
+				  struct wmi_twt_add_dialog_complete_event_param *params,
+				  struct wmi_twt_add_dialog_additional_params *additional_params);
+#endif
+
 #ifdef FEATURE_WLAN_APF
 /**
  * typedef apf_get_offload_cb - APF offload callback signature
@@ -350,8 +375,12 @@ struct sme_context {
 	void *fw_state_context;
 #endif /* FEATURE_FW_STATE */
 	tx_queue_cb tx_queue_cb;
+#ifdef WLAN_SUPPORT_TWT
 	twt_enable_cb twt_enable_cb;
 	twt_disable_cb twt_disable_cb;
+	twt_add_dialog_cb twt_add_dialog_cb;
+	void *twt_context;
+#endif
 #ifdef FEATURE_WLAN_APF
 	apf_get_offload_cb apf_get_offload_cb;
 	apf_read_mem_cb apf_read_mem_cb;

+ 39 - 0
core/sme/src/common/sme_api.c

@@ -45,6 +45,7 @@
 #include "cds_regdomain.h"
 #include "sme_power_save_api.h"
 #include "wma.h"
+#include "wma_twt.h"
 #include "sch_api.h"
 #include "sme_nan_datapath.h"
 #include "csr_api.h"
@@ -14406,6 +14407,7 @@ QDF_STATUS sme_deregister_tx_queue_cb(mac_handle_t mac_handle)
 }
 
 #ifdef WLAN_SUPPORT_TWT
+
 QDF_STATUS sme_register_twt_enable_complete_cb(mac_handle_t mac_handle,
 					       twt_enable_cb twt_enable_cb)
 {
@@ -14447,6 +14449,43 @@ QDF_STATUS sme_deregister_twt_disable_complete_cb(mac_handle_t mac_handle)
 {
 	return sme_register_twt_disable_complete_cb(mac_handle, NULL);
 }
+
+QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle,
+			      twt_add_dialog_cb twt_add_dialog_cb,
+			      struct wmi_twt_add_dialog_param *twt_params,
+			      void *context)
+{
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+	QDF_STATUS status;
+	void *wma_handle;
+
+	SME_ENTER();
+	wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+	if (!wma_handle) {
+		sme_err("wma_handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.twt_add_dialog_cb = twt_add_dialog_cb;
+		mac->sme.twt_context = context;
+		sme_release_global_lock(&mac->sme);
+	}
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_err("failed to register add dlg callback");
+		return status;
+	}
+
+	status = wma_twt_process_add_dialog(twt_params);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		sme_err("failed to call wma_start_oem_data_cmd.");
+
+	SME_EXIT();
+	return status;
+}
+
 #endif
 
 QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id,

+ 10 - 13
core/wma/inc/wma_internal.h

@@ -1727,20 +1727,17 @@ int wma_twt_en_complete_event_handler(void *handle,
  */
 int wma_twt_disable_comp_event_handler(void *handle, uint8_t *event,
 				       uint32_t len);
-#else
-static inline int wma_twt_en_complete_event_handler(void *handle,
-						    uint8_t *event,
-						    uint32_t len)
-{
-	return 0;
-}
 
-static inline int wma_twt_disable_comp_event_handler(void *handle,
-						     uint8_t *event,
-						     uint32_t len)
-{
-	return 0;
-}
+/**
+ * wma_twt_add_dialog_complete_event_handler - TWT add dlg complete evt handler
+ * @handle: wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success
+ */
+int wma_twt_add_dialog_complete_event_handler(void *handle,
+					      uint8_t *event, uint32_t len);
 #endif
 
 /**

+ 5 - 0
core/wma/src/wma_main.c

@@ -3364,6 +3364,11 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc,
 					   wmi_twt_disable_complete_event_id,
 					   wma_twt_disable_comp_event_handler,
 					   WMA_RX_SERIALIZER_CTX);
+	wmi_unified_register_event_handler
+				(wma_handle->wmi_handle,
+				 wmi_twt_add_dialog_complete_event_id,
+				 wma_twt_add_dialog_complete_event_handler,
+				 WMA_RX_SERIALIZER_CTX);
 #endif
 
 	wma_register_apf_events(wma_handle);

+ 52 - 4
core/wma/src/wma_twt.c

@@ -21,7 +21,6 @@
  *
  * WLAN Host Device Driver TWT - Target Wake Time Implementation
  */
-
 #include "wma_twt.h"
 #include "wmi_unified_twt_api.h"
 #include "wma_internal.h"
@@ -51,9 +50,9 @@ int wma_twt_en_complete_event_handler(void *handle,
 				      uint8_t *event, uint32_t len)
 {
 	struct wmi_twt_enable_complete_event_param param;
-	tp_wma_handle wma_handle = (tp_wma_handle) handle;
+	tp_wma_handle wma_handle = handle;
 	wmi_unified_t wmi_handle;
-	struct mac_context *mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE);
+	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
 	int status = -EINVAL;
 
 	if (!wma_handle) {
@@ -146,6 +145,56 @@ QDF_STATUS wma_twt_process_add_dialog(
 	return wmi_unified_twt_add_dialog_cmd(wmi_handle, params);
 }
 
+int wma_twt_add_dialog_complete_event_handler(void *handle,
+					      uint8_t *event, uint32_t len)
+{
+	struct wmi_twt_add_dialog_complete_event_param param = {0};
+	struct wmi_twt_add_dialog_additional_params additional_params = {0};
+	tp_wma_handle wma_handle = handle;
+	wmi_unified_t wmi_handle;
+	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
+	int status = -EINVAL;
+
+	if (!wma_handle) {
+		wma_err("Invalid wma handle for TWT add dialog complete");
+		return status;
+	}
+
+	if (!mac) {
+		wma_err("Invalid MAC context");
+		return status;
+	}
+
+	wmi_handle = (wmi_unified_t)wma_handle->wmi_handle;
+	if (!wmi_handle) {
+		wma_err("Invalid wma handle for TWT add dialog complete");
+		return status;
+	}
+
+	status = wmi_extract_twt_add_dialog_comp_event(wmi_handle, event,
+						       &param);
+	if (QDF_IS_STATUS_ERROR(status))
+		return qdf_status_to_os_return(status);
+
+	if (param.num_additional_twt_params) {
+		status = wmi_extract_twt_add_dialog_comp_additional_params(wmi_handle,
+									   event,
+									   len, 0,
+									   &additional_params);
+		if (QDF_IS_STATUS_ERROR(status))
+			return qdf_status_to_os_return(status);
+	}
+
+	wma_debug("TWT: Extract TWT add dialog event :%d", status);
+
+	if (mac->sme.twt_add_dialog_cb)
+		mac->sme.twt_add_dialog_cb(mac->sme.twt_context, &param,
+					   &additional_params);
+	mac->sme.twt_add_dialog_cb = NULL;
+
+	return status;
+}
+
 QDF_STATUS wma_twt_process_del_dialog(
 		struct wmi_twt_del_dialog_param *params)
 {
@@ -165,4 +214,3 @@ QDF_STATUS wma_twt_process_del_dialog(
 
 	return wmi_unified_twt_del_dialog_cmd(wmi_handle, params);
 }
-