diff mbox series

[2/7] TWT: Add support to offload TWT Session setup handling work to the driver

Message ID 20230425160155.ptf75cet67rh67rf@infineon.com
State Superseded
Headers show
Series [1/7] hostapd_cli: wpa_cli: introduce a CMD to dump the driver capability flags2 | expand

Commit Message

Gokul Sivakumar April 25, 2023, 4:01 p.m. UTC
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 low layer.

Now introduce a new TWT Offload code path and then when the TWT Setup is
triggered either through the "$ wpa_cli twt_setup" or directly though the
control SOCK CMD "TWT_SETUP", fillup the generic TWT Setup param struct
and pass it to the NL80211 driver interface file driver_nl80211.c, where
the request could be passed down to the low layer. And the low layer can
initiate a TWT Setup request while updating the TWT session negotiation
handshake state machine as needed.

Also introduce a driver capability flag "TWT_OFFLOAD" to inform about
the capability of the low layer to handle the TWT related operations.

For backward compatibility, as per current behaviour when wpa_suppicant
is compiled with the build flag CONFIG_TESTING_OPTIONS=y, it continues to
trigger the existing code path where TWT Setup Action frame is constructed
by wpa_supplicant instead of offloading that work to the low layer.

Example: To Initiate an Individual TWT Setup of type "Request" with service
period 20.48 ms, Service interval 64 ms and session type "Trigger based",
"Implicit", "Announced", run the following wpa_cli cmd,

$ wpa_cli -i wlan0 twt_setup setup_cmd=0 min_twt=80 mantissa=8000 \
	exponent=3 trigger=1 implicit=1 flow_type=0 control=0

Signed-off-by: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
---
 src/drivers/driver.h              |  29 +++++
 src/drivers/driver_common.c       |   1 +
 src/drivers/driver_nl80211.c      |  35 ++++++
 wpa_supplicant/ctrl_iface.c       |   7 +-
 wpa_supplicant/driver_i.h         |  10 ++
 wpa_supplicant/twt.c              | 187 +++++++++++++++++++++++++++++-
 wpa_supplicant/wpa_supplicant_i.h |  13 +++
 7 files changed, 275 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2932eff80..a7c6490f6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2226,6 +2226,8 @@  struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA	0x0000000000002000ULL
 /** Driver supports MLO in station/AP mode */
 #define WPA_DRIVER_FLAGS2_MLO			0x0000000000004000ULL
+/** Driver supports TWT offload */
+#define WPA_DRIVER_FLAGS2_TWT_OFFLOAD		0x0000000000008000ULL
 	u64 flags2;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2922,6 +2924,27 @@  struct driver_sta_mlo_info {
 	} links[MAX_NUM_MLD_LINKS];
 };
 
+struct drv_setup_twt_params {
+	u8 dtok;
+	u64 twt;
+	u8 min_twt;
+	u8 exponent;
+	u16 mantissa;
+	u8 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;
+	u8 negotiation_type;
+	u8 twt_info_frame_disabled;
+	u8 min_twt_unit;	/* true - in TUs, false - in 256us */
+};
+
 /**
  * struct wpa_driver_ops - Driver interface API definition
  *
@@ -5028,6 +5051,12 @@  struct wpa_driver_ops {
 			      const u8 *match, size_t match_len,
 			      bool multicast);
 #endif /* CONFIG_TESTING_OPTIONS */
+
+	/**
+	 * setup_twt - Setup a TWT session
+	 * @params: Setup TWT params
+	 */
+	int (*setup_twt)(void *priv, struct drv_setup_twt_params *params);
 };
 
 /**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index ba28a6b27..a1f0bd924 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -369,6 +369,7 @@  const char * driver_flag2_to_string(u64 flag2)
 	DF2S(SEC_RTT_STA);
 	DF2S(PROT_RANGE_NEG_STA);
 	DF2S(MLO);
+	DF2S(TWT_OFFLOAD);
 	}
 	return "UNKNOWN";
 #undef DF2S
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ba4a6eb14..e8a86cd18 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -13452,6 +13452,40 @@  static int testing_nl80211_radio_disable(void *priv, int disabled)
 
 #endif /* CONFIG_TESTING_OPTIONS */
 
+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;
+	int ret = -1;
+
+	if (!(drv->capa.flags2 & WPA_DRIVER_FLAGS2_TWT_OFFLOAD))
+		return ret;
+
+	/*
+	 * Call the Vendor implementation for initiating
+	 * TWT Setup Request to the Vendor Driver
+	 */
+
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: TWT Setup: Failed to invoke driver TWT setup function: %s",
+			   strerror(-ret));
+	} else {
+		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);
+	}
+
+	return ret;
+}
 
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
@@ -13605,4 +13639,5 @@  const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.register_frame = testing_nl80211_register_frame,
 	.radio_disable = testing_nl80211_radio_disable,
 #endif /* CONFIG_TESTING_OPTIONS */
+	.setup_twt = wpa_driver_nl80211_setup_twt,
 };
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 9abfeb216..7b8bd75c2 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10319,6 +10319,8 @@  static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_SME */
 }
 
