Cumulative patch from commit 147848ec4d26613d5a117d4b35dbc7ff98dd65d1

147848e nl80211: Do not add all virtual interfaces to drv->if_indices
de88430 nl80211: Fix del_ifidx() with mixed parent interface cases
829a1b3 P2P: Clear p2p_auth_invite after each persistent group invitation
e403ba8 Parse DMG capabilities when reporting to external interfaces
f7454c9 P2P: Add 60 GHz in channel to frequency conversion
fc3f1d1 Remove unused hostapd_ip_diff()
7bb7090 Add DRIVER_EVENT AVOID_FREQUENCIES for testing
d73c7b9 GAS: Send error response if no room for pending dialog context
658d495 HS 2.0: Include OSU client sample in wpa_supplicant release package

Change-Id: Ie2109f25bd8de2c926d4116eed37b458ae6a6950
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 49f6e87..b406880 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -989,14 +989,17 @@
 				   "for " MACSTR " (dialog token %u)",
 				   MAC2STR(sa), dialog_token);
 			wpabuf_free(buf);
-			return;
+			tx_buf = gas_anqp_build_initial_resp_buf(
+				dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
+				0, NULL);
+		} else {
+			di->prot = prot;
+			di->sd_resp = buf;
+			di->sd_resp_pos = 0;
+			tx_buf = gas_anqp_build_initial_resp_buf(
+				dialog_token, WLAN_STATUS_SUCCESS,
+				comeback_delay, NULL);
 		}
-		di->prot = prot;
-		di->sd_resp = buf;
-		di->sd_resp_pos = 0;
-		tx_buf = gas_anqp_build_initial_resp_buf(
-			dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
-			NULL);
 	} else {
 		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
 		tx_buf = gas_anqp_build_initial_resp_buf(
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 709e13a..9f7d0f5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -7693,11 +7693,14 @@
 				 int ifidx)
 {
 	struct nl_msg *msg;
+	struct wpa_driver_nl80211_data *drv2;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
 
 	/* stop listening for EAPOL on this interface */
-	del_ifidx(drv, ifidx);
+	dl_list_for_each(drv2, &drv->global->interfaces,
+			 struct wpa_driver_nl80211_data, list)
+		del_ifidx(drv2, ifidx);
 
 	msg = nlmsg_alloc();
 	if (!msg)
@@ -7808,8 +7811,17 @@
 	if (ifidx <= 0)
 		return -1;
 
-	/* start listening for EAPOL on this interface */
-	add_ifidx(drv, ifidx);
+	/*
+	 * Some virtual interfaces need to process EAPOL packets and events on
+	 * the parent interface. This is used mainly with hostapd.
+	 */
+	if (drv->hostapd ||
+	    iftype == NL80211_IFTYPE_AP_VLAN ||
+	    iftype == NL80211_IFTYPE_WDS ||
+	    iftype == NL80211_IFTYPE_MONITOR) {
+		/* start listening for EAPOL on this interface */
+		add_ifidx(drv, ifidx);
+	}
 
 	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
 	    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
@@ -10179,8 +10191,12 @@
 		   __func__, type, ifname, ifindex, bss->added_if);
 	if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
 		nl80211_remove_iface(drv, ifindex);
-	else if (ifindex > 0 && !bss->added_if)
-		del_ifidx(drv, ifindex);
+	else if (ifindex > 0 && !bss->added_if) {
+		struct wpa_driver_nl80211_data *drv2;
+		dl_list_for_each(drv2, &drv->global->interfaces,
+				 struct wpa_driver_nl80211_data, list)
+			del_ifidx(drv2, ifindex);
+	}
 
 	if (type != WPA_IF_AP_BSS)
 		return 0;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 06cb646..ac19064 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -98,6 +98,10 @@
 		if (channel < 36 || channel > 161)
 			return -1;
 		return 5000 + 5 * channel;
+	case 180: /* 60 GHz band, channels 1..4 */
+		if (channel < 1 || channel > 4)
+			return -1;
+		return 56160 + 2160 * channel;
 	}
 	return -1;
 }
diff --git a/src/utils/ip_addr.c b/src/utils/ip_addr.c
index 3647c76..92a3590 100644
--- a/src/utils/ip_addr.c
+++ b/src/utils/ip_addr.c
@@ -33,30 +33,6 @@
 }
 
 
-int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
-{
-	if (a == NULL && b == NULL)
-		return 0;
-	if (a == NULL || b == NULL)
-		return 1;
-
-	switch (a->af) {
-	case AF_INET:
-		if (a->u.v4.s_addr != b->u.v4.s_addr)
-			return 1;
-		break;
-#ifdef CONFIG_IPV6
-	case AF_INET6:
-		if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0)
-			return 1;
-		break;
-#endif /* CONFIG_IPV6 */
-	}
-
-	return 0;
-}
-
-
 int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
 {
 #ifndef CONFIG_NATIVE_WINDOWS
diff --git a/src/utils/ip_addr.h b/src/utils/ip_addr.h
index 79ac20c..0670411 100644
--- a/src/utils/ip_addr.h
+++ b/src/utils/ip_addr.h
@@ -22,7 +22,6 @@
 
 const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
 			    size_t buflen);
