Write hostapd pid to a file am: fa798f237b am: 62bade5796
am: cac82f62b7

Change-Id: Ic63bd018d7cc8d964b575a09bce1f82e74e24664
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index de37def..ea3a39a 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -947,7 +947,10 @@
 L_CFLAGS += -DCONFIG_ANDROID_LOG
 endif
 
-OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+OBJS_c = hostapd_cli.c
+OBJS_c += src/common/wpa_ctrl.c
+OBJS_c += src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/common/cli.c
 OBJS_c += src/utils/eloop.c
 OBJS_c += src/utils/common.c
 ifdef CONFIG_WPA_TRACE
diff --git a/hostapd/Makefile b/hostapd/Makefile
index baa7819..ba094ba 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -87,7 +87,10 @@
 OBJS += ../src/ap/neighbor_db.o
 OBJS += ../src/ap/rrm.o
 
-OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+OBJS_c = hostapd_cli.o
+OBJS_c += ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/common/cli.o
 
 NEED_RC4=y
 NEED_AES=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 6dc7e8c..1b506a7 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -636,8 +636,7 @@
 }
 
 
-static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
-				    const char *val)
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
 {
 	char *secret;
 
@@ -645,7 +644,7 @@
 	if (secret == NULL)
 		return -1;
 
-	secret++;
+	*secret++ = '\0';
 
 	if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
 		return -1;
@@ -2411,6 +2410,9 @@
 		bss->radius_das_time_window = atoi(pos);
 	} else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
 		bss->radius_das_require_event_timestamp = atoi(pos);
+	} else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
+		   0) {
+		bss->radius_das_require_message_authenticator = atoi(pos);
 #endif /* CONFIG_NO_RADIUS */
 	} else if (os_strcmp(buf, "auth_algs") == 0) {
 		bss->auth_algs = atoi(pos);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index c244624..a310c05 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1088,6 +1088,9 @@
 #
 # DAS require Event-Timestamp
 #radius_das_require_event_timestamp=1
+#
+# DAS require Message-Authenticator
+#radius_das_require_message_authenticator=1
 
 ##### RADIUS authentication server configuration ##############################
 
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 5c1f297..04819d1 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -15,6 +15,7 @@
 #include "utils/eloop.h"
 #include "utils/edit.h"
 #include "common/version.h"
+#include "common/cli.h"
 
 #ifndef CONFIG_NO_CTRL_IFACE
 
@@ -22,74 +23,6 @@
 "hostapd_cli v" VERSION_STR "\n"
 "Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
 
-
-static const char *const hostapd_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const hostapd_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-"   notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-"   notice, this list of conditions and the following disclaimer in the\n"
-"   documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-"   names of its contributors may be used to endorse or promote products\n"
-"   derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
-
-static const char *const commands_help =
-"Commands:\n"
-"   mib                  get MIB variables (dot1x, dot11, radius)\n"
-"   sta <addr>           get MIB variables for one station\n"
-"   all_sta              get MIB variables for all stations\n"
-"   new_sta <addr>       add a new station\n"
-"   deauthenticate <addr>  deauthenticate a station\n"
-"   disassociate <addr>  disassociate a station\n"
-#ifdef CONFIG_IEEE80211W
-"   sa_query <addr>      send SA Query to a station\n"
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-"   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
-"   wps_check_pin <PIN>  verify PIN checksum\n"
-"   wps_pbc              indicate button pushed to initiate PBC\n"
-"   wps_cancel           cancel the pending WPS operation\n"
-#ifdef CONFIG_WPS_NFC
-"   wps_nfc_tag_read <hexdump>  report read NFC tag with WPS data\n"
-"   wps_nfc_config_token <WPS/NDEF>  build NFC configuration token\n"
-"   wps_nfc_token <WPS/NDEF/enable/disable>  manager NFC password token\n"
-#endif /* CONFIG_WPS_NFC */
-"   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
-"   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
-"   wps_get_status       show current WPS status\n"
-#endif /* CONFIG_WPS */
-"   get_config           show current configuration\n"
-"   help                 show this usage help\n"
-"   interface [ifname]   show interfaces/select interface\n"
-"   level <debug level>  change debug level\n"
-"   license              show full hostapd_cli license\n"
-"   quit                 exit hostapd_cli\n";
-
 static struct wpa_ctrl *ctrl_conn;
 static int hostapd_cli_quit = 0;
 static int hostapd_cli_attached = 0;
@@ -105,6 +38,13 @@
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
+static int event_handler_registered = 0;
+
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+
+static void print_help(FILE *stream, const char *cmd);
+static char ** list_cmd_list(void);
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
 
 
 static void usage(void)
@@ -129,9 +69,32 @@
 		"   -B           run a daemon in the background\n"
 		"   -i<ifname>   Interface to listen on (default: first "
 		"interface found in the\n"
-		"                socket path)\n\n"
-		"%s",
-		commands_help);
+		"                socket path)\n\n");
+	print_help(stderr, NULL);
+}
+
+
+static void register_event_handler(struct wpa_ctrl *ctrl)
+{
+	if (!ctrl_conn)
+		return;
+	if (interactive) {
+		event_handler_registered =
+			!eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
+						  hostapd_cli_receive,
+						  NULL, NULL);
+	}
+}
+
+
+static void unregister_event_handler(struct wpa_ctrl *ctrl)
+{
+	if (!ctrl_conn)
+		return;
+	if (interactive && event_handler_registered) {
+		eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
+		event_handler_registered = 0;
+	}
 }
 
 
@@ -174,6 +137,7 @@
 	if (ctrl_conn == NULL)
 		return;
 
+	unregister_event_handler(ctrl_conn);
 	if (hostapd_cli_attached) {
 		wpa_ctrl_detach(ctrl_conn);
 		hostapd_cli_attached = 0;
@@ -223,36 +187,6 @@
 }
 
 
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
-		     char *argv[])
-{
-	int i, res;
-	char *pos, *end;
-
-	pos = buf;
-	end = buf + buflen;
-
-	res = os_snprintf(pos, end - pos, "%s", cmd);
-	if (os_snprintf_error(end - pos, res))
-		goto fail;
-	pos += res;
-
-	for (i = 0; i < argc; i++) {
-		res = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (os_snprintf_error(end - pos, res))
-			goto fail;
-		pos += res;
-	}
-
-	buf[buflen - 1] = '\0';
-	return 0;
-
-fail:
-	printf("Too long command\n");
-	return -1;
-}
-
-
 static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
 			   int min_args, int argc, char *argv[])
 {
@@ -384,6 +318,21 @@
 }
 
 
+static char ** hostapd_complete_deauthenticate(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&stations);
+		break;
+	}
+
+	return res;
+}
+
+
 static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
 					char *argv[])
 {
@@ -402,6 +351,21 @@
 }
 
 
+static char ** hostapd_complete_disassociate(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&stations);
+		break;
+	}
+
+	return res;
+}
+
+
 #ifdef CONFIG_IEEE80211W
 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
 				    char *argv[])
@@ -774,15 +738,30 @@
 
 static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	printf("%s", commands_help);
+	print_help(stdout, argc > 0 ? argv[0] : NULL);
 	return 0;
 }
 
 
+static char ** hostapd_cli_complete_help(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = list_cmd_list();
+		break;
+	}
+
+	return res;
+}
+
+
 static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
-	printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+	printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
 	return 0;
 }
 
@@ -893,6 +872,28 @@
 }
 
 
+static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
+				       struct dl_list *interfaces)
+{
+	struct dirent *dent;
+	DIR *dir;
+
+	if (!ctrl || !interfaces)
+		return;
+	dir = opendir(ctrl_iface_dir);
+	if (dir == NULL)
+		return;
+
+	while ((dent = readdir(dir))) {
+		if (strcmp(dent->d_name, ".") == 0 ||
+		    strcmp(dent->d_name, "..") == 0)
+			continue;
+		cli_txt_list_add(interfaces, dent->d_name);
+	}
+	closedir(dir);
+}
+
+
 static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
 {
 	struct dirent *dent;
@@ -934,6 +935,7 @@
 		printf("Connected to interface '%s.\n", ctrl_ifname);
 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
 			hostapd_cli_attached = 1;
+			register_event_handler(ctrl_conn);
 		} else {
 			printf("Warning: Failed to attach to "
 			       "hostapd.\n");
@@ -946,6 +948,24 @@
 }
 
 
+static char ** hostapd_complete_interface(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+	DEFINE_DL_LIST(interfaces);
+
+	switch (arg) {
+	case 1:
+		hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
+		res = cli_txt_list_array(&interfaces);
+		cli_txt_list_flush(&interfaces);
+		break;
+	}
+
+	return res;
+}
+
+
 static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	char cmd[256];
@@ -1228,73 +1248,135 @@
 struct hostapd_cli_cmd {
 	const char *cmd;
 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+	char ** (*completion)(const char *str, int pos);
+	const char *usage;
 };
 
 static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
-	{ "ping", hostapd_cli_cmd_ping },
-	{ "mib", hostapd_cli_cmd_mib },
-	{ "relog", hostapd_cli_cmd_relog },
-	{ "status", hostapd_cli_cmd_status },
-	{ "sta", hostapd_cli_cmd_sta },
-	{ "all_sta", hostapd_cli_cmd_all_sta },
-	{ "new_sta", hostapd_cli_cmd_new_sta },
-	{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
-	{ "disassociate", hostapd_cli_cmd_disassociate },
+	{ "ping", hostapd_cli_cmd_ping, NULL,
+	  "= pings hostapd" },
+	{ "mib", hostapd_cli_cmd_mib, NULL,
+	  "= get MIB variables (dot1x, dot11, radius)" },
+	{ "relog", hostapd_cli_cmd_relog, NULL, NULL },
+	{ "status", hostapd_cli_cmd_status, NULL, NULL },
+	{ "sta", hostapd_cli_cmd_sta, NULL,
+	  "<addr> = get MIB variables for one station" },
+	{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
+	   "= get MIB variables for all stations" },
+	{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
+	  "<addr> = add a new station" },
+	{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
+	  hostapd_complete_deauthenticate,
+	  "<addr> = deauthenticate a station" },
+	{ "disassociate", hostapd_cli_cmd_disassociate,
+	  hostapd_complete_disassociate,
+	  "<addr> = disassociate a station" },
 #ifdef CONFIG_IEEE80211W
-	{ "sa_query", hostapd_cli_cmd_sa_query },
+	{ "sa_query", hostapd_cli_cmd_sa_query, NULL,
+	  "<addr> = send SA Query to a station" },
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
-	{ "wps_pin", hostapd_cli_cmd_wps_pin },
-	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
-	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
-	{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
+	{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
+	  "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
+	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
+	  "<PIN> = verify PIN checksum" },
+	{ "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
+	  "= indicate button pushed to initiate PBC" },
+	{ "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
+	  "= cancel the pending WPS operation" },
 #ifdef CONFIG_WPS_NFC
-	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
-	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
-	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
-	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
+	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
+	  "<hexdump> = report read NFC tag with WPS data" },
+	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
+	  "<WPS/NDEF> = build NFC configuration token" },
+	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
+	  "<WPS/NDEF/enable/disable> = manager NFC password token" },
+	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
+	  NULL },
 #endif /* CONFIG_WPS_NFC */
-	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
-	{ "wps_config", hostapd_cli_cmd_wps_config },
-	{ "wps_get_status", hostapd_cli_cmd_wps_get_status },
+	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
+	  "<cmd> [params..] = enable/disable AP PIN" },
+	{ "wps_config", hostapd_cli_cmd_wps_config, NULL,
+	  "<SSID> <auth> <encr> <key> = configure AP" },
+	{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
+	  "= show current WPS status" },
 #endif /* CONFIG_WPS */
-	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
-	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
-	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
-	{ "get_config", hostapd_cli_cmd_get_config },
-	{ "help", hostapd_cli_cmd_help },
-	{ "interface", hostapd_cli_cmd_interface },
+	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
+	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
+	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
+	{ "get_config", hostapd_cli_cmd_get_config, NULL,
+	  "= show current configuration" },
+	{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
+	  "= show this usage help" },
+	{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
+	  "[ifname] = show interfaces/select interface" },
 #ifdef CONFIG_FST
-	{ "fst", hostapd_cli_cmd_fst },
+	{ "fst", hostapd_cli_cmd_fst, NULL, NULL },
 #endif /* CONFIG_FST */
