diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b8dee8dbf..c67c6f46c 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -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,7 @@
 #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_FILS 26
 #define WLAN_ACTION_PROTECTED_FTM 34
 #define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
@@ -820,6 +822,19 @@ enum nai_realm_eap_cred_type {
 	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
 };
 
+#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_RESERVED             10
+#define S1G_ACT_TWT_INFORMATION      11
+
 /*
  * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
  * measurement requests
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index fb665b160..77baa1bb5 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -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
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d679b56af..1a1c2ca82 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10108,6 +10108,32 @@ static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
 	return ret;
 }
 
+static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
+					  char *cmd)
+{
+	int ret;
+	int dtok = 1;
+	int exponent = 10;
+	int mantissa = 8192;
+	int min_twt = 255;
+
+	char* tok_s = os_strstr(cmd, "dialog=");
+	if (tok_s)
+		dtok = atoi(tok_s + strlen("dialog="));
+
+	tok_s = os_strstr(cmd, "exponent=");
+	if (tok_s)
+		exponent = atoi(tok_s + strlen("exponent="));
+
+	tok_s = os_strstr(cmd, "mantissa=");
+	if (tok_s)
+		exponent = atoi(tok_s + strlen("mantissa="));
+
+	ret = wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt);
+
+	return ret;
+}
+
 
 static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
 {
@@ -11330,6 +11356,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
 		if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
 			reply_len = -1;
+	} 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_strcmp(buf, "ERP_FLUSH") == 0) {
 		wpas_ctrl_iface_erp_flush(wpa_s);
 	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
new file mode 100644
index 000000000..6b62631b7
--- /dev/null
+++ b/wpa_supplicant/twt.c
@@ -0,0 +1,90 @@
+/*
+ * 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 "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+
+
+/**
+ * wpas_twt_send_setup - Send TWT setup request to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @dtok: Dialog token.
+ * @exponent: TWT wake-interval exponent
+ * @mantissa:  TWT wake-interval Mantissa
+ * @min_twt:  TWT Minimum TWT Wake Duration.
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
+			int dtok, int exponent, int mantissa, int min_twt)
+{
+	struct wpabuf *buf;
+	u16 req_type = 0;
+	unsigned char targ_wait_time[8] = {0};
+
+	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 + dialog token */
+	/* 17 = target wait time IE */
+	buf = wpabuf_alloc(3 + 17);
+	
+	if (buf == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"TWT: Failed to allocate TWT Setup Request");
+		return -ENOMEM;
+	}
+
+	wpa_dbg(wpa_s, 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, 0x10); /* control field */
+
+	req_type |= (0x1); /* This STA is a TWT Requesting STA */
+	req_type |= (0x70); /* TWT SP includes trigger frames, TWT Implicit, TWT un-announced */
+	req_type |= ((exponent & 0x1f) << 10);
+	/* high bit is 'protection, leave it false for now */
+	wpabuf_put_u8(buf, req_type);
+	wpabuf_put_u8(buf, req_type >> 8);
+	/* Not sure exactly how this is used */
+	wpabuf_put_data(buf, targ_wait_time, sizeof(targ_wait_time));
+	wpabuf_put_u8(buf, min_twt); /* minimum twt wake duration */
+	wpabuf_put_u8(buf, mantissa);
+	wpabuf_put_u8(buf, mantissa >> 8);
+	wpabuf_put_u8(buf, 0); /* 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_dbg(wpa_s, MSG_DEBUG,
+			"TWT: Failed to send TWT Setup Request");
+		wpabuf_free(buf);
+		return -ECANCELED;
+	}
+
+	wpabuf_free(buf);
+	return 0;
+}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index b3e256b0f..b84670df9 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2942,6 +2942,12 @@ static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
 	return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
 }
 
+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_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -3822,6 +3828,10 @@ 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>]"
+	},
 	{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
 	  "= flush ERP keys" },
 	{ "mac_rand_scan",
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index dfd8c61eb..705352c17 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1557,6 +1557,10 @@ 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,
+			int dtok, int exponent, int mantissa, int min_twt);
+
 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);
