Cumulative patch from commit 01a025937c67f0eca6021d94b8ec3b144f8b1730

01a0259 WPS: Add support for 60 GHz band
0ef1e29 WPS: Fix shorter authentication timeout during no-SelReg iteration
3465176 nl80211: Verify that cipher suite conversion succeeds
a250722 Try to set PMK only with key mgmt offload support in the driver
4a7ce98 Make IPv6 NA multicast-to-unicast conversion configurable
9f390f4 Interworking: Fix network selection warning without SIM/USIM support
a0ad9e8 Remove WPA per-VLAN groups when no more stations remain
87b5b53 Make VLAN ID available in STA info over control interface
5678a2d P2P: Allow wpa_supplicant to start if social channels are not supported
209214b vlan: Move CONFIG_FULL_DYNAMIC_VLAN includes to proper places
a6da824 Do not use C++ reserved words as variable names
eaa3728 wpa_gui: Themed icon loader
9a3cb41 Fix wpa_priv (CONFIG_PRIVSEP=y) build
8b423ed Declare all read only data structures as const
fd4fb28 OpenSSL: Try to ensure we don't throw away the PIN unnecessarily
fabc6dd mesh: Retransmit the last Commit Message in the Committed state
068669f vlan: Verify RADIUS returned VLAN-ID and dynamic_vlan=required
5add410 WPS: Use shorter authentication timeout during no-SelReg iteration
e7d2034 WPS: Enforce five second minimum time before AP iteration
bd143cc Remove trailing whitespace from Makefile
74802c0 P2P: Do not create a P2P Device interface if P2P is disabled
579674e Document p2p_disabled option in wpa_supplicant.conf
8ea8a89 nl80211: Extend unique MAC address assignment for station iftype

Change-Id: I8bc8a63f37c0892b83376b9d5a5859827ae50554
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index cccbfab..c44f70d 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -819,9 +819,9 @@
 
 	if (full_config && bss->wps_state && bss->wpa &&
 	    (!(bss->wpa & 2) ||
-	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
 		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
-			   "WPA2/CCMP forced WPS to be disabled");
+			   "WPA2/CCMP/GCMP forced WPS to be disabled");
 		bss->wps_state = 0;
 	}
 #endif /* CONFIG_WPS */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 7b4a7ea..c3573a4 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -490,6 +490,7 @@
 
 	int osen;
 	int proxy_arp;
+	int na_mcast_to_ucast;
 #ifdef CONFIG_HS20
 	int hs20;
 	int disable_dgaf;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 41ab988..60afcb0 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -153,6 +153,13 @@
 	}
 #endif /* CONFIG_SAE */
 
+	if (sta->vlan_id > 0) {
+		res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
+				  sta->vlan_id);
+		if (!os_snprintf_error(buflen - len, res))
+			len += res;
+	}
+
 	return len;
 }
 
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 5b26558..9e7d70d 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -609,7 +609,7 @@
 				return WLAN_STATUS_SUCCESS;
 			sta->sae->sync++;
 
-			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+			ret = auth_sae_send_commit(hapd, sta, bssid, 0);
 			if (ret)
 				return ret;
 
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 56c3ce0..0238257 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -561,6 +561,19 @@
 		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
 		    !cache->psk)
 			cache->accepted = HOSTAPD_ACL_REJECT;
+
+		if (cache->vlan_id &&
+		    !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
+			hostapd_logger(hapd, query->addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "Invalid VLAN ID %d received from RADIUS server",
+				       cache->vlan_id);
+			cache->vlan_id = 0;
+		}
+		if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+		    !cache->vlan_id)
+			cache->accepted = HOSTAPD_ACL_REJECT;
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
 	cache->next = hapd->acl_cache;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 863a539..ef26834 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1285,7 +1285,7 @@
 					  struct sta_info *sta,
 					  struct radius_msg *msg)
 {
-	u8 *class;
+	u8 *attr_class;
 	size_t class_len;
 	struct eapol_state_machine *sm = sta->eapol_sm;
 	int count, i;
@@ -1307,12 +1307,12 @@
 
 	nclass_count = 0;
 
-	class = NULL;
+	attr_class = NULL;
 	for (i = 0; i < count; i++) {
 		do {
 			if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
-						    &class, &class_len,
-						    class) < 0) {
+						    &attr_class, &class_len,
+						    attr_class) < 0) {
 				i = count;
 				break;
 			}