-	{ "raw", hostapd_cli_cmd_raw },
-	{ "level", hostapd_cli_cmd_level },
-	{ "license", hostapd_cli_cmd_license },
-	{ "quit", hostapd_cli_cmd_quit },
-	{ "set", hostapd_cli_cmd_set },
-	{ "get", hostapd_cli_cmd_get },
-	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
-	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
-	{ "chan_switch", hostapd_cli_cmd_chan_switch },
-	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
-	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
-	{ "vendor", hostapd_cli_cmd_vendor },
-	{ "enable", hostapd_cli_cmd_enable },
-	{ "reload", hostapd_cli_cmd_reload },
-	{ "disable", hostapd_cli_cmd_disable },
-	{ "erp_flush", hostapd_cli_cmd_erp_flush },
-	{ "log_level", hostapd_cli_cmd_log_level },
-	{ "pmksa", hostapd_cli_cmd_pmksa },
-	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush },
-	{ "set_neighbor", hostapd_cli_cmd_set_neighbor },
-	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor },
-	{ "req_lci", hostapd_cli_cmd_req_lci },
-	{ "req_range", hostapd_cli_cmd_req_range },
-	{ "driver_flags", hostapd_cli_cmd_driver_flags },
-	{ NULL, NULL }
+	{ "raw", hostapd_cli_cmd_raw, NULL, NULL },
+	{ "level", hostapd_cli_cmd_level, NULL,
+	  "<debug level> = change debug level" },
+	{ "license", hostapd_cli_cmd_license, NULL,
+	  "= show full hostapd_cli license" },
+	{ "quit", hostapd_cli_cmd_quit, NULL,
+	  "= exit hostapd_cli" },
+	{ "set", hostapd_cli_cmd_set, NULL, NULL },
+	{ "get", hostapd_cli_cmd_get, NULL, NULL },
+	{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
+	{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
+	{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
+	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
+	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
+	{ "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
+	{ "enable", hostapd_cli_cmd_enable, NULL, NULL },
+	{ "reload", hostapd_cli_cmd_reload, NULL, NULL },
+	{ "disable", hostapd_cli_cmd_disable, NULL, NULL },
+	{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
+	{ "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
+	{ "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
+	{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
+	{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
+	{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
+	{ "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
+	{ "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
+	{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
+	{ NULL, NULL, NULL, NULL }
 };
 
 
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
+			   const char *pad)
+{
+	char c;
+	size_t n;
+
+	if (cmd->usage == NULL)
+		return;
+	fprintf(stream, "%s%s ", pad, cmd->cmd);
+	for (n = 0; (c = cmd->usage[n]); n++) {
+		fprintf(stream, "%c", c);
+		if (c == '\n')
+			fprintf(stream, "%s", pad);
+	}
+	fprintf(stream, "\n");
+}
+
+
+static void print_help(FILE *stream, const char *cmd)
+{
+	int n;
+
+	fprintf(stream, "commands:\n");
+	for (n = 0; hostapd_cli_commands[n].cmd; n++) {
+		if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
+			print_cmd_help(stream, &hostapd_cli_commands[n], "  ");
+	}
+}
+
+
 static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	const struct hostapd_cli_cmd *cmd, *match = NULL;
@@ -1334,6 +1416,34 @@
 }
 
 
+static void cli_event(const char *str)
+{
+	const char *start, *s;
+
+	start = os_strchr(str, '>');
+	if (start == NULL)
+		return;
+
+	start++;
+
+	if (str_starts(start, AP_STA_CONNECTED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_add(&stations, s + 1);
+		return;
+	}
+
+	if (str_starts(start, AP_STA_DISCONNECTED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_del_addr(&stations, s + 1);
+		return;
+	}
+}
+
+
 static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
 				     int action_monitor)
 {
@@ -1348,6 +1458,7 @@
 			if (action_monitor)
 				hostapd_cli_action_process(buf, len);
 			else {
+				cli_event(buf);
 				if (in_read && first)
 					printf("\n");
 				first = 0;
@@ -1361,35 +1472,9 @@
 }
 
 
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
 {
-	char *pos;
-	int argc = 0;
-
-	pos = cmd;
-	for (;;) {
-		while (*pos == ' ')
-			pos++;
-		if (*pos == '\0')
-			break;
-		argv[argc] = pos;
-		argc++;
-		if (argc == max_args)
-			break;
-		if (*pos == '"') {
-			char *pos2 = os_strrchr(pos, '"');
-			if (pos2)
-				pos = pos2 + 1;
-		}
-		while (*pos != '\0' && *pos != ' ')
-			pos++;
-		if (*pos == ' ')
-			*pos++ = '\0';
-	}
-
-	return argc;
+	hostapd_cli_recv_pending(ctrl_conn, 0, 0);
 }
 
 
@@ -1405,6 +1490,7 @@
 			printf("Connection to hostapd re-established\n");
 			if (wpa_ctrl_attach(ctrl_conn) == 0) {
 				hostapd_cli_attached = 1;
+				register_event_handler(ctrl_conn);
 			} else {
 				printf("Warning: Failed to attach to "
 				       "hostapd.\n");
@@ -1439,17 +1525,82 @@
 }
 
 
+static char ** list_cmd_list(void)
+{
+	char **res;
+	int i, count;
+
+	count = ARRAY_SIZE(hostapd_cli_commands);
+	res = os_calloc(count + 1, sizeof(char *));
+	if (res == NULL)
+		return NULL;
+
+	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+		res[i] = os_strdup(hostapd_cli_commands[i].cmd);
+		if (res[i] == NULL)
+			break;
+	}
+
+	return res;
+}
+
+
+static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
+				      int pos)
+{
+	int i;
+
+	for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+		if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
+			continue;
+		if (hostapd_cli_commands[i].completion)
+			return hostapd_cli_commands[i].completion(str, pos);
+		if (!hostapd_cli_commands[i].usage)
+			return NULL;
+		edit_clear_line();
+		printf("\r%s\n", hostapd_cli_commands[i].usage);
+		edit_redraw();
+		break;
+	}
+
+	return NULL;
+}
+
+
+static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
+					      int pos)
+{
+	char **res;
+	const char *end;
+	char *cmd;
+
+	end = os_strchr(str, ' ');
+	if (end == NULL || str + pos < end)
+		return list_cmd_list();
+
+	cmd = os_malloc(pos + 1);
+	if (cmd == NULL)
+		return NULL;
+	os_memcpy(cmd, str, pos);
+	cmd[end - str] = '\0';
+	res = hostapd_cli_cmd_completion(cmd, str, pos);
+	os_free(cmd);
+	return res;
+}
+
+
 static void hostapd_cli_interactive(void)
 {
 	printf("\nInteractive mode\n\n");
 
 	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
 	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
-		  NULL, NULL, NULL, NULL);
+		  hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
 	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
 
 	eloop_run();
 
+	cli_txt_list_flush(&stations);
 	edit_deinit(NULL, NULL);
 	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
 }
@@ -1553,8 +1704,7 @@
 	interactive = (argc == optind) && (action_file == NULL);
 
 	if (interactive) {
-		printf("%s\n\n%s\n\n", hostapd_cli_version,
-		       hostapd_cli_license);
+		printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
 	}
 
 	if (eloop_init())
@@ -1602,6 +1752,7 @@
 	if (interactive || action_file) {
 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
 			hostapd_cli_attached = 1;
+			register_event_handler(ctrl_conn);
 		} else {
 			printf("Warning: Failed to attach to hostapd.\n");
 			if (action_file)
@@ -1619,6 +1770,7 @@
 	else
 		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
 
+	unregister_event_handler(ctrl_conn);
 	os_free(ctrl_ifname);
 	eloop_destroy();
 	hostapd_cli_cleanup();
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 2345dd9..228de2b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -841,6 +841,15 @@
 	}
 #endif /* CONFIG_IEEE80211N */
 
+#ifdef CONFIG_IEEE80211AC
+	if (full_config && conf->ieee80211ac &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11ac = 1;
+		wpa_printf(MSG_ERROR,
+			   "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
+	}
+#endif /* CONFIG_IEEE80211AC */
+
 #ifdef CONFIG_WPS
 	if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
 		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 0ae9a6e..64daf4c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -263,6 +263,7 @@
 	int radius_das_port;
 	unsigned int radius_das_time_window;
 	int radius_das_require_event_timestamp;
+	int radius_das_require_message_authenticator;
 	struct hostapd_ip_addr radius_das_client_addr;
 	u8 *radius_das_shared_secret;
 	size_t radius_das_shared_secret_len;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 14c154f..17a3ea4 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -514,20 +514,28 @@
 			  "channel=%u\n"
 			  "secondary_channel=%d\n"
 			  "ieee80211n=%d\n"
-			  "ieee80211ac=%d\n"
-			  "vht_oper_chwidth=%d\n"
-			  "vht_oper_centr_freq_seg0_idx=%d\n"
-			  "vht_oper_centr_freq_seg1_idx=%d\n",
+			  "ieee80211ac=%d\n",
 			  iface->conf->channel,
-			  iface->conf->secondary_channel,
-			  iface->conf->ieee80211n,
-			  iface->conf->ieee80211ac,
-			  iface->conf->vht_oper_chwidth,
-			  iface->conf->vht_oper_centr_freq_seg0_idx,
-			  iface->conf->vht_oper_centr_freq_seg1_idx);
+			  iface->conf->ieee80211n && !hapd->conf->disable_11n ?
+			  iface->conf->secondary_channel : 0,
+			  iface->conf->ieee80211n && !hapd->conf->disable_11n,
+			  iface->conf->ieee80211ac &&
+			  !hapd->conf->disable_11ac);
 	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
+	if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "vht_oper_chwidth=%d\n"
+				  "vht_oper_centr_freq_seg0_idx=%d\n"
+				  "vht_oper_centr_freq_seg1_idx=%d\n",
+				  iface->conf->vht_oper_chwidth,
+				  iface->conf->vht_oper_centr_freq_seg0_idx,
+				  iface->conf->vht_oper_centr_freq_seg1_idx);
+		if (os_snprintf_error(buflen - len, ret))
+			return len;
+		len += ret;
+	}
 
 	for (i = 0; i < iface->num_bss; i++) {
 		struct hostapd_data *bss = iface->bss[i];
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 30f57f4..65f513d 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1044,6 +1044,8 @@
 		das_conf.time_window = conf->radius_das_time_window;
 		das_conf.require_event_timestamp =
 			conf->radius_das_require_event_timestamp;
+		das_conf.require_message_authenticator =
+			conf->radius_das_require_message_authenticator;
 		das_conf.ctx = hapd;
 		das_conf.disconnect = hostapd_das_disconnect;
 		hapd->radius_das = radius_das_init(&das_conf);
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 07672ce..2556da3 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -381,6 +381,7 @@
 	struct sockaddr_in *paddr, uaddr;
 	struct iapp_data *iapp;
 	struct ip_mreqn mreq;
+	int reuseaddr = 1;
 
 	iapp = os_zalloc(sizeof(*iapp));
 	if (iapp == NULL)
@@ -443,6 +444,18 @@
 	os_memset(&uaddr, 0, sizeof(uaddr));
 	uaddr.sin_family = AF_INET;
 	uaddr.sin_port = htons(IAPP_UDP_PORT);
+
+	if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+		       sizeof(reuseaddr)) < 0) {
+		wpa_printf(MSG_INFO,
+			   "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
+			   strerror(errno));
+		/*
+		 * Ignore this and try to continue. This is fine for single
+		 * BSS cases, but may fail if multiple BSSes enable IAPP.
+		 */
+	}
+
 	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
 		 sizeof(uaddr)) < 0) {
 		wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 11f12f9..eed5483 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2557,8 +2557,9 @@
 		       "handle_action - unknown action category %d or invalid "
 		       "frame",
 		       mgmt->u.action.category);
-	if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
-	    !(mgmt->sa[0] & 0x01)) {
+	if (!is_multicast_ether_addr(mgmt->da) &&
+	    !(mgmt->u.action.category & 0x80) &&
+	    !is_multicast_ether_addr(mgmt->sa)) {
 		struct ieee80211_mgmt *resp;
 
 		/*
@@ -2605,7 +2606,6 @@
 		    struct hostapd_frame_info *fi)
 {
 	struct ieee80211_mgmt *mgmt;
-	int broadcast;
 	u16 fc, stype;
 	int ret = 0;
 
@@ -2621,11 +2621,7 @@
 		return 1;
 	}
 
-	broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
-		mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
-		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
-
-	if (!broadcast &&
+	if (!is_broadcast_ether_addr(mgmt->bssid) &&
 #ifdef CONFIG_P2P
 	    /* Invitation responses can be sent with the peer MAC as BSSID */
 	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
@@ -2906,7 +2902,7 @@
 			     size_t len, int ok)
 {
 	struct sta_info *sta;
-	if (mgmt->da[0] & 0x01)
+	if (is_multicast_ether_addr(mgmt->da))
 		return;
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
@@ -2930,7 +2926,7 @@
 			       size_t len, int ok)
 {
 	struct sta_info *sta;
-	if (mgmt->da[0] & 0x01)
+	if (is_multicast_ether_addr(mgmt->da))
 		return;
 	sta = ap_get_sta(hapd, mgmt->da);
 	if (!sta) {
@@ -3135,7 +3131,7 @@
 
 	wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
 		   MACSTR, MAC2STR(src));
-	if (src[0] & 0x01) {
+	if (is_multicast_ether_addr(src)) {
 		/* Broadcast bit set in SA?! Ignore the frame silently. */
 		return;
 	}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 42b0299..80ff996 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -414,6 +414,7 @@
 
 	if (!hostapd_config_get_radius_attr(req_attr,
 					    RADIUS_ATTR_NAS_PORT) &&
+	    sta->aid > 0 &&
 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
 		wpa_printf(MSG_ERROR, "Could not add NAS-Port");
 		return -1;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index faf38c9..95b40da 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -269,12 +269,6 @@
 }
 
 
-static int str_starts(const char *str, const char *start)
-{
-	return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
 static void wps_reload_config(void *eloop_data, void *user_ctx)
 {
 	struct hostapd_iface *iface = eloop_data;
diff --git a/src/common/cli.c b/src/common/cli.c
new file mode 100644
index 0000000..b583d1c
--- /dev/null
+++ b/src/common/cli.c
@@ -0,0 +1,267 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functions
+ * Copyright (c) 2004-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 "common/cli.h"
+
+
+const char *const cli_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
+
+const char *const cli_full_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+"   notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+"   notice, this list of conditions and the following disclaimer in the\n"
+"   documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+"   names of its contributors may be used to endorse or promote products\n"
+"   derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+
+void cli_txt_list_free(struct cli_txt_entry *e)
+{
+	dl_list_del(&e->list);
+	os_free(e->txt);
+	os_free(e);
+}
+
+
+void cli_txt_list_flush(struct dl_list *list)
+{
+	struct cli_txt_entry *e;
+
+	while ((e = dl_list_first(list, struct cli_txt_entry, list)))
+		cli_txt_list_free(e);
+}
+
+
+struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
+					const char *txt)
+{
+	struct cli_txt_entry *e;
+
+	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+		if (os_strcmp(e->txt, txt) == 0)
+			return e;
+	}
+	return NULL;
+}
+
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
+{
+	struct cli_txt_entry *e;
+
+	e = cli_txt_list_get(txt_list, txt);
+	if (e)
+		cli_txt_list_free(e);
+}
+
+
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
+{
+	u8 addr[ETH_ALEN];
+	char buf[18];
+
+	if (hwaddr_aton(txt, addr) < 0)
+		return;
+	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	cli_txt_list_del(txt_list, buf);
+}
+
+
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+			   int separator)
+{
+	const char *end;
+	char *buf;
+
+	end = os_strchr(txt, separator);
+	if (end == NULL)
+		end = txt + os_strlen(txt);
+	buf = dup_binstr(txt, end - txt);
+	if (buf == NULL)
+		return;
+	cli_txt_list_del(txt_list, buf);
+	os_free(buf);
+}
+
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
+{
+	struct cli_txt_entry *e;
+
+	e = cli_txt_list_get(txt_list, txt);
+	if (e)
+		return 0;
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL)
+		return -1;
+	e->txt = os_strdup(txt);
+	if (e->txt == NULL) {
+		os_free(e);
+		return -1;
+	}
+	dl_list_add(txt_list, &e->list);
+	return 0;
+}
+
+
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
+{
+	u8 addr[ETH_ALEN];
+	char buf[18];
+
+	if (hwaddr_aton(txt, addr) < 0)
+		return -1;
+	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	return cli_txt_list_add(txt_list, buf);
+}
+
+
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+			  int separator)
+{
+	const char *end;
+	char *buf;
+	int ret;
+
+	end = os_strchr(txt, separator);
+	if (end == NULL)
+		end = txt + os_strlen(txt);
+	buf = dup_binstr(txt, end - txt);
+	if (buf == NULL)
+		return -1;
+	ret = cli_txt_list_add(txt_list, buf);
+	os_free(buf);
+	return ret;
+}
+
+
+char ** cli_txt_list_array(struct dl_list *txt_list)
+{
+	unsigned int i, count = dl_list_len(txt_list);
+	char **res;
+	struct cli_txt_entry *e;
+
+	res = os_calloc(count + 1, sizeof(char *));
+	if (res == NULL)
+		return NULL;
+
+	i = 0;
+	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+		res[i] = os_strdup(e->txt);
+		if (res[i] == NULL)
+			break;
+		i++;
+	}
+
+	return res;
+}
+
+
+int get_cmd_arg_num(const char *str, int pos)
+{
+	int arg = 0, i;
+
+	for (i = 0; i <= pos; i++) {
+		if (str[i] != ' ') {
+			arg++;
+			while (i <= pos && str[i] != ' ')
+				i++;
+		}
+	}
+
+	if (arg > 0)
+		arg--;
+	return arg;
+}
+
+
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[])
+{
+	int i, res;
+	char *pos, *end;
+
+	pos = buf;
+	end = buf + buflen;
+
+	res = os_snprintf(pos, end - pos, "%s", cmd);
+	if (os_snprintf_error(end - pos, res))
+		goto fail;
+	pos += res;
+
+	for (i = 0; i < argc; i++) {
+		res = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (os_snprintf_error(end - pos, res))
+			goto fail;
+		pos += res;
+	}
+
+	buf[buflen - 1] = '\0';
+	return 0;
+
+fail:
+	printf("Too long command\n");
+	return -1;
+}
+
+
+int tokenize_cmd(char *cmd, char *argv[])
+{
+	char *pos;
+	int argc = 0;
+
+	pos = cmd;
+	for (;;) {
+		while (*pos == ' ')
+			pos++;
+		if (*pos == '\0')
+			break;
+		argv[argc] = pos;
+		argc++;
+		if (argc == max_args)
+			break;
+		if (*pos == '"') {
+			char *pos2 = os_strrchr(pos, '"');
+			if (pos2)
+				pos = pos2 + 1;
+		}
+		while (*pos != '\0' && *pos != ' ')
+			pos++;
+		if (*pos == ' ')
+			*pos++ = '\0';
+	}
+
+	return argc;
+}
diff --git a/src/common/cli.h b/src/common/cli.h
new file mode 100644
index 0000000..41ef329
--- /dev/null
+++ b/src/common/cli.h
@@ -0,0 +1,47 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functionality
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CLI_H
+#define CLI_H
+
+#include "utils/list.h"
+
+extern const char *const cli_license;
+extern const char *const cli_full_license;
+
+struct cli_txt_entry {
+	struct dl_list list;
+	char *txt;
+};
+
+void cli_txt_list_free(struct cli_txt_entry *e);
+void cli_txt_list_flush(struct dl_list *list);
+
+struct cli_txt_entry *
+cli_txt_list_get(struct dl_list *txt_list, const char *txt);
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+			   int separator);
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+			  int separator);
+
+char ** cli_txt_list_array(struct dl_list *txt_list);
+
+int get_cmd_arg_num(const char *str, int pos);
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+	      char *argv[]);
+
+#define max_args 10
+int tokenize_cmd(char *cmd, char *argv[]);
+
+#endif /* CLI_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 912d1e1..2312b22 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -115,6 +115,15 @@
  *	indicated through an event using the same sub command through
  *	@QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are
  *	listed in qca_wlan_vendor_attr_sap_conditional_chan_switch.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND: Set GPIO pins. This uses the
