From 013beb7bc5036bf627fce3707a7a83344ffa05aa Mon Sep 17 00:00:00 2001
From: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
Date: Mon, 11 Jul 2022 11:16:37 +0530
Subject: [PATCH 41/49] add support to offload TWT setup request handling to
 the Firmware

With "TWT_SETUP" control sock cmd interface currently available in the
wpa_supplicant, it is currently possible to generate the TWT Setup Action
frame with the desired TWT session params like SP, SI, TWT Setup cmd type,
Flow ID, Trigger/Non-Trigger based, Un-Announced/Announced session types,
etc, without informing the TWT state machine in the Firmware.

Now introduce a new TWT Offload code path and then when the TWT Setup is
triggerd either through the "$ wpa_cli twt_setup" or directly though the
control sock cmd "TWT_SETUP", construct a Vendor nl80211 cmd of type "TWT"
and pass it to the driver if it supports this new vendor cmd. The driver
then could inform the TWT module in the firmware through the corresponding
IOVAR to initiate a TWT Setup request while updating the TWT negotiation
handshake state machine as needed.


Signed-off-by: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
Signed-off-by: Ian Lin <ian.lin@infineon.com>
---
 src/common/ifx_vendor.h           | 157 ++++++++++++++++++++++++++++++
 src/drivers/driver.h              |  38 ++++++++
 src/drivers/driver_nl80211.c      | 124 ++++++++++++++++++++++-
 src/drivers/driver_nl80211.h      |   3 +
 src/drivers/driver_nl80211_capa.c |  12 +++
 wpa_supplicant/Makefile           |   8 ++
 wpa_supplicant/ctrl_iface.c       |  12 ++-
 wpa_supplicant/defconfig_base     |   7 ++
 wpa_supplicant/driver_i.h         |  12 +++
 wpa_supplicant/twt.c              | 119 +++++++++++++++++++++-
 wpa_supplicant/wpa_supplicant_i.h |   8 ++
 11 files changed, 494 insertions(+), 6 deletions(-)

diff --git a/src/common/ifx_vendor.h b/src/common/ifx_vendor.h
index 2ea9af0a7..a94694c93 100644
--- a/src/common/ifx_vendor.h
+++ b/src/common/ifx_vendor.h
@@ -54,6 +54,9 @@
  *
  * @IFX_VENDOR_SCMD_AMSDU: Vendor command to enable/disable AMSDU on all the TID queues
  *
+ * @IFX_VENDOR_SCMD_TWT: Vendor subcommand to configure TWT
+ *	Uses attributes defined in enum ifx_vendor_attr_twt.
+ *
  * @IFX_VENDOR_SCMD_MAX: This acts as a the tail of cmds list.
  *      Make sure it located at the end of the list.
  */
@@ -70,6 +73,7 @@ enum ifx_nl80211_vendor_subcmds {
 	IFX_VENDOR_SCMD_MUEDCA_OPT_ENABLE = 11,
 	IFX_VENDOR_SCMD_LDPC_CAP	= 12,
 	IFX_VENDOR_SCMD_AMSDU		= 13,
+	IFX_VENDOR_SCMD_TWT		= 14,
 	IFX_VENDOR_SCMD_MAX
 };
 
@@ -92,4 +96,157 @@ enum ifx_vendor_attr {
 	IFX_VENDOR_ATTR_MAX		= 11
 };
 
