Accumulative patch from commit 17b8995cf5813d7c027cd7a6884700e791d72392

17b8995 Interworking: Try to use same BSS entry for storing GAS results
3db5439 Optimize Extended Capabilities element to be of minimal length
8cd6b7b hostapd/wpa_s: Use driver's extended capabilities
acb5464 Add ctrl_iface command FLUSH for clearing wpa_supplicant state
97236ce WPS: Skip rescanning after provisioning if AP was configured
4342326 Add ignore_old_scan_res configuration parameter
9599ccc WPS: Clear after_wps on new WPS connection
702621e WPS: Use latest updated BSS entry if multiple BSSID matches found
ab547b5 WPS: Add more helpful debug for invalid WPS_REG command parsing
a679c0f WPS: Allow hostapd process to control independent WPS interfaces
ccdff94 WPS AP: Add support for reconfiguration with in-memory config
8970bae nl80211: Use nla_nest_start/end instead of nla_put_nested
558d69e P2P: Omit P2P Group Info in case of no connected peers
65a32cd AP: Fix infinite loop in WPA state machine when out of random bytes
a5f61b2 Fix OLBC non-HT AP detection to check channel
69554d7 ap_list: Remove unused functions
08c99ca ap_list: Remove unused iteration list pointers
6b16917 ap_list: Remove unused fields
66f1f75 P2P: Fix provision discovery response handling in some cases
2f9b66d Extend ROAM command to handle multiple SSIDs per BSS

Change-Id: I46002b1d3bbf6e376c2ae09bcb2c824c54805bbd
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c2b9fff..cd266b4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -214,6 +214,8 @@
 	int ignore_if_down_event;
 	struct rfkill_data *rfkill;
 	struct wpa_driver_capa capa;
+	u8 *extended_capa, *extended_capa_mask;
+	unsigned int extended_capa_len;
 	int has_capability;
 
 	int operstate;
@@ -2554,6 +2556,7 @@
 
 
 struct wiphy_info_data {
+	struct wpa_driver_nl80211_data *drv;
 	struct wpa_driver_capa *capa;
 
 	unsigned int error:1;
@@ -2795,6 +2798,7 @@
 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 	struct wiphy_info_data *info = arg;
 	struct wpa_driver_capa *capa = info->capa;
+	struct wpa_driver_nl80211_data *drv = info->drv;
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
@@ -2842,6 +2846,30 @@
 	wiphy_info_probe_resp_offload(capa,
 				      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
 
+	if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+	    drv->extended_capa == NULL) {
+		drv->extended_capa =
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		if (drv->extended_capa) {
+			os_memcpy(drv->extended_capa,
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+			drv->extended_capa_len =
+				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+		}
+		drv->extended_capa_mask =
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		if (drv->extended_capa_mask) {
+			os_memcpy(drv->extended_capa_mask,
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		} else {
+			os_free(drv->extended_capa);
+			drv->extended_capa = NULL;
+			drv->extended_capa_len = 0;
+		}
+	}
+
 	return NL_SKIP;
 }
 
@@ -2854,6 +2882,7 @@
 
 	os_memset(info, 0, sizeof(*info));
 	info->capa = &drv->capa;
+	info->drv = drv;
 
 	msg = nlmsg_alloc();
 	if (!msg)
@@ -3751,6 +3780,8 @@
 	if (drv->in_interface_list)
 		dl_list_del(&drv->list);
 
+	os_free(drv->extended_capa);
+	os_free(drv->extended_capa_mask);
 	os_free(drv);
 }
 
@@ -3781,7 +3812,6 @@
 		    struct wpa_driver_scan_params *params)
 {
 	struct nl_msg *msg;
-	int err;
 	size_t i;
 
 	msg = nlmsg_alloc();
@@ -3794,23 +3824,20 @@
 		goto fail;
 
 	if (params->num_ssids) {
-		struct nl_msg *ssids = nlmsg_alloc();
+		struct nlattr *ssids;
+
+		ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
 		if (ssids == NULL)
 			goto fail;
 		for (i = 0; i < params->num_ssids; i++) {
 			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
 					  params->ssids[i].ssid,
 					  params->ssids[i].ssid_len);
-			if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
-				    params->ssids[i].ssid) < 0) {
-				nlmsg_free(ssids);
+			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+				    params->ssids[i].ssid) < 0)
 				goto fail;
-			}
 		}
