Cumulative patch from commit 077dcfb8c48d2509a6e116c0de3ad57d2fbfe4fe

077dcfb AP: Debug print management frame TX result
ca911d6 MBO: Parse non-preferred channel list on the AP
3f48274 WNM: Fix a memory leak on AP error path
f5ca176 VLAN: Fix vlan_compare() for tagged VLANs
1260564 hostapd_cli: Add support for RAW command
940491c MBO: Mandate use of PMF for WPA2+MBO association (STA)
4c57228 MBO: Mandate use of PMF for WPA2+MBO association (AP)
8dd49f0 MBO: Update STA cellular data capability based on WNM Notification
6332aaf MBO: Track STA cellular data capability from association request
f3cb7a6 WNM: Minimal processing for WNM Notification Request frames on AP
e578343 MBO: Indicate WNM-Notification support on AP when MBO is enabled
990b7b6 Simplify hostapd_build_ap_extra_ies() with helper functions
d010048 MBO: Expire non-matching bss_tmp_disallowed entries as part of check
f4c74e1 MBO: Parse MBO IE in ieee802_11_parse_elems()
016082e MBO: Send WNM-Notification when cellular capabilities change
c0e2a17 hostapd: Add MBO IE to BSS Transition Management Request frame
fb9a1c3 hostapd: Add MBO IE to Beacon, Probe Response, Association Response
c484b19 Move Hotspot 2.0 element in (Re)Association Request frames
a0c38e5 Re-order elements in (Re)Association Request frames
9a493fa WNM: Add candidate list to BSS transition query
84d1c0f WNM: Add candidate list to BSS transition response
cf11ab7 utils: Derive phy type by frequency and bandwidth
c8082d2 MBO: Add MBO IE to BSS Transition Management Response frame
dd59990 MBO: Parse MBO IE in BSS Transition Management Request frames
5e57ba2 MBO: Add Supported Operating Classes element to Association Request
7d46f58 MBO: Add global operating class definitions
cb06cf3 MBO: Prevent association to APs that explicitly disallow this
c5d193d MBO: Add cellular capability to MBO IE
2d5b861 MBO: Send MBO WNM-Notification Request frames to notify changes
92c6e2e MBO: Implement MBO non-preferred channel report in Association Request
facf2c7 MBO: Add non-preferred channel configuration in wpa_supplicant
425dd78 MBO: Add Multi Band Operation definitions
a159958 ndis: Use the new get_ie() helper to avoid duplicated code
231b04b utils: Share a single helper function to get IE by ID
ea69d97 wpa_supplicant: Share a single get_mode() implementation
75cc211 VLAN: Check vlan_desc validity in a failure debug print
43022ab Use 64-bit TX/RX byte counters for statistics
3f81ac0 AP: Set STA assoc flag in the driver before sending Assoc Resp frame
bb598c3 AP: Add support for full station state
dc55b6b nl80211: Add support for full station state operations
5558b99 EAP-FAST peer: Remove fixed return value from eap_fast_parse_phase1()
4b16c15 EAP-pwd server: Use os_get_random() for unpredictable token
239952b DFS: Remove the os_random() fallback
98a516e WPS: Use only os_get_random() for PIN generation
f441e5a Use os_get_random() for Shared Key authentication challenge
8c676b5 Add RADIUS Service-Type attribute with a value of Framed
09d96de mesh: Drop Authentication frames from BLOCKED STA
70c9396 SAE: Fix PMKID calculation for PMKSA cache
1492fbb Print Acct-Session-Id and Acct-Multi-Session-Id 64-bit values
e21ceca kqueue: Use 0 instead of NULL for udata
640b0b9 ctype functions require an unsigned char
a5a3efc Fix compile on NetBSD for vlan
a084c24 wired: Fix compile on NetBSD for wired driver
634e2e2 Add CONFIG_ELOOP_KQUEUE to defconfig
99a94f5 nl80211: Avoid wpa_printf %s call with NULL pointer in set_param()
ba91e92 wpa_supplicant: Parse ifname argument from DATA_TEST_CONFIG
8be640b VLAN: Add per-STA vif option
d0bdc96 VLAN: Actually add tagged VLANs to AP_VLAN
f9c0018 VLAN: Factor out per-vid code in newlink/dellink
8e44c19 radius: Add tagged VLAN parsing
1889af2 VLAN: Separate station grouping and uplink configuration
3a583e0 OpenSSL: Fix PKCS#12 parsing of extra certificates with OpenSSL 1.0.1
ddd0032 wpa_cli: Clean up logical operation
24c382a TDLS: Clean up os_memcmp use
6136d43 trace: Free symbols on program exit
8bcf8de OpenSSL: Fix memory leak in PKCS12 additional certificate parsing
03e3ddf OpenSSL: Fix memory leak in HMAC_CTX compatibility wrapper function
d9a0f69 OpenSSL: Fix memory leak in OCSP parsing
29bc76e OpenSSL: Do not use library init/deinit functions with 1.1.0
0f09637 OpenSSL: Fix memory leak in subjectAltName parsing
e60913b curl: Fix memory leak in subjectAltName parsing
6014890 OpenSSL: Fix memory leak with EVP_CIPHER_CTX_new()
99a1735 rfkill: Fix a memory leak
1f1e599 OpenSSL: Fix memory leak on error path
b907491 wpa_supplicant: Basic support for PBSS/PCP
86b5c40 nl80211: Basic support for PBSS/PCP
afa453a Sync with mac80211-next.git include/uapi/linux/nl80211.h
d1d8a2b EAP peer: Simplify buildNotify return
1314bc1 Clean up EAP peer PCSC identity functions