+ *	attributes defined in enum qca_wlan_gpio_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY: Fetch hardware capabilities.
+ *	This uses @QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY to indicate which
+ *	capabilities are to be fetched and other
+ *	enum qca_wlan_vendor_attr_get_hw_capability attributes to return the
+ *	requested capabilities.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -200,6 +209,8 @@
 	QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122,
 	QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123,
 	QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124,
+	QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND = 125,
+	QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY = 126,
 };
 
 
@@ -417,6 +428,25 @@
 };
 
 /**
+ * enum qca_access_policy - Access control policy
+ *
+ * Access control policy is applied on the configured IE
+ * (QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE).
+ * To be set with QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY.
+ *
+ * @QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: Deny Wi-Fi connections which match
+ *	the specific configuration (IE) set, i.e., allow all the
+ *	connections which do not match the configuration.
+ * @QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: Accept Wi-Fi connections which match
+ *	the specific configuration (IE) set, i.e., deny all the
+ *	connections which do not match the configuration.
+ */
+enum qca_access_policy {
+	QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED,
+	QCA_ACCESS_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
  * enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture
  * @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32)
  * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value
@@ -603,8 +633,8 @@
 };
 
 /* Attributes for data used by
- * QCA_NL80211_VENDOR_SUBCMD_SET_CONFIGURATION and
- * QCA_NL80211_VENDOR_SUBCMD_GET_CONFIGURATION subcommands.
+ * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION subcommands.
  */
 enum qca_wlan_vendor_attr_config {
 	QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID,
@@ -668,6 +698,45 @@
 	 * packet count. The peer is disconnected once this threshold is
 	 * reached. */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT,
+	/* Attribute used to set scan default IEs to the driver.
+	 *
+	 * These IEs can be used by scan operations that will be initiated by
+	 * the driver/firmware.
+	 *
+	 * For further scan requests coming to the driver, these IEs should be
+	 * merged with the IEs received along with scan request coming to the
+	 * driver. If a particular IE is present in the scan default IEs but not
+	 * present in the scan request, then that IE should be added to the IEs
+	 * sent in the Probe Request frames for that scan request. */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES,
+	/* Unsigned 32-bit attribute for generic commands */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND,
+	/* Unsigned 32-bit value attribute for generic commands */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE,
+	/* Unsigned 32-bit data attribute for generic command response */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA,
+	/* Unsigned 32-bit length attribute for
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH,
+	/* Unsigned 32-bit flags attribute for
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS,
+	/* Unsigned 32-bit, defining the access policy.
+	 * See enum qca_access_policy. Used with
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY,
+	/* Sets the list of full set of IEs for which a specific access policy
+	 * has to be applied. Used along with
+	 * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access.
+	 * Zero length payload can be used to clear this access constraint. */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST,
+	/* Unsigned 32-bit, specifies the interface index (netdev) for which the
+	 * corresponding configurations are applied. If the interface index is
+	 * not specified, the configurations are attributed to the respective
+	 * wiphy. */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX,
+	/* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */
+	QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER,
 
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
@@ -713,4 +782,54 @@
 	QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ */
+enum qca_wlan_gpio_attr {
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0,
+	/* Unsigned 32-bit attribute for GPIO command */
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND,
+	/* Unsigned 32-bit attribute for GPIO PIN number to configure */
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+	/* Unsigned 32-bit attribute for GPIO value to configure */
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+	/* Unsigned 32-bit attribute for GPIO pull type */
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+	/* Unsigned 32-bit attribute for GPIO interrupt mode */
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX =
+	QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
+ */
+enum qca_wlan_vendor_attr_get_hw_capability {
+	QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_INVALID,
+	/* Antenna isolation
+	 * An attribute used in the response.
+	 * The content of this attribute is encoded in a byte array. Each byte
+	 * value is an antenna isolation value. The array length is the number
+	 * of antennas.
+	 */
+	QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION,
+	/* Request HW capability
+	 * An attribute used in the request.
+	 * The content of this attribute is a u32 array for one or more of
+	 * hardware capabilities (attribute IDs) that are being requested. Each
+	 * u32 value has a value from this
+	 * enum qca_wlan_vendor_attr_get_hw_capability
+	 * identifying which capabilities are requested.
+	 */
+	QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_MAX =
+	QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST - 1,
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 7f33686..19e0e2b 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -49,6 +49,8 @@
 
 static void HMAC_CTX_free(HMAC_CTX *ctx)
 {
+	if (!ctx)
+		return;
 	HMAC_CTX_cleanup(ctx);
 	bin_clear_free(ctx, sizeof(*ctx));
 }
@@ -67,6 +69,9 @@
 
 static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
 {
+	if (!ctx)
+		return;
+	EVP_MD_CTX_cleanup(ctx);
 	bin_clear_free(ctx, sizeof(*ctx));
 }
 
@@ -74,7 +79,11 @@
 
 static BIGNUM * get_group5_prime(void)
 {
-#ifdef OPENSSL_IS_BORINGSSL
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+	return BN_get_rfc3526_prime_1536(NULL);
+#elif !defined(OPENSSL_IS_BORINGSSL)
+	return get_rfc3526_prime_1536(NULL);
+#else
 	static const unsigned char RFC3526_PRIME_1536[] = {
 		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
 		0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -94,9 +103,7 @@
 		0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
 	};
         return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
-#else /* OPENSSL_IS_BORINGSSL */
-	return get_rfc3526_prime_1536(NULL);
-#endif /* OPENSSL_IS_BORINGSSL */
+#endif
 }
 
 #ifdef OPENSSL_NO_SHA256
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a85ed32..a5c5c1b 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1118,13 +1118,19 @@
 };
 
 struct wpa_driver_mesh_bss_params {
-#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS	0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS		0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT	0x00000002
+#define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS	0x00000004
+#define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE		0x00000008
 	/*
 	 * TODO: Other mesh configuration parameters would go here.
 	 * See NL80211_MESHCONF_* for all the mesh config parameters.
 	 */
 	unsigned int flags;
+	int auto_plinks;
 	int peer_link_timeout;
+	int max_peer_links;
+	u16 ht_opmode;
 };
 
 struct wpa_driver_mesh_join_params {
@@ -1136,7 +1142,6 @@
 	struct hostapd_freq_params freq;
 	int beacon_int;
 	int dtim_period;
-	int max_peer_links;
 	struct wpa_driver_mesh_bss_params conf;
 #define WPA_DRIVER_MESH_FLAG_USER_MPM	0x00000001
 #define WPA_DRIVER_MESH_FLAG_DRIVER_MPM	0x00000002
@@ -3603,6 +3608,23 @@
 	 * Returns: 0 on success or -1 on failure
 	 */
 	int (*p2p_lo_stop)(void *priv);
+
+	/**
+	 * set_default_scan_ies - Set default scan IEs
+	 * @priv: Private driver interface data
+	 * @ies: Scan default IEs buffer
+	 * @ies_len: Length of IEs in bytes
+	 * Returns: 0 on success or -1 on failure
+	 *
+	 * The driver can use these by default when there are no scan IEs coming
+	 * in the subsequent scan requests. Also in case of one or more of IEs
+	 * given in set_default_scan_ies() are missing in the subsequent scan
+	 * request, the driver should merge the missing scan IEs in the scan
+	 * request from the IEs set by set_default_scan_ies() in the Probe
+	 * Request frames sent.
+	 */
+	int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len);
+
 };
 
 
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index ba3cad0..a88345f 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -868,6 +868,16 @@
 		return;
 	}
 
+	if (stype == WLAN_FC_STYPE_ACTION &&
+	    (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 ||
+	     is_broadcast_ether_addr(mgmt->bssid))) {
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = buf;
+		event.rx_mgmt.frame_len = len;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+		return;
+	}
+
 	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
 		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
 			   __func__);
@@ -889,12 +899,6 @@
 		iebuf = mgmt->u.reassoc_req.variable;
 		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
 		break;
-	case WLAN_FC_STYPE_ACTION:
-		os_memset(&event, 0, sizeof(event));
-		event.rx_mgmt.frame = buf;
-		event.rx_mgmt.frame_len = len;
-		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-		break;
 	case WLAN_FC_STYPE_AUTH:
 		if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
 			break;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ae40f42..8d43c69 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -200,6 +200,10 @@
 
 static int i802_set_iface_flags(struct i802_bss *bss, int up);
 static int nl80211_set_param(void *priv, const char *param);
+#ifdef CONFIG_MESH
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+				   struct wpa_driver_mesh_bss_params *params);
+#endif /* CONFIG_MESH */
 
 
 /* Converts nl80211_chan_width to a common format */
@@ -2332,7 +2336,8 @@
 
 	if (drv->hostapd || bss->static_ap)
 		nlmode = NL80211_IFTYPE_AP;