+/*
+ * enum ifx_vendor_attr_twt - Attributes for the TWT vendor command
+ *
+ * @IFX_VENDOR_ATTR_TWT_UNSPEC: Reserved value 0
+ *
+ * @IFX_VENDOR_ATTR_TWT_OPER: To specify the type of TWT operation
+ *	to be performed. Uses attributes defined in enum ifx_twt_oper.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAMS: Nester attributes representing the
+ *	parameters configured for TWT. These parameters are defined in
+ *	the enum ifx_vendor_attr_twt_param.
+ *
+ * @IFX_VENDOR_ATTR_TWT_MAX: This acts as a the tail of cmds list.
+ *      Make sure it located at the end of the list.
+ */
+enum ifx_vendor_attr_twt {
+	IFX_VENDOR_ATTR_TWT_UNSPEC,
+	IFX_VENDOR_ATTR_TWT_OPER,
+	IFX_VENDOR_ATTR_TWT_PARAMS,
+	IFX_VENDOR_ATTR_TWT_MAX
+};
+
+/*
+ * enum ifx_twt_oper - TWT operation to be specified using the vendor
+ * attribute IFX_VENDOR_ATTR_TWT_OPER
+ *
+ * @IFX_TWT_OPER_UNSPEC: Reserved value 0
+ *
+ * @IFX_TWT_OPER_SETUP: Setup a TWT session. Required parameters are
+ *	obtained through the nested attrs under IFX_VENDOR_ATTR_TWT_PARAMS.
+ *
+ * @IFX_TWT_OPER_MAX: This acts as a the tail of the list.
+ *      Make sure it located at the end of the list.
+ */
+enum ifx_twt_oper {
+	IFX_TWT_OPER_UNSPEC,
+	IFX_TWT_OPER_SETUP,
+	IFX_TWT_OPER_MAX
+};
+
+/*
+ * enum ifx_vendor_attr_twt_param - TWT parameters
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_UNSPEC: Reserved value 0
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE: Specifies the type of Negotiation to be
+ *	done during Setup. The four possible types are
+ *	0 - Individual TWT Negotiation
+ *	1 - Wake TBTT Negotiation
+ *	2 - Broadcast TWT in Beacon
+ *	3 - Broadcast TWT Membership Negotiation
+ *
+ *	The possible values are defined in the enum ifx_twt_param_nego_type
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE: Specifies the type of TWT Setup frame
+ *	when sent by the TWT Requesting STA
+ *	0 - Request
+ *	1 - Suggest
+ *	2 - Demand
+ *
+ *	when sent by the TWT Responding STA.
+ *	3 - Grouping
+ *	4 - Accept
+ *	5 - Alternate
+ *	6 - Dictate
+ *	7 - Reject
+ *
+ *	The possible values are defined in the enum ifx_twt_oper_setup_cmd_type.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN: Dialog Token used by the TWT Requesting STA to
+ *	identify the TWT Setup request/response transaction.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME: Target Wake Time.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION: Nominal Minimum TWT Wake Duration.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT: TWT Wake Interval Exponent.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA: TWT Wake Interval Mantissa.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR: Specify this is a TWT Requesting / Responding STA.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER: Specify Trigger based / Non-Trigger based TWT Session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT: Specify Implicit / Explicit TWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE: Specify Un-Announced / Announced TWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID: Flow ID of an iTWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID: Brocast TWT ID of a bTWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION: Specifies whether Tx within SP is protected.
+ *	Set to 1 to indicate that TXOPs within the TWT SPs shall be initiated
+ *	with a NAV protection mechanism, such as (MU) RTS/CTS or CTS-to-self frame;
+ *	otherwise, it shall set it to 0.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL: TWT channel field which is set to 0, unless
+ * 	the HE STA sets up a subchannel selective transmission operation.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED: TWT Information frame RX handing
+ *	disabled / enabled.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT: Nominal Minimum TWT Wake Duration
+ *	Unit. 0 represents unit in "256 usecs" and 1 represents unit in "TUs".
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_MAX: This acts as a the tail of the list.
+ *      Make sure it located at the end of the list.
+ */
+enum ifx_vendor_attr_twt_param {
+	IFX_VENDOR_ATTR_TWT_PARAM_UNSPEC,
+	IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE,
+	IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE,
+	IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME,
+	IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA,
+	IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR,
+	IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER,
+	IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT,
+	IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE,
+	IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID,
+	IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID,
+	IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION,
+	IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL,
+	IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED,
+	IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT,
+	IFX_VENDOR_ATTR_TWT_PARAM_MAX
+};
+
+enum ifx_twt_param_nego_type {
+	IFX_TWT_PARAM_NEGO_TYPE_INVALID			= -1,
+	IFX_TWT_PARAM_NEGO_TYPE_ITWT			= 0,
+	IFX_TWT_PARAM_NEGO_TYPE_WAKE_TBTT		= 1,
+	IFX_TWT_PARAM_NEGO_TYPE_BTWT_IE_BCN		= 2,
+	IFX_TWT_PARAM_NEGO_TYPE_BTWT			= 3,
+	IFX_TWT_PARAM_NEGO_TYPE_MAX			= 4
+};
+
+enum ifx_twt_oper_setup_cmd_type {
+	IFX_TWT_OPER_SETUP_CMD_TYPE_INVALID	= -1,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_REQUEST	= 0,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_SUGGEST	= 1,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_DEMAND	= 2,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_GROUPING	= 3,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_ACCEPT	= 4,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_ALTERNATE	= 5,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_DICTATE	= 6,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_REJECT	= 7,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_MAX		= 8
+};
+
 #endif /* IFX_VENDOR_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d778b1eaa..af4d0a5d0 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -26,6 +26,9 @@
 #include "pae/ieee802_1x_kay.h"
 #endif /* CONFIG_MACSEC */
 #include "utils/list.h"
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#include "common/ifx_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 
 #define HOSTAPD_CHAN_DISABLED 0x00000001
 #define HOSTAPD_CHAN_NO_IR 0x00000002