Change-Id: I9db475a2a4ebc88d2ee024319ed59a850636bb16
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index ffc9052..0dc41dc 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -546,6 +546,14 @@
 			continue;
 		}
 
+		if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+			wpa_printf(MSG_DEBUG,
+				   "MBO: Candidate BSS " MACSTR
+				   " retry delay is not over yet",
+				   MAC2STR(nei->bssid));
+			continue;
+		}
+
 		if (target->level < bss->level && target->level < -80) {
 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
 				   " (pref %d) does not have sufficient signal level (%d)",
@@ -567,12 +575,190 @@
 }
 
 
+static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
+{
+	const u8 *ie_a, *ie_b;
+
+	if (!a || !b)
+		return 0;
+
+	ie_a = wpa_bss_get_ie(a, eid);
+	ie_b = wpa_bss_get_ie(b, eid);
+
+	if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
+		return 0;
+
+	return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
+}
+
+
+static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	u32 info = 0;
+
+	info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
+
+	/*
+	 * Leave the security and key scope bits unset to indicate that the
+	 * security information is not available.
+	 */
+
+	if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
+		info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+	if (bss->caps & WLAN_CAPABILITY_QOS)
+		info |= NEI_REP_BSSID_INFO_QOS;
+	if (bss->caps & WLAN_CAPABILITY_APSD)
+		info |= NEI_REP_BSSID_INFO_APSD;
+	if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
+		info |= NEI_REP_BSSID_INFO_RM;
+	if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
+		info |= NEI_REP_BSSID_INFO_DELAYED_BA;
+	if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
+		info |= NEI_REP_BSSID_INFO_IMM_BA;
+	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
+		info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
+	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
+		info |= NEI_REP_BSSID_INFO_HT;
+
+	return info;
+}
+
+
+static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info,
+			   u8 op_class, u8 chan, u8 phy_type, u8 pref)
+{
+	u8 *pos = buf;
+
+	if (len < 18) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Not enough room for Neighbor Report element");
+		return -1;
+	}
+
+	*pos++ = WLAN_EID_NEIGHBOR_REPORT;
+	/* length: 13 for basic neighbor report + 3 for preference subelement */
+	*pos++ = 16;
+	os_memcpy(pos, bssid, ETH_ALEN);
+	pos += ETH_ALEN;
+	WPA_PUT_LE32(pos, bss_info);
+	pos += 4;
+	*pos++ = op_class;
+	*pos++ = chan;
+	*pos++ = phy_type;
+	*pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE;
+	*pos++ = 1;
+	*pos++ = pref;
+	return pos - buf;
+}
+
+
+static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
+			       struct wpa_bss *bss, u8 *buf, size_t len,
+			       u8 pref)
+{
+	const u8 *ie;
+	u8 op_class, chan;
+	int sec_chan = 0, vht = 0;
+	enum phy_type phy_type;
+	u32 info;
+	struct ieee80211_ht_operation *ht_oper = NULL;
+	struct ieee80211_vht_operation *vht_oper = NULL;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+	if (ie && ie[1] >= 2) {
+		ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+
+		if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+			sec_chan = 1;
+		else if (ht_oper->ht_param &
+			 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+			sec_chan = -1;
+	}
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
+	if (ie && ie[1] >= 1) {
+		vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+		if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
+		    vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
+		    vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
+			vht = vht_oper->vht_op_info_chwidth;
+	}
+
+	if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
+					  &chan) == NUM_HOSTAPD_MODES) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Cannot determine operating class and channel");
+		return -2;
+	}
+
+	phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
+					  (vht_oper != NULL));
+	if (phy_type == PHY_TYPE_UNSPECIFIED) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Cannot determine BSS phy type for Neighbor Report");
+		return -2;
+	}
+
+	info = wnm_get_bss_info(wpa_s, bss);
+
+	return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan,
+			       phy_type, pref);
+}
+
+
+static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+{
+	u8 *pos = buf;
+	unsigned int i, pref = 255;
+	struct os_reltime now;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (!ssid)
+		return 0;
+
+	/*
+	 * TODO: Define when scan results are no longer valid for the candidate
+	 * list.
+	 */
+	os_get_reltime(&now);
+	if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
+		return 0;
+
+	wpa_printf(MSG_DEBUG,
+		   "WNM: Add candidate list to BSS Transition Management Response frame");
+	for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
+		struct wpa_bss *bss = wpa_s->last_scan_res[i];
+		int res;
+
+		if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
+			res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
+			if (res == -2)
+				continue; /* could not build entry for BSS */
+			if (res < 0)
+				break; /* no more room for candidates */
+			if (pref == 1)
+				break;
+
+			pos += res;
+			len -= res;
+		}
+	}
+
+	wpa_hexdump(MSG_DEBUG,
+		    "WNM: BSS Transition Management Response candidate list",
+		    buf, pos - buf);
+
+	return pos - buf;
+}
+
+
 static void wnm_send_bss_transition_mgmt_resp(
 	struct wpa_supplicant *wpa_s, u8 dialog_token,
 	enum bss_trans_mgmt_status_code status, u8 delay,
 	const u8 *target_bssid)
 {
-	u8 buf[1000], *pos;
+	u8 buf[2000], *pos;
 	struct ieee80211_mgmt *mgmt;
 	size_t len;
 	int res;
@@ -612,6 +798,17 @@
 		pos += ETH_ALEN;
 	}
 
