Cumulative patch from commit 1b56d398a7646c66fd3df8f0a5159c920f99de36

1b56d39 wpa_supplicant: Fix misplaced os_free
8597ebd Fix hostapd segfault on beacon hint event
c69ed4d bsd: Fix hostapd compiler warning
d950477 Fix authentication algorithm negotiation in SME code
1412bee nl80211: Show DFS region info in debug messages
fd92413 hostapd: Increase timeout for channel list update to 5 seconds
ff5e1d1 nl80211: Treat RSSI as part of each sched scan matchset
04c366c Fix memory leaks and wrong memory access
fd67275 wpa_supplicant: Fix wrong size memory allocation
4b0f228 nl80211: Fix channel switching with VHT80
e28f39b nl80211: Verify that ifindex attribute is included in survey
4701f37 wpa_cli: Add tdls_external_control to tab completion for SET

Change-Id: Iad3348c5c012c018cc1bfb759a36dbdb237b6468
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 79ab4ba..368b202 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -140,6 +140,7 @@
 
 	bss->radius = os_zalloc(sizeof(*bss->radius));
 	if (bss->radius == NULL) {
+		os_free(conf->bss);
 		os_free(conf);
 		os_free(bss);
 		return NULL;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 220211c..f9edf3b 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1028,7 +1028,7 @@
 		if (os_strncmp(previous_country, country, 2) != 0) {
 			wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
 			iface->wait_channel_update = 1;
-			eloop_register_timeout(1, 0,
+			eloop_register_timeout(5, 0,
 					       channel_list_update_timeout,
 					       iface, NULL);
 			return 0;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2f4536e..7ad8576 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -47,6 +47,7 @@
 	REGDOM_SET_BY_USER,
 	REGDOM_SET_BY_DRIVER,
 	REGDOM_SET_BY_COUNTRY_IE,
+	REGDOM_BEACON_HINT,
 };
 
 /**
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 71c9ce9..ca64d5c 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -68,34 +68,6 @@
 
 /* Generic functions for hostapd and wpa_supplicant */
 
-static enum ieee80211_opmode
-get80211opmode(struct bsd_driver_data *drv)
-{
-	struct ifmediareq ifmr;
-
-	(void) memset(&ifmr, 0, sizeof(ifmr));
-	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
-
-	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
-		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
-			if (ifmr.ifm_current & IFM_FLAG0)
-				return IEEE80211_M_AHDEMO;
-			else
-				return IEEE80211_M_IBSS;
-		}
-		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
-			return IEEE80211_M_HOSTAP;
-		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
-			return IEEE80211_M_MONITOR;
-#ifdef IEEE80211_M_MBSS
-		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
-			return IEEE80211_M_MBSS;
-#endif /* IEEE80211_M_MBSS */
-	}
-	return IEEE80211_M_STA;
-}
-
-
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
@@ -314,14 +286,6 @@
 	return 0;
 }
 
-#ifdef HOSTAPD
-static int
-bsd_commit(void *priv)
-{
-	return bsd_ctrl_iface(priv, 1);
-}
-#endif /* HOSTAPD */
-
 static int
 bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
@@ -530,28 +494,6 @@
 	return bsd_ctrl_iface(priv, 1);
 }
 
-#ifdef HOSTAPD
-static int
-bsd_set_sta_authorized(void *priv, const u8 *addr,
-		       int total_flags, int flags_or, int flags_and)
-{
-	int authorized = -1;
-
-	/* For now, only support setting Authorized flag */
-	if (flags_or & WPA_STA_AUTHORIZED)
-		authorized = 1;
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		authorized = 0;
-
-	if (authorized < 0)
-		return 0;
-
-	return bsd_send_mlme_param(priv, authorized ?
-				   IEEE80211_MLME_AUTHORIZE :
-				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
-}
-#endif /* HOSTAPD */
-
 static void
 bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
 {
@@ -933,6 +875,33 @@
 	os_free(drv);
 }
 
+
+static int
+bsd_commit(void *priv)
+{
+	return bsd_ctrl_iface(priv, 1);
+}
+
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr,
+		       int total_flags, int flags_or, int flags_and)
+{
+	int authorized = -1;
+
+	/* For now, only support setting Authorized flag */
+	if (flags_or & WPA_STA_AUTHORIZED)
+		authorized = 1;
+	if (!(flags_and & WPA_STA_AUTHORIZED))
+		authorized = 0;
+
+	if (authorized < 0)
+		return 0;
+
+	return bsd_send_mlme_param(priv, authorized ?
+				   IEEE80211_MLME_AUTHORIZE :
+				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
+}
 #else /* HOSTAPD */
 
 static int
@@ -1485,6 +1454,33 @@
 	return 0;
 }
 
