diff mbox series

[v2,3/7] TWT: Add support to offload TWT Session Teardown handling work to the driver

Message ID 20230426104602.29853-3-gokulkumar.sivakumar@infineon.com
State Superseded
Headers show
Series [v2,1/7] hostapd_cli: wpa_cli: introduce a CMD to dump the driver capability flags2 | expand

Commit Message

Gokul Sivakumar April 26, 2023, 10:45 a.m. UTC
With "TWT_TEARDOWN" control SOCK CMD interface currently available in the
wpa_supplicant,it is currently possible to generate the TWT Teardown Action
frame with the desired TWT session params like Negotiation Type, Flow ID,
Bcast TWT ID,etc, without informing the TWT state machine in the low layer.

Now introduce a new TWT Offload code path and then when the TWT Teardown is
triggered either through the "$ wpa_cli twt_teardown" or directly though
the control SOCK CMD "TWT_TEARDOWN", fillup the generic TWT Teardown 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 Teardown while updating the TWT session negotiation
handshake state machine as needed.

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

Example: To initiate an Individual TWT Teardown with flow ID "5",
run the following wpa_cli cmd,

$ wpa_cli -i wlan0 twt_teardown flags=5 control=0

Signed-off-by: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
---
 src/drivers/driver.h              | 13 +++++
 src/drivers/driver_nl80211.c      | 33 ++++++++++++
 wpa_supplicant/ctrl_iface.c       |  5 --
 wpa_supplicant/driver_i.h         | 10 ++++
 wpa_supplicant/twt.c              | 83 ++++++++++++++++++++++++++++++-
 wpa_supplicant/wpa_supplicant_i.h |  4 ++
 6 files changed, 141 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a7c6490f6..9edd3ba97 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2945,6 +2945,13 @@  struct drv_setup_twt_params {
 	u8 min_twt_unit;	/* true - in TUs, false - in 256us */
 };
 
+struct drv_teardown_twt_params {
+	u8 negotiation_type;
+	u8 flow_id;
+	u8 bcast_twt_id;
+	u8 teardown_all_twt;
+};
+
 /**
  * struct wpa_driver_ops - Driver interface API definition
  *
@@ -5057,6 +5064,12 @@  struct wpa_driver_ops {
 	 * @params: Setup TWT params
 	 */
 	int (*setup_twt)(void *priv, struct drv_setup_twt_params *params);
+
+	/**
+	 * teardown_twt - Teardown the already negotiated TWT session
+	 * @params: Teardown TWT params
+	 */
+	int (*teardown_twt)(void *priv, struct drv_teardown_twt_params *params);
 };
 
 /**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 03b0ae606..25ff98978 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -13492,6 +13492,38 @@  static int wpa_driver_nl80211_setup_twt(void *priv, struct drv_setup_twt_params
 	return ret;
 }
 
+
+static int wpa_driver_nl80211_teardown_twt(void *priv, struct drv_teardown_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 Teardown Request to the Vendor Driver
+	 */
+
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: TWT Teardown: Failed to invoke driver "
+			   "TWT teardown function: %s",
+			   strerror(-ret));
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: TWT Teardown: Neg Type: %d teardown_all_twt: %d "
+			   "flow_id: %d bcast_twt_id: %d",
+			   params->negotiation_type, params->teardown_all_twt,
+			   params->flow_id, params->bcast_twt_id);
+	}
+
+	return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -13645,4 +13677,5 @@  const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.radio_disable = testing_nl80211_radio_disable,
 #endif /* CONFIG_TESTING_OPTIONS */
 	.setup_twt = wpa_driver_nl80211_setup_twt,
+	.teardown_twt = wpa_driver_nl80211_teardown_twt,
 };
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 7b8bd75c2..06daea723 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10406,7 +10406,6 @@  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)
@@ -10421,8 +10420,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)
 {
@@ -12716,14 +12713,12 @@  char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} 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;
 	} 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/driver_i.h b/wpa_supplicant/driver_i.h
