Cumulative patch from commit 8615bdfac90174c3730ae5e6607b85f8bbec847e

8615bdf Increase global ctrl_iface buffer to same size as per-interface
c5a64e2 GAS client: Use Protected Dual of Public Action frames with PMF
5ce00d0 GAS server: Add support for Protected Dual of Public Action frames
e24fe94 Add definitions for Protected Dual of Public Action frames
7b2c42f hostapd: Fix PMF robust Action frame processing rules
ea6e040 Clear more configuration parameters to default on FLUSH
cf70d29 wpa_supplicant: Schedule PNO on completion of ongoing sched_scan
080cc44 nl80211: Fix sizeof check in vendor command/event handling
a487b35 hostapd: Fix segmentation fault when calling hostapd_cli all_sta
a6cff8b wpa_supplicant: Fix seg fault in wpas_ctrl_radio_work_flush() in error case
f62a3c2 P2P: Clone dtim_period to a new interface
88a0bca Update copyright years in the manpages
32185f5 Sync manpages and command-line options
b948e78 Add manpage for eapol_test
36bd29e wpa_supplicant: Fix usage text based on build options
dcdd383 P2P: Reduce peer expiration age to 60 sec and allow customization
dd27185 Skip normal scan when PNO is already in progress
a2d6365 P2P: Extend the listen time based on the active concurrent session

Change-Id: Iad81dc478319e59d8cfb673e2988d8bd3099b313
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 3fb9e04..8c0cbab 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -86,6 +86,9 @@
 {
 	int len, res, ret, i;
 
+	if (!sta)
+		return 0;
+
 	len = 0;
 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
 			  MAC2STR(sta->addr));
@@ -203,7 +206,11 @@
 		if (ret < 0 || (size_t) ret >= buflen)
 			return 0;
 		return ret;
-	}		
+	}
+
+	if (!sta->next)
+		return 0;
+
 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
 }
 
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 8349c4d..b5fb7df 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1,6 +1,6 @@
 /*
  * Generic advertisement service (GAS) server
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -19,6 +19,13 @@
 #include "gas_serv.h"
 
 
+static void convert_to_protected_dual(struct wpabuf *msg)
+{
+	u8 *categ = wpabuf_mhead_u8(msg);
+	*categ = WLAN_ACTION_PROTECTED_DUAL;
+}
+
+
 static struct gas_dialog_info *
 gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
 {
@@ -774,7 +781,7 @@
 
 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
 					  const u8 *sa, u8 dialog_token,
-					  struct anqp_query_info *qi)
+					  struct anqp_query_info *qi, int prot)
 {
 	struct wpabuf *buf, *tx_buf;
 
@@ -806,6 +813,7 @@
 			wpabuf_free(buf);
 			return;
 		}
+		di->prot = prot;
 		di->sd_resp = buf;
 		di->sd_resp_pos = 0;
 		tx_buf = gas_anqp_build_initial_resp_buf(
@@ -819,7 +827,8 @@
 	}
 	if (!tx_buf)
 		return;
-
+	if (prot)
+		convert_to_protected_dual(tx_buf);
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -828,7 +837,7 @@
 
 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
 					const u8 *sa,
-					const u8 *data, size_t len)
+					const u8 *data, size_t len, int prot)
 {
 	const u8 *pos = data;
 	const u8 *end = data + len;
@@ -878,6 +887,8 @@
 			return;
 		wpabuf_put_data(buf, adv_proto, 2 + slen);
 		wpabuf_put_le16(buf, 0); /* Query Response Length */
+		if (prot)
+			convert_to_protected_dual(buf);
 		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 					wpabuf_head(buf), wpabuf_len(buf));
 		wpabuf_free(buf);
@@ -929,7 +940,7 @@
 		pos += elen;
 	}
 
-	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
 }
 
 
@@ -975,6 +986,8 @@
 		if (tx_buf) {
 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
+			if (dialog->prot)
+				convert_to_protected_dual(tx_buf);
 			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
 						dst,
 						wpabuf_head(tx_buf),
@@ -1012,6 +1025,8 @@
 		dialog->sd_frag_id, (int) frag_len);
 	dialog->sd_frag_id++;
 
+	if (dialog->prot)
+		convert_to_protected_dual(tx_buf);
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -1022,7 +1037,7 @@
 
 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
 					 const u8 *sa,
-					 const u8 *data, size_t len)
+					 const u8 *data, size_t len, int prot)
 {
 	struct gas_dialog_info *dialog;
 	struct wpabuf *buf, *tx_buf;
@@ -1120,6 +1135,8 @@
 	}
 
 send_resp:
+	if (prot)
+		convert_to_protected_dual(tx_buf);
 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -1137,22 +1154,30 @@
 	const struct ieee80211_mgmt *mgmt;
 	size_t hdr_len;
 	const u8 *sa, *data;
+	int prot;
 
 	mgmt = (const struct ieee80211_mgmt *) buf;
 	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
 	if (hdr_len > len)
 		return;
-	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+	    mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
 		return;
