Accumulative patch from commit ce26864e79144cba12d5ff98632570593cc57b8a

187f87f hostapd: Allow ctrl_iface group to be specified on command line
9f890c9 TDLS: Support both external and internal setup in disabling link
864fe3a TDLS: Fix TDLS Setup Request processing in existing-peer cases
1d43e28 TDLS: Fix TPK M2 processing in concurrent initiation case
ef8151a P2P: Write p2p_ignore_shared_freq to configuration file on updates
8047f70 P2P: Ignore Tx acknowledgment status for Invitation Response
18a2eaa Add ap_vendor_elements for wpa_supplicant AP/P2P GO mode
b084df8 Add vendor_elements into Beacon/Probe Response IE parameters
b92e08f nl80211: Add debug prints for set_ap parameters
c30a4ab nl80211: Fix mode settings with split wiphy dump

Change-Id: I859638e630b6ca32b64e09943fce4d96f779897b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index f20721b..2153329 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1076,6 +1076,14 @@
 		return -1;
 	}
 
+	if (!hapd->conf->ctrl_interface_gid_set &&
+	    hapd->iface->interfaces->ctrl_iface_group &&
+	    chown(hapd->conf->ctrl_interface, -1,
+		  hapd->iface->interfaces->ctrl_iface_group) < 0) {
+		perror("chown[ctrl_interface]");
+		return -1;
+	}
+
 #ifdef ANDROID
 	/*
 	 * Android is using umask 0077 which would leave the control interface
@@ -1148,6 +1156,13 @@
 		goto fail;
 	}
 
+	if (!hapd->conf->ctrl_interface_gid_set &&
+	    hapd->iface->interfaces->ctrl_iface_group &&
+	    chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
+		perror("chown[ctrl_interface/ifname]");
+		goto fail;
+	}
+
 	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
 		perror("chmod[ctrl_interface/ifname]");
 		goto fail;
@@ -1316,6 +1331,11 @@
 			perror("mkdir[ctrl_interface]");
 			goto fail;
 		}
+	} else if (interface->ctrl_iface_group &&
+		   chown(interface->global_iface_path, -1,
+			 interface->ctrl_iface_group) < 0) {
+		perror("chown[ctrl_interface]");
+		goto fail;
 	}
 
 	if (os_strlen(interface->global_iface_path) + 1 +
@@ -1369,6 +1389,12 @@
 		}
 	}
 
+	if (interface->ctrl_iface_group &&
+	    chown(fname, -1, interface->ctrl_iface_group) < 0) {
+		perror("chown[ctrl_interface]");
+		goto fail;
+	}
+
 	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
 		perror("chmod[ctrl_interface/ifname]");
 		goto fail;
diff --git a/hostapd/main.c b/hostapd/main.c
index d4256d0..4b0da3c 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 #ifndef CONFIG_NATIVE_WINDOWS
 #include <syslog.h>
+#include <grp.h>
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "utils/common.h"
@@ -480,7 +481,8 @@
 		"\n"
 		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
 		"\\\n"
-		"         [-g <global ctrl_iface>] <configuration file(s)>\n"
+		"         [-g <global ctrl_iface>] [-G <group>] \\\n"
+		"         <configuration file(s)>\n"
 		"\n"
 		"options:\n"
 		"   -h   show this usage\n"
@@ -488,6 +490,7 @@
 		"   -B   run daemon in the background\n"
 		"   -e   entropy file\n"
 		"   -g   global control interface path\n"
+		"   -G   group for control interfaces\n"
 		"   -P   PID file\n"
 		"   -K   include key data in debug messages\n"
 #ifdef CONFIG_DEBUG_FILE
@@ -531,6 +534,22 @@
 }
 
 
+static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
+					const char *group)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+	struct group *grp;
+	grp = getgrnam(group);
+	if (grp == NULL) {
+		wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
+		return -1;
+	}
+	interfaces->ctrl_iface_group = grp->gr_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+	return 0;
+}
+
+
 int main(int argc, char *argv[])
 {
 	struct hapd_interfaces interfaces;
@@ -556,7 +575,7 @@
 	interfaces.global_ctrl_sock = -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "Bde:f:hKP:tvg:");
+		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -594,7 +613,9 @@
 		case 'g':
 			hostapd_get_global_ctrl_iface(&interfaces, optarg);
 			break;
-
+		case 'G':
+			hostapd_get_ctrl_iface_group(&interfaces, optarg);
+			break;
 		default:
 			usage();
 			break;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index b71d51d..8205d13 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -173,6 +173,14 @@
 	}
 #endif /* CONFIG_HS20 */
 
