Cumulative patch from commit f2d6c17aa0f9107a0e8092238b849461447cdd21

f2d6c17 nl80211: Support network hierarchy of a master interface under bridge
f85399f Reserve QCA vendor specific nl80211 commands 116..118
3bd5886 hostapd: Handle running out of DFS channels
cc1af6f FST: Fix session setup failure with peer without MB IE
dfe0745 P2P: Add optional op_class argument to P2P_SET listen_channel
e4a1469 P2P: Adjust service discovery maximum fragment size for 60 GHz
c7fb678 D-Bus: Add association response status code property for failure cases
2940bf6 hostapd: Use ifname of the current context in debug messages
6448e06 hostapd: Allow use of driver-generated interface addresses
f2accfe AP: Save EAPOL received before Association Response ACK
1307301 wpaspy: Add support for TERMINATE command
a2c88a8 wpaspy: Add support for UDP connection
3e67171 hostapd: Add global TERMINATE command
618f5d0 hostapd: Add INTERFACES ctrl_iface command
180e5b9 hostapd: Update ctrl_interface for UDP to include the selected port
56e2fc2 wpa_supplicant: Add ctrl parameter to INTERFACES command
b9066c6 hostapd: Allow UDP ctrl_iface configuration to set the UDP port
56885ee hostapd: Add UDP support for ctrl_iface
acf57fa ctrl_iface_common: Use sockaddr_storage instead of sockaddr_un
89b781b hostapd: Use common functions for ctrl_iface
1a2124c wpa_supplicant: Use common functions for ctrl_iface
ca974ae Add common ctrl_iface files
d60886c wpa_supplicant: Add monitor support for global UDP ctrl_iface
f0e5d3b wpa_supplicant: Share attach/detach/send UDP ctrl_iface functions
db7fb43 wpa_supplicant: Allow UDP ctrl_iface configuration to set the UDP port
3598695 P2P: Update peer WFD IE from PD Response and GO Negotiation Response
c69ef1d P2P: Respect p2p_ignore_shared_freq on p2p_group_add
4115b05 P2P: Fix shared freq print in wpas_p2p_init_go_params()

Change-Id: Id939064b95210ee1a195f7a9f7c069da520d77ca
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f19cac6..2d07c67 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -665,6 +665,9 @@
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
 
+	/* Use driver-generated interface addresses when adding multiple BSSs */
+	u8 use_driver_iface_addr;
+
 #ifdef CONFIG_FST
 	struct fst_iface_cfg fst_cfg;
 #endif /* CONFIG_FST */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index bda23f0..47adba7 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -704,7 +704,8 @@
 							skip_radar);
 			if (!channel) {
 				wpa_printf(MSG_ERROR, "could not get valid channel");
-				return -1;
+				hostapd_set_state(iface, HAPD_IFACE_DFS);
+				return 0;
 			}
 
 			iface->freq = channel->freq;
@@ -793,7 +794,6 @@
 
 	if (!channel) {
 		wpa_printf(MSG_ERROR, "No valid channel available");
-		hostapd_setup_interface_complete(iface, err);
 		return err;
 	}
 
@@ -858,8 +858,9 @@
 						&vht_oper_centr_freq_seg1_idx,
 						skip_radar);
 		if (!channel) {
-			/* FIXME: Wait for channel(s) to become available */
-			hostapd_disable_iface(iface);
+			wpa_printf(MSG_INFO,
+				   "%s: no DFS channels left, waiting for NOP to finish",
+				   __func__);
 			return err;
 		}
 
@@ -982,6 +983,11 @@
 	/* TODO add correct implementation here */
 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
 		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+
+	/* Handle cases where all channels were initially unavailable */
+	if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+		hostapd_handle_dfs(iface);
+
 	return 0;
 }
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 303786b..55ca9e8 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -512,6 +512,9 @@
 	if (hostapd_drv_none(hapd))
 		return 0;
 
+	if (iface->conf->use_driver_iface_addr)
+		return 0;
+
 	/* Generate BSSID mask that is large enough to cover the BSSIDs. */
 
 	/* Determine the bits necessary to cover the number of BSSIDs. */