-	else if (bss->if_dynamic)
+	else if (bss->if_dynamic ||
+		 nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
 		nlmode = nl80211_get_ifmode(bss);
 	else
 		nlmode = NL80211_IFTYPE_STATION;
@@ -3479,6 +3484,37 @@
 }
 
 
+#ifdef CONFIG_MESH
+static int nl80211_set_mesh_config(void *priv,
+				   struct wpa_driver_mesh_bss_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
+	if (!msg)
+		return -1;
+
+	ret = nl80211_put_mesh_config(msg, params);
+	if (ret < 0) {
+		nlmsg_free(msg);
+		return ret;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_ERROR,
+			   "nl80211: Mesh config set failed: %d (%s)",
+			   ret, strerror(-ret));
+		return ret;
+	}
+	return 0;
+}
+#endif /* CONFIG_MESH */
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
 				     struct wpa_driver_ap_params *params)
 {
@@ -3492,6 +3528,9 @@
 	int smps_mode;
 	u32 suites[10], suite;
 	u32 ver;
+#ifdef CONFIG_MESH
+	struct wpa_driver_mesh_bss_params mesh_params;
+#endif /* CONFIG_MESH */
 
 	beacon_set = params->reenable ? 0 : bss->beacon_set;
 
@@ -3586,8 +3625,10 @@
 		goto fail;
 
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
-	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
-	    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+	    (!params->pairwise_ciphers ||
+	     params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
+	    (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
 		goto fail;
 
 	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
@@ -3715,6 +3756,18 @@
 			bss->bandwidth = params->freq->bandwidth;
 		}
 	}
+
+#ifdef CONFIG_MESH
+	if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
+		os_memset(&mesh_params, 0, sizeof(mesh_params));
+		mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+		mesh_params.ht_opmode = params->ht_opmode;
+		ret = nl80211_set_mesh_config(priv, &mesh_params);
+		if (ret < 0)
+			return ret;
+	}
+#endif /* CONFIG_MESH */
+
 	return ret;
 fail:
 	nlmsg_free(msg);
@@ -4381,8 +4434,7 @@
 				   "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
 
 	if (!drv->device_ap_sme && drv->use_monitor &&
-	    nl80211_create_monitor_interface(drv) &&
-	    !drv->device_ap_sme)
+	    nl80211_create_monitor_interface(drv))
 		return -1;
 
 	if (drv->device_ap_sme &&
@@ -4903,6 +4955,14 @@
 	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
 		return -1;
 
+	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+	    (params->pairwise_suite == WPA_CIPHER_NONE ||
+	     params->pairwise_suite == WPA_CIPHER_WEP104 ||
+	     params->pairwise_suite == WPA_CIPHER_WEP40) &&
+	    (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+	     nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+		return -1;
+
 	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
 	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
 		return -1;
@@ -8403,6 +8463,46 @@
 }
 
 
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+				   struct wpa_driver_mesh_bss_params *params)
+{
+	struct nlattr *container;
+
+	container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+	if (!container)
+		return -1;
+
+	if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+	     nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+			 params->auto_plinks)) ||
+	    ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
+	     nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+			 params->max_peer_links)))
+		return -1;
+
+	/*
+	 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+	 * the timer could disconnect stations even in that case.
+	 */
+	if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
+	    nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+			params->peer_link_timeout)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+		return -1;
+	}
+
+	if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
+	    nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
+		return -1;
+	}
+
+	nla_nest_end(msg, container);
+
+	return 0;
+}
+
+
 static int nl80211_join_mesh(struct i802_bss *bss,
 			     struct wpa_driver_mesh_join_params *params)
 {
@@ -8447,29 +8547,12 @@
 		goto fail;
 	nla_nest_end(msg, container);
 
-	container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
-	if (!container)
+	params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+	params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
+	params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
+	if (nl80211_put_mesh_config(msg, &params->conf) < 0)
 		goto fail;
 
-	if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
-	    nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
-		goto fail;
-	if (nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
-			params->max_peer_links))
-		goto fail;
-
-	/*
-	 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
-	 * the timer could disconnect stations even in that case.
-	 */
-	if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
-			params->conf.peer_link_timeout)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
-		goto fail;
-	}
-
-	nla_nest_end(msg, container);
-
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
@@ -9469,6 +9552,7 @@
 	.set_prob_oper_freq = nl80211_set_prob_oper_freq,
 	.p2p_lo_start = nl80211_p2p_lo_start,
 	.p2p_lo_stop = nl80211_p2p_lo_stop,
+	.set_default_scan_ies = nl80211_set_default_scan_ies,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 	.configure_data_frame_filters = nl80211_configure_data_frame_filters,
 	.get_ext_capab = nl80211_get_ext_capab,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 283dfd9..d0ec48c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -159,6 +159,7 @@
 	unsigned int set_prob_oper_freq:1;
 	unsigned int scan_vendor_cmd_avail:1;
 	unsigned int connect_reassoc:1;
+	unsigned int set_wifi_conf_vendor_cmd_avail:1;
 
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
@@ -301,5 +302,6 @@
 int wpa_driver_nl80211_abort_scan(void *priv);
 int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
 				   struct wpa_driver_scan_params *params);
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
 
 #endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 1134886..df10c21 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -709,6 +709,9 @@
 				case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
 					drv->scan_vendor_cmd_avail = 1;
 					break;
+				case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
+					drv->set_wifi_conf_vendor_cmd_avail = 1;
+					break;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 				}
 			}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index c089891..c115b6b 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -1070,4 +1070,54 @@
 	return ret;
 }
 
+
+/**
+ * nl80211_set_default_scan_ies - Set the scan default IEs to the driver
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ies: Pointer to IEs buffer
+ * @ies_len: Length of IEs in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg = NULL;
+	struct nlattr *attr;
+	int ret = -1;
+
+	if (!drv->set_wifi_conf_vendor_cmd_avail)
+		return -1;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
+		goto fail;
+
+	attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+	if (attr == NULL)
+		goto fail;
+
+	wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan default IEs", ies, ies_len);
+	if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES,
+		    ies_len, ies))
+		goto fail;
+
+	nla_nest_end(msg, attr);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_ERROR,
+			   "nl80211: Set scan default IEs failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto fail;
+	}
+
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+
 #endif /* CONFIG_DRIVER_NL80211_QCA */
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index d3e0595..e8a5135 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - roboswitch driver interface
- * Copyright (c) 2008-2009 Jouke Witteveen
+ * Copyright (c) 2008-2012 Jouke Witteveen
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -401,7 +401,9 @@
 		os_free(drv);
 		return NULL;
 	}
-	if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
+	/* BCM63xx devices provide 0 here */
+	if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR &&
+	    if_mii(&drv->ifr)->phy_id != 0) {
 		wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
 			   "RoboSwitch?)", __func__);
 		os_free(drv);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 6980b09..dfc5870 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -98,7 +98,7 @@
 }
 
 
-static int get_mka_param_body_type(const void *body)
+static u8 get_mka_param_body_type(const void *body)
 {
 	const struct ieee802_1x_mka_hdr *hdr = body;
 	return hdr->type;
@@ -532,14 +532,16 @@
 	peer->sak_used = FALSE;
 	os_memcpy(&peer->sci, &participant->current_peer_sci,
 		  sizeof(peer->sci));
-	dl_list_add(&participant->live_peers, &peer->list);
 
 	secy_get_available_receive_sc(participant->kay, &sc_ch);
 
 	rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
-	if (!rxsc)
+	if (!rxsc) {
+		os_free(peer);
 		return NULL;
+	}
 
+	dl_list_add(&participant->live_peers, &peer->list);
 	dl_list_add(&participant->rxsc_list, &rxsc->list);
 	secy_create_receive_sc(participant->kay, rxsc);
 
@@ -602,6 +604,11 @@
 			break;
 	}
 
+	rxsc = ieee802_1x_kay_init_receive_sc(&participant->current_peer_sci,
+					      sc_ch);
+	if (!rxsc)
+		return NULL;
+
 	os_memcpy(&peer->sci, &participant->current_peer_sci,
 		  sizeof(peer->sci));
 	peer->mn = mn;
@@ -618,10 +625,6 @@
 
 	secy_get_available_receive_sc(participant->kay, &sc_ch);
 
-	rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
-	if (!rxsc)
-		return NULL;
-
 	dl_list_add(&participant->rxsc_list, &rxsc->list);
 	secy_create_receive_sc(participant->kay, rxsc);
 
@@ -916,7 +919,7 @@
 	struct ieee802_1x_mka_hdr *hdr;
 	size_t body_len;
 	size_t left_len;
-	int body_type;
+	u8 body_type;
 	u32 peer_mn;
 	be32 _peer_mn;
 	const u8 *peer_mi;
@@ -997,6 +1000,12 @@
 
 	hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
 	body_len = get_mka_param_body_len(hdr);
+	if (body_len % 16 != 0) {
+		wpa_printf(MSG_ERROR,
+			   "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+			   body_len);
+		return -1;
+	}
 
 	for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
 		peer_mi = MKA_HDR_LEN + peer_msg + i;
@@ -1051,6 +1060,12 @@
 
 	hdr = (struct ieee802_1x_mka_hdr *) peer_msg;
 	body_len = get_mka_param_body_len(hdr);
+	if (body_len % 16 != 0) {
+		wpa_printf(MSG_ERROR,
+			   "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+			   body_len);
+		return -1;
+	}
 
 	for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
 		peer_mi = MKA_HDR_LEN + peer_msg + i;
@@ -1154,7 +1169,7 @@
 	u32 pn = 1;
 
 	length = ieee802_1x_mka_get_sak_use_length(participant);
-	body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_sak_use_body));
+	body = wpabuf_put(buf, length);
 
 	body->type = MKA_SAK_USE;
 	set_mka_param_body_len(body, length - MKA_HDR_LEN);
@@ -1759,7 +1774,7 @@
 	struct ieee802_1x_mka_icv_body *body;
 	size_t body_len;
 	size_t left_len;
-	int body_type;
+	u8 body_type;
 	const u8 *pos;
 
 	pos = mka_msg;
@@ -2097,7 +2112,6 @@
 	struct ieee802_1x_kay_peer *key_server = NULL;
 	struct ieee802_1x_kay *kay = participant->kay;
 	Boolean i_is_key_server;
-	int i;
 
 	if (participant->is_obliged_key_server) {
 		participant->new_sak = TRUE;
@@ -2122,11 +2136,9 @@
 			key_server = peer;
 		} else if (peer->key_server_priority ==
 			   key_server->key_server_priority) {
-			for (i = 0; i < 6; i++) {
-				if (peer->sci.addr[i] <
-				    key_server->sci.addr[i])
-					key_server = peer;
-			}
+			if (os_memcmp(peer->sci.addr, key_server->sci.addr,
+				      ETH_ALEN) < 0)
+				key_server = peer;
 		}
 	}
 
@@ -2138,20 +2150,12 @@
 			i_is_key_server = TRUE;
 		} else if (kay->actor_priority
 					== key_server->key_server_priority) {
-			for (i = 0; i < 6; i++) {
-				if (kay->actor_sci.addr[i]
-					< key_server->sci.addr[i]) {
-					i_is_key_server = TRUE;
-				}
-			}
+			if (os_memcmp(kay->actor_sci.addr, key_server->sci.addr,
+				      ETH_ALEN) < 0)
+				i_is_key_server = TRUE;
 		}
-	}
-
-	if (!key_server && !i_is_key_server) {
-		participant->principal = FALSE;
-		participant->is_key_server = FALSE;
-		participant->is_elected = FALSE;
-		return 0;
+	} else if (participant->can_be_key_server) {
+		i_is_key_server = TRUE;
 	}
 
 	if (i_is_key_server) {
@@ -2172,9 +2176,7 @@
 		os_memcpy(&kay->key_server_sci, &kay->actor_sci,
 			  sizeof(kay->key_server_sci));
 		kay->key_server_priority = kay->actor_priority;
-	}
-
-	if (key_server) {
+	} else if (key_server) {
 		ieee802_1x_cp_set_electedself(kay->cp, FALSE);
 		if (os_memcmp(&kay->key_server_sci, &key_server->sci,
 			      sizeof(kay->key_server_sci))) {
@@ -2189,6 +2191,10 @@
 		os_memcpy(&kay->key_server_sci, &key_server->sci,
 			  sizeof(kay->key_server_sci));
 		kay->key_server_priority = key_server->key_server_priority;
+	} else {
+		participant->principal = FALSE;
+		participant->is_key_server = FALSE;
+		participant->is_elected = FALSE;
 	}
 
 	return 0;
@@ -2983,7 +2989,7 @@
 	struct ieee802_1x_mka_hdr *hdr;
 	size_t body_len;
 	size_t left_len;
-	int body_type;
+	u8 body_type;
 	int i;
 	const u8 *pos;
 	Boolean my_included;
@@ -3024,9 +3030,12 @@
 		}
 		if (ieee802_1x_kay_is_in_potential_peer(
 			    participant, participant->current_peer_id.mi)) {
-			ieee802_1x_kay_move_live_peer(
-				participant, participant->current_peer_id.mi,
-				be_to_host32(participant->current_peer_id.mn));
+			if (!ieee802_1x_kay_move_live_peer(
+				    participant,
+				    participant->current_peer_id.mi,
+				    be_to_host32(participant->
+						 current_peer_id.mn)))
+				return -1;
 			ieee802_1x_kay_elect_key_server(participant);
 			ieee802_1x_kay_decide_macsec_use(participant);
 		}
@@ -3060,7 +3069,8 @@
 			goto next_para_set;
 
 		handled[body_type] = TRUE;
