@@ -10134,6 +10134,21 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
return ret;
}
+static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int ret;
+ int flags = 0x1;
+
+ char* tok_s = os_strstr(cmd, "flags=");
+ if (tok_s)
+ flags = atoi(tok_s + strlen("flags="));
+
+ ret = wpas_twt_send_teardown(wpa_s, flags);
+
+ return ret;
+}
+
static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
{
@@ -11359,6 +11374,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "TWT_SETUP", 20) == 0) {
if (wpas_ctrl_iface_send_twt_setup(wpa_s, buf + 9))
reply_len = -1;
+ } else if (os_strncmp(buf, "TWT_TEARDOWN", 20) == 0) {
+ if (wpas_ctrl_iface_send_twt_teardown(wpa_s, buf + 9))
+ reply_len = -1;
} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
wpas_ctrl_iface_erp_flush(wpa_s);
} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
@@ -88,3 +88,50 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
wpabuf_free(buf);
return 0;
}
+
+/**
+ * wpas_twt_send_teardown - Send TWT teardown request to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @flags: The byte that goes inside the teardown IE
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s,
+ int flags)
+{
+ struct wpabuf *buf;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "TWT: No connection, no TWT.");
+ return -ENOTCONN;
+ }
+
+ /* 3 = action category + action code + flags */
+ buf = wpabuf_alloc(3);
+
+ if (buf == NULL) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "TWT: Failed to allocate TWT Teardown Request");
+ return -ENOMEM;
+ }
+
+ wpa_dbg(wpa_s, 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_dbg(wpa_s, MSG_DEBUG,
+ "TWT: Failed to send TWT Teardown Request");
+ wpabuf_free(buf);
+ return -ECANCELED;
+ }
+
+ wpabuf_free(buf);
+ return 0;
+}
@@ -2948,6 +2948,11 @@ static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc,
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[])
{
@@ -3832,6 +3837,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
"[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>]"
},
+ { "twt_teardown",
+ wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none,
+ "[flags=<value>]"
+ },
{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
"= flush ERP keys" },
{ "mac_rand_scan",
@@ -1560,6 +1560,8 @@ int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
int dtok, int exponent, int mantissa, int min_twt);
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s,
+ int flags);
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,