@@ -905,12 +908,9 @@
 	hapd->started = 1;
 
 	if (!first || first == -1) {
-		if (is_zero_ether_addr(conf->bssid)) {
-			/* Allocate the next available BSSID. */
-			do {
-				inc_byte_array(hapd->own_addr, ETH_ALEN);
-			} while (mac_in_conf(hapd->iconf, hapd->own_addr));
-		} else {
+		u8 *addr = hapd->own_addr;
+
+		if (!is_zero_ether_addr(conf->bssid)) {
 			/* Allocate the configured BSSID. */
 			os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
 
@@ -922,11 +922,18 @@
 					   "the radio", conf->iface);
 				return -1;
 			}
+		} else if (hapd->iconf->use_driver_iface_addr) {
+			addr = NULL;
+		} else {
+			/* Allocate the next available BSSID. */
+			do {
+				inc_byte_array(hapd->own_addr, ETH_ALEN);
+			} while (mac_in_conf(hapd->iconf, hapd->own_addr));
 		}
 
 		hapd->interface_added = 1;
 		if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
-				   conf->iface, hapd->own_addr, hapd,
+				   conf->iface, addr, hapd,
 				   &hapd->drv_priv, force_ifname, if_addr,
 				   conf->bridge[0] ? conf->bridge : NULL,
 				   first == -1)) {
@@ -935,6 +942,9 @@
 			hapd->interface_added = 0;
 			return -1;
 		}
+
+		if (!addr)
+			os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
 	}
 
 	if (conf->wmm_enabled < 0)
@@ -1859,6 +1869,7 @@
 	hapd->iface = hapd_iface;
 	hapd->driver = hapd->iconf->driver;
 	hapd->ctrl_sock = -1;
+	dl_list_init(&hapd->ctrl_dst);
 
 	return hapd;
 }
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index d6d96db..60516ae 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -41,7 +41,7 @@
 
 	size_t count;
 	int global_ctrl_sock;
-	struct wpa_ctrl_dst *global_ctrl_dst;
+	struct dl_list global_ctrl_dst;
 	char *global_iface_path;
 	char *global_iface_name;
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -155,7 +155,7 @@
 	int tkip_countermeasures;
 
 	int ctrl_sock;
-	struct wpa_ctrl_dst *ctrl_dst;
+	struct dl_list ctrl_dst;
 
 	void *ssl_ctx;
 	void *eap_sim_db_priv;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index b36e68d..134ae06 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2782,6 +2782,25 @@
 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
 	hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+	if (sta->pending_eapol_rx) {
+		struct os_reltime now, age;
+
+		os_get_reltime(&now);
+		os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
+		if (age.sec == 0 && age.usec < 200000) {
+			wpa_printf(MSG_DEBUG,
+				   "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
+				   MAC2STR(sta->addr));
+			ieee802_1x_receive(
+				hapd, mgmt->da,
+				wpabuf_head(sta->pending_eapol_rx->buf),
+				wpabuf_len(sta->pending_eapol_rx->buf));
+		}
+		wpabuf_free(sta->pending_eapol_rx->buf);
+		os_free(sta->pending_eapol_rx);
+		sta->pending_eapol_rx = NULL;
+	}
 }
 
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index c774d5c..42b0299 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -861,6 +861,29 @@
 }
 
 
+static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
+				  size_t len)
+{
+	if (sta->pending_eapol_rx) {
+		wpabuf_free(sta->pending_eapol_rx->buf);
+	} else {
+		sta->pending_eapol_rx =
+			os_malloc(sizeof(*sta->pending_eapol_rx));
+		if (!sta->pending_eapol_rx)
+			return;
+	}
+
+	sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
+	if (!sta->pending_eapol_rx->buf) {
+		os_free(sta->pending_eapol_rx);
+		sta->pending_eapol_rx = NULL;
+		return;
+	}
+
+	os_get_reltime(&sta->pending_eapol_rx->rx_time);
+}
+
+
 /**
  * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
  * @hapd: hostapd BSS data
@@ -891,6 +914,13 @@
 		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
 		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
 			   "associated/Pre-authenticating STA");
+
+		if (sta && (sta->flags & WLAN_STA_AUTH)) {
+			wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
+				   " for later use", MAC2STR(sta->addr));
+			ieee802_1x_save_eapol(sta, buf, len);
+		}
+
 		return;
 	}
 
@@ -1183,6 +1213,12 @@
 	eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
 #endif /* CONFIG_HS20 */
 