-		if (mak_body_handler[body_type].body_rx) {
+		if (body_type < ARRAY_SIZE(mak_body_handler) &&
+		    mak_body_handler[body_type].body_rx) {
 			mak_body_handler[body_type].body_rx
 				(participant, pos, left_len);
 		} else {
@@ -3320,7 +3330,7 @@
 	default:
 		participant->is_obliged_key_server = FALSE;
 		participant->can_be_key_server = TRUE;
-		participant->is_key_server = FALSE;
+		participant->is_key_server = TRUE;
 		participant->is_elected = FALSE;
 		break;
 	}
@@ -3428,6 +3438,7 @@
 		return;
 	}
 
+	eloop_cancel_timeout(ieee802_1x_participant_timer, participant, NULL);
 	dl_list_del(&participant->list);
 
 	/* remove live peer */
diff --git a/src/radius/radius.c b/src/radius/radius.c
index defcd92..407e4f8 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -538,7 +538,8 @@
 
 
 int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
-			      size_t secret_len)
+			      size_t secret_len,
+			      int require_message_authenticator)
 {
 	const u8 *addr[4];
 	size_t len[4];
@@ -577,7 +578,11 @@
 	}
 
 	if (attr == NULL) {
-		/* Message-Authenticator is MAY; not required */
+		if (require_message_authenticator) {
+			wpa_printf(MSG_WARNING,
+				   "Missing Message-Authenticator attribute in RADIUS message");
+			return 1;
+		}
 		return 0;
 	}
 
diff --git a/src/radius/radius.h b/src/radius/radius.h
index cba2b91..cd510d2 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -242,7 +242,8 @@
 int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
 			       size_t secret_len);
 int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
-			       size_t secret_len);
+			      size_t secret_len,
+			      int require_message_authenticator);
 struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
 					     const u8 *data, size_t data_len);
 struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index b7d991b..8a3d7e0 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -23,6 +23,7 @@
 	struct hostapd_ip_addr client_addr;
 	unsigned int time_window;
 	int require_event_timestamp;
+	int require_message_authenticator;
 	void *ctx;
 	enum radius_das_res (*disconnect)(void *ctx,
 					  struct radius_das_attrs *attr);
@@ -234,9 +235,11 @@
 		radius_msg_dump(msg);
 
 	if (radius_msg_verify_das_req(msg, das->shared_secret,
-				       das->shared_secret_len)) {
-		wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
-			   "from %s:%d - drop", abuf, from_port);
+				       das->shared_secret_len,
+				       das->require_message_authenticator)) {
+		wpa_printf(MSG_DEBUG,
+			   "DAS: Invalid authenticator or Message-Authenticator in packet from %s:%d - drop",
+			   abuf, from_port);
 		goto fail;
 	}
 
@@ -362,6 +365,8 @@
 
 	das->time_window = conf->time_window;
 	das->require_event_timestamp = conf->require_event_timestamp;
+	das->require_message_authenticator =
+		conf->require_message_authenticator;
 	das->ctx = conf->ctx;
 	das->disconnect = conf->disconnect;
 
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index ce731d4..9863fdc 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -44,6 +44,7 @@
 	const struct hostapd_ip_addr *client_addr;
 	unsigned int time_window;
 	int require_event_timestamp;
+	int require_message_authenticator;
 	void *ctx;
 	enum radius_das_res (*disconnect)(void *ctx,
 					  struct radius_das_attrs *attr);
diff --git a/src/utils/common.c b/src/utils/common.c
index 9856463..68413b2 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -1194,3 +1194,9 @@
 
 	return ssid->ssid_len ? 0 : -1;
 }
+
+
+int str_starts(const char *str, const char *start)
+{
+	return os_strncmp(str, start, os_strlen(start)) == 0;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 197e4d1..7785677 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -550,6 +550,8 @@
 		     char *outp, size_t out_size);
 int is_ctrl_char(char c);
 
+int str_starts(const char *str, const char *start);
+
 
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 0118d98..65c6fa4 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -435,11 +435,7 @@
 
 int os_file_exists(const char *fname)
 {
-	FILE *f = fopen(fname, "rb");
-	if (f == NULL)
-		return 0;
-	fclose(f);
-	return 1;
+	return access(fname, F_OK) == 0;
 }
 
 
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index 2f1157b..383ed3d 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -11,7 +11,11 @@
  */
 
 #include "includes.h"
+#ifdef __APPLE__
+#include <PCSC/winscard.h>
+#else
 #include <winscard.h>
+#endif
 
 #include "common.h"
 #include "pcsc_funcs.h"
@@ -110,7 +114,11 @@
 struct scard_data {
 	SCARDCONTEXT ctx;
 	SCARDHANDLE card;
+#ifdef __APPLE__
+	uint32_t protocol;
+#else
 	DWORD protocol;
+#endif
 	sim_types sim_type;
 	int pin1_required;
 };
@@ -504,7 +512,12 @@
 struct scard_data * scard_init(const char *reader)
 {
 	long ret;
-	unsigned long len, pos;
+#ifdef __APPLE__
+	uint32_t len;
+#else
+	unsigned long len;
+#endif
+	unsigned long pos;
 	struct scard_data *scard;
 #ifdef CONFIG_NATIVE_WINDOWS
 	TCHAR *readers = NULL;
@@ -605,7 +618,7 @@
 	readers = NULL;
 
 	wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
-		   (unsigned int) scard->card, scard->protocol,
+		   (unsigned int) scard->card, (unsigned long) scard->protocol,
 		   scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
 
 	ret = SCardBeginTransaction(scard->card);
@@ -764,7 +777,11 @@
 			   unsigned char *_recv, size_t *recv_len)
 {
 	long ret;
+#ifdef __APPLE__
+	uint32_t rlen;
+#else
 	unsigned long rlen;
+#endif
 
 	wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
 			_send, send_len);
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 968fc03..a685ce4 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -100,12 +100,6 @@
 }
 
 
-static int str_starts(const char *str, const char *start)
-{
-	return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
 /***************************************************************************
  * Advertisements.
  * These are multicast to the world to tell them we are here.
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 0e08152..a8d6a7f 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -49,6 +49,12 @@
 L_CFLAGS += -mabi=aapcs-linux
 endif
 
+# C++ flags for binder interface
+L_CPPFLAGS := -std=c++11 -Wall -Werror
+# TODO: Remove these allowed warnings later.
+L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter
+L_CPPFLAGS += -Wno-unused-private-field
+
 INCLUDES = $(LOCAL_PATH)
 INCLUDES += $(LOCAL_PATH)/src
 INCLUDES += $(LOCAL_PATH)/src/common
@@ -94,6 +100,7 @@
 OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
 OBJS_c += src/utils/wpa_debug.c
 OBJS_c += src/utils/common.c
+OBJS_c += src/common/cli.c
 OBJS_d =
 OBJS_priv =
 
@@ -1349,13 +1356,8 @@
 L_CFLAGS += $(DBUS_CFLAGS)
 
 ifdef CONFIG_CTRL_IFACE_BINDER
-BINDER=y
+WPA_SUPPLICANT_USE_BINDER=y
 L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
-OBJS += binder/binder.cpp binder/binder_manager.cpp
-OBJS += binder/supplicant.cpp binder/iface.cpp
-OBJS += binder/fi/w1/wpa_supplicant/ISupplicant.aidl
-OBJS += binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
-OBJS += binder/fi/w1/wpa_supplicant/IIface.aidl
 endif
 
 ifdef CONFIG_READLINE
@@ -1595,9 +1597,9 @@
 ifeq ($(DBUS), y)
 LOCAL_SHARED_LIBRARIES += libdbus
 endif
-ifeq ($(BINDER), y)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder frameworks/native/aidl/binder
-LOCAL_SHARED_LIBRARIES += libutils libbinder
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+LOCAL_SHARED_LIBRARIES += libbinder libutils
+LOCAL_STATIC_LIBRARIES += libwpa_binder libwpa_binder_interface
 endif
 include $(BUILD_EXECUTABLE)
 
@@ -1637,3 +1639,42 @@
 LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
 LOCAL_COPY_HEADERS += src/common/qca-vendor.h
 include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(WPA_SUPPLICANT_USE_BINDER), y)
+### Binder interface library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder_interface
+LOCAL_AIDL_INCLUDES := \
+    $(LOCAL_PATH)/binder \
+    frameworks/native/aidl/binder
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH)/binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_SRC_FILES := \
+    binder/binder_constants.cpp \
+    binder/fi/w1/wpa_supplicant/ISupplicant.aidl \
+    binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl \
+    binder/fi/w1/wpa_supplicant/IIface.aidl
+LOCAL_SHARED_LIBRARIES := libbinder
+include $(BUILD_STATIC_LIBRARY)
+
+### Binder service library ###
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_binder
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_SRC_FILES := \
+    binder/binder.cpp binder/binder_manager.cpp \
+    binder/supplicant.cpp binder/iface.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libutils
+LOCAL_STATIC_LIBRARIES := libwpa_binder_interface
+include $(BUILD_STATIC_LIBRARY)
+
+endif # BINDER == y
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 2e61abe..f3e86c1 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -110,6 +110,7 @@
 OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
 OBJS_c += ../src/utils/wpa_debug.o
 OBJS_c += ../src/utils/common.o
+OBJS_c += ../src/common/cli.o
 OBJS += wmm_ac.o
 
 ifndef CONFIG_OS
@@ -930,9 +931,13 @@
 #dynamic symbol loading that is now used in pcsc_funcs.c
 #LIBS += -lwinscard
 else
+ifdef CONFIG_OSX
+LIBS += -framework PCSC
+else
 LIBS += -lpcsclite -lpthread
 endif
 endif
+endif
 
 ifdef CONFIG_SIM_SIMULATOR
 CFLAGS += -DCONFIG_SIM_SIMULATOR
diff --git a/wpa_supplicant/binder/.clang-format b/wpa_supplicant/binder/.clang-format
new file mode 100644
index 0000000..dbfdabf
--- /dev/null
+++ b/wpa_supplicant/binder/.clang-format
@@ -0,0 +1,9 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Mozilla
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+AccessModifierOffset: -8
+AlignAfterOpenBracket: AlwaysBreak
+SortIncludes: false
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
index 28f7a2b..750e878 100644
--- a/wpa_supplicant/binder/binder.cpp
+++ b/wpa_supplicant/binder/binder.cpp
@@ -8,36 +8,35 @@
  */
 
 #include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 
 #include "binder_manager.h"
 
 extern "C" {
-#include "utils/includes.h"
-#include "utils/common.h"
-#include "utils/eloop.h"
 #include "binder.h"
 #include "binder_i.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
 }
 
 void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
 {
-	struct wpa_global *global = (wpa_global *) eloop_ctx;
-	struct wpas_binder_priv *priv = (wpas_binder_priv *) sock_ctx;
+	struct wpa_global *global = (wpa_global *)eloop_ctx;
+	struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx;
 
-	wpa_printf(MSG_DEBUG, "Processing binder events on FD %d",
-		   priv->binder_fd);
+	wpa_printf(
+	    MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd);
 	android::IPCThreadState::self()->handlePolledCommands();
 }
 
-
-struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global)
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global)
 {
 	struct wpas_binder_priv *priv;
 	wpa_supplicant_binder::BinderManager *binder_manager;
 
-	priv = (wpas_binder_priv *) os_zalloc(sizeof(*priv));
+	priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv));
 	if (!priv)
 		return NULL;
 	priv->global = global;
@@ -49,8 +48,8 @@
 	if (priv->binder_fd < 0)
 		goto err;
 	/* Look for read events from the binder socket in the eloop. */
-	if (eloop_register_read_sock(priv->binder_fd, wpas_binder_sock_handler,
-				     global, priv) < 0)
+	if (eloop_register_read_sock(
+		priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0)
 		goto err;
 
 	binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
@@ -59,7 +58,7 @@
 	binder_manager->registerBinderService(global);
 	/* We may not need to store this binder manager reference in the
 	 * global data strucure because we've made it a singleton class. */
-	priv->binder_manager = (void *) binder_manager;
+	priv->binder_manager = (void *)binder_manager;
 
 	return priv;
 
@@ -68,7 +67,6 @@
 	return NULL;
 }
 
-
 void wpas_binder_deinit(struct wpas_binder_priv *priv)
 {
 	if (!priv)
@@ -79,28 +77,26 @@
 	android::IPCThreadState::shutdown();
 }
 
-
 int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
 {
 	if (!wpa_s->global->binder)
 		return 1;
 
 	wpa_supplicant_binder::BinderManager *binder_manager =
-		wpa_supplicant_binder::BinderManager::getInstance();
+	    wpa_supplicant_binder::BinderManager::getInstance();
 	if (!binder_manager)
 		return 1;
 
 	return binder_manager->registerInterface(wpa_s);
 }
 
-
 int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
 {
 	if (!wpa_s->global->binder)
 		return 1;
 
 	wpa_supplicant_binder::BinderManager *binder_manager =
-		wpa_supplicant_binder::BinderManager::getInstance();
+	    wpa_supplicant_binder::BinderManager::getInstance();
 	if (!binder_manager)
 		return 1;
 
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
index a165074..019e327 100644
--- a/wpa_supplicant/binder/binder.h
+++ b/wpa_supplicant/binder/binder.h
@@ -7,8 +7,8 @@
  * See README for more details.
  */
 
-#ifndef BINDER_H
-#define BINDER_H
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_H
 
 #ifdef _cplusplus
 extern "C" {
@@ -22,13 +22,13 @@
 struct wpas_binder_priv;
 struct wpa_global;
 
-struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global);
+struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global);
 void wpas_binder_deinit(struct wpas_binder_priv *priv);
 
 #ifdef CONFIG_CTRL_IFACE_BINDER
 int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
 int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
-#else /* CONFIG_CTRL_IFACE_BINDER */
+#else  /* CONFIG_CTRL_IFACE_BINDER */
 static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
 {
 	return 0;
@@ -43,4 +43,4 @@
 }
 #endif /* _cplusplus */
 
