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@xxxxxxxxxxxx> --- 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 6252529cb..0a5789390 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2253,6 +2253,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) \ @@ -2951,6 +2953,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 * @@ -5075,6 +5098,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 2e9548f30..a2bd568b6 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -371,6 +371,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 7f6abb3ff..488b2905e 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -13647,6 +13647,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", @@ -13801,4 +13835,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 48953c1d9..2a72a7947 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -1179,4 +1179,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 1c31569c6..9e367657f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1659,6 +1659,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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap