Cumulative patch from commit 32b62704fac6af74f60b2effb173474e11ff089d

32b6270 Android: Fix ARRAY_SIZE() compilation
7617388 Interworking: Report STATUS:sp_type even if domain is not configured
c20bc9d P2P: Remove compiler warning without CONFIG_IEEE80211N
ca9bc5b P2P: Add VHT support
20ea1ca P2P: Add VHT parameter to P2P operations
53cfad4 nl80211: Mark VHT 80 MHz channels
f2112b2 wpa_supplicant: Add CONFIG_IEEE80211AC
6b02335 hostapd: Mask out not-supported VHT capabilities
7f0303d hostapd: Verify VHT 160/80+80 MHz driver support
c781eb8 hostapd: Verify VHT capabilities are supported by driver
b29b012 Fix some VHT Capabilities definitions
7066a8e hostapd: Fix wrong VHT configuration capabilities flags
6651f1f nl80211: Use max tx power from regulatory domain
7ac3616 nl80211: Replace perror() and printf() calls with wpa_printf()
4d9fb08 WPS: Clear known_wps_freq in addition to after_wps
d20c340 Interworking: Clear known_wps_freq for network selection
f3be6ee tests: Allow test case descriptions to be written into database
1bd05d0 Interworking: Force normal scan for network selection
51e9f22 P2P: Add option to allow additional client channels
556b30d P2P: Add option to remove channels from GO use
e7ecab4 Use ARRAY_SIZE() macro
39044a7 Introduce ARRAY_SIZE() macro
2e94624 DFS: Handle radar event when CAC actived correctly
5eaf240 DFS: Fix overlapped() function to check only DFS channels
345276a DFS: Adjust center freq correctly for VHT20/VHT40
1dc17db DFS: Fix available channels list for VHT80
34068ac nl80211: Add debug prints on nl_recvmsgs() failure
10b8592 nl80211: Make eloop sockets non-blocking
5f65e9f nl80211: Abstract handling of sockets on eloop
e8d1168 nl80211: Register for IBSS auth frames before eloop
03610ad Clean up get_seqnum() use for IPN
29179b8 Stop ctrl_iface monitor send loop on reinit failure
a2a535f Remove unnecessary wpa_s->conf checks
3318376 Add explicit buffer length checks for p2p_build_wps_ie()
0f01201 Verify that readlink() did not truncate result
f5eb9da nl80211: Clean up if_add() for hostapd use
a288da6 OpenSSL: Fix memory leak on error path
6cb4f11 nl80211: Fix strerror() value in P2P Dev debug messages
35f8363 DFS: Add forgotten break statement
2f243b8 Remove os_strncpy()
24f051e Replace remainining strncpy() uses with strlcpy()
41c526f P2P: Fix snprintf buffer length for group ifname backup

Change-Id: I2e1506cb9219a5a37efbb2ae0dc180fb081c809f
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 8536e48..019b334 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -358,7 +358,7 @@
 				157, 184, 192 };
 	unsigned int i;
 
-	for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(allowed); i++)
 		if (chan->chan == allowed[i])
 			return 1;
 
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 9023eab..72f582d 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -467,7 +467,7 @@
 				   int freq, int channel, int ht_enabled,
 				   int vht_enabled, int sec_channel_offset,
 				   int vht_oper_chwidth, int center_segment0,
-				   int center_segment1)
+				   int center_segment1, u32 vht_caps)
 {
 	int tmp;
 
@@ -494,6 +494,11 @@
 			return -1;
 		break;
 	case VHT_CHANWIDTH_80P80MHZ:
+		if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+			wpa_printf(MSG_ERROR,
+				   "80+80 channel width is not supported!");
+			return -1;
+		}
 		if (center_segment1 == center_segment0 + 4 ||
 		    center_segment1 == center_segment0 - 4)
 			return -1;
@@ -517,6 +522,12 @@
 		break;
 	case VHT_CHANWIDTH_160MHZ:
 		data->bandwidth = 160;
+		if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+				  VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+			wpa_printf(MSG_ERROR,
+				   "160MHZ channel width is not supported!");
+			return -1;
+		}
 		if (center_segment1)
 			return -1;
 		if (!sec_channel_offset)
@@ -545,7 +556,8 @@
 	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
 				    vht_enabled, sec_channel_offset,
 				    vht_oper_chwidth,
-				    center_segment0, center_segment1))
+				    center_segment0, center_segment1,
+				    hapd->iface->current_mode->vht_capab))
 		return -1;
 
 	if (hapd->driver == NULL)
@@ -724,6 +736,7 @@
 			  int center_segment0, int center_segment1)
 {
 	struct hostapd_freq_params data;
+	int res;
 
 	if (!hapd->driver || !hapd->driver->start_dfs_cac)
 		return 0;
@@ -737,10 +750,15 @@
 	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
 				    vht_enabled, sec_channel_offset,
 				    vht_oper_chwidth, center_segment0,
-				    center_segment1))
+				    center_segment1,
+				    hapd->iface->current_mode->vht_capab))
 		return -1;
 