-#endif /* BINDER_H */
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */
diff --git a/wpa_supplicant/binder/binder_constants.cpp b/wpa_supplicant/binder/binder_constants.cpp
new file mode 100644
index 0000000..0d452b1
--- /dev/null
+++ b/wpa_supplicant/binder/binder_constants.cpp
@@ -0,0 +1,18 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "binder_constants.h"
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+const char kServiceName[] = "wpa_supplicant";
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_constants.h b/wpa_supplicant/binder/binder_constants.h
new file mode 100644
index 0000000..a4d9b55
--- /dev/null
+++ b/wpa_supplicant/binder/binder_constants.h
@@ -0,0 +1,21 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H
+
+namespace wpa_supplicant_binder {
+namespace binder_constants {
+
+extern const char kServiceName[];
+
+} /* namespace binder_constants */
+} /* namespace wpa_supplicant_binder */
+
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */
diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h
index e8087b6..5140d6d 100644
--- a/wpa_supplicant/binder/binder_i.h
+++ b/wpa_supplicant/binder/binder_i.h
@@ -14,7 +14,8 @@
 extern "C" {
 #endif // _cplusplus
 
-struct wpas_binder_priv {
+struct wpas_binder_priv
+{
 	int binder_fd;
 	struct wpa_global *global;
 	void *binder_manager;
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
index 728f4b7..27e8ded 100644
--- a/wpa_supplicant/binder/binder_manager.cpp
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -9,27 +9,25 @@
 
 #include <binder/IServiceManager.h>
 
+#include "binder_constants.h"
 #include "binder_manager.h"
 
 extern "C" {
-#include "utils/includes.h"
 #include "utils/common.h"
+#include "utils/includes.h"
 }
 
 namespace wpa_supplicant_binder {
 
-const char BinderManager::kBinderServiceName[] = "fi.w1.wpa_supplicant";
 BinderManager *BinderManager::instance_ = NULL;
 
-
-BinderManager * BinderManager::getInstance()
+BinderManager *BinderManager::getInstance()
 {
 	if (!instance_)
 		instance_ = new BinderManager();
 	return instance_;
 }
 
-
 void BinderManager::destroyInstance()
 {
 	if (instance_)
@@ -37,20 +35,17 @@
 	instance_ = NULL;
 }
 
-
 int BinderManager::registerBinderService(struct wpa_global *global)
 {
 	/* Create the main binder service object and register with
 	 * system service manager. */
 	supplicant_object_ = new Supplicant(global);
-	android::String16 service_name(kBinderServiceName);
+	android::String16 service_name(binder_constants::kServiceName);
 	android::defaultServiceManager()->addService(
-		service_name,
-		android::IInterface::asBinder(supplicant_object_));
+	    service_name, android::IInterface::asBinder(supplicant_object_));
 	return 0;
 }
 
-
 int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
 {
 	if (!wpa_s)
@@ -73,7 +68,6 @@
 	return 0;
 }
 
-
 int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
 {
 	if (!wpa_s || !wpa_s->binder_object_key)
@@ -89,10 +83,9 @@
 	return 0;
 }
 
-
 int BinderManager::getIfaceBinderObjectByKey(
-	const void *iface_object_key,
-	android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+    const void *iface_object_key,
+    android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
 {
 	if (!iface_object_key || !iface_object)
 		return 1;
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
index 687e740..d8b7dd0 100644
--- a/wpa_supplicant/binder/binder_manager.h
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -7,14 +7,14 @@
  * See README for more details.
  */
 
-#ifndef BINDER_MANAGER_H
-#define BINDER_MANAGER_H
+#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
+#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
 
 #include <map>
 #include <string>
 
-#include "supplicant.h"
 #include "iface.h"
+#include "supplicant.h"
 
 struct wpa_global;
 struct wpa_supplicant;
@@ -27,18 +27,17 @@
  * class which is created by the supplicant core and can be used
  * to get references to the binder objects.
  */
-class BinderManager {
+class BinderManager
+{
 public:
-	static const char kBinderServiceName[];
-
-	static BinderManager * getInstance();
+	static BinderManager *getInstance();
 	static void destroyInstance();
 	int registerBinderService(struct wpa_global *global);
 	int registerInterface(struct wpa_supplicant *wpa_s);
 	int unregisterInterface(struct wpa_supplicant *wpa_s);
 	int getIfaceBinderObjectByKey(
-		const void *iface_object_key,
-		android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
+	    const void *iface_object_key,
+	    android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
 
 private:
 	BinderManager() = default;
@@ -56,4 +55,4 @@
 
 } /* namespace wpa_supplicant_binder */
 
-#endif /* BINDER_MANAGER_H */
+#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */
diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp
index af2548d..c61b3b0 100644
--- a/wpa_supplicant/binder/iface.cpp
+++ b/wpa_supplicant/binder/iface.cpp
@@ -11,9 +11,6 @@
 
 namespace wpa_supplicant_binder {
 
-Iface::Iface(struct wpa_supplicant *wpa_s)
-	: wpa_s_(wpa_s)
-{
-}
+Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {}
 
 } /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h
index acc8e55..c0ee12c 100644
--- a/wpa_supplicant/binder/iface.h
+++ b/wpa_supplicant/binder/iface.h
@@ -7,14 +7,14 @@
  * See README for more details.
  */
 
-#ifndef IFACE_H
-#define IFACE_H
+#ifndef WPA_SUPPLICANT_BINDER_IFACE_H
+#define WPA_SUPPLICANT_BINDER_IFACE_H
 
 #include "fi/w1/wpa_supplicant/BnIface.h"
 
 extern "C" {
-#include "utils/includes.h"
 #include "utils/common.h"
+#include "utils/includes.h"
 #include "../wpa_supplicant_i.h"
 }
 
@@ -39,4 +39,4 @@
 
 } /* namespace wpa_supplicant_binder */
 
-#endif /* IFACE_H */
+#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */
diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp
index 6844e5a..76569b1 100644
--- a/wpa_supplicant/binder/supplicant.cpp
+++ b/wpa_supplicant/binder/supplicant.cpp
@@ -7,28 +7,24 @@
  * See README for more details.
  */
 
-#include "binder_manager.h"
 #include "supplicant.h"
+#include "binder_manager.h"
 
 namespace wpa_supplicant_binder {
 
-Supplicant::Supplicant(struct wpa_global *global)
-	: wpa_global_(global)
-{
-}
-
+Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {}
 
 android::binder::Status Supplicant::CreateInterface(
-	const android::os::PersistableBundle &params,
-	android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+    const android::os::PersistableBundle &params,
+    android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
 {
 	android::String16 driver, ifname, confname, bridge_ifname;
 
 	/* Check if required Ifname argument is missing */
 	if (!params.getString(android::String16("Ifname"), &ifname))
 		return android::binder::Status::fromServiceSpecificError(
-			ERROR_INVALID_ARGS,
-			android::String8("Ifname missing in params."));
+		    ERROR_INVALID_ARGS,
+		    android::String8("Ifname missing in params."));
 	/* Retrieve the remaining params from the dictionary */
 	params.getString(android::String16("Driver"), &driver);
 	params.getString(android::String16("ConfigFile"), &confname);
@@ -38,11 +34,12 @@
 	 * Try to get the wpa_supplicant record for this iface, return
 	 * an error if we already control it.
 	 */
-	if (wpa_supplicant_get_iface(wpa_global_,
-				     android::String8(ifname).string()) != NULL)
+	if (wpa_supplicant_get_iface(
+		wpa_global_, android::String8(ifname).string()) != NULL)
 		return android::binder::Status::fromServiceSpecificError(
-			ERROR_IFACE_EXISTS,
-			android::String8("wpa_supplicant already controls this interface."));
+		    ERROR_IFACE_EXISTS,
+		    android::String8("wpa_supplicant already controls this "
+				     "interface."));
 
 	android::binder::Status status;
 	struct wpa_supplicant *wpa_s = NULL;
@@ -52,36 +49,38 @@
 	iface.driver = os_strdup(android::String8(driver).string());
 	iface.ifname = os_strdup(android::String8(ifname).string());
 	iface.confname = os_strdup(android::String8(confname).string());
-	iface.bridge_ifname = os_strdup(
-		android::String8(bridge_ifname).string());
+	iface.bridge_ifname =
+	    os_strdup(android::String8(bridge_ifname).string());
 	/* Otherwise, have wpa_supplicant attach to it. */
 	wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
 	/* The supplicant core creates a corresponding binder object via
 	 * BinderManager when |wpa_supplicant_add_iface| is called. */
 	if (!wpa_s || !wpa_s->binder_object_key) {
 		status = android::binder::Status::fromServiceSpecificError(
-			ERROR_UNKNOWN,
-			android::String8("wpa_supplicant couldn't grab this interface."));
+		    ERROR_UNKNOWN,
+		    android::String8(
+			"wpa_supplicant couldn't grab this interface."));
 	} else {
 		BinderManager *binder_manager = BinderManager::getInstance();
 
 		if (!binder_manager ||
 		    binder_manager->getIfaceBinderObjectByKey(
-			    wpa_s->binder_object_key, aidl_return))
-			status = android::binder::Status::fromServiceSpecificError(
+			wpa_s->binder_object_key, aidl_return))
+			status =
+			    android::binder::Status::fromServiceSpecificError(
 				ERROR_UNKNOWN,
-				android::String8("wpa_supplicant encountered a binder error."));
+				android::String8("wpa_supplicant encountered a "
+						 "binder error."));
 		else
 			status = android::binder::Status::ok();
 	}
-	os_free((void *) iface.driver);
-	os_free((void *) iface.ifname);
-	os_free((void *) iface.confname);
-	os_free((void *) iface.bridge_ifname);
+	os_free((void *)iface.driver);
+	os_free((void *)iface.ifname);
+	os_free((void *)iface.confname);
+	os_free((void *)iface.bridge_ifname);
 	return status;
 }
 
-
 android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
 {
 	struct wpa_supplicant *wpa_s;
@@ -89,35 +88,38 @@
 	wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
 	if (!wpa_s || !wpa_s->binder_object_key)
 		return android::binder::Status::fromServiceSpecificError(
-			ERROR_IFACE_UNKNOWN,
-			android::String8("wpa_supplicant does not control this interface."));
+		    ERROR_IFACE_UNKNOWN,
+		    android::String8("wpa_supplicant does not control this "
+				     "interface."));
 	if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
 		return android::binder::Status::fromServiceSpecificError(
-			ERROR_UNKNOWN,
-			android::String8("wpa_supplicant couldn't remove this interface."));
+		    ERROR_UNKNOWN,
+		    android::String8(
+			"wpa_supplicant couldn't remove this interface."));
 	return android::binder::Status::ok();
 }
 
-
 android::binder::Status Supplicant::GetInterface(
-	const std::string &ifname,
-	android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+    const std::string &ifname,
+    android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
 {
 	struct wpa_supplicant *wpa_s;
 
 	wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
 	if (!wpa_s || !wpa_s->binder_object_key)
 		return android::binder::Status::fromServiceSpecificError(
-			ERROR_IFACE_UNKNOWN,
-			android::String8("wpa_supplicant does not control this interface."));
+		    ERROR_IFACE_UNKNOWN,
+		    android::String8(
+			"wpa_supplicant does not control this interface."));
 
 	BinderManager *binder_manager = BinderManager::getInstance();
 	if (!binder_manager ||
-	    binder_manager->getIfaceBinderObjectByKey(wpa_s->binder_object_key,
-						      aidl_return))
+	    binder_manager->getIfaceBinderObjectByKey(
+		wpa_s->binder_object_key, aidl_return))
 		return android::binder::Status::fromServiceSpecificError(
-			ERROR_UNKNOWN,
-			android::String8("wpa_supplicant encountered a binder error."));
+		    ERROR_UNKNOWN,
+		    android::String8(
+			"wpa_supplicant encountered a binder error."));
 
 	return android::binder::Status::ok();
 }
diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h
index b96f4e6..136b99b 100644
--- a/wpa_supplicant/binder/supplicant.h
+++ b/wpa_supplicant/binder/supplicant.h
@@ -7,16 +7,16 @@
  * See README for more details.
  */
 
-#ifndef SUPPLICANT_H
-#define SUPPLICANT_H
+#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H
+#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H
 
 #include "fi/w1/wpa_supplicant/BnSupplicant.h"
 #include "fi/w1/wpa_supplicant/IIface.h"
 #include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
 
 extern "C" {
-#include "utils/includes.h"
 #include "utils/common.h"
+#include "utils/includes.h"
 #include "../wpa_supplicant_i.h"
 }
 
@@ -34,24 +34,22 @@
 	virtual ~Supplicant() = default;
 
 	android::binder::Status CreateInterface(
-		const android::os::PersistableBundle &params,
-		android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
-		override;
-	android::binder::Status RemoveInterface(
-		const std::string &ifname) override;
+	    const android::os::PersistableBundle &params,
+	    android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
+	android::binder::Status
+	RemoveInterface(const std::string &ifname) override;
 	android::binder::Status GetInterface(
-		const std::string &ifname,
-		android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
-		override;
+	    const std::string &ifname,
+	    android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return) override;
 
 private:
 	/* Raw pointer to the global structure maintained by the core. */
 	struct wpa_global *wpa_global_;
 	/* All the callback objects registered by the clients. */
 	std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
-		callbacks_;
+	    callbacks_;
 };
 
 } /* namespace wpa_supplicant_binder */
 
-#endif /* SUPPLICANT_H */
+#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index ce631dd..3f69936 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2005,6 +2005,7 @@
 	{ INT(dot11MeshHoldingTimeout) },
 #endif /* CONFIG_MESH */
 	{ INT(wpa_ptk_rekey) },
+	{ INT(group_rekey) },
 	{ STR(bgscan) },
 	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index e72f844..994d5ea 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -785,6 +785,7 @@
 	INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
 #endif /* CONFIG_MESH */
 	INT(wpa_ptk_rekey);
