TWT: Support sending TWT Setup and Teardown Action frames
This adds new control interface commands TWT_SETUP and TWT_TEARDOWN. For now, these are only for testing purposes to be able to trigger transmission of the TWT Action frames without configuring any local behavior for TWT in the driver. Signed-off-by: Ben Greear <greearb@candelatech.com>
This commit is contained in:
parent
edbaffc4f6
commit
7fd2f24962
7 changed files with 295 additions and 0 deletions
|
@ -446,6 +446,7 @@
|
|||
#define WLAN_EID_WHITE_SPACE_MAP 205
|
||||
#define WLAN_EID_FTM_PARAMETERS 206
|
||||
#define WLAN_EID_S1G_BCN_COMPAT 213
|
||||
#define WLAN_EID_TWT 216
|
||||
#define WLAN_EID_S1G_CAPABILITIES 217
|
||||
#define WLAN_EID_VENDOR_SPECIFIC 221
|
||||
#define WLAN_EID_S1G_OPERATION 232
|
||||
|
@ -603,6 +604,10 @@
|
|||
#define WLAN_ACTION_ROBUST_AV_STREAMING 19
|
||||
#define WLAN_ACTION_UNPROTECTED_DMG 20
|
||||
#define WLAN_ACTION_VHT 21
|
||||
#define WLAN_ACTION_S1G 22
|
||||
#define WLAN_ACTION_S1G_RELAY 23
|
||||
#define WLAN_ACTION_FLOW_CONTROL 24
|
||||
#define WLAN_ACTION_CTRL_RESP_MCS_NEG 25
|
||||
#define WLAN_ACTION_FILS 26
|
||||
#define WLAN_ACTION_PROTECTED_FTM 34
|
||||
#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
|
||||
|
@ -820,6 +825,19 @@ enum nai_realm_eap_cred_type {
|
|||
NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
|
||||
};
|
||||
|
||||
/* Unprotected S1G Action field values for WLAN_ACTION_S1G */
|
||||
#define S1G_ACT_AID_SWITCH_REQUEST 0
|
||||
#define S1G_ACT_AID_SWITCH_RESPONSE 1
|
||||
#define S1G_ACT_SYNC_CONTROL 2
|
||||
#define S1G_ACT_STA_INFO_ANNOUNCE 3
|
||||
#define S1G_ACT_EDCA_PARAM_SET 4
|
||||
#define S1G_ACT_EL_OPERATION 5
|
||||
#define S1G_ACT_TWT_SETUP 6
|
||||
#define S1G_ACT_TWT_TEARDOWN 7
|
||||
#define S1G_ACT_SECT_GROUP_ID_LIST 8
|
||||
#define S1G_ACT_SECT_ID_FEEDBACK 9
|
||||
#define S1G_ACT_TWT_INFORMATION 11
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
|
||||
* measurement requests
|
||||
|
|
|
@ -103,6 +103,7 @@ OBJS += src/utils/crc32.c
|
|||
OBJS += wmm_ac.c
|
||||
OBJS += op_classes.c
|
||||
OBJS += rrm.c
|
||||
OBJS += twt.c
|
||||
OBJS += robust_av.c
|
||||
OBJS_p = wpa_passphrase.c
|
||||
OBJS_p += src/utils/common.c
|
||||
|
|
|
@ -95,6 +95,7 @@ OBJS += ../src/utils/ip_addr.o
|
|||
OBJS += ../src/utils/crc32.o
|
||||
OBJS += op_classes.o
|
||||
OBJS += rrm.o
|
||||
OBJS += twt.o
|
||||
OBJS += robust_av.o
|
||||
OBJS_p = wpa_passphrase.o
|
||||
OBJS_p += ../src/utils/common.o
|
||||
|
|
|
@ -9792,6 +9792,96 @@ static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
|
|||
#endif /* CONFIG_SME */
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 dtok = 1;
|
||||
int exponent = 10;
|
||||
int mantissa = 8192;
|
||||
u8 min_twt = 255;
|
||||
unsigned long long twt = 0;
|
||||
bool requestor = true;
|
||||
int setup_cmd = 0;
|
||||
bool trigger = true;
|
||||
bool implicit = true;
|
||||
bool flow_type = true;
|
||||
int flow_id = 0;
|
||||
bool protection = false;
|
||||
u8 twt_channel = 0;
|
||||
const char *tok_s;
|
||||
|
||||
tok_s = os_strstr(cmd, " dialog=");
|
||||
if (tok_s)
|
||||
dtok = atoi(tok_s + os_strlen(" dialog="));
|
||||
|
||||
tok_s = os_strstr(cmd, " exponent=");
|
||||
if (tok_s)
|
||||
exponent = atoi(tok_s + os_strlen(" exponent="));
|
||||
|
||||
tok_s = os_strstr(cmd, " mantissa=");
|
||||
if (tok_s)
|
||||
mantissa = atoi(tok_s + os_strlen(" mantissa="));
|
||||
|
||||
tok_s = os_strstr(cmd, " min_twt=");
|
||||
if (tok_s)
|
||||
min_twt = atoi(tok_s + os_strlen(" min_twt="));
|
||||
|
||||
tok_s = os_strstr(cmd, " setup_cmd=");
|
||||
if (tok_s)
|
||||
setup_cmd = atoi(tok_s + os_strlen(" setup_cmd="));
|
||||
|
||||
tok_s = os_strstr(cmd, " twt=");
|
||||
if (tok_s)
|
||||
sscanf(tok_s + os_strlen(" twt="), "%llu", &twt);
|
||||
|
||||
tok_s = os_strstr(cmd, " requestor=");
|
||||
if (tok_s)
|
||||
requestor = atoi(tok_s + os_strlen(" requestor="));
|
||||
|
||||
tok_s = os_strstr(cmd, " trigger=");
|
||||
if (tok_s)
|
||||
trigger = atoi(tok_s + os_strlen(" trigger="));
|
||||
|
||||
tok_s = os_strstr(cmd, " implicit=");
|
||||
if (tok_s)
|
||||
implicit = atoi(tok_s + os_strlen(" implicit="));
|
||||
|
||||
tok_s = os_strstr(cmd, " flow_type=");
|
||||
if (tok_s)
|
||||
flow_type = atoi(tok_s + os_strlen(" flow_type="));
|
||||
|
||||
tok_s = os_strstr(cmd, " flow_id=");
|
||||
if (tok_s)
|
||||
flow_id = atoi(tok_s + os_strlen(" flow_id="));
|
||||
|
||||
tok_s = os_strstr(cmd, " protection=");
|
||||
if (tok_s)
|
||||
protection = atoi(tok_s + os_strlen(" protection="));
|
||||
|
||||
tok_s = os_strstr(cmd, " twt_channel=");
|
||||
if (tok_s)
|
||||
twt_channel = atoi(tok_s + os_strlen(" twt_channel="));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s,
|
||||
const char *cmd)
|
||||
{
|
||||
u8 flags = 0x1;
|
||||
const char *tok_s;
|
||||
|
||||
tok_s = os_strstr(cmd, " flags=");
|
||||
if (tok_s)
|
||||
flags = atoi(tok_s + os_strlen(" flags="));
|
||||
|
||||
return wpas_twt_send_teardown(wpa_s, flags);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
|
||||
|
@ -11285,6 +11375,18 @@ 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);
|
||||
} 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;
|
||||
} 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)
|
||||
|
|
143
wpa_supplicant/twt.c
Normal file
143
wpa_supplicant/twt.c
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* wpa_supplicant - TWT
|
||||
* Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "wpa_supplicant_i.h"
|
||||
#include "driver_i.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
|
||||
/**
|
||||
* wpas_twt_send_setup - Send TWT Setup frame (Request) 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
|
||||
* 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)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u16 req_type = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TWT: No connection - cannot send TWT Setup frame");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* 3 = Action category + Action code + Dialog token */
|
||||
/* 17 = TWT element */
|
||||
buf = wpabuf_alloc(3 + 17);
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TWT: Failed to allocate TWT Setup frame (Request)");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TWT: Setup request, dtok: %d exponent: %d mantissa: %d min-twt: %d",
|
||||
dtok, exponent, mantissa, min_twt);
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_S1G);
|
||||
wpabuf_put_u8(buf, S1G_ACT_TWT_SETUP);
|
||||
wpabuf_put_u8(buf, dtok);
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_EID_TWT);
|
||||
wpabuf_put_u8(buf, 15); /* len */
|
||||
|
||||
wpabuf_put_u8(buf, BIT(4)); /* Control field:
|
||||
* B4 = TWT Information Frame Disabled */
|
||||
|
||||
if (requestor)
|
||||
req_type |= BIT(0); /* This STA is a TWT Requesting STA */
|
||||
/* TWT Setup Command field */
|
||||
req_type |= (setup_cmd & 0x7) << 1;
|
||||
if (trigger)
|
||||
req_type |= BIT(4); /* TWT SP includes trigger frames */
|
||||
if (implicit)
|
||||
req_type |= BIT(5); /* Implicit TWT */
|
||||
if (flow_type)
|
||||
req_type |= BIT(6); /* Flow Type: Unannounced TWT */
|
||||
req_type |= (flow_id & 0x7) << 7;
|
||||
req_type |= (exponent & 0x1f) << 10; /* TWT Wake Interval Exponent */
|
||||
if (protection)
|
||||
req_type |= BIT(15);
|
||||
wpabuf_put_le16(buf, req_type);
|
||||
wpabuf_put_le64(buf, twt);
|
||||
wpabuf_put_u8(buf, min_twt); /* Nominal Minimum TWT Wake Duration */
|
||||
wpabuf_put_le16(buf, mantissa); /* TWT Wake Interval Mantissa */
|
||||
wpabuf_put_u8(buf, twt_channel); /* TWT Channel */
|
||||
|
||||
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
|
||||
wpa_s->own_addr, wpa_s->bssid,
|
||||
wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TWT: Failed to send TWT Setup Request");
|
||||
ret = -ECANCELED;
|
||||
}
|
||||
|
||||
wpabuf_free(buf);
|
||||
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)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int ret = 0;
|
||||
|
||||
if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TWT: No connection - cannot send TWT Teardown frame");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* 3 = Action category + Action code + flags */
|
||||
buf = wpabuf_alloc(3);
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TWT: Failed to allocate TWT Teardown frame");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TWT: Teardown request, flags: 0x%x", flags);
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_S1G);
|
||||
wpabuf_put_u8(buf, S1G_ACT_TWT_TEARDOWN);
|
||||
wpabuf_put_u8(buf, flags);
|
||||
|
||||
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
|
||||
wpa_s->own_addr, wpa_s->bssid,
|
||||
wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TWT: Failed to send TWT Teardown frame");
|
||||
ret = -ECANCELED;
|
||||
}
|
||||
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
|
@ -2926,6 +2926,20 @@ static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
|
|||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_cli_cmd(ctrl, "TWT_SETUP", 0, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_twt_teardown(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_cli_cmd(ctrl, "TWT_TEARDOWN", 0, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "ERP_FLUSH");
|
||||
|
@ -3805,6 +3819,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
|
|||
wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
|
||||
"[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)"
|
||||
},
|
||||
{ "twt_setup",
|
||||
wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
|
||||
"[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>] [min_twt=<Min TWT>] [setup_cmd=<setup-cmd>] [twt=<u64>] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=<twt chanel id>] = Send TWT Setup frame"
|
||||
},
|
||||
{ "twt_teardown",
|
||||
wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none,
|
||||
"[flags=<value>] = Send TWT Teardown frame"
|
||||
},
|
||||
{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
|
||||
"= flush ERP keys" },
|
||||
{ "mac_rand_scan",
|
||||
|
|
|
@ -1514,6 +1514,14 @@ 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);
|
||||
|
||||
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);
|
||||
int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
|
||||
|
||||
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
|
||||
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
|
||||
const u8 *report, size_t report_len);
|
||||
|
|
Loading…
Reference in a new issue