+	if (hapd->conf->vendor_elements) {
+		size_t add = wpabuf_len(hapd->conf->vendor_elements);
+		if (wpabuf_resize(&beacon, add) == 0)
+			wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
+		if (wpabuf_resize(&proberesp, add) == 0)
+			wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
+	}
+
 	*beacon_ret = beacon;
 	*proberesp_ret = proberesp;
 	*assocresp_ret = assocresp;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 8ab4f3e..f5aed99 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -40,6 +40,7 @@
 	int global_ctrl_sock;
 	char *global_iface_path;
 	char *global_iface_name;
+	gid_t ctrl_iface_group;
 	struct hostapd_iface **iface;
 };
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index efd5cab..c2b9fff 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5100,21 +5100,19 @@
 			  struct hostapd_channel_data *chan,
 			  struct nlattr *tb_freq[])
 {
+	enum hostapd_hw_mode m;
+
 	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
 	chan->flag = 0;
 
-	/* mode is not set */
-	if (mode->mode >= NUM_HOSTAPD_MODES) {
-		/* crude heuristic */
-		if (chan->freq < 4000)
-			mode->mode = HOSTAPD_MODE_IEEE80211B;
-		else if (chan->freq > 50000)
-			mode->mode = HOSTAPD_MODE_IEEE80211AD;
-		else
-			mode->mode = HOSTAPD_MODE_IEEE80211A;
-	}
+	if (chan->freq < 4000)
+		m = HOSTAPD_MODE_IEEE80211B;
+	else if (chan->freq > 50000)
+		m = HOSTAPD_MODE_IEEE80211AD;
+	else
+		m = HOSTAPD_MODE_IEEE80211A;
 
-	switch (mode->mode) {
+	switch (m) {
 	case HOSTAPD_MODE_IEEE80211AD:
 		chan->chan = (chan->freq - 56160) / 2160;
 		break;
@@ -5238,12 +5236,6 @@
 			continue;
 		mode->rates[idx] = nla_get_u32(
 			tb_rate[NL80211_BITRATE_ATTR_RATE]);
-
-		/* crude heuristic */
-		if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
-		    mode->rates[idx] > 200)
-			mode->mode = HOSTAPD_MODE_IEEE80211G;
-
 		idx++;
 	}
 
@@ -5321,12 +5313,31 @@
 
 
 static struct hostapd_hw_modes *
-wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+				     u16 *num_modes)
 {
 	u16 m;
 	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
 	int i, mode11g_idx = -1;
 
+	/* heuristic to set up modes */
+	for (m = 0; m < *num_modes; m++) {
+		if (!modes[m].num_channels)
+			continue;
+		if (modes[m].channels[0].freq < 4000) {
+			modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+			for (i = 0; i < modes[m].num_rates; i++) {
+				if (modes[m].rates[i] > 200) {
+					modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+					break;
+				}
+			}
+		} else if (modes[m].channels[0].freq > 50000)
+			modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+		else
+			modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+	}
+
 	/* If only 802.11g mode is included, use it to construct matching
 	 * 802.11b mode data. */
 
@@ -5572,7 +5583,8 @@
 
 	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
 		nl80211_set_ht40_flags(drv, &result);
-		return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+		return wpa_driver_nl80211_postprocess_modes(result.modes,
+							    num_modes);
 	}
 	msg = NULL;
  nla_put_failure:
@@ -5790,32 +5802,49 @@
 		cmd = NL80211_CMD_SET_BEACON;
 
 	nl80211_cmd(drv, msg, 0, cmd);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
+		    params->head, params->head_len);
 	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
+		    params->tail, params->tail_len);
 	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
+	wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
 	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+	wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
 	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+	wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
+			  params->ssid, params->ssid_len);
 	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
 		params->ssid);
-	if (params->proberesp && params->proberesp_len)
+	if (params->proberesp && params->proberesp_len) {
+		wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
+			    params->proberesp, params->proberesp_len);
 		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
 			params->proberesp);
+	}
 	switch (params->hide_ssid) {
 	case NO_SSID_HIDING:
+		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
 		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
 			    NL80211_HIDDEN_SSID_NOT_IN_USE);
 		break;
 	case HIDDEN_SSID_ZERO_LEN:
+		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
 		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
 			    NL80211_HIDDEN_SSID_ZERO_LEN);
 		break;
 	case HIDDEN_SSID_ZERO_CONTENTS:
+		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
 		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
 			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
 		break;
 	}
+	wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
 	if (params->privacy)
 		NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+	wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
 	if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
 	    (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
 		/* Leave out the attribute */
@@ -5826,6 +5855,7 @@
 		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
 			    NL80211_AUTHTYPE_OPEN_SYSTEM);
 
+	wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
 	ver = 0;
 	if (params->wpa_version & WPA_PROTO_WPA)
 		ver |= NL80211_WPA_VERSION_1;