@@ -1322,7 +1322,7 @@
 		if (nclass[nclass_count].data == NULL)
 			break;
 
-		os_memcpy(nclass[nclass_count].data, class, class_len);
+		os_memcpy(nclass[nclass_count].data, attr_class, class_len);
 		nclass[nclass_count].len = class_len;
 		nclass_count++;
 	}
@@ -2342,9 +2342,9 @@
 }
 
 
-static const char * bool_txt(Boolean bool)
+static const char * bool_txt(Boolean val)
 {
-	return bool ? "TRUE" : "FALSE";
+	return val ? "TRUE" : "FALSE";
 }
 
 
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
index b0d42dc..0adcc97 100644
--- a/src/ap/ndisc_snoop.c
+++ b/src/ap/ndisc_snoop.c
@@ -81,6 +81,18 @@
 }
 
 
+static void ucast_to_stas(struct hostapd_data *hapd, const u8 *buf, size_t len)
+{
+	struct sta_info *sta;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (!(sta->flags & WLAN_STA_AUTHORIZED))
+			continue;
+		x_snoop_mcast_to_ucast_convert_send(hapd, sta, (u8 *) buf, len);
+	}
+}
+
+
 static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
 			 size_t len)
 {
@@ -133,16 +145,12 @@
 		}
 		break;
 	case ROUTER_ADVERTISEMENT:
-		if (!hapd->conf->disable_dgaf)
-			return;
-		/* fall through */
+		if (hapd->conf->disable_dgaf)
+			ucast_to_stas(hapd, buf, len);
+		break;
 	case NEIGHBOR_ADVERTISEMENT:
-		for (sta = hapd->sta_list; sta; sta = sta->next) {
-			if (!(sta->flags & WLAN_STA_AUTHORIZED))
-				continue;
-			x_snoop_mcast_to_ucast_convert_send(hapd, sta,
-							    (u8 *) buf, len);
-		}
+		if (hapd->conf->na_mcast_to_ucast)
+			ucast_to_stas(hapd, buf, len);
 		break;
 	default:
 		break;
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index baabbe3..b89a1f4 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -9,6 +9,13 @@
  */
 
 #include "utils/includes.h"
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
 #include "utils/common.h"
 #include "hostapd.h"
@@ -20,12 +27,6 @@
 
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-
 #include "drivers/priv_netlink.h"
 #include "utils/eloop.h"
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index b83b460..f23a57a 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -45,6 +45,12 @@
 				       struct wpa_group *group);
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
 			  const u8 *pmk, struct wpa_ptk *ptk);
+static void wpa_group_free(struct wpa_authenticator *wpa_auth,
+			   struct wpa_group *group);
+static void wpa_group_get(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group);
+static void wpa_group_put(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -262,15 +268,22 @@
 static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_authenticator *wpa_auth = eloop_ctx;
-	struct wpa_group *group;
+	struct wpa_group *group, *next;
 
 	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
-	for (group = wpa_auth->group; group; group = group->next) {
+	group = wpa_auth->group;
+	while (group) {
+		wpa_group_get(wpa_auth, group);
+
 		group->GTKReKey = TRUE;
 		do {
 			group->changed = FALSE;
 			wpa_group_sm_step(wpa_auth, group);
 		} while (group->changed);
+
+		next = group->next;
+		wpa_group_put(wpa_auth, group);
+		group = next;
 	}
 
 	if (wpa_auth->conf.wpa_group_rekey) {
@@ -573,6 +586,7 @@
 
 	sm->wpa_auth = wpa_auth;
 	sm->group = wpa_auth->group;
+	wpa_group_get(sm->wpa_auth, sm->group);
 
 	return sm;
 }
@@ -651,6 +665,7 @@
 #endif /* CONFIG_IEEE80211R */
 	os_free(sm->last_rx_eapol_key);
 	os_free(sm->wpa_ie);
+	wpa_group_put(sm->wpa_auth, sm->group);
 	os_free(sm);
 }
 
@@ -2994,9 +3009,9 @@
 }
 
 