+	if (status == WNM_BSS_TM_ACCEPT)
+		pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
+#ifdef CONFIG_MBO
+	if (status != WNM_BSS_TM_ACCEPT) {
+		pos += wpas_mbo_ie_bss_trans_reject(
+			wpa_s, pos, buf + sizeof(buf) - pos,
+			MBO_TRANSITION_REJECT_REASON_UNSPECIFIED);
+	}
+#endif /* CONFIG_MBO */
+
 	len = pos - (u8 *) &mgmt->u.action.category;
 
 	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
@@ -821,6 +1018,9 @@
 {
 	unsigned int beacon_int;
 	u8 valid_int;
+#ifdef CONFIG_MBO
+	const u8 *vendor;
+#endif /* CONFIG_MBO */
 
 	if (end - pos < 5)
 		return;
@@ -881,6 +1081,12 @@
 		}
 	}
 
+#ifdef CONFIG_MBO
+	vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
+	if (vendor)
+		wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
+#endif /* CONFIG_MBO */
+
 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
 		unsigned int valid_ms;
 
@@ -959,16 +1165,17 @@
 
 
 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
-				       u8 query_reason)
+				       u8 query_reason, int cand_list)
 {
-	u8 buf[1000], *pos;
+	u8 buf[2000], *pos;
 	struct ieee80211_mgmt *mgmt;
 	size_t len;
 	int ret;
 
 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
-		   MACSTR " query_reason=%u",
-		   MAC2STR(wpa_s->bssid), query_reason);
+		   MACSTR " query_reason=%u%s",
+		   MAC2STR(wpa_s->bssid), query_reason,
+		   cand_list ? " candidate list" : "");
 
 	mgmt = (struct ieee80211_mgmt *) buf;
 	os_memset(&buf, 0, sizeof(buf));
@@ -983,6 +1190,9 @@
 	mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
 	pos = mgmt->u.action.u.bss_tm_query.variable;
 
+	if (cand_list)
+		pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
+
 	len = pos - (u8 *) &mgmt->u.action.category;
 
 	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,