@@ -5834,6 +5864,8 @@
 	if (ver)
 		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
 
+	wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
+		   params->key_mgmt_suites);
 	num_suites = 0;
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
 		suites[num_suites++] = WLAN_AKM_SUITE_8021X;
@@ -5848,6 +5880,8 @@
 	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
 		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
 
+	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
+		   params->pairwise_ciphers);
 	num_suites = 0;
 	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
 		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
@@ -5864,6 +5898,8 @@
 			num_suites * sizeof(u32), suites);
 	}
 
+	wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
+		   params->group_cipher);
 	switch (params->group_cipher) {
 	case WPA_CIPHER_CCMP:
 		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
@@ -5888,21 +5924,29 @@
 	}
 
 	if (params->beacon_ies) {
+		wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
+				params->beacon_ies);
 		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
 			wpabuf_head(params->beacon_ies));
 	}
 	if (params->proberesp_ies) {
+		wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
+				params->proberesp_ies);
 		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
 			wpabuf_len(params->proberesp_ies),
 			wpabuf_head(params->proberesp_ies));
 	}
 	if (params->assocresp_ies) {
+		wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
+				params->assocresp_ies);
 		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
 			wpabuf_len(params->assocresp_ies),
 			wpabuf_head(params->assocresp_ies));
 	}
 
 	if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
+		wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
+			   params->ap_max_inactivity);
 		NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
 			    params->ap_max_inactivity);
 	}
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 2ed9730..3beefd2 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -547,7 +547,13 @@
 		"P2P: Invitation Response TX callback: success=%d", success);
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 
-	if (success && p2p->cfg->invitation_received) {
+	if (!success)
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: Assume Invitation Response was actually "
+			"received by the peer even though Ack was not "
+			"reported");
+
+	if (p2p->cfg->invitation_received) {
 		p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
 					      p2p->inv_sa,
 					      p2p->inv_group_bssid_ptr,
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index bcd924c..8ceaf6c 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1464,6 +1464,57 @@
 	if (peer == NULL)
 		goto error;
 
+	/* If found, use existing entry instead of adding a new one;
+	 * how to handle the case where both ends initiate at the
+	 * same time? */
+	if (existing_peer) {
+		if (peer->tpk_success) {
+			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
+				   "direct link is enabled - tear down the "
+				   "old link first");
+#if 0
+			/* TODO: Disabling the link would be more proper
+			 * operation here, but it seems to trigger a race with
+			 * some drivers handling the new request frame. */
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+#else
+			if (sm->tdls_external_setup)
+				wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+						 src_addr);
+			else
+				wpa_tdls_del_key(sm, peer);
+#endif
+			wpa_tdls_peer_free(sm, peer);
+		}
+
+		/*
+		 * An entry is already present, so check if we already sent a
+		 * TDLS Setup Request. If so, compare MAC addresses and let the
+		 * STA with the lower MAC address continue as the initiator.
+		 * The other negotiation is terminated.
+		 */
+		if (peer->initiator) {
+			if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
+				wpa_printf(MSG_DEBUG, "TDLS: Discard request "
+					   "from peer with higher address "
+					   MACSTR, MAC2STR(src_addr));
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "TDLS: Accept request "
+					   "from peer with lower address "
+					   MACSTR " (terminate previously "
+					   "initiated negotiation",
+					   MAC2STR(src_addr));
+				if (sm->tdls_external_setup)
+					wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+							 src_addr);
+				else
+					wpa_tdls_del_key(sm, peer);
+				wpa_tdls_peer_free(sm, peer);
+			}
+		}
+	}
+
 	/* capability information */
 	peer->capability = WPA_GET_LE16(cpos);
 	cpos += 2;
@@ -1595,52 +1646,6 @@
 	}
 
 skip_rsn:
-	/* If found, use existing entry instead of adding a new one;
-	 * how to handle the case where both ends initiate at the
-	 * same time? */
-	if (existing_peer) {
-		if (peer->tpk_success) {
-			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
-				   "direct link is enabled - tear down the "
-				   "old link first");
-#if 0
-			/* TODO: Disabling the link would be more proper
-			 * operation here, but it seems to trigger a race with
-			 * some drivers handling the new request frame. */
-			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-#else
-			if (sm->tdls_external_setup)
-				wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
-						 src_addr);
-			else
-				wpa_tdls_del_key(sm, peer);
-#endif
-			wpa_tdls_peer_free(sm, peer);
-		}
-
-		/*
-		 * An entry is already present, so check if we already sent a
-		 * TDLS Setup Request. If so, compare MAC addresses and let the
-		 * STA with the lower MAC address continue as the initiator.
-		 * The other negotiation is terminated.
-		 */
-		if (peer->initiator) {
-			if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
-				wpa_printf(MSG_DEBUG, "TDLS: Discard request "
-					   "from peer with higher address "
-					   MACSTR, MAC2STR(src_addr));
-				return -1;
-			} else {
-				wpa_printf(MSG_DEBUG, "TDLS: Accept request "
-					   "from peer with lower address "
-					   MACSTR " (terminate previously "
-					   "initiated negotiation",
-					   MAC2STR(src_addr));
-				wpa_tdls_disable_link(sm, peer->addr);
-			}
-		}
-	}
-
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
 		if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