+static enum ieee80211_opmode
+get80211opmode(struct bsd_driver_data *drv)
+{
+	struct ifmediareq ifmr;
+
+	(void) memset(&ifmr, 0, sizeof(ifmr));
+	(void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+
+	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
+			if (ifmr.ifm_current & IFM_FLAG0)
+				return IEEE80211_M_AHDEMO;
+			else
+				return IEEE80211_M_IBSS;
+		}
+		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+			return IEEE80211_M_HOSTAP;
+		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+			return IEEE80211_M_MONITOR;
+#ifdef IEEE80211_M_MBSS
+		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
+			return IEEE80211_M_MBSS;
+#endif /* IEEE80211_M_MBSS */
+	}
+	return IEEE80211_M_STA;
+}
+
 static void *
 wpa_driver_bsd_init(void *ctx, const char *ifname)
 {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 646d3f8..5323e99 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1550,6 +1550,33 @@
 }
 
 
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
+{
+	int freq1 = 0;
+
+	switch (convert2width(width)) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		return 0;
+	case CHAN_WIDTH_40:
+		freq1 = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		freq1 = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		freq1 = cf1 - 70;
+		break;
+	case CHAN_WIDTH_UNKNOWN:
+	case CHAN_WIDTH_80P80:
+		/* FIXME: implement this */
+		return 0;
+	}
+
+	return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
 static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
 				 struct nlattr *ifindex, struct nlattr *freq,
 				 struct nlattr *type, struct nlattr *bw,
@@ -1591,6 +1618,14 @@
 			chan_offset = -1;
 			break;
 		}
+	} else if (bw && cf1) {
+		/* This can happen for example with VHT80 ch switch */
+		chan_offset = calculate_chan_offset(nla_get_u32(bw),
+						    nla_get_u32(freq),
+						    nla_get_u32(cf1),
+						    cf2 ? nla_get_u32(cf2) : 0);
+	} else {
+		wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
 	}
 
 	os_memset(&data, 0, sizeof(data));
@@ -2965,8 +3000,10 @@
 		break;
 	case NL80211_CMD_REG_BEACON_HINT:
 		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+		os_memset(&data, 0, sizeof(data));
+		data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
 		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-				     NULL);
+				     &data);
 		break;
 	case NL80211_CMD_NEW_STATION:
 		nl80211_new_station_event(drv, tb);
@@ -4960,10 +4997,20 @@
 			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
 				drv->filter_ssids[i].ssid_len,
 				drv->filter_ssids[i].ssid);
+			if (params->filter_rssi)
+				NLA_PUT_U32(msg,
+					    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+					    params->filter_rssi);
 
 			nla_nest_end(msg, match_set_ssid);
 		}
 
+		/*
+		 * Due to backward compatibility code, newer kernels treat this
+		 * matchset (with only an RSSI filter) as the default for all
+		 * other matchsets, unless it's the only one, in which case the
+		 * matchset will actually allow all SSIDs above the RSSI.
+		 */
 		if (params->filter_rssi) {
 			struct nlattr *match_set_rssi;
 			match_set_rssi = nla_nest_start(msg, 0);
@@ -6537,6 +6584,23 @@
 }
 
 
+static const char * dfs_domain_name(enum nl80211_dfs_regions region)
+{
+	switch (region) {
+	case NL80211_DFS_UNSET:
+		return "DFS-UNSET";
+	case NL80211_DFS_FCC:
+		return "DFS-FCC";
+	case NL80211_DFS_ETSI:
+		return "DFS-ETSI";
+	case NL80211_DFS_JP:
+		return "DFS-JP";
+	default:
+		return "DFS-invalid";
+	}
+}
+
+
 static int nl80211_get_reg(struct nl_msg *msg, void *arg)
 {
 	struct phy_info_arg *results = arg;
@@ -6563,8 +6627,16 @@
 		return NL_SKIP;
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
-		   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+	if (tb_msg[NL80211_ATTR_DFS_REGION]) {
+		enum nl80211_dfs_regions dfs_domain;
+		dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
+			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
+			   dfs_domain_name(dfs_domain));
+	} else {
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+	}
 
 	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
 	{
@@ -10619,6 +10691,9 @@
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
+	if (!tb[NL80211_ATTR_IFINDEX])
+		return NL_SKIP;
+
 	ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
 	if (!tb[NL80211_ATTR_SURVEY_INFO])
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index ca347e7..957dee5 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3862,8 +3862,10 @@
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ie, ie_len, &msg))
 		return;
-	if (msg.minor_reason_code == NULL)
+	if (msg.minor_reason_code == NULL) {
+		p2p_parse_free(&msg);
 		return;
+	}
 
 	p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
 		" reason_code=%u minor_reason_code=%u",
@@ -3884,8 +3886,10 @@
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ie, ie_len, &msg))
 		return;
-	if (msg.minor_reason_code == NULL)
+	if (msg.minor_reason_code == NULL) {
+		p2p_parse_free(&msg);
 		return;
+	}
 
 	p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
 		" reason_code=%u minor_reason_code=%u",
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 76436f5..e28f93e 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -1136,6 +1136,7 @@
 
 	if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
 		p2p_dbg(p2p, "Was not expecting GO Negotiation Confirm - ignore");
+		p2p_parse_free(&msg);
 		return;
 	}
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;