-	return hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+	if (!res)
+		hapd->cac_started = 1;
+
+	return res;
 }
 
 
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 37bbd20..a30861f 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -55,13 +55,37 @@
 }
 
 
-static int dfs_is_ht40_allowed(struct hostapd_channel_data *chan)
+static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
 {
-	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
-			  184, 192 };
-	unsigned int i;
+	/*
+	 * The tables contain first valid channel number based on channel width.
+	 * We will also choose this first channel as the control one.
+	 */
+	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+			     184, 192 };
+	/*
+	 * VHT80, valid channels based on center frequency:
+	 * 42, 58, 106, 122, 138, 155
+	 */
+	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+	int *allowed = allowed_40;
+	unsigned int i, allowed_no = 0;
 
-	for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++) {
+	switch (n_chans) {
+	case 2:
+		allowed = allowed_40;
+		allowed_no = ARRAY_SIZE(allowed_40);
+		break;
+	case 4:
+		allowed = allowed_80;
+		allowed_no = ARRAY_SIZE(allowed_80);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
+		break;
+	}
+
+	for (i = 0; i < allowed_no; i++) {
 		if (chan->chan == allowed[i])
 			return 1;
 	}
@@ -92,7 +116,7 @@
 		/* Skip HT40/VHT uncompatible channels */
 		if (hapd->iconf->ieee80211n &&
 		    hapd->iconf->secondary_channel) {
-			if (!dfs_is_ht40_allowed(chan))
+			if (!dfs_is_chan_allowed(chan, n_chans))
 				continue;
 
 			for (j = 1; j < n_chans; j++) {
@@ -130,7 +154,14 @@
 
 	switch (hapd->iconf->vht_oper_chwidth) {
 	case VHT_CHANWIDTH_USE_HT:
-		hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+		if (hapd->iconf->secondary_channel == 1)
+			hapd->iconf->vht_oper_centr_freq_seg0_idx =
+				chan->chan + 2;
+		else if (hapd->iconf->secondary_channel == -1)
+			hapd->iconf->vht_oper_centr_freq_seg0_idx =
+				chan->chan - 2;
+		else
+			hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan;
 		break;
 	case VHT_CHANWIDTH_80MHZ:
 		hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6;
@@ -138,6 +169,7 @@
 	case VHT_CHANWIDTH_160MHZ:
 		hapd->iconf->vht_oper_centr_freq_seg0_idx =
 						chan->chan + 14;
+		break;
 	default:
 		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
 		break;
@@ -385,14 +417,15 @@
 	u8 radar_chan;
 	int res = 0;
 
-	if (hapd->iface->freq == freq)
-		res++;
-
 	/* Our configuration */
 	mode = hapd->iface->current_mode;
 	start_chan_idx = dfs_get_start_chan_idx(hapd);
 	n_chans = dfs_get_used_n_chans(hapd);
 
+	/* Check we are on DFS channel(s) */
+	if (!dfs_check_chans_radar(hapd, start_chan_idx, n_chans))
+		return 0;
+
 	/* Reported via radar event */
 	switch (chan_width) {
 	case CHAN_WIDTH_20_NOHT:
@@ -422,6 +455,8 @@
 
 	for (i = 0; i < n_chans; i++) {
 		chan = &mode->channels[start_chan_idx + i];
+		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+			continue;
 		for (j = 0; j < radar_n_chans; j++) {
 			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
 				   chan->chan, radar_chan + j * 4);
@@ -511,29 +546,13 @@
 			     int ht_enabled, int chan_offset, int chan_width,
 			     int cf1, int cf2)
 {
-	struct hostapd_channel_data *channel;
-	int err = 1;
-
 	if (success) {
 		/* Complete iface/ap configuration */
 		set_dfs_state(hapd, freq, ht_enabled, chan_offset,
 			      chan_width, cf1, cf2,
 			      HOSTAPD_CHAN_DFS_AVAILABLE);
+		hapd->cac_started = 0;
 		hostapd_setup_interface_complete(hapd->iface, 0);
-	} else {
-		/* Switch to new channel */
-		set_dfs_state(hapd, freq, ht_enabled, chan_offset,
-			      chan_width, cf1, cf2,
-			      HOSTAPD_CHAN_DFS_UNAVAILABLE);
-		channel = dfs_get_valid_channel(hapd);
-		if (channel) {
-			hapd->iconf->channel = channel->chan;
-			hapd->iface->freq = channel->freq;
-			err = 0;
-		} else
-			wpa_printf(MSG_ERROR, "No valid channel available");
-
-		hostapd_setup_interface_complete(hapd->iface, err);
 	}
 
 	return 0;
@@ -553,7 +572,13 @@
 		err = 0;
 	}
 
-	hapd->driver->stop_ap(hapd->drv_priv);
+	if (!hapd->cac_started) {
+		wpa_printf(MSG_DEBUG, "DFS radar detected");
+		hapd->driver->stop_ap(hapd->drv_priv);
+	} else {
+		wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
+		hapd->cac_started = 0;
+	}
 
 	hostapd_setup_interface_complete(hapd->iface, err);
 	return 0;
@@ -579,10 +604,6 @@
 	if (!res)
 		return 0;
 
-	/* we are working on non-DFS channel - skip event */
-	if (res == 0)
-		return 0;
-
 	/* radar detected while operating, switch the channel. */
 	res = hostapd_dfs_start_channel_switch(hapd);
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dbf1b52..d79c3e5 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -152,6 +152,9 @@
 
 	int parameter_set_count;
 
+	/* DFS specific parameters */
+	int cac_started;
+
 	/* Time Advertisement */
 	u8 time_update_counter;
 	struct wpabuf *time_adv;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 609ed53..d2831d4 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -270,7 +270,7 @@
 		first = sec_chan;
 
 	ok = 0;
-	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
 		if (first == allowed[k]) {
 			ok = 1;
 			break;
@@ -653,6 +653,92 @@
 	return 1;
 }
 
+
+#ifdef CONFIG_IEEE80211AC
+
+static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
+{
+	u32 req_cap = conf & cap;
+
+	/*
+	 * Make sure we support all requested capabilities.
+	 * NOTE: We assume that 'cap' represents a capability mask,
+	 * not a discrete value.
+	 */
+	if ((hw & req_cap) != req_cap) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
+			   name);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+				     const char *name)
+{
+	u32 hw_max = hw & cap;
+	u32 conf_val = conf & cap;
+
+	if (conf_val > hw_max) {
+		int offset = find_first_bit(cap);
+		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+			   name, conf_val >> offset, hw_max >> offset);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
+{
+	u32 hw = iface->current_mode->vht_capab;
+	u32 conf = iface->conf->vht_capab;
+
+	wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
+		   hw, conf);
+
+#define VHT_CAP_CHECK(cap) \
+	do { \
+		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+	do { \
+		if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+			return 0; \
+	} while (0)
+
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+	return 1;
+}
+#endif /* CONFIG_IEEE80211AC */
+
 #endif /* CONFIG_IEEE80211N */
 
 
@@ -664,6 +750,10 @@
 		return 0;
 	if (!ieee80211n_supported_ht_capab(iface))
 		return -1;
+#ifdef CONFIG_IEEE80211AC
+	if (!ieee80211ac_supported_vht_capab(iface))
+		return -1;
+#endif /* CONFIG_IEEE80211AC */
 	ret = ieee80211n_check_40mhz(iface);
 	if (ret)
 		return ret;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 0012c0f..38590a3 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -113,9 +113,60 @@
 			   struct ieee80211_vht_capabilities *vht_cap,
 			   struct ieee80211_vht_capabilities *neg_vht_cap)
 {
+	u32 cap, own_cap, sym_caps;
+
 	if (vht_cap == NULL)
 		return;
 	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
 
-	/* TODO: mask own capabilities, like get_ht_capab() */
+	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
+	own_cap = hapd->iconf->vht_capab;
+
+	/* mask out symmetric VHT capabilities we don't support */
+	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
+	cap &= ~sym_caps | (own_cap & sym_caps);
+
+	/* mask out beamformer/beamformee caps if not supported */
+	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+			 VHT_CAP_BEAMFORMEE_STS_MAX);
+
+	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
+			 VHT_CAP_SOUNDING_DIMENSION_MAX);
+
+	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
+		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+	/* mask channel widths we don't support */
+	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+		break;
+	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
+			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+		}
+		break;
+	default:
+		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+		break;
+	}
+
+	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
+		cap &= ~VHT_CAP_SHORT_GI_160;
+
+	/*
+	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+	 */
+	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
+		cap &= ~VHT_CAP_TXSTBC;
+	if (!(own_cap & VHT_CAP_TXSTBC))
+		cap &= ~VHT_CAP_RXSTBC_MASK;
+
+	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
 }
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0286c5b..03b15c2 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1863,6 +1863,7 @@
 {
 	struct wpa_igtk_kde igtk;
 	struct wpa_group *gsm = sm->group;
+	u8 rsc[WPA_KEY_RSC_LEN];
 
 	if (!sm->mgmt_frame_prot)
 		return pos;
@@ -1870,8 +1871,10 @@
 	igtk.keyid[0] = gsm->GN_igtk;
 	igtk.keyid[1] = 0;
 	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
-	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
 		os_memset(igtk.pn, 0, sizeof(igtk.pn));
+	else
+		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
 	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
 	if (sm->wpa_auth->conf.disable_gtk) {
 		/*