@@ -1807,6 +1812,16 @@
 			   "TPK M2: " MACSTR, MAC2STR(src_addr));
 		return -1;
 	}
+	if (!peer->initiator) {
+		/*
+		 * This may happen if both devices try to initiate TDLS at the
+		 * same time and we accept the TPK M1 from the peer in
+		 * wpa_tdls_process_tpk_m1() and clear our previous state.
+		 */
+		wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so "
+			   "ignore TPK M2 from " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
 	wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
 
 	if (len < 3 + 2 + 1)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 720ff7b..8a996f9 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -305,6 +305,11 @@
 
 	bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
 
+	if (wpa_s->conf->ap_vendor_elements) {
+		bss->vendor_elements =
+			wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+	}
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 1ffe05e..1b71ca7 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1833,6 +1833,7 @@
 	wpabuf_free(config->wps_nfc_dev_pw);
 	os_free(config->ext_password_backend);
 	os_free(config->sae_groups);
+	wpabuf_free(config->ap_vendor_elements);
 	os_free(config);
 }
 
@@ -2953,6 +2954,43 @@
 }
 
 
+static int wpa_config_process_ap_vendor_elements(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	struct wpabuf *tmp;
+	int len = os_strlen(pos) / 2;
+	u8 *p;
+
+	if (!len) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
+			   line);
+		return -1;
+	}
+
+	tmp = wpabuf_alloc(len);
+	if (tmp) {
+		p = wpabuf_put(tmp, len);
+
+		if (hexstr2bin(pos, p, len)) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "ap_vendor_elements", line);
+			wpabuf_free(tmp);
+			return -1;
+		}
+
+		wpabuf_free(config->ap_vendor_elements);
+		config->ap_vendor_elements = tmp;
+	} else {
+		wpa_printf(MSG_ERROR, "Cannot allocate memory for "
+			   "ap_vendor_elements");
+		return -1;
+	}
+
+	return 0;
+}
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -3050,6 +3088,7 @@
 	{ FUNC(sae_groups), 0 },
 	{ INT(dtim_period), 0 },
 	{ INT(beacon_int), 0 },
+	{ FUNC(ap_vendor_elements), 0 },
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 03fe6fc..00990cb 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -834,6 +834,16 @@
 	 * blocks that do not specify beacon_int.
 	 */
 	int beacon_int;
+
+	/**
+	 * ap_vendor_elements: Vendor specific elements for Beacon/ProbeResp
+	 *
+	 * This parameter can be used to define additional vendor specific
+	 * elements for Beacon and Probe Response frames in AP/P2P GO mode. The
+	 * format for these element(s) is a hexdump of the raw information
+	 * elements (id+len+payload for one or more elements).
+	 */
+	struct wpabuf *ap_vendor_elements;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index ff99cd7..d5de030 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -917,6 +917,9 @@
 	if (config->p2p_no_group_iface)
 		fprintf(f, "p2p_no_group_iface=%u\n",
 			config->p2p_no_group_iface);
+	if (config->p2p_ignore_shared_freq)
+		fprintf(f, "p2p_ignore_shared_freq=%u\n",
+			config->p2p_ignore_shared_freq);
 #endif /* CONFIG_P2P */
 	if (config->country[0] && config->country[1]) {
 		fprintf(f, "country=%c%c\n",
@@ -990,6 +993,17 @@
 		}
 		fprintf(f, "\n");
 	}
+
+	if (config->ap_vendor_elements) {
+		int i, len = wpabuf_len(config->ap_vendor_elements);
+		const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
+		if (len > 0) {
+			fprintf(f, "ap_vendor_elements=");
+			for (i = 0; i < len; i++)
+				fprintf(f, "%02x", *p++);
+			fprintf(f, "\n");
+		}
+	}
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 1ded4e1..b407060 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -295,6 +295,13 @@
 # Default value for Beacon interval (if not overridden in network block)
 #beacon_int=100
 
+# Additional vendor specific elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements). This is used in AP and P2P GO modes.
+#ap_vendor_elements=dd0411223301
+
 # Interworking (IEEE 802.11u)
 
 # Enable Interworking