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/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])