+	INT(group_rekey);
 	INT(ignore_broadcast_ssid);
 #ifdef CONFIG_HT_OVERRIDES
 	INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 1ecdfc0..010b594 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -487,6 +487,14 @@
 	int wpa_ptk_rekey;
 
 	/**
+	 * group_rekey - Group rekeying time in seconds
+	 *
+	 * This value, if non-zero, is used as the dot11RSNAConfigGroupRekeyTime
+	 * parameter when operating in Authenticator role in IBSS.
+	 */
+	int group_rekey;
+
+	/**
 	 * scan_freq - Array of frequencies to scan or %NULL for all
 	 *
 	 * This is an optional zero-terminated array of frequencies in
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 199f04f..82ba3b0 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -933,6 +933,7 @@
 #ifdef CONFIG_HS20
 	INT(update_identifier);
 #endif /* CONFIG_HS20 */
+	INT(group_rekey);
 
 #undef STR
 #undef INT
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4aa0f24..9543fd1 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2919,15 +2919,10 @@
 
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
 
-	ssid = wpa_config_add_network(wpa_s->conf);
+	ssid = wpa_supplicant_add_network(wpa_s);
 	if (ssid == NULL)
 		return -1;
 
-	wpas_notify_network_added(wpa_s, ssid);
-
-	ssid->disabled = 1;
-	wpa_config_set_network_defaults(ssid);
-
 	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
 	if (os_snprintf_error(buflen, ret))
 		return -1;
@@ -2940,7 +2935,7 @@
 {
 	int id;
 	struct wpa_ssid *ssid;
-	int was_disabled;
+	int result;
 
 	/* cmd: "<network id>" or "all" */
 	if (os_strcmp(cmd, "all") == 0) {
@@ -2976,54 +2971,17 @@
 	id = atoi(cmd);
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
 
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid)
-		wpas_notify_network_removed(wpa_s, ssid);
-	if (ssid == NULL) {
+	result = wpa_supplicant_remove_network(wpa_s, id);
+	if (result == -1) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
 			   "id=%d", id);
 		return -1;
 	}
-
-	if (wpa_s->last_ssid == ssid)
-		wpa_s->last_ssid = NULL;
-
-	if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
-#ifdef CONFIG_SME
-		wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-		/*
-		 * Invalidate the EAP session cache if the current or
-		 * previously used network is removed.
-		 */
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	}
-
-	if (ssid == wpa_s->current_ssid) {
-		wpa_sm_set_config(wpa_s->wpa, NULL);
-		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-
-		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
-			wpa_s->own_disconnect_req = 1;
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-	}
-
-	was_disabled = ssid->disabled;
-
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+	if (result == -2) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
 			   "network id=%d", id);
 		return -1;
 	}
-
-	if (!was_disabled && wpa_s->sched_scanning) {
-		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
-			   "network from filters");
-		wpa_supplicant_cancel_sched_scan(wpa_s);
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-	}
-
 	return 0;
 }
 
@@ -9127,16 +9085,7 @@
 		reply_len = wpa_supplicant_ctrl_iface_list_networks(
 			wpa_s, NULL, reply, reply_size);
 	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
-#ifdef CONFIG_SME
-		wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
-		wpa_s->reassociate = 0;
-		wpa_s->disconnected = 1;
-		wpa_supplicant_cancel_sched_scan(wpa_s);
-		wpa_supplicant_cancel_scan(wpa_s);
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-		eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+		wpas_request_disconnection(wpa_s);
 	} else if (os_strcmp(buf, "SCAN") == 0) {
 		wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
 	} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index de6d216..f185f27 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1475,10 +1475,7 @@
 					   struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->current_ssid != NULL) {
-		wpa_s->disconnected = 1;
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-
+		wpas_request_disconnection(wpa_s);
 		return NULL;
 	}
 
@@ -1507,7 +1504,7 @@
 	dbus_message_iter_init(message, &iter);
 
 	if (wpa_s->dbus_new_path)
-		ssid = wpa_config_add_network(wpa_s->conf);
+		ssid = wpa_supplicant_add_network(wpa_s);
 	if (ssid == NULL) {
 		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
 			   __func__);
@@ -1516,9 +1513,6 @@
 			"wpa_supplicant could not add a network on this interface.");
 		goto err;
 	}
-	wpas_notify_network_added(wpa_s, ssid);
-	ssid->disabled = 1;
-	wpa_config_set_network_defaults(ssid);
 
 	dbus_error_init(&error);
 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
@@ -1665,8 +1659,7 @@
 	const char *op;
 	char *iface, *net_id;
 	int id;
-	struct wpa_ssid *ssid;
-	int was_disabled;
+	int result;
 
 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
 			      DBUS_TYPE_INVALID);
@@ -1689,27 +1682,12 @@
 		goto out;
 	}
 
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
+	result = wpa_supplicant_remove_network(wpa_s, id);
+	if (result == -1) {
 		reply = wpas_dbus_error_network_unknown(message);
 		goto out;
 	}
-
-	was_disabled = ssid->disabled;
-
-	wpas_notify_network_removed(wpa_s, ssid);
-
-	if (ssid == wpa_s->current_ssid)
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-	else if (!was_disabled && wpa_s->sched_scanning) {
-		wpa_printf(MSG_DEBUG,
-			   "Stop ongoing sched_scan to remove network from filters");
-		wpa_supplicant_cancel_sched_scan(wpa_s);
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-	}
-
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+	if (result == -2) {
 		wpa_printf(MSG_ERROR,
 			   "%s[dbus]: error occurred when removing network %d",
 			   __func__, id);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e8f62ef..e540832 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -717,16 +717,13 @@
 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
 
 	if (wpa_s->dbus_path)
-		ssid = wpa_config_add_network(wpa_s->conf);
+		ssid = wpa_supplicant_add_network(wpa_s);
 	if (ssid == NULL) {
 		reply = dbus_message_new_error(
 			message, WPAS_ERROR_ADD_NETWORK_ERROR,
 			"wpa_supplicant could not add a network on this interface.");
 		goto out;
 	}
-	wpas_notify_network_added(wpa_s, ssid);
-	ssid->disabled = 1;
-	wpa_config_set_network_defaults(ssid);
 
 	/* Construct the object path for this network. */
 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -758,7 +755,7 @@
 	const char *op;
 	char *iface = NULL, *net_id = NULL;
 	int id;
-	struct wpa_ssid *ssid;
+	int result;
 
 	if (!dbus_message_get_args(message, NULL,
 				   DBUS_TYPE_OBJECT_PATH, &op,
@@ -781,19 +778,12 @@
 	}
 
 	id = strtoul(net_id, NULL, 10);
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
+	result = wpa_supplicant_remove_network(wpa_s, id);
+	if (result == -1) {
 		reply = wpas_dbus_new_invalid_network_error(message);
 		goto out;
 	}
-
-	wpas_notify_network_removed(wpa_s, ssid);
-
-	if (ssid == wpa_s->current_ssid)
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+	if (result == -2) {
 		reply = dbus_message_new_error(
 			message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
 			"error removing the specified on this interface.");
@@ -1069,8 +1059,7 @@
 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s)
 {
-	wpa_s->disconnected = 1;
-	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpas_request_disconnection(wpa_s);
 
 	return wpas_dbus_new_success_reply(message);
 }
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 396a0dc..7a16b7a 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -969,4 +969,12 @@
 	return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
 }
 
+static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s,
+					       const u8 *ies, size_t len)
+{
+	if (!wpa_s->driver->set_default_scan_ies)
+		return -1;
+	return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len);
+}
+
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 50461b6..ef62d70 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2234,7 +2234,7 @@
 				       union wpa_event_data *data)
 {
 	u8 bssid[ETH_ALEN];
-	int ft_completed;
+	int ft_completed, already_authorized;
 	int new_bss = 0;
 
 #ifdef CONFIG_AP
@@ -2310,6 +2310,8 @@
 	if (wpa_s->l2)
 		l2_packet_notify_auth_start(wpa_s->l2);
 
+	already_authorized = data && data->assoc_info.authorized;
+
 	/*
 	 * Set portEnabled first to FALSE in order to get EAP state machine out
 	 * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
@@ -2318,11 +2320,12 @@
 	 * AUTHENTICATED without ever giving chance to EAP state machine to
 	 * reset the state.
 	 */
-	if (!ft_completed) {
+	if (!ft_completed && !already_authorized) {
 		eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
 		eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
 	}
-	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed ||
+	    already_authorized)
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 	/* 802.1X::portControl = Auto */
 	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2414,7 +2417,7 @@
 	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
 	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
 	    wpa_s->ibss_rsn == NULL) {
-		wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+		wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid);
 		if (!wpa_s->ibss_rsn) {
 			wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
 			wpa_supplicant_deauthenticate(
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index c00db31..53d7d57 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -221,6 +221,7 @@
 	peer->supp = wpa_sm_init(ctx);
 	if (peer->supp == NULL) {
 		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+		os_free(ctx);
 		return -1;
 	}
 
@@ -404,7 +405,7 @@
 
 
 static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
-				    const u8 *own_addr)
+				    const u8 *own_addr, struct wpa_ssid *ssid)
 {
 	struct wpa_auth_config conf;
 	struct wpa_auth_callbacks cb;
@@ -418,7 +419,7 @@
 	conf.rsn_pairwise = WPA_CIPHER_CCMP;
 	conf.wpa_group = WPA_CIPHER_CCMP;
 	conf.eapol_version = 2;
-	conf.wpa_group_rekey = 600;
+	conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600;
 
 	os_memset(&cb, 0, sizeof(cb));
 	cb.ctx = ibss_rsn;
@@ -665,7 +666,8 @@
 }
 
 
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+				struct wpa_ssid *ssid)
 {
 	struct ibss_rsn *ibss_rsn;
 
@@ -674,7 +676,7 @@
 		return NULL;
 	ibss_rsn->wpa_s = wpa_s;
 
-	if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
+	if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) {
 		ibss_rsn_deinit(ibss_rsn);
 		return NULL;
 	}
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 67fae2d..626c543 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -51,7 +51,8 @@
 };
 
 
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+				struct wpa_ssid *ssid);
 void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
 int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
 void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 5b5c3e6..91667b0 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -18,6 +18,7 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "bss.h"
+#include "scan.h"
 
 /* type + length + oui + oui type */
 #define MBO_IE_HEADER 6
@@ -810,4 +811,5 @@
 	cell_capa[6] = mbo_cell_capa;
 
 	wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
+	wpa_supplicant_set_default_scan_ies(wpa_s);
 }
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index cdfe51c..741670b 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -404,7 +404,7 @@
 		params.dtim_period = ssid->dtim_period;
 	else if (wpa_s->conf->dtim_period > 0)
 		params.dtim_period = wpa_s->conf->dtim_period;
-	params.max_peer_links = wpa_s->conf->max_peer_links;
+	params.conf.max_peer_links = wpa_s->conf->max_peer_links;
 
 	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
 		params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
@@ -414,10 +414,10 @@
 
 	if (wpa_s->conf->user_mpm) {
 		params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
-		params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+		params.conf.auto_plinks = 0;
 	} else {
 		params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
-		params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+		params.conf.auto_plinks = 1;
 	}
 	params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
 
@@ -438,6 +438,8 @@
 		params.ies = wpa_s->ifmsh->mconf->rsn_ie;
 		params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
 		params.basic_rates = wpa_s->ifmsh->basic_rates;
+		params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+		params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
 	}
 
 	wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index cb8df66..31eeb38 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1076,7 +1076,7 @@
 		   "go_dev_addr=" MACSTR,
 		   MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
 
-	return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+	return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP);
 }
 
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 119da28..371c16a 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -426,6 +426,39 @@
 #endif /* CONFIG_INTERWORKING */
 
 
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *default_ies = NULL;
+	u8 ext_capab[18];
+	int ext_capab_len;
+	enum wpa_driver_if_type type = WPA_IF_STATION;
+
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+		type = WPA_IF_P2P_CLIENT;
+#endif /* CONFIG_P2P */
+
+	wpa_drv_get_ext_capa(wpa_s, type);
+
+	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+					     sizeof(ext_capab));
+	if (ext_capab_len > 0 &&
+	    wpabuf_resize(&default_ies, ext_capab_len) == 0)
+		wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
+
+#ifdef CONFIG_MBO
+	/* Send cellular capabilities for potential MBO STAs */
+	if (wpabuf_resize(&default_ies, 9) == 0)
+		wpas_mbo_scan_ie(wpa_s, default_ies);
+#endif /* CONFIG_MBO */
+
+	if (default_ies)
+		wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
+					     wpabuf_len(default_ies));
+	wpabuf_free(default_ies);
+}
+
+
 static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 {
 	struct wpabuf *extra_ie = NULL;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 9f8d04e..b2bb386 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -56,5 +56,6 @@
 void scan_snr(struct wpa_scan_res *res);
 void scan_est_throughput(struct wpa_supplicant *wpa_s,
 			 struct wpa_scan_res *res);
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 7012dfb..ca3d8f8 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -14,6 +14,7 @@
 #include <dirent.h>
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
+#include "common/cli.h"
 #include "common/wpa_ctrl.h"
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -30,42 +31,6 @@
 "wpa_cli v" VERSION_STR "\n"
 "Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
 
-
-static const char *const wpa_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const wpa_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-"   notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-"   notice, this list of conditions and the following disclaimer in the\n"
-"   documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-"   names of its contributors may be used to endorse or promote products\n"
-"   derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
-
 #define VENDOR_ELEM_FRAME_ID \
 	"  0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
 	"3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \
@@ -90,11 +55,6 @@
 static int interactive = 0;
 static char *ifname_prefix = NULL;
 
-struct cli_txt_entry {
-	struct dl_list list;
-	char *txt;
-};
-
 static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
@@ -130,168 +90,6 @@
 }
 
 