-		err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-		nlmsg_free(ssids);
-		if (err < 0)
-			goto fail;
+		nla_nest_end(msg, ssids);
 	}
 
 	if (params->extra_ies) {
@@ -3822,22 +3849,17 @@
 	}
 
 	if (params->freqs) {
-		struct nl_msg *freqs = nlmsg_alloc();
+		struct nlattr *freqs;
+		freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
 		if (freqs == NULL)
 			goto fail;
 		for (i = 0; params->freqs[i]; i++) {
 			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
 				   "MHz", params->freqs[i]);
-			if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
-				nlmsg_free(freqs);
+			if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
 				goto fail;
-			}
 		}
-		err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
-				     freqs);
-		nlmsg_free(freqs);
-		if (err < 0)
-			goto fail;
+		nla_nest_end(msg, freqs);
 	}
 
 	os_free(drv->filter_ssids);
@@ -3864,7 +3886,7 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1, timeout;
-	struct nl_msg *msg, *rates = NULL;
+	struct nl_msg *msg = NULL;
 
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
 	drv->scan_for_auth = 0;
@@ -3874,9 +3896,11 @@
 		return -1;
 
 	if (params->p2p_probe) {
+		struct nlattr *rates;
+
 		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
 
-		rates = nlmsg_alloc();
+		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
 		if (rates == NULL)
 			goto nla_put_failure;
 
@@ -3886,11 +3910,9 @@
 		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
 		 * rates are left enabled.
 		 */
-		NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+		NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
 			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-		if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
-		    0)
-			goto nla_put_failure;
+		nla_nest_end(msg, rates);
 
 		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
 	}
@@ -3944,7 +3966,6 @@
 
 nla_put_failure:
 	nlmsg_free(msg);
-	nlmsg_free(rates);
 	return ret;
 }
 
@@ -3964,8 +3985,6 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1;
 	struct nl_msg *msg;
-	struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
-	struct nl_msg *match_set_rssi = NULL;
 	size_t i;
 
 	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
@@ -3984,46 +4003,42 @@
 	if ((drv->num_filter_ssids &&
 	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
 	    params->filter_rssi) {
-		match_sets = nlmsg_alloc();
+		struct nlattr *match_sets;
+		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
 		if (match_sets == NULL)
 			goto nla_put_failure;
 
 		for (i = 0; i < drv->num_filter_ssids; i++) {
+			struct nlattr *match_set_ssid;
 			wpa_hexdump_ascii(MSG_MSGDUMP,
 					  "nl80211: Sched scan filter SSID",
 					  drv->filter_ssids[i].ssid,
 					  drv->filter_ssids[i].ssid_len);
 
-			match_set_ssid = nlmsg_alloc();
+			match_set_ssid = nla_nest_start(msg, i + 1);
 			if (match_set_ssid == NULL)
 				goto nla_put_failure;
-			NLA_PUT(match_set_ssid,
-				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
 				drv->filter_ssids[i].ssid_len,
 				drv->filter_ssids[i].ssid);
 
-			if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
-			    0)
-				goto nla_put_failure;
+			nla_nest_end(msg, match_sets);
 		}
 
 		if (params->filter_rssi) {
-			match_set_rssi = nlmsg_alloc();
+			struct nlattr *match_set_rssi;
+			match_set_rssi = nla_nest_start(msg, 0);
 			if (match_set_rssi == NULL)
 				goto nla_put_failure;
-			NLA_PUT_U32(match_set_rssi,
-				    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+			NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 				    params->filter_rssi);
 			wpa_printf(MSG_MSGDUMP,
 				   "nl80211: Sched scan RSSI filter %d dBm",
 				   params->filter_rssi);
-			if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
-				goto nla_put_failure;
+			nla_nest_end(msg, match_set_rssi);
 		}
 
-		if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-				   match_sets) < 0)
-			goto nla_put_failure;
+		nla_nest_end(msg, match_sets);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4041,9 +4056,6 @@
 		   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-	nlmsg_free(match_set_ssid);
-	nlmsg_free(match_sets);
-	nlmsg_free(match_set_rssi);
 	nlmsg_free(msg);
 	return ret;
 }
