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/src/ap/mbo_ap.c b/src/ap/mbo_ap.c
new file mode 100644
index 0000000..5e0f92a
--- /dev/null
+++ b/src/ap/mbo_ap.c
@@ -0,0 +1,245 @@
+/*
+ * hostapd - MBO
+ * Copyright (c) 2016, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "mbo_ap.h"
+
+
+void mbo_ap_sta_free(struct sta_info *sta)
+{
+	struct mbo_non_pref_chan_info *info, *prev;
+
+	info = sta->non_pref_chan;
+	sta->non_pref_chan = NULL;
+	while (info) {
+		prev = info;
+		info = info->next;
+		os_free(prev);
+	}
+}
+
+
+static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
+				       const u8 *buf, size_t len)
+{
+	struct mbo_non_pref_chan_info *info, *tmp;
+	char channels[200], *pos, *end;
+	size_t num_chan, i;
+	int ret;
+
+	if (len <= 4)
+		return; /* Not enough room for any channels */
+
+	num_chan = len - 4;
+	info = os_zalloc(sizeof(*info) + num_chan);
+	if (!info)
+		return;
+	info->op_class = buf[0];
+	info->pref = buf[len - 3];
+	info->reason_code = buf[len - 2];
+	info->reason_detail = buf[len - 1];
+	info->num_channels = num_chan;
+	buf++;
+	os_memcpy(info->channels, buf, num_chan);
+	if (!sta->non_pref_chan) {
+		sta->non_pref_chan = info;
+	} else {
+		tmp = sta->non_pref_chan;
+		while (tmp->next)
+			tmp = tmp->next;
+		tmp->next = info;
+	}
+
+	pos = channels;
+	end = pos + sizeof(channels);
+	*pos = '\0';
+	for (i = 0; i < num_chan; i++) {
+		ret = os_snprintf(pos, end - pos, "%s%u",
+				  i == 0 ? "" : " ", buf[i]);
+		if (os_snprintf_error(end - pos, ret)) {
+			*pos = '\0';
+			break;
+		}
+		pos += ret;
+	}
+
+	wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+		   " non-preferred channel list (op class %u, pref %u, reason code %u, reason detail %u, channels %s)",
+		   MAC2STR(sta->addr), info->op_class, info->pref,
+		   info->reason_code, info->reason_detail, channels);
+}
+
+
+void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
+			    struct ieee802_11_elems *elems)
+{
+	const u8 *pos, *attr, *end;
+	size_t len;
+
+	if (!hapd->conf->mbo_enabled || !elems->mbo)
+		return;
+
+	pos = elems->mbo + 4;
+	len = elems->mbo_len - 4;
+	wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
+
+	attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
+	if (attr && attr[1] >= 1)
+		sta->cell_capa = attr[2];
+
+	mbo_ap_sta_free(sta);
+	end = pos + len;
+	while (end - pos > 1) {
+		u8 ie_len = pos[1];
+
+		if (2 + ie_len > end - pos)
+			break;
+
+		if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
+			mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
+		pos += 2 + pos[1];
+	}
+}
+
+
+int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
+{
+	char *pos = buf, *end = buf + buflen;
+	int ret;
+	struct mbo_non_pref_chan_info *info;
+	u8 i;
+	unsigned int count = 0;
+
+	if (!sta->cell_capa)
+		return 0;
+
+	ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
+	if (os_snprintf_error(end - pos, ret))
+		return pos - buf;
+	pos += ret;
+
+	for (info = sta->non_pref_chan; info; info = info->next) {
+		char *pos2 = pos;
+
+		ret = os_snprintf(pos2, end - pos2,
+				  "non_pref_chan[%u]=%u:%u:%u:%u:",
+				  count, info->op_class, info->pref,
+				  info->reason_code, info->reason_detail);
+		count++;
+		if (os_snprintf_error(end - pos2, ret))
+			break;
+		pos2 += ret;
+
+		for (i = 0; i < info->num_channels; i++) {
+			ret = os_snprintf(pos2, end - pos2, "%u%s",
+					  info->channels[i],
+					  i + 1 < info->num_channels ?
+					  "," : "");
+			if (os_snprintf_error(end - pos2, ret)) {
+				pos2 = NULL;
+				break;
+			}
+			pos2 += ret;
+		}
+
+		if (!pos2)
+			break;
+		ret = os_snprintf(pos2, end - pos2, "\n");
+		if (os_snprintf_error(end - pos2, ret))
+			break;
+		pos2 += ret;
+		pos = pos2;
+	}
+
+	return pos - buf;
+}
+
+
+static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
+					   const u8 *buf, size_t len)
+{
+	if (len < 1)
+		return;
+	wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
+		   " updated cellular data capability: %u",
+		   MAC2STR(sta->addr), buf[0]);
+	sta->cell_capa = buf[0];
+}
+
+
+static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
+				      const u8 *buf, size_t len,
+				      int *first_non_pref_chan)
+{
+	switch (type) {
+	case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
+		if (*first_non_pref_chan) {
+			/*
+			 * Need to free the previously stored entries now to
+			 * allow the update to replace all entries.
+			 */
+			*first_non_pref_chan = 0;
+			mbo_ap_sta_free(sta);
+		}
+		mbo_ap_parse_non_pref_chan(sta, buf, len);
+		break;
+	case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
+		mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "MBO: Ignore unknown WNM Notification WFA subelement %u",
+			   type);
+		break;
+	}
+}
+
+
+void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
+				 const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+	u8 ie_len;
+	struct sta_info *sta;
+	int first_non_pref_chan = 1;
+
+	if (!hapd->conf->mbo_enabled)
+		return;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta)
+		return;
+
+	pos = buf;
+	end = buf + len;
+
+	while (end - pos > 1) {
+		ie_len = pos[1];
+
+		if (2 + ie_len > end - pos)
+			break;
+
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+		    ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
+			mbo_ap_wnm_notif_req_elem(sta, pos[5],
+						  pos + 6, ie_len - 4,
+						  &first_non_pref_chan);
+		else
+			wpa_printf(MSG_DEBUG,
+				   "MBO: Ignore unknown WNM Notification element %u (len=%u)",
+				   pos[0], pos[1]);
+
+		pos += 2 + pos[1];
+	}
+}