+	if (sta->pending_eapol_rx) {
+		wpabuf_free(sta->pending_eapol_rx->buf);
+		os_free(sta->pending_eapol_rx);
+		sta->pending_eapol_rx = NULL;
+	}
+
 	if (sm == NULL)
 		return;
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index cd89e99..70a59cc 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -56,6 +56,11 @@
 	u8 channels[];
 };
 
+struct pending_eapol_rx {
+	struct wpabuf *buf;
+	struct os_reltime rx_time;
+};
+
 struct sta_info {
 	struct sta_info *next; /* next entry in sta list */
 	struct sta_info *hnext; /* next entry in hash table list */
@@ -113,6 +118,8 @@
 	/* IEEE 802.1X related data */
 	struct eapol_state_machine *eapol_sm;
 
+	struct pending_eapol_rx *pending_eapol_rx;
+
 	u64 acct_session_id;
 	struct os_reltime acct_session_start;
 	int acct_session_started;
diff --git a/src/common/ctrl_iface_common.c b/src/common/ctrl_iface_common.c
new file mode 100644
index 0000000..acd2410
--- /dev/null
+++ b/src/common/ctrl_iface_common.c
@@ -0,0 +1,152 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <netdb.h>
+#include <sys/un.h>
+
+#include "utils/common.h"
+#include "ctrl_iface_common.h"
+
+static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
+			    struct sockaddr_storage *b, socklen_t b_len)
+{
+	struct sockaddr_in *in_a, *in_b;
+	struct sockaddr_in6 *in6_a, *in6_b;
+	struct sockaddr_un *u_a, *u_b;
+
+	if (a->ss_family != b->ss_family)
+		return 1;
+
+	switch (a->ss_family) {
+	case AF_INET:
+		in_a = (struct sockaddr_in *) a;
+		in_b = (struct sockaddr_in *) b;
+
+		if (in_a->sin_port != in_b->sin_port)
+			return 1;
+		if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
+			return 1;
+		break;
+	case AF_INET6:
+		in6_a = (struct sockaddr_in6 *) a;
+		in6_b = (struct sockaddr_in6 *) b;
+
+		if (in6_a->sin6_port != in6_b->sin6_port)
+			return 1;
+		if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
+			      sizeof(in6_a->sin6_addr)) != 0)
+			return 1;
+		break;
+	case AF_UNIX:
+		u_a = (struct sockaddr_un *) a;
+		u_b = (struct sockaddr_un *) b;
+
+		if (a_len != b_len ||
+		    os_memcmp(u_a->sun_path, u_b->sun_path,
+			      a_len - offsetof(struct sockaddr_un, sun_path))
+		    != 0)
+			return 1;
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+		    socklen_t socklen)
+{
+	char host[NI_MAXHOST] = { 0 };
+	char service[NI_MAXSERV] = { 0 };
+	char addr_txt[200];
+
+	switch (sock->ss_family) {
+	case AF_INET:
+	case AF_INET6:
+		getnameinfo((struct sockaddr *) sock, socklen,
+			    host, sizeof(host),
+			    service, sizeof(service),
+			    NI_NUMERICHOST);
+
+		wpa_printf(level, "%s %s:%s", msg, host, service);
+		break;
+	case AF_UNIX:
+		printf_encode(addr_txt, sizeof(addr_txt),
+			      (u8 *) ((struct sockaddr_un *) sock)->sun_path,
+			      socklen - offsetof(struct sockaddr_un, sun_path));
+		wpa_printf(level, "%s %s", msg, addr_txt);
+		break;
+	default:
+		wpa_printf(level, "%s", msg);
+		break;
+	}
+}
+
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+		      socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	os_memcpy(&dst->addr, from, fromlen);
+	dst->addrlen = fromlen;
+	dst->debug_level = MSG_INFO;
+	dl_list_add(ctrl_dst, &dst->list);
+
+	sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
+	return 0;
+}
+
+
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+		      socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+		if (!sockaddr_compare(from, fromlen,
+				      &dst->addr, dst->addrlen)) {
+			sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				       from, fromlen);
+			dl_list_del(&dst->list);
+			os_free(dst);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+		     socklen_t fromlen, const char *level)
+{
+	struct wpa_ctrl_dst *dst;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+	dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+		if (!sockaddr_compare(from, fromlen,
+				      &dst->addr, dst->addrlen)) {
+			sockaddr_print(MSG_DEBUG,
+				       "CTRL_IFACE changed monitor level",
+				       from, fromlen);
+			dst->debug_level = atoi(level);
+			return 0;
+		}
+	}
+
+	return -1;
+}
diff --git a/src/common/ctrl_iface_common.h b/src/common/ctrl_iface_common.h
new file mode 100644
index 0000000..0b6e3e7
--- /dev/null
+++ b/src/common/ctrl_iface_common.h
@@ -0,0 +1,38 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef CONTROL_IFACE_COMMON_H
+#define CONTROL_IFACE_COMMON_H
+
+#include "utils/list.h"
+
+/**
+ * struct wpa_ctrl_dst - Data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant.
+ */
+struct wpa_ctrl_dst {
+	struct dl_list list;
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+	int debug_level;
+	int errors;
+};
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+		    socklen_t socklen);
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+		       socklen_t fromlen);
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+		      socklen_t fromlen);
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+		     socklen_t fromlen, const char *level);
+
+#endif /* CONTROL_IFACE_COMMON_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index a3ee91d..f3d185e 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -162,6 +162,7 @@
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
 	/* 110..114 - reserved for QCA */
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
+	/* 116..118 - reserved for QCA */
 };
 
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 570dee6..5fb6652 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5912,6 +5912,14 @@
 			params->ifname, master_ifname);
 		/* start listening for EAPOL on the master interface */
 		add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