-static void cli_txt_list_free(struct cli_txt_entry *e)
-{
-	dl_list_del(&e->list);
-	os_free(e->txt);
-	os_free(e);
-}
-
-
-static void cli_txt_list_flush(struct dl_list *list)
-{
-	struct cli_txt_entry *e;
-	while ((e = dl_list_first(list, struct cli_txt_entry, list)))
-		cli_txt_list_free(e);
-}
-
-
-static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
-					       const char *txt)
-{
-	struct cli_txt_entry *e;
-	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
-		if (os_strcmp(e->txt, txt) == 0)
-			return e;
-	}
-	return NULL;
-}
-
-
-static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
-{
-	struct cli_txt_entry *e;
-	e = cli_txt_list_get(txt_list, txt);
-	if (e)
-		cli_txt_list_free(e);
-}
-
-
-static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
-{
-	u8 addr[ETH_ALEN];
-	char buf[18];
-	if (hwaddr_aton(txt, addr) < 0)
-		return;
-	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-	cli_txt_list_del(txt_list, buf);
-}
-
-
-#ifdef CONFIG_P2P
-static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
-				  int separator)
-{
-	const char *end;
-	char *buf;
-	end = os_strchr(txt, separator);
-	if (end == NULL)
-		end = txt + os_strlen(txt);
-	buf = dup_binstr(txt, end - txt);
-	if (buf == NULL)
-		return;
-	cli_txt_list_del(txt_list, buf);
-	os_free(buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
-{
-	struct cli_txt_entry *e;
-	e = cli_txt_list_get(txt_list, txt);
-	if (e)
-		return 0;
-	e = os_zalloc(sizeof(*e));
-	if (e == NULL)
-		return -1;
-	e->txt = os_strdup(txt);
-	if (e->txt == NULL) {
-		os_free(e);
-		return -1;
-	}
-	dl_list_add(txt_list, &e->list);
-	return 0;
-}
-
-
-#ifdef CONFIG_P2P
-static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
-{
-	u8 addr[ETH_ALEN];
-	char buf[18];
-	if (hwaddr_aton(txt, addr) < 0)
-		return -1;
-	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-	return cli_txt_list_add(txt_list, buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
-				 int separator)
-{
-	const char *end;
-	char *buf;
-	int ret;
-	end = os_strchr(txt, separator);
-	if (end == NULL)
-		end = txt + os_strlen(txt);
-	buf = dup_binstr(txt, end - txt);
-	if (buf == NULL)
-		return -1;
-	ret = cli_txt_list_add(txt_list, buf);
-	os_free(buf);
-	return ret;
-}
-
-
-static char ** cli_txt_list_array(struct dl_list *txt_list)
-{
-	unsigned int i, count = dl_list_len(txt_list);
-	char **res;
-	struct cli_txt_entry *e;
-
-	res = os_calloc(count + 1, sizeof(char *));
-	if (res == NULL)
-		return NULL;
-
-	i = 0;
-	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
-		res[i] = os_strdup(e->txt);
-		if (res[i] == NULL)
-			break;
-		i++;
-	}
-
-	return res;
-}
-
-
-static int get_cmd_arg_num(const char *str, int pos)
-{
-	int arg = 0, i;
-
-	for (i = 0; i <= pos; i++) {
-		if (str[i] != ' ') {
-			arg++;
-			while (i <= pos && str[i] != ' ')
-				i++;
-		}
-	}
-
-	if (arg > 0)
-		arg--;
-	return arg;
-}
-
-
-static int str_starts(const char *src, const char *match)
-{
-	return os_strncmp(src, match, os_strlen(match)) == 0;
-}
-
-
 static int wpa_cli_show_event(const char *event)
 {
 	const char *start;
@@ -458,36 +256,6 @@
 }
 
 
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
-		     char *argv[])
-{
-	int i, res;
-	char *pos, *end;
-
-	pos = buf;
-	end = buf + buflen;
-
-	res = os_snprintf(pos, end - pos, "%s", cmd);
-	if (os_snprintf_error(end - pos, res))
-		goto fail;
-	pos += res;
-
-	for (i = 0; i < argc; i++) {
-		res = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (os_snprintf_error(end - pos, res))
-			goto fail;
-		pos += res;
-	}
-
-	buf[buflen - 1] = '\0';
-	return 0;
-
-fail:
-	printf("Too long command\n");
-	return -1;
-}
-
-
 static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
 		       int argc, char *argv[])
 {
@@ -587,7 +355,7 @@
 
 static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
+	printf("%s\n\n%s\n", wpa_cli_version, cli_full_license);
 	return 0;
 }
 
@@ -1824,6 +1592,48 @@
 }
 
 
+static char ** wpa_cli_complete_get_capability(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	const char *fields[] = {
+		"eap", "pairwise", "group", "group_mgmt", "key_mgmt",
+		"proto", "auth_alg", "modes", "channels", "freq",
+#ifdef CONFIG_TDLS
+		"tdls",
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_ERP
+		"erp",
+#endif /* CONFIG_ERP */
+#ifdef CONFIG_FIPS
+		"fips",
+#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+		"acs",
+#endif /* CONFIG_ACS */
+	};
+	int i, num_fields = ARRAY_SIZE(fields);
+	char **res = NULL;
+
+	if (arg == 1) {
+		res = os_calloc(num_fields + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		for (i = 0; i < num_fields; i++) {
+			res[i] = os_strdup(fields[i]);
+			if (res[i] == NULL)
+				return res;
+		}
+	}
+	if (arg == 2) {
+		res = os_calloc(1 + 1, sizeof(char *));
+		if (res == NULL)
+			return NULL;
+		res[0] = os_strdup("strict");
+	}
+	return res;
+}
+
+
 static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
 {
 	printf("Available interfaces:\n");
@@ -3100,8 +2910,8 @@
 	{ "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
 	  cli_cmd_flag_none,
 	  "<<idx> | <bssid>> = get detailed scan result info" },
-	{ "get_capability", wpa_cli_cmd_get_capability, NULL,
-	  cli_cmd_flag_none,
+	{ "get_capability", wpa_cli_cmd_get_capability,
+	  wpa_cli_complete_get_capability, cli_cmd_flag_none,
 	  "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
 	  "= get capabilities" },
 	{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
@@ -3705,12 +3515,6 @@
 }
 
 
-static int str_match(const char *a, const char *b)
-{
-	return os_strncmp(a, b, os_strlen(b)) == 0;
-}
-
-
 static int wpa_cli_exec(const char *program, const char *arg1,
 			const char *arg2)
 {
@@ -3766,7 +3570,7 @@
 			pos = prev;
 	}
 
-	if (str_match(pos, WPA_EVENT_CONNECTED)) {
+	if (str_starts(pos, WPA_EVENT_CONNECTED)) {
 		int new_id = -1;
 		os_unsetenv("WPA_ID");
 		os_unsetenv("WPA_ID_STR");
@@ -3802,48 +3606,48 @@
 			wpa_cli_last_id = new_id;
 			wpa_cli_exec(action_file, ifname, "CONNECTED");
 		}
-	} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+	} else if (str_starts(pos, WPA_EVENT_DISCONNECTED)) {
 		if (wpa_cli_connected) {
 			wpa_cli_connected = 0;
 			wpa_cli_exec(action_file, ifname, "DISCONNECTED");
 		}
-	} else if (str_match(pos, AP_EVENT_ENABLED)) {
+	} else if (str_starts(pos, AP_EVENT_ENABLED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	} else if (str_match(pos, AP_EVENT_DISABLED)) {
+	} else if (str_starts(pos, AP_EVENT_DISABLED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	} else if (str_match(pos, MESH_GROUP_STARTED)) {
+	} else if (str_starts(pos, MESH_GROUP_STARTED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	} else if (str_match(pos, MESH_GROUP_REMOVED)) {
+	} else if (str_starts(pos, MESH_GROUP_REMOVED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	} else if (str_match(pos, MESH_PEER_CONNECTED)) {
+	} else if (str_starts(pos, MESH_PEER_CONNECTED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	} else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+	} else if (str_starts(pos, MESH_PEER_DISCONNECTED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	} else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+	} else if (str_starts(pos, P2P_EVENT_GROUP_STARTED)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+	} else if (str_starts(pos, P2P_EVENT_GROUP_REMOVED)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+	} else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+	} else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+	} else if (str_starts(pos, P2P_EVENT_GO_NEG_FAILURE)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+	} else if (str_starts(pos, WPS_EVENT_SUCCESS)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, WPS_EVENT_FAIL)) {
+	} else if (str_starts(pos, WPS_EVENT_FAIL)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, AP_STA_CONNECTED)) {
+	} else if (str_starts(pos, AP_STA_CONNECTED)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, AP_STA_DISCONNECTED)) {
+	} else if (str_starts(pos, AP_STA_DISCONNECTED)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+	} else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+	} else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
+	} else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
 		wpa_cli_exec(action_file, ifname, pos);
-	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
+	} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
 		printf("wpa_supplicant is terminating - stop monitoring\n");
 		wpa_cli_quit = 1;
 	}
@@ -3953,7 +3757,7 @@
 			pos = msg;
 	}
 
-	if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+	if (str_starts(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
 		edit_clear_line();
 		printf("\rConnection to wpa_supplicant lost - trying to "
 		       "reconnect\n");
@@ -4004,37 +3808,6 @@
 	}
 }
 
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
-{
-	char *pos;
-	int argc = 0;
-
-	pos = cmd;
-	for (;;) {
-		while (*pos == ' ')
-			pos++;
-		if (*pos == '\0')
-			break;
-		argv[argc] = pos;
-		argc++;
-		if (argc == max_args)
-			break;
-		if (*pos == '"') {
-			char *pos2 = os_strrchr(pos, '"');
-			if (pos2)
-				pos = pos2 + 1;
-		}
-		while (*pos != '\0' && *pos != ' ')
-			pos++;
-		if (*pos == ' ')
-			*pos++ = '\0';
-	}
-
-	return argc;
-}
-
 
 static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
 {
@@ -4444,7 +4217,7 @@
 	interactive = (argc == optind) && (action_file == NULL);
 
 	if (interactive)
-		printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
+		printf("%s\n\n%s\n\n", wpa_cli_version, cli_license);
 
 	if (eloop_init())
 		return -1;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 7ed7efa..5bb1f72 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1901,6 +1901,11 @@
 	if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
 		return;
 
+#ifdef CONFIG_HT_OVERRIDES
+	if (ssid->disable_ht40)
+		return;
+#endif /* CONFIG_HT_OVERRIDES */
+
 	/* Check/setup HT40+/HT40- */
 	for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
 		if (ht40plus[j] == channel) {
@@ -1925,22 +1930,16 @@
 
 	freq->channel = pri_chan->chan;
 
-	switch (ht40) {
-	case -1:
+	if (ht40 == -1) {
 		if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
 			return;
-		freq->sec_channel_offset = -1;
-		break;
-	case 1:
+	} else {
 		if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
 			return;
-		freq->sec_channel_offset = 1;
-		break;
-	default:
-		break;
 	}
+	freq->sec_channel_offset = ht40;
 
-	if (freq->sec_channel_offset && obss_scan) {
+	if (obss_scan) {
 		struct wpa_scan_results *scan_res;
 
 		scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -2754,6 +2753,95 @@
 
 
 /**
+ * wpa_supplicant_add_network - Add a new network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (!ssid)
+		return NULL;
+	wpas_notify_network_added(wpa_s, ssid);
+	ssid->disabled = 1;
+	wpa_config_set_network_defaults(ssid);
+
+	return ssid;
+}
+
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+	struct wpa_ssid *ssid;
+	int was_disabled;
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (!ssid)
+		return -1;
+	wpas_notify_network_removed(wpa_s, ssid);
+
+	if (wpa_s->last_ssid == ssid)
+		wpa_s->last_ssid = NULL;
+
+	if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+		wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+		/*
+		 * Invalidate the EAP session cache if the current or
+		 * previously used network is removed.
+		 */
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	}
+
+	if (ssid == wpa_s->current_ssid) {
+		wpa_sm_set_config(wpa_s->wpa, NULL);
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+			wpa_s->own_disconnect_req = 1;
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	was_disabled = ssid->disabled;
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0)
+		return -2;
+
+	if (!was_disabled && wpa_s->sched_scanning) {
+		wpa_printf(MSG_DEBUG,
+			   "Stop ongoing sched_scan to remove network from filters");
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
+
+	return 0;
+}
+
+
+/**
  * wpa_supplicant_enable_network - Mark a configured network as enabled
  * @wpa_s: wpa_supplicant structure for a network interface
  * @ssid: wpa_ssid structure for a configured network or %NULL
@@ -4875,6 +4963,8 @@
 	wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
 #endif /* CONFIG_MBO */
 
+	wpa_supplicant_set_default_scan_ies(wpa_s);
+
 	return 0;
 }
 
@@ -6022,6 +6112,27 @@
 }
 
 
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+	wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+	wpa_s->reassociate = 0;
+	wpa_s->disconnected = 1;
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpa_supplicant_cancel_scan(wpa_s);
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+}
+
+
 void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
 		    struct wpa_used_freq_data *freqs_data,
 		    unsigned int len)
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 1d86a71..6ece942 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -896,6 +896,10 @@
 # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
 # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
 #
+# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
+# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
+# Authenticator role in IBSS.
+#
 # Following fields are only used with internal EAP implementation.
 # eap: space-separated list of accepted EAP methods
 #	MD5 = EAP-MD5 (unsecure and does not generate keying material ->
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index dd6a60d..f3f96a3 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1107,6 +1107,8 @@
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 				   int reason_code);
 
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
 void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
 				   struct wpa_ssid *ssid);
 void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1162,6 +1164,7 @@
 int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
 		    size_t ssid_len);
 void wpas_request_connection(struct wpa_supplicant *wpa_s);
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
 int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
 int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);