-static const char * wpa_bool_txt(int bool)
+static const char * wpa_bool_txt(int val)
 {
-	return bool ? "TRUE" : "FALSE";
+	return val ? "TRUE" : "FALSE";
 }
 
 
@@ -3281,6 +3296,63 @@
 }
 
 
+/*
+ * Remove and free the group from wpa_authenticator. This is triggered by a
+ * callback to make sure nobody is currently iterating the group list while it
+ * gets modified.
+ */
+static void wpa_group_free(struct wpa_authenticator *wpa_auth,
+			   struct wpa_group *group)
+{
+	struct wpa_group *prev = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
+		   group->vlan_id);
+
+	while (prev) {
+		if (prev->next == group) {
+			/* This never frees the special first group as needed */
+			prev->next = group->next;
+			os_free(group);
+			break;
+		}
+		prev = prev->next;
+	}
+
+}
+
+
+/* Increase the reference counter for group */
+static void wpa_group_get(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group)
+{
+	/* Skip the special first group */
+	if (wpa_auth->group == group)
+		return;
+
+	group->references++;
+}
+
+
+/* Decrease the reference counter and maybe free the group */
+static void wpa_group_put(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group)
+{
+	/* Skip the special first group */
+	if (wpa_auth->group == group)
+		return;
+
+	group->references--;
+	if (group->references)
+		return;
+	wpa_group_free(wpa_auth, group);
+}
+
+
+/*
+ * Add a group that has its references counter set to zero. Caller needs to
+ * call wpa_group_get() on the return value to mark the entry in use.
+ */
 static struct wpa_group *
 wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 {
@@ -3331,7 +3403,10 @@
 	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
 		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
 
+	wpa_group_get(sm->wpa_auth, group);
+	wpa_group_put(sm->wpa_auth, sm->group);
 	sm->group = group;
+
 	return 0;
 }
 
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 7b2cd3e..57b098f 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -169,6 +169,8 @@
 	u8 IGTK[2][WPA_IGTK_MAX_LEN];
 	int GN_igtk, GM_igtk;
 #endif /* CONFIG_IEEE80211W */
+	/* Number of references except those in struct wpa_group->next */
+	unsigned int references;
 };
 
 
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 68eaeca..caed01e 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -347,8 +347,12 @@
 			bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
 
 		bss->wpa_pairwise = 0;
-		if (cred->encr_type & WPS_ENCR_AES)
-			bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+		if (cred->encr_type & WPS_ENCR_AES) {
+			if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
+				bss->wpa_pairwise |= WPA_CIPHER_GCMP;
+			else
+				bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+		}
 		if (cred->encr_type & WPS_ENCR_TKIP)
 			bss->wpa_pairwise |= WPA_CIPHER_TKIP;
 		bss->rsn_pairwise = bss->wpa_pairwise;
@@ -530,7 +534,11 @@
 		fprintf(nconf, "wpa_pairwise=");
 		prefix = "";
 		if (cred->encr_type & WPS_ENCR_AES) {
-			fprintf(nconf, "CCMP");
+			if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
+				fprintf(nconf, "GCMP");
+			else
+				fprintf(nconf, "CCMP");
+
 			prefix = " ";
 		}
 		if (cred->encr_type & WPS_ENCR_TKIP) {
@@ -844,7 +852,9 @@
 	struct hostapd_data *hapd = ctx;
 
 	return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
-		WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+		WPS_RF_50GHZ :
+		hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
+		WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
 }
 
 
@@ -1041,7 +1051,9 @@
 	} else {
 		wps->dev.rf_bands =
 			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
-			WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+			WPS_RF_50GHZ :
+			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
+			WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
 	}
 
 	if (conf->wpa & WPA_PROTO_RSN) {