@@ -2519,6 +2522,31 @@ struct drv_acs_params {
 	int edmg_enabled;
 };
 
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+struct drv_setup_twt_params {
+	u8 dtok;
+	u64 twt;
+	u8 min_twt;
+	u8 exponent;
+	u16 mantissa;
+	enum ifx_twt_oper_setup_cmd_type setup_cmd;
+	u8 requestor;
+	u8 trigger;
+	u8 implicit;
+	u8 flow_type;
+	u8 flow_id;
+	u8 bcast_twt_id;
+	u8 protection;
+	u8 twt_channel;
+	u8 control;
+	enum ifx_twt_param_nego_type negotiation_type;
+	u8 twt_info_frame_disabled;
+	u8 min_twt_unit;	/* true - in TUs, false - in 256us */
+};
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
+#endif /* CONFIG_DRIVER_NL80211_IFX */
+
 struct wpa_bss_trans_info {
 	u8 mbo_transition_reason;
 	u8 n_candidates;
@@ -4630,6 +4658,16 @@ struct wpa_driver_ops {
 			      const u8 *match, size_t match_len,
 			      bool multicast);
 #endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+	/**
+	 * setup_twt - Setup a TWT session
+	 * @params: Setup TWT params
+	 */
+	int (*setup_twt)(void *priv, struct drv_setup_twt_params *params);
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 };
 
 /**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index de58b17e1..fd6fe91a1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -43,7 +43,9 @@
 #include "radiotap_iter.h"
 #include "rfkill.h"
 #include "driver_nl80211.h"
-
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#include "common/ifx_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 
 #ifndef NETLINK_CAP_ACK
 #define NETLINK_CAP_ACK 10
@@ -12284,6 +12286,121 @@ static int testing_nl80211_register_frame(void *priv, u16 type,
 }
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+static int wpa_driver_nl80211_setup_twt(void *priv, struct drv_setup_twt_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg = NULL;
+	struct nlattr *data, *twt_param_attrs;
+	int ret = -1;
+
+	if (!drv->ifx_twt_offload)
+		goto fail;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_IFX) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, IFX_VENDOR_SCMD_TWT))
+		goto fail;
+
+	data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+	if (!data)
+		goto fail;
+
+	if (nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_OPER, IFX_TWT_OPER_SETUP))
+		goto fail;
+
+	twt_param_attrs = nla_nest_start(msg, IFX_VENDOR_ATTR_TWT_PARAMS);
+	if (!twt_param_attrs)
+		goto fail;
+
+	if (nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE,
+		       params->negotiation_type) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE,
+		       params->setup_cmd) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN,
+		       params->dtok) ||
+
+	    (params->twt &&
+	     nla_put_u64(msg, IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME,
+			 params->twt)) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION,
+		       params->min_twt) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT,
+		       params->exponent) ||
+
+	    nla_put_u16(msg, IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA,
+			params->mantissa) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR,
+		       params->requestor) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER,
+		       params->trigger) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT,
+		       params->implicit) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE,
+		       params->flow_type) ||
+
+	    (params->flow_id &&
+	     nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID,
+			params->flow_id)) ||
+
+	    (params->bcast_twt_id &&
+	     nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID,
+			params->bcast_twt_id)) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION,
+		       params->protection) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL,
+		       params->twt_channel) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED,
+		       params->twt_info_frame_disabled) ||
+
+	    nla_put_u8(msg, IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT,
+		       params->min_twt_unit))
+		goto fail;
+
+	nla_nest_end(msg, twt_param_attrs);
+	nla_nest_end(msg, data);
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: TWT Setup: Neg Type: %d REQ Type: %d TWT: %lu min_twt: %d "
+		   "exponent: %d mantissa: %d requestor: %d trigger: %d implicit: %d "
+		   "flow_type: %d flow_id: %d bcast_twt_id: %d protection: %d "
+		   "twt_channel: %d twt_info_frame_disabled: %d min_twt_unit: %d",
+		   params->negotiation_type, params->setup_cmd, params->twt,
+		   params->min_twt, params->exponent, params->mantissa,
+		   params->requestor, params->trigger, params->implicit,
+		   params->flow_type, params->flow_id, params->bcast_twt_id,
+		   params->protection, params->twt_channel,
+		   params->twt_info_frame_disabled, params->min_twt_unit);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: TWT Setup: Failed to invoke driver "
+			   "TWT setup function: %s",
+			   strerror(-ret));
+	}
+
+	return ret;
+fail:
+	nl80211_nlmsg_clear(msg);
+	nlmsg_free(msg);
+	return ret;
+}
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
@@ -12429,4 +12546,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #ifdef CONFIG_TESTING_OPTIONS
 	.register_frame = testing_nl80211_register_frame,
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+	.setup_twt = wpa_driver_nl80211_setup_twt,
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 };
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 80d456472..f681afb41 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -180,6 +180,9 @@ struct wpa_driver_nl80211_data {
 	unsigned int unsol_bcast_probe_resp:1;
 	unsigned int qca_do_acs:1;
 	unsigned int brcm_do_acs:1;
+#ifdef CONFIG_DRIVER_NL80211_IFX
+	unsigned int ifx_twt_offload:1;
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index d5cdafa9f..19d1569bf 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -17,6 +17,9 @@
 #include "common/qca-vendor.h"
 #include "common/qca-vendor-attr.h"
 #include "common/brcm_vendor.h"
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#include "common/ifx_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 #include "driver_nl80211.h"
 
 
@@ -1049,6 +1052,15 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 					break;
 				}
 #endif /* CONFIG_DRIVER_NL80211_BRCM */