+#endif /* CONFIG_TESTING_OPTIONS */
+
 
 static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 					  const char *cmd)
@@ -10333,7 +10335,7 @@  static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	bool trigger = true;
 	bool implicit = true;
 	bool flow_type = true;
-	int flow_id = 0;
+	int flow_id = 0xFF;
 	bool protection = false;
 	u8 twt_channel = 0;
 	u8 control = BIT(4); /* Control field (IEEE Std 802.11ax-2021,
@@ -10404,6 +10406,7 @@  static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 				   control);
 }
 
+#ifdef CONFIG_TESTING_OPTIONS
 
 static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s,
 					     const char *cmd)
@@ -12706,12 +12709,14 @@  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;
 	} else if (os_strcmp(buf, "TWT_SETUP") == 0) {
 		if (wpas_ctrl_iface_send_twt_setup(wpa_s, ""))
 			reply_len = -1;
+#ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strncmp(buf, "TWT_TEARDOWN ", 13) == 0) {
 		if (wpas_ctrl_iface_send_twt_teardown(wpa_s, buf + 12))
 			reply_len = -1;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index d707cf556..17530ac4d 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1172,4 +1172,14 @@  wpas_drv_get_sta_mlo_info(struct wpa_supplicant *wpa_s,
 	return wpa_s->driver->get_sta_mlo_info(wpa_s->drv_priv, mlo_info);
 }
 
+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 /* DRIVER_I_H */
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
index 8ec2c85ac..3c126d455 100644
--- a/wpa_supplicant/twt.c
+++ b/wpa_supplicant/twt.c
@@ -16,7 +16,8 @@ 
 #ifdef CONFIG_TESTING_OPTIONS
 
 /**
- * wpas_twt_send_setup - Send TWT Setup frame (Request) to our AP
+ * wpas_twt_test_send_setup - Send TWT Setup frame (Request) to our AP
+ * by initiatng an Action frame constructed by the wpa_supplicant.
  * @wpa_s: Pointer to wpa_supplicant
  * @dtok: Dialog token
  * @exponent: Wake-interval exponent
@@ -26,11 +27,11 @@ 
  * Returns: 0 in case of success, negative error code otherwise
  *
  */
-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)
+int wpas_twt_test_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)
 {
 	struct wpabuf *buf;
 	u16 req_type = 0;
@@ -95,6 +96,180 @@  int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 	return ret;
 }
 
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+/**
+ * wpas_twt_offload_send_setup - Send TWT Setup frame to our AP
+ * by offloading the responsibility of initiating TWT Teardown to the driver
+ * @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.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;
+
+	/* Initialize with an invalid TWT session ID - 0xFF */
+	params.flow_id = 0xFF;
+	params.bcast_twt_id = 0xFF;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
+		wpa_printf(MSG_DEBUG,
+			   "TWT offload: No connection - cannot send TWT Setup Request");
+		return -ENOTCONN;
+	}
+
+	/* exponent range - 0 to 31 */
+	if (exponent >= 0 && exponent <= 0x1F) {
+		params.exponent = (u8)exponent;
+	} else {
+		wpa_printf(MSG_ERROR,
+				"TWT offload: setup cmd exponent %d not supported",
+				exponent);
+		ret = -EOPNOTSUPP;
+		goto fail;
+	}
+
+	/* mantissa range - 1 to 65535 */
+	if ((mantissa > 0) && (mantissa <= 0xFFFF)) {
+		params.mantissa = (u16)mantissa;
+	} else {
+		wpa_printf(MSG_ERROR,
+				"TWT offload: setup cmd mantissa %d not supported",
+				mantissa);
+		ret = -EOPNOTSUPP;
+		goto fail;
+	}
+
+	/* Setup Command Field - IEEE 802.11ax-2021 Table 9-297 */
+	if ((setup_cmd >= 0) && (setup_cmd <= 7)) {
+		params.setup_cmd = setup_cmd;
+	} else {
+		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 = negotiation_type;
+		params.flow_id = flow_id;
+		break;
+	case 1: /* Wake TBTT Negotiation */
+		params.negotiation_type = negotiation_type;
+		break;
+	case 2: /* Broadcast TWT IE in Beacon */
+		params.negotiation_type = negotiation_type;
+		break;
+	case 3: /* Broadcast TWT membership */
+		params.negotiation_type = negotiation_type;
+		params.bcast_twt_id = flow_id;
+		break;
+	default:
+		wpa_printf(MSG_ERROR,
+			   "TWT offload: specified Nego type not supported");
+		ret = -EOPNOTSUPP;
+		goto fail;
+	}
+
+	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;
+}
+
+
+/**
+ * wpas_twt_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_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)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	return wpas_twt_test_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_TESTING_OPTIONS */
+
+	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);
+}
+
+#ifdef CONFIG_TESTING_OPTIONS
 
 /**
  * wpas_twt_send_teardown - Send TWT teardown request to our AP
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d5b3dab67..6226c8725 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1658,6 +1658,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);
 
+/* TWT functions */
+#ifdef CONFIG_TESTING_OPTIONS
+int wpas_twt_test_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_TESTING_OPTIONS */
+int wpas_twt_offload_setup_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 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,