+	/*
+	 * Note: Public Action and Protected Dual of Public Action frames share
+	 * the same payload structure, so it is fine to use definitions of
+	 * Public Action frames to process both.
+	 */
+	prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
 	sa = mgmt->sa;
 	len -= hdr_len;
 	data = &mgmt->u.action.u.public_action.action;
 	switch (data[0]) {
 	case WLAN_PA_GAS_INITIAL_REQ:
-		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
 		break;
 	case WLAN_PA_GAS_COMEBACK_REQ:
-		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
 		break;
 	}
 }
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 4213cf6..74739fe 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -50,6 +50,7 @@
 	size_t sd_resp_pos; /* Offset in sd_resp */
 	u8 sd_frag_id;
 	u16 comeback_delay;
+	int prot; /* whether Protected Dual of Public Action frame is used */
 
 	unsigned int requested;
 	unsigned int received;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1e3693d..dee3c7a 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1588,8 +1588,8 @@
 
 #ifdef CONFIG_IEEE80211W
 	if (sta && (sta->flags & WLAN_STA_MFP) &&
-	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
-	      robust_action_frame(mgmt->u.action.category))) {
+	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
+	    robust_action_frame(mgmt->u.action.category)) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "Dropped unprotected Robust Action frame from "
@@ -1619,6 +1619,7 @@
 		return 1;
 #endif /* CONFIG_WNM */
 	case WLAN_ACTION_PUBLIC:
+	case WLAN_ACTION_PROTECTED_DUAL:
 		if (hapd->public_action_cb) {
 			hapd->public_action_cb(hapd->public_action_cb_ctx,
 					       (u8 *) mgmt, len,
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 12dc83e..592ae54 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -271,6 +271,7 @@
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_PROTECTED_DUAL 9
 #define WLAN_ACTION_WNM 10
 #define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
@@ -286,6 +287,19 @@
 #define WLAN_PA_GAS_COMEBACK_RESP 13
 #define WLAN_TDLS_DISCOVERY_RESPONSE 14
 
+/* Protected Dual of Public Action frames */
+#define WLAN_PROT_DSE_ENABLEMENT 1
+#define WLAN_PROT_DSE_DEENABLEMENT 2
+#define WLAN_PROT_EXT_CSA 4
+#define WLAN_PROT_MEASUREMENT_REQ 5
+#define WLAN_PROT_MEASUREMENT_REPORT 6
+#define WLAN_PROT_DSE_POWER_CONSTRAINT 8
+#define WLAN_PROT_VENDOR_SPECIFIC 9
+#define WLAN_PROT_GAS_INITIAL_REQ 10
+#define WLAN_PROT_GAS_INITIAL_RESP 11
+#define WLAN_PROT_GAS_COMEBACK_REQ 12
+#define WLAN_PROT_GAS_COMEBACK_RESP 13
+
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
 #define WLAN_SA_QUERY_REQUEST 0
 #define WLAN_SA_QUERY_RESPONSE 1
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 0b8eed5..b5bf368 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3584,7 +3584,7 @@
 
 		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
 			struct nl80211_vendor_cmd_info *vinfo;
-			if (nla_len(nl) != sizeof(vinfo)) {
+			if (nla_len(nl) != sizeof(*vinfo)) {
 				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
 				continue;
 			}
@@ -3600,7 +3600,7 @@
 
 		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
 			struct nl80211_vendor_cmd_info *vinfo;
-			if (nla_len(nl) != sizeof(vinfo)) {
+			if (nla_len(nl) != sizeof(*vinfo)) {
 				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
 				continue;
 			}
@@ -4216,6 +4216,18 @@
 	/* GAS Comeback Response */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
 		ret = -1;
+	/* Protected GAS Initial Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
+		ret = -1;
+	/* Protected GAS Initial Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
+		ret = -1;
+	/* Protected GAS Comeback Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
+		ret = -1;
+	/* Protected GAS Comeback Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
+		ret = -1;
 #endif /* CONFIG_P2P || CONFIG_INTERWORKING */
 #ifdef CONFIG_P2P
 	/* P2P Public Action */
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index f2aa971..8aabfc0 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -43,7 +43,7 @@
  */
 #ifndef P2P_PEER_EXPIRATION_AGE
 #define P2P_PEER_EXPIRATION_AGE 60
-#endif
+#endif /* P2P_PEER_EXPIRATION_AGE */
 
 #define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2)
 
@@ -3151,13 +3151,13 @@
 
 static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
 {
-	/*
-	 * TODO: could remain constantly in Listen state for some time if there
-	 * are no other concurrent uses for the radio. For now, go to listen
-	 * state once per second to give other uses a chance to use the radio.
-	 */
 	p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
-	p2p_set_timeout(p2p, 0, 500000);
+
+	if (p2p->cfg->is_concurrent_session_active &&
+	    p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx))
+		p2p_set_timeout(p2p, 0, 500000);
+	else
+		p2p_set_timeout(p2p, 0, 200000);
 }
 
 
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 25a91e7..2ce6ea6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -789,6 +789,15 @@
 	 */
 	void (*presence_resp)(void *ctx, const u8 *src, u8 status,
 			      const u8 *noa, size_t noa_len);
+
+	/**
+	 * is_concurrent_session_active - Check whether concurrent session is
+	 * active on other virtual interfaces
+	 * @ctx: Callback context from cb_ctx
+	 * Returns: 1 if concurrent session is active on other virtual interface
+	 * or 0 if not.
+	 */
+	int (*is_concurrent_session_active)(void *ctx);
 };