+
+#ifdef CONFIG_DRIVER_NL80211_IFX
+			} else if (vinfo->vendor_id == OUI_IFX) {
+				switch (vinfo->subcmd) {
+				case IFX_VENDOR_SCMD_TWT:
+					drv->ifx_twt_offload = 1;
+					break;
+				}
+#endif /* CONFIG_DRIVER_NL80211_IFX */
 			}
 
 			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 66aedaff7..16e484ce6 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -823,6 +823,14 @@ CFLAGS += -DCONFIG_WPS_STRICT
 OBJS += ../src/wps/wps_validate.o
 endif
 
+ifdef CONFIG_DRIVER_NL80211_IFX
+CFLAGS += -DCONFIG_DRIVER_NL80211_IFX
+endif # CONFIG_DRIVER_NL80211_IFX == y
+
+ifdef CONFIG_TWT_OFFLOAD_IFX
+CFLAGS += -DCONFIG_TWT_OFFLOAD_IFX
+endif # CONFIG_TWT_OFFLOAD_IFX == y
+
 ifdef CONFIG_WPS_TESTING
 CFLAGS += -DCONFIG_WPS_TESTING
 endif
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 1d4c8bcc2..f93b8d65e 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -9988,6 +9988,7 @@ static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
 	return -1;
 #endif /* CONFIG_SME */
 }
+#endif /* CONFIG_TESTING_OPTIONS */
 
 
 static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
@@ -10066,10 +10067,18 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	if (tok_s)
 		control = atoi(tok_s + os_strlen(" control="));
 
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+	return wpas_twt_offload_send_setup(wpa_s, dtok, exponent, mantissa,
+					   min_twt, setup_cmd, twt, requestor,
+					   trigger, implicit, flow_type,
+					   flow_id, protection, twt_channel,
+					   control);
+#else
 	return wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt,
 				   setup_cmd, twt, requestor, trigger, implicit,
 				   flow_type, flow_id, protection, twt_channel,
 				   control);
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
 }
 
 
@@ -10086,7 +10095,6 @@ static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s,
 	return wpas_twt_send_teardown(wpa_s, flags);
 }
 