@@ -4532,18 +4544,15 @@
 				    NL80211_KEYTYPE_GROUP);
 		}
 	} else if (addr && is_broadcast_ether_addr(addr)) {
-		struct nl_msg *types;
-		int err;
+		struct nlattr *types;
+
 		wpa_printf(MSG_DEBUG, "   broadcast key");
-		types = nlmsg_alloc();
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		nla_nest_end(msg, types);
 	}
 	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4577,29 +4586,21 @@
 	else
 		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
 	if (addr && is_broadcast_ether_addr(addr)) {
-		struct nl_msg *types;
-		int err;
-		types = nlmsg_alloc();
+		struct nlattr *types;
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		nla_nest_end(msg, types);
 	} else if (addr) {
-		struct nl_msg *types;
-		int err;
-		types = nlmsg_alloc();
+		struct nlattr *types;
+
+		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
 		if (!types)
 			goto nla_put_failure;
-		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
-		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-				     types);
-		nlmsg_free(types);
-		if (err)
-			goto nla_put_failure;
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+		nla_nest_end(msg, types);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6071,7 +6072,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *wme = NULL;
+	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
 	int ret = -ENOBUFS;
 
@@ -6138,18 +6139,18 @@
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
 	if (params->flags & WPA_STA_WMM) {
-		wme = nlmsg_alloc();
+		struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
 		if (!wme)
 			goto nla_put_failure;
 
 		wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
-		NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+		NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
 				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
-		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+		NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
 				(params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
 				WMM_QOSINFO_STA_SP_MASK);
-		if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
-			goto nla_put_failure;
+		nla_nest_end(msg, wme);
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6161,7 +6162,6 @@
 	if (ret == -EEXIST)
 		ret = 0;
  nla_put_failure:
-	nlmsg_free(wme);
 	nlmsg_free(msg);
 	return ret;
 }
@@ -6245,7 +6245,7 @@
 				     enum nl80211_iftype iftype,
 				     const u8 *addr, int wds)
 {
-	struct nl_msg *msg, *flags = NULL;
+	struct nl_msg *msg;
 	int ifidx;
 	int ret = -ENOBUFS;
 
@@ -6262,20 +6262,15 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
 	if (iftype == NL80211_IFTYPE_MONITOR) {
-		int err;
+		struct nlattr *flags;
 
-		flags = nlmsg_alloc();
+		flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
 		if (!flags)
 			goto nla_put_failure;
 
-		NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+		NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-		err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-		nlmsg_free(flags);
-
-		if (err)
-			goto nla_put_failure;
+		nla_nest_end(msg, flags);
 	} else if (wds) {
 		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
 	}
@@ -6908,19 +6903,14 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *flags = NULL;
+	struct nl_msg *msg;
+	struct nlattr *flags;
 	struct nl80211_sta_flag_update upd;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	flags = nlmsg_alloc();
-	if (!flags) {
-		nlmsg_free(msg);
-		return -ENOMEM;
-	}
-
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -6931,35 +6921,34 @@
 	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
 	 * can be removed eventually.
 	 */
+	flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+	if (!flags)
+		goto nla_put_failure;
 	if (total_flags & WPA_STA_AUTHORIZED)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
 
 	if (total_flags & WPA_STA_WMM)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
 
 	if (total_flags & WPA_STA_SHORT_PREAMBLE)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
 	if (total_flags & WPA_STA_MFP)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
 
 	if (total_flags & WPA_STA_TDLS_PEER)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
 
-	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-		goto nla_put_failure;
+	nla_nest_end(msg, flags);
 
 	os_memset(&upd, 0, sizeof(upd));
 	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
 	upd.set = sta_flags_nl80211(flags_or);
 	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
-	nlmsg_free(flags);
-
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
 	nlmsg_free(msg);
-	nlmsg_free(flags);
 	return -ENOBUFS;
 }
 
@@ -7664,6 +7653,11 @@
 	if (!drv->has_capability)
 		return -1;
 	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	if (drv->extended_capa && drv->extended_capa_mask) {
+		capa->extended_capa = drv->extended_capa;
+		capa->extended_capa_mask = drv->extended_capa_mask;
+		capa->extended_capa_len = drv->extended_capa_len;
+	}
 	return 0;
 }
 
@@ -9032,7 +9026,8 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *cqm = NULL;
+	struct nl_msg *msg;
+	struct nlattr *cqm;
 	int ret = -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
@@ -9046,20 +9041,18 @@
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
-	cqm = nlmsg_alloc();
+	cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
 	if (cqm == NULL)
 		goto nla_put_failure;
 
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-	if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
-		goto nla_put_failure;
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+	nla_nest_end(msg, cqm);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 
 nla_put_failure:
-	nlmsg_free(cqm);
 	nlmsg_free(msg);
 	return ret;
 }