+
+		/* check if master itself is under bridge */
+		if (linux_br_get(master_ifname, master_ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
+				   master_ifname);
+			br_ifindex = if_nametoindex(master_ifname);
+			os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+		}
 	} else {
 		master_ifname[0] = '\0';
 	}
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index e0c055f..d6157b1 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -220,7 +220,7 @@
 
 				if (peer_addr &&
 				    fst_iface_is_connected(iface, peer_addr,
-							   TRUE) &&
+							   FALSE) &&
 				    band_id == fst_iface_get_band_id(iface)) {
 					os_memcpy(iface_peer_addr, peer_addr,
 						  ETH_ALEN);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index fe0096f..9f0b3f3 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -1268,6 +1268,11 @@
 		dev->client_timeout = msg.config_timeout[1];
 	}
 
+	if (msg.wfd_subelems) {
+		wpabuf_free(dev->info.wfd_subelems);
+		dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+	}
+
 	if (!msg.operating_channel && !go) {
 		/*
 		 * Note: P2P Client may omit Operating Channel attribute to
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e6535d4..93a0535 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -1349,6 +1349,9 @@
 			" with no pending request", MAC2STR(sa));
 		p2p_parse_free(&msg);
 		return;
+	} else if (msg.wfd_subelems) {
+		wpabuf_free(dev->info.wfd_subelems);
+		dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
 	}
 
 	if (dev->dialog_token != msg.dialog_token) {
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 2ef4c51..a8bc5ba 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -425,9 +425,16 @@
 		     u8 dialog_token, const struct wpabuf *resp_tlvs)
 {
 	struct wpabuf *resp;
+	size_t max_len;
+
+	/*
+	 * In the 60 GHz, we have a smaller maximum frame length for management
+	 * frames.
+	 */
+	max_len = (freq > 56160) ? 928 : 1400;
 
 	/* TODO: fix the length limit to match with the maximum frame length */
-	if (wpabuf_len(resp_tlvs) > 1400) {
+	if (wpabuf_len(resp_tlvs) > max_len) {
 		p2p_dbg(p2p, "SD response long enough to require fragmentation");
 		if (p2p->sd_resp) {
 			/*
@@ -614,7 +621,7 @@
 {
 	struct wpabuf *resp;
 	u8 dialog_token;
-	size_t frag_len;
+	size_t frag_len, max_len;
 	int more = 0;
 
 	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
@@ -638,9 +645,14 @@
 		return;
 	}
 
+	/*
+	 * In the 60 GHz, we have a smaller maximum frame length for management
+	 * frames.
+	 */
+	max_len = (rx_freq > 56160) ? 928 : 1400;
 	frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
-	if (frag_len > 1400) {
-		frag_len = 1400;
+	if (frag_len > max_len) {
+		frag_len = max_len;
 		more = 1;
 	}
 	resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,