-#endif /* CONFIG_TESTING_OPTIONS */
 
 
 static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
@@ -12202,6 +12210,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 		sme_event_unprot_disconnect(
 			wpa_s, wpa_s->bssid, NULL,
 			WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+#endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "TWT_SETUP ", 10) == 0) {
 		if (wpas_ctrl_iface_send_twt_setup(wpa_s, buf + 9))
 			reply_len = -1;
@@ -12214,7 +12223,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} else if (os_strcmp(buf, "TWT_TEARDOWN") == 0) {
 		if (wpas_ctrl_iface_send_twt_teardown(wpa_s, ""))
 			reply_len = -1;
-#endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
 		if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
 			reply_len = -1;
diff --git a/wpa_supplicant/defconfig_base b/wpa_supplicant/defconfig_base
index 1c83967ae..bfaed5d91 100644
--- a/wpa_supplicant/defconfig_base
+++ b/wpa_supplicant/defconfig_base
@@ -641,3 +641,10 @@ CONFIG_TESTING_OPTIONS=y
 
 CONFIG_SUITEB192=y
 CONFIG_SUITEB=y
+
+# Enable all IFX/Cypress changes
+CONFIG_DRIVER_NL80211_IFX=y
+
+# Offload the TWT Session management to FW
+CONFIG_TWT_OFFLOAD_IFX=y
+
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index c7ba94ebd..eab01da24 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1127,4 +1127,16 @@ static inline int wpa_drv_dpp_listen(struct wpa_supplicant *wpa_s, bool enable)
 	return wpa_s->driver->dpp_listen(wpa_s->drv_priv, enable);
 }
 
+#ifdef CONFIG_DRIVER_NL80211_IFX
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+static inline int wpa_drv_setup_twt(struct wpa_supplicant *wpa_s,
+				    struct drv_setup_twt_params *params)
+{
+	if (!wpa_s->driver->setup_twt)
+		return -1;
+	return wpa_s->driver->setup_twt(wpa_s->drv_priv, params);
+}
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
+#endif /* CONFIG_DRIVER_NL80211_IFX */
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
index 8ec2c85ac..59933c875 100644
--- a/wpa_supplicant/twt.c
+++ b/wpa_supplicant/twt.c
@@ -12,8 +12,122 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+/**
+ * wpas_twt_offload_send_setup - Send TWT Setup frame to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @dtok: Dialog token
+ * @exponent: Wake-interval exponent
+ * @mantissa: Wake-interval mantissa
+ * @min_twt: Minimum TWT wake duration in units of 256 usec
+ * @setup_cmd: 0 == request, 1 == suggest, etc.  Table 9-297
+ * @twt: Target Wake Time
+ * @requestor: Specify this is a TWT Requesting / Responding STA
+ * @trigger: Specify Trigger based / Non-Trigger based TWT Session
+ * @implicit: Specify Implicit / Explicit TWT session
+ * @flow_type: Specify Un-Announced / Announced TWT session
+ * @flow_id: Flow ID / Broacast TWT ID to be used in the TWT session
+ * @protection: Specifies whether Tx within SP is protected by RTS & CTS
+ * @twt_channel: Set by the HE SST non-AP STA
+ * @control: Control Field in the TWT Setup Action frame
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_offload_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
+				int mantissa, u8 min_twt, int setup_cmd, u64 twt,
+				bool requestor, bool trigger, bool implicit,
+				bool flow_type, u8 flow_id, bool protection,
+				u8 twt_channel, u8 control)
+{
+	int ret = 0;
+	struct drv_setup_twt_params params;
+	u8 negotiation_type, twt_info_frame_disabled, min_twt_unit;
+
+	params.dtok = dtok;
+	params.exponent = (u8)exponent;
+	params.mantissa = (u16)mantissa;
+	params.min_twt = min_twt;
+	params.twt = twt;
+	params.requestor = requestor ? 1 : 0;
+	params.trigger = trigger ? 1 : 0;
+	params.implicit = implicit ? 1 : 0;
+	params.flow_type = flow_type ? 1 : 0;
+	params.protection = protection ? 1 : 0;
+	params.twt_channel = twt_channel;
+	params.flow_id = 0;
+	params.bcast_twt_id = 0;
+
+	/* Setup Command Field - IEEE 802.11ax-2021 Table 9-297 */
+	switch(setup_cmd) {
+		case 0: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_REQUEST;
+			break;
+		case 1: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_SUGGEST;
+			break;
+		case 2: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_DEMAND;
+			break;
+		case 3: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_GROUPING;
+			break;
+		case 4: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_ACCEPT;
+			break;
+		case 5: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_ALTERNATE;
+			break;
+		case 6: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_DICTATE;
+			break;
+		case 7: params.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_REJECT;
+			break;
+		default:
+			wpa_printf(MSG_ERROR,
+				   "TWT offload: specified Setup cmd type not supported");
+			ret = -EOPNOTSUPP;
+			goto fail;
+	}
+
+	/* Control Field - IEEE 802.11ax-2021 Figure 9-687 */
+	params.control = control;
+							/* NDP Paging Indicator : Bit 0		 */
+							/* Responder PM Mode : Bit 1		 */
+	negotiation_type = (control & 0xc) >> 2;	/* Negotiation type : Bit 2-3		 */
+	twt_info_frame_disabled = (control & 0x10) >> 4;/* TWT Information Frame Disabled: Bit 4 */
+	min_twt_unit = (control & 0x20) >> 5;		/* Wake Duration Unit : Bit 5		 */
+							/* Reserved : Bit 6-7			 */
+
+	/* Negotiation Type Field - IEEE 802.11ax-2021 Table 9.296a */
+	switch(negotiation_type) {
+		case 0:	/* Individual TWT */
+			params.negotiation_type = IFX_TWT_PARAM_NEGO_TYPE_ITWT;
+			params.flow_id = flow_id;
+			break;
+		case 1: /* Wake TBTT Negotiation */
+			params.negotiation_type = IFX_TWT_PARAM_NEGO_TYPE_WAKE_TBTT;
+			break;
+		case 2: /* Broadcast TWT IE in Beacon */
+			params.negotiation_type = IFX_TWT_PARAM_NEGO_TYPE_BTWT_IE_BCN;
+			break;
+		case 3: /* Broadcast TWT membership */
+			params.negotiation_type = IFX_TWT_PARAM_NEGO_TYPE_BTWT;
+			params.bcast_twt_id = flow_id;
+			break;
+		default:
+			wpa_printf(MSG_ERROR,
+				   "TWT offload: specified Nego type not supported");
+			ret = -EOPNOTSUPP;
+			goto fail;
+	}
 
