[PATCH 2/7] TWT: Add support to offload TWT Session setup handling work to the driver
Gokul Sivakumar
gokulkumar.sivakumar at infineon.com
Tue Apr 25 09:01:55 PDT 2023
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 at 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 --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, ¶ms)) {
+ 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,
--
2.25.1
More information about the Hostap
mailing list