-int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
 int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
 
 #endif /* IP_ADDR_H */
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
new file mode 100644
index 0000000..75b169e
--- /dev/null
+++ b/src/utils/utils_module_tests.c
@@ -0,0 +1,249 @@
+/*
+ * utils module tests
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/bitfield.h"
+#include "utils/ext_password.h"
+#include "utils/trace.h"
+
+
+struct printf_test_data {
+	u8 *data;
+	size_t len;
+	char *encoded;
+};
+
+static const struct printf_test_data printf_tests[] = {
+	{ (u8 *) "abcde", 5, "abcde" },
+	{ (u8 *) "a\0b\nc\ed\re\tf\"\\", 13, "a\\0b\\nc\\ed\\re\\tf\\\"\\\\" },
+	{ (u8 *) "\x00\x31\x00\x32\x00\x39", 6, "\\x001\\0002\\09" },
+	{ (u8 *) "\n\n\n", 3, "\n\12\x0a" },
+	{ (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12,
+	  "\\xc3\\xa5\xc3\\xa4\\xc3\\xb6\\xc3\\x85\\xc3\\x84\\xc3\\x96" },
+	{ (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12,
+	  "\\303\\245\\303\\244\\303\\266\\303\\205\\303\\204\\303\\226" },
+	{ (u8 *) "\xe5\xe4\xf6\xc5\xc4\xd6", 6,
+	  "\\xe5\\xe4\\xf6\\xc5\\xc4\\xd6" },
+	{ NULL, 0, NULL }
+};
+
+
+static int printf_encode_decode_tests(void)
+{
+	int i;
+	size_t binlen;
+	char buf[100];
+	u8 bin[100];
+	int errors = 0;
+
+	wpa_printf(MSG_INFO, "printf encode/decode tests");
+
+	for (i = 0; printf_tests[i].data; i++) {
+		const struct printf_test_data *test = &printf_tests[i];
+		printf_encode(buf, sizeof(buf), test->data, test->len);
+		wpa_printf(MSG_INFO, "%d: -> \"%s\"", i, buf);
+
+		binlen = printf_decode(bin, sizeof(bin), buf);
+		if (binlen != test->len ||
+		    os_memcmp(bin, test->data, binlen) != 0) {
+			wpa_hexdump(MSG_ERROR, "Error in decoding#1",
+				    bin, binlen);
+			errors++;
+		}
+
+		binlen = printf_decode(bin, sizeof(bin), test->encoded);
+		if (binlen != test->len ||
+		    os_memcmp(bin, test->data, binlen) != 0) {
+			wpa_hexdump(MSG_ERROR, "Error in decoding#2",
+				    bin, binlen);
+			errors++;
+		}
+	}
+
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d printf test(s) failed", errors);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int bitfield_tests(void)
+{
+	struct bitfield *bf;
+	int i;
+	int errors = 0;
+
+	wpa_printf(MSG_INFO, "bitfield tests");
+
+	bf = bitfield_alloc(123);
+	if (bf == NULL)
+		return -1;
+
+	for (i = 0; i < 123; i++) {
+		if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+			errors++;
+		if (i > 0 && bitfield_is_set(bf, i - 1))
+			errors++;
+		bitfield_set(bf, i);
+		if (!bitfield_is_set(bf, i))
+			errors++;
+		bitfield_clear(bf, i);
+		if (bitfield_is_set(bf, i))
+			errors++;
+	}
+
+	for (i = 123; i < 200; i++) {
+		if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+			errors++;
+		if (i > 0 && bitfield_is_set(bf, i - 1))
+			errors++;
+		bitfield_set(bf, i);
+		if (bitfield_is_set(bf, i))
+			errors++;
+		bitfield_clear(bf, i);
+		if (bitfield_is_set(bf, i))
+			errors++;
+	}
+
+	for (i = 0; i < 123; i++) {
+		if (bitfield_is_set(bf, i) || bitfield_is_set(bf, i + 1))
+			errors++;
+		bitfield_set(bf, i);
+		if (!bitfield_is_set(bf, i))
+			errors++;
+	}
+
+	for (i = 0; i < 123; i++) {
+		if (!bitfield_is_set(bf, i))
+			errors++;
+		bitfield_clear(bf, i);
+		if (bitfield_is_set(bf, i))
+			errors++;
+	}
+
+	for (i = 0; i < 123; i++) {
+		if (bitfield_get_first_zero(bf) != i)
+			errors++;
+		bitfield_set(bf, i);
+	}
+	if (bitfield_get_first_zero(bf) != -1)
+		errors++;
+	for (i = 0; i < 123; i++) {
+		if (!bitfield_is_set(bf, i))
+			errors++;
+		bitfield_clear(bf, i);
+		if (bitfield_get_first_zero(bf) != i)
+			errors++;
+		bitfield_set(bf, i);
+	}
+	if (bitfield_get_first_zero(bf) != -1)
+		errors++;
+
+	bitfield_free(bf);
+
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d bitfield test(s) failed", errors);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int int_array_tests(void)
+{
+	int test1[] = { 1, 2, 3, 4, 5, 6, 0 };
+	int test2[] = { 1, -1, 0 };
+	int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 };
+	int test3_res[] = { -1, 1, 2, 3, 4, 0 };
+	int errors = 0;
+	int len;
+
+	wpa_printf(MSG_INFO, "int_array tests");
+
+	if (int_array_len(test1) != 6 ||
+	    int_array_len(test2) != 2)
+		errors++;
+
+	int_array_sort_unique(test3);
+	len = int_array_len(test3_res);
+	if (int_array_len(test3) != len)
+		errors++;
+	else if (os_memcmp(test3, test3_res, len * sizeof(int)) != 0)
+		errors++;
+
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d int_array test(s) failed", errors);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int ext_password_tests(void)
+{
+	struct ext_password_data *data;
+	int ret = 0;
+	struct wpabuf *pw;
+
+	wpa_printf(MSG_INFO, "ext_password tests");
+
+	data = ext_password_init("unknown", "foo");
+	if (data != NULL)
+		return -1;
+
+	data = ext_password_init("test", NULL);
+	if (data == NULL)
+		return -1;
+	pw = ext_password_get(data, "foo");
+	if (pw != NULL)
+		ret = -1;
+	ext_password_free(pw);
+
+	ext_password_deinit(data);
+
+	pw = ext_password_get(NULL, "foo");
+	if (pw != NULL)
+		ret = -1;
+	ext_password_free(pw);
+
+	return ret;
+}
+
+
+static int trace_tests(void)
+{
+	wpa_printf(MSG_INFO, "trace tests");
+
+	wpa_trace_show("test backtrace");
+	wpa_trace_dump_funcname("test funcname", trace_tests);
+
+	return 0;
+}
+
+
+int utils_module_tests(void)
+{
+	int ret = 0;
+
+	wpa_printf(MSG_INFO, "utils module tests");
+
+	if (printf_encode_decode_tests() < 0 ||
+	    ext_password_tests() < 0 ||
+	    trace_tests() < 0 ||
+	    bitfield_tests() < 0 ||
+	    int_array_tests() < 0)
+		ret = -1;
+
+	return ret;
+}
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 49f7907..c0913e0 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -100,6 +100,7 @@
 ifdef CONFIG_MODULE_TESTS
 CFLAGS += -DCONFIG_MODULE_TESTS
 OBJS += wpas_module_tests.o
+OBJS += ../src/utils/utils_module_tests.o
 ifdef CONFIG_WPS
 OBJS += ../src/wps/wps_module_tests.o
 endif
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 30df7ca..4a624c5 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -130,4 +130,9 @@
 struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
 int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
 
+static inline int bss_is_dmg(const struct wpa_bss *bss)
+{
+	return bss->freq > 45000;
+}
+
 #endif /* BSS_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 9f01271..88a4cd9 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2204,17 +2204,43 @@
 			return -1;
 		pos += ret;
 	}
-	if (bss->caps & IEEE80211_CAP_IBSS) {
-		ret = os_snprintf(pos, end - pos, "[IBSS]");
+	if (bss_is_dmg(bss)) {
+		const char *s;
+		ret = os_snprintf(pos, end - pos, "[DMG]");
 		if (ret < 0 || ret >= end - pos)
 			return -1;
 		pos += ret;
-	}
-	if (bss->caps & IEEE80211_CAP_ESS) {
-		ret = os_snprintf(pos, end - pos, "[ESS]");
+		switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
+		case IEEE80211_CAP_DMG_IBSS:
+			s = "[IBSS]";
+			break;
+		case IEEE80211_CAP_DMG_AP:
+			s = "[ESS]";
+			break;
+		case IEEE80211_CAP_DMG_PBSS:
+			s = "[PBSS]";
+			break;
+		default:
+			s = "";
+			break;
+		}
+		ret = os_snprintf(pos, end - pos, "%s", s);
 		if (ret < 0 || ret >= end - pos)
 			return -1;
 		pos += ret;
+	} else {
+		if (bss->caps & IEEE80211_CAP_IBSS) {
+			ret = os_snprintf(pos, end - pos, "[IBSS]");
+			if (ret < 0 || ret >= end - pos)
+				return -1;
+			pos += ret;
+		}
+		if (bss->caps & IEEE80211_CAP_ESS) {
+			ret = os_snprintf(pos, end - pos, "[ESS]");
+			if (ret < 0 || ret >= end - pos)
+				return -1;
+			pos += ret;
+		}
 	}
 	if (p2p) {
 		ret = os_snprintf(pos, end - pos, "[P2P]");
@@ -3544,17 +3570,43 @@
 				return 0;
 			pos += ret;
 		}
-		if (bss->caps & IEEE80211_CAP_IBSS) {
-			ret = os_snprintf(pos, end - pos, "[IBSS]");
+		if (bss_is_dmg(bss)) {
+			const char *s;
+			ret = os_snprintf(pos, end - pos, "[DMG]");
 			if (ret < 0 || ret >= end - pos)
 				return 0;
 			pos += ret;
-		}
-		if (bss->caps & IEEE80211_CAP_ESS) {
-			ret = os_snprintf(pos, end - pos, "[ESS]");
+			switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
+			case IEEE80211_CAP_DMG_IBSS:
+				s = "[IBSS]";
+				break;
+			case IEEE80211_CAP_DMG_AP:
+				s = "[ESS]";
+				break;
+			case IEEE80211_CAP_DMG_PBSS:
+				s = "[PBSS]";
+				break;
+			default:
+				s = "";
+				break;
+			}
+			ret = os_snprintf(pos, end - pos, "%s", s);
 			if (ret < 0 || ret >= end - pos)
 				return 0;
 			pos += ret;
+		} else {
+			if (bss->caps & IEEE80211_CAP_IBSS) {
+				ret = os_snprintf(pos, end - pos, "[IBSS]");
+				if (ret < 0 || ret >= end - pos)
+					return 0;
+				pos += ret;
+			}
+			if (bss->caps & IEEE80211_CAP_ESS) {
+				ret = os_snprintf(pos, end - pos, "[ESS]");
+				if (ret < 0 || ret >= end - pos)
+					return 0;
+				pos += ret;
+			}
 		}
 		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
 		    wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
@@ -5650,6 +5702,8 @@
 	wpa_s->global->p2p_per_sta_psk = 0;
 	wpa_s->conf->num_sec_device_types = 0;
 	wpa_s->p2p_disable_ip_addr_req = 0;
+	os_free(wpa_s->global->p2p_go_avoid_freq.range);
+	wpa_s->global->p2p_go_avoid_freq.range = NULL;
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS_TESTING
@@ -6117,6 +6171,15 @@
 		ev = EVENT_INTERFACE_ENABLED;
 	} else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
 		ev = EVENT_INTERFACE_DISABLED;
+	} else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
+		ev = EVENT_AVOID_FREQUENCIES;
+		if (param == NULL)
+			param = "";
+		if (freq_range_list_parse(&event.freq_range, param) < 0)
+			return -1;
+		wpa_supplicant_event(wpa_s, ev, &event);
+		os_free(event.freq_range.range);
+		return 0;
 	} else {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
 			cmd);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index bd38d65..6e1eedb 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -3546,11 +3546,22 @@
 	res = get_bss_helper(args, error, __func__);
 	if (!res)
 		return FALSE;
-
-	if (res->caps & IEEE80211_CAP_IBSS)
-		mode = "ad-hoc";
-	else
-		mode = "infrastructure";
+	if (bss_is_dmg(res)) {
+		switch (res->caps & IEEE80211_CAP_DMG_MASK) {
+		case IEEE80211_CAP_DMG_PBSS:
+		case IEEE80211_CAP_DMG_IBSS:
+			mode = "ad-hoc";
+			break;
+		case IEEE80211_CAP_DMG_AP:
+			mode = "infrastructure";
+			break;
+		}
+	} else {
+		if (res->caps & IEEE80211_CAP_IBSS)
+			mode = "ad-hoc";
+		else
+			mode = "infrastructure";
+	}
 
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
 						&mode, error);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 39d31e2..0b9077b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -713,12 +713,6 @@
 }
 
 
-static int bss_is_dmg(struct wpa_bss *bss)
-{
-	return bss->freq > 45000;
-}
-
-
 /*
  * Test whether BSS is in an ESS.
  * This is done differently in DMG (60 GHz) and non-DMG bands
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index bbe15d8..393f13b 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2977,6 +2977,7 @@
 	    os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
 			   "invitation to re-invoke a persistent group");
+		os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
 	} else if (!wpa_s->conf->persistent_reconnect)
 		return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
 
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 86b70a9..38493d4 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -86,5 +86,11 @@
 	}
 #endif /* CONFIG_WPS */
 
+	{
+		int utils_module_tests(void);
+		if (utils_module_tests() < 0)
+			ret = -1;
+	}
+
 	return ret;
 }