-#ifdef CONFIG_TESTING_OPTIONS
+	params.twt_info_frame_disabled = twt_info_frame_disabled;
+	params.min_twt_unit = min_twt_unit;		/* 1 - in TUs, 0 - in 256us */
+
+	if (wpa_drv_setup_twt(wpa_s, &params)) {
+		wpa_printf(MSG_ERROR, "TWT offload: Failed to send TWT Setup Request");
+		ret = -ECANCELED;
+		goto fail;
+	}
+
+fail:
+	return ret;
+}
+
+#else
 
 /**
  * wpas_twt_send_setup - Send TWT Setup frame (Request) to our AP
@@ -95,6 +209,7 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 	return ret;
 }
 
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
 
 /**
  * wpas_twt_send_teardown - Send TWT teardown request to our AP
@@ -138,5 +253,3 @@ int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
 	wpabuf_free(buf);
 	return ret;
 }
-
-#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b671b54e7..1f538724e 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1643,11 +1643,19 @@ void add_freq(int *freqs, int *num_freqs, int freq);
 int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
 			 u8 *op_class, u8 *chan, u8 *phy_type);
 
+#ifdef CONFIG_TWT_OFFLOAD_IFX
+int wpas_twt_offload_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
+				int mantissa, u8 min_twt, int setup_cmd, u64 twt,
+				bool requestor, bool trigger, bool implicit,
+				bool flow_type, u8 flow_id, bool protection,
+				u8 twt_channel, u8 control);
+#else
 int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 			int mantissa, u8 min_twt, int setup_cmd, u64 twt,
 			bool requestor, bool trigger, bool implicit,
 			bool flow_type, u8 flow_id, bool protection,
 			u8 twt_channel, u8 control);
+#endif /* CONFIG_TWT_OFFLOAD_IFX */
 int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
 
 void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
-- 
2.17.1