index 17530ac4d..587733395 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1182,4 +1182,14 @@  wpa_drv_setup_twt(struct wpa_supplicant *wpa_s,
 	return wpa_s->driver->setup_twt(wpa_s->drv_priv, params);
 }
 
+static inline int
+wpa_drv_teardown_twt(struct wpa_supplicant *wpa_s,
+		     struct drv_teardown_twt_params *params)
+{
+	if (!wpa_s->driver->teardown_twt)
+		return -1;
+
+	return wpa_s->driver->teardown_twt(wpa_s->drv_priv, params);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
index 3c126d455..75ebfe56f 100644
--- a/wpa_supplicant/twt.c
+++ b/wpa_supplicant/twt.c
@@ -272,13 +272,14 @@  int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 #ifdef CONFIG_TESTING_OPTIONS
 
 /**
- * wpas_twt_send_teardown - Send TWT teardown request to our AP
+ * wpas_twt_test_send_teardown - Send TWT teardown request to our AP
+ * by initiating an Action from constructed by wpa_supplicant
  * @wpa_s: Pointer to wpa_supplicant
  * @flags: The byte that goes inside the TWT Teardown element
  * Returns: 0 in case of success, negative error code otherwise
  *
  */
-int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
+int wpas_twt_test_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
 {
 	struct wpabuf *buf;
 	int ret = 0;
@@ -315,3 +316,81 @@  int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
 }
 
 #endif /* CONFIG_TESTING_OPTIONS */
+
+
+/**
+ * wpas_twt_offload_send_teardown - send TWT teardown request to our AP
+ * by offloading the responsibility of initiating TWT Teardown to the driver
+ * @wpa_s: pointer to wpa_supplicant
+ * @flags: the byte that goes inside the twt teardown element
+ * returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_offload_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
+{
+	int ret = 0;
+	struct drv_teardown_twt_params params;
+	u8 negotiation_type, flow_id, teardown_all_twt;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
+		wpa_printf(MSG_DEBUG,
+			   "TWT offload: No connection - cannot send TWT Teardown Request");
+		return -ENOTCONN;
+	}
+
+	/* TWT Flow Field - IEEE 802.11ax-2021 Figure 9-965 */
+	flow_id = flags & 0x07;			/* Flow ID : Bit 0-2		*/
+						/* Reserved : Bit 3-4		*/
+	negotiation_type = (flags & 0x60) >> 5;	/* Negotiation type : Bit 5-6	*/
+	teardown_all_twt = (flags & 0x80) >> 7;	/* Teardown all TWT : Bit 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.teardown_all_twt = teardown_all_twt;
+
+	if (wpa_drv_teardown_twt(wpa_s, &params)) {
+		wpa_printf(MSG_ERROR, "TWT offload: Failed to send TWT Teardown Request");
+		ret = -ECANCELED;
+		goto fail;
+	}
+
+fail:
+	return ret;
+}
+
+/**
+ * wpas_twt_send_teardown - send TWT teardown request to our AP
+ * @wpa_s: pointer to wpa_supplicant
+ * @flags: the byte that goes inside the twt teardown element
+ * returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+	return wpas_twt_test_send_teardown(wpa_s, flags);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	return wpas_twt_offload_send_teardown(wpa_s, flags);
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 6226c8725..9da15f7a2 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1676,6 +1676,10 @@  int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 			bool requestor, bool trigger, bool implicit,
 			bool flow_type, u8 flow_id, bool protection,
 			u8 twt_channel, u8 control);
+#ifdef CONFIG_TESTING_OPTIONS
+int wpas_twt_test_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
+#endif /* CONFIG_TESTING_OPTIONS */
+int wpas_twt_offload_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
 int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
 
 void wpas_rrm_reset(struct wpa_supplicant *wpa_s);