wpa_supplicant: Update to 29-Aug-2012 TOT

commit 6ffdc2f7bd496ace7a46e055f9714e7db4b1f722
Author: Jouni Malinen <jouni@qca.qualcomm.com>
Date:   Fri Mar 2 22:31:04 2012 +0200

    WFD: Add preliminary WSD request processing and response

    This commit does not yet address support for different device roles,
    i.e., the same set of subelements are returned regardless of which
    role was indicated in the request.

    Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

Change-Id: I9d63acce719b982c02e589bb59602382e82988c8
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
index 6df7160..5906527 100644
--- a/src/drivers/android_drv.h
+++ b/src/drivers/android_drv.h
@@ -14,8 +14,6 @@
 
 #define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
 
-#define WEXT_CSCAN_AMOUNT		9
-
 #define MAX_SSID_LEN 32
 
 #define MAX_DRV_CMD_SIZE		248
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0aab61e..e392072 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -274,6 +274,15 @@
 	size_t num_filter_ssids;
 
 	/**
+	 * filter_rssi - Filter by RSSI
+	 *
+	 * The driver may filter scan results in firmware to reduce host
+	 * wakeups and thereby save power. Specify the RSSI threshold in s32
+	 * dBm.
+	 */
+	s32 filter_rssi;
+
+	/**
 	 * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
 	 *
 	 * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
@@ -731,6 +740,11 @@
 	 * This is used by driver which advertises this capability.
 	 */
 	int ap_max_inactivity;
+
+	/**
+	 * disable_dgaf - Whether group-addressed frames are disabled
+	 */
+	int disable_dgaf;
 };
 
 /**
@@ -751,6 +765,7 @@
 #define WPA_DRIVER_CAPA_ENC_TKIP	0x00000004
 #define WPA_DRIVER_CAPA_ENC_CCMP	0x00000008
 #define WPA_DRIVER_CAPA_ENC_WEP128	0x00000010
+#define WPA_DRIVER_CAPA_ENC_GCMP	0x00000020
 	unsigned int enc;
 
 #define WPA_DRIVER_AUTH_OPEN		0x00000001
@@ -817,6 +832,8 @@
 #define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
 /* Driver supports inactivity timer in AP mode */
 #define WPA_DRIVER_FLAGS_INACTIVITY_TIMER		0x00800000
+/* Driver expects user space implementation of MLME in AP mode */
+#define WPA_DRIVER_FLAGS_AP_MLME			0x01000000
 	unsigned int flags;
 
 	int max_scan_ssids;
@@ -983,6 +1000,23 @@
 	TDLS_DISABLE
 };
 
+enum wnm_oper {
+	WNM_SLEEP_ENTER_CONFIRM,
+	WNM_SLEEP_ENTER_FAIL,
+	WNM_SLEEP_EXIT_CONFIRM,
+	WNM_SLEEP_EXIT_FAIL,
+	WNM_SLEEP_TFS_REQ_IE_ADD,   /* STA requests driver to add TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_NONE,  /* STA requests empty TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_SET,   /* AP requests driver to set TFS req IE for
+				     * a STA */
+	WNM_SLEEP_TFS_RESP_IE_ADD,  /* AP requests driver to add TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */
+	WNM_SLEEP_TFS_RESP_IE_SET,  /* AP requests driver to set TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
+};
+
 /**
  * struct wpa_signal_info - Information about channel signal quality
  */
@@ -1042,7 +1076,8 @@
 	 * @ifname: Interface name (for multi-SSID/VLAN support)
 	 * @priv: private driver interface data
 	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
-	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
+	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
+	 *	%WPA_ALG_GCMP);
 	 *	%WPA_ALG_NONE clears the key.
 	 * @addr: Address of the peer STA (BSSID of the current AP when setting
 	 *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
@@ -1059,11 +1094,11 @@
 	 *	for Rx keys (in most cases, this is only used with broadcast
 	 *	keys and set to zero for unicast keys); %NULL if not set
 	 * @seq_len: length of the seq, depends on the algorithm:
-	 *	TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
+	 *	TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
 	 * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
 	 *	8-byte Rx Mic Key
 	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
-	 *	TKIP: 32, CCMP: 16, IGTK: 16)
+	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
 	 *
 	 * Returns: 0 on success, -1 on failure
 	 *
@@ -1568,9 +1603,9 @@
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This function is used to fetch the last used TSC/packet number for
-	 * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so
-	 * there is no strict requirement on implementing support for unicast
-	 * keys (i.e., addr != %NULL).
+	 * a TKIP, CCMP, GCMP, or BIP/IGTK key. It is mainly used with group
+	 * keys, so there is no strict requirement on implementing support for
+	 * unicast keys (i.e., addr != %NULL).
 	 */
 	int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
 			  int idx, u8 *seq);
@@ -2399,6 +2434,18 @@
 	int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
 
 	/**
+	 * wnm_oper - Notify driver of the WNM frame reception
+	 * @priv: Private driver interface data
+	 * @oper: WNM operation. See %enum wnm_oper
+	 * @peer: Destination (peer) MAC address
+	 * @buf: Buffer for the driver to fill in (for getting IE)
+	 * @buf_len: Return the len of buf
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*wnm_oper)(void *priv, enum wnm_oper oper, const u8 *peer,
+			u8 *buf, u16 *buf_len);
+
+	/**
 	 * signal_poll - Get current connection information
 	 * @priv: Private driver interface data
 	 * @signal_info: Connection info structure
@@ -3006,7 +3053,14 @@
 	 *
 	 * Described in wpa_event_data.ch_switch
 	 * */
-	EVENT_CH_SWITCH
+	EVENT_CH_SWITCH,
+
+	/**
+	 * EVENT_WNM - Request WNM operation
+	 *
+	 * This event can be used to request a WNM operation to be performed.
+	 */
+	EVENT_WNM
 };
 
 
@@ -3209,6 +3263,24 @@
 	} tdls;
 
 	/**
+	 * struct wnm - Data for EVENT_WNM
+	 */
+	struct wnm {
+		u8 addr[ETH_ALEN];
+		enum {
+			WNM_OPER_SLEEP,
+		} oper;
+		enum {
+			WNM_SLEEP_ENTER,
+			WNM_SLEEP_EXIT
+		} sleep_action;
+		int sleep_intval;
+		u16 reason_code;
+		u8 *buf;
+		u16 buf_len;
+	} wnm;
+
+	/**
 	 * struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
 	 *
 	 * During FT (IEEE 802.11r) authentication sequence, the driver is
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 73898d3..fefae8c 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -14,6 +14,12 @@
 #include <sys/ioctl.h>
 
 #include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "l2_packet/l2_packet.h"
+#include "p2p/p2p.h"
+
+#include "common.h"
 #ifndef _BYTE_ORDER
 #ifdef WORDS_BIGENDIAN
 #define _BYTE_ORDER _BIG_ENDIAN
@@ -837,7 +843,88 @@
 }
 #endif /* CONFIG_IEEE80211R */
 
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+#ifdef CONFIG_HS20
+static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
+				 size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	union wpa_event_data event;
+
+	/* Send the Action frame for HS20 processing */
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
+	    sizeof(mgmt->u.action.u.public_action))
+		return;
+
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
+	    mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+		return;
+
+	wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_mgmt.frame = (const u8 *) mgmt;
+	event.rx_mgmt.frame_len = len;
+	wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+}
+#endif /* CONFIG_HS20 */
+
+#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
+				 size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	union wpa_event_data event;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	u16 stype;
+
+	/* Do 11R processing for WNM ACTION frames */
+	if (len < IEEE80211_HDRLEN)
+		return;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+		return;
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+		   (int) len);
+
+	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+			   __func__);
+		return;
+	}
+
+	switch (stype) {
+	case WLAN_FC_STYPE_ACTION:
+		if (&mgmt->u.action.category > buf + len)
+			break;
+		os_memset(&event, 0, sizeof(event));
+		event.rx_action.da = mgmt->da;
+		event.rx_action.sa = mgmt->sa;
+		event.rx_action.bssid = mgmt->bssid;
+		event.rx_action.category = mgmt->u.action.category;
+		event.rx_action.data = &mgmt->u.action.category;
+		event.rx_action.len = buf + len - event.rx_action.data;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+		break;
+	default:
+		break;
+	}
+}
+#endif /* CONFIG_IEEE80211V */
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211V)
 static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 				size_t len)
 {
@@ -847,6 +934,12 @@
 #ifdef CONFIG_IEEE80211R
 	atheros_raw_recv_11r(ctx, src_addr, buf, len);
 #endif /* CONFIG_IEEE80211R */
+#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+	atheros_raw_recv_11v(ctx, src_addr, buf, len);
+#endif /* CONFIG_IEEE80211V */
+#ifdef CONFIG_HS20
+	atheros_raw_recv_hs20(ctx, src_addr, buf, len);
+#endif /* CONFIG_HS20 */
 }
 #endif /* CONFIG_WPS || CONFIG_IEEE80211R */
 
@@ -862,8 +955,15 @@
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_IEEE80211R
 	filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
-			       IEEE80211_FILTER_TYPE_AUTH);
+			       IEEE80211_FILTER_TYPE_AUTH |
+			       IEEE80211_FILTER_TYPE_ACTION);
 #endif
+#ifdef CONFIG_IEEE80211V
+	filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_IEEE80211V */
+#ifdef CONFIG_HS20
+	filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_HS20 */
 	if (filt.app_filterype) {
 		ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
 				   sizeof(struct ieee80211req_set_filter));
@@ -1165,8 +1265,8 @@
 		 */
 		wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
 #endif /* CONFIG_WPS */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
-#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
 	} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
 		/*
 		 * Atheros driver uses a hack to pass Probe Request frames as a
@@ -1175,50 +1275,136 @@
 		 * Format: "Manage.prob_req <frame len>" | zero padding | frame
 		 */
 		int len = atoi(custom + 16);
-		if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
 			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
 				   "length %d", len);
 			return;
 		}
 		atheros_raw_receive(drv, NULL,
-				    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 	} else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
 		/* Format: "Manage.assoc_req <frame len>" | zero padding |
 		 * frame */
 		int len = atoi(custom + 17);
-		if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
 			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
 				   "assoc_req/auth event length %d", len);
 			return;
 		}
 		atheros_raw_receive(drv, NULL,
-				    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 	} else if (strncmp(custom, "Manage.action ", 14) == 0) {
 		/* Format: "Manage.assoc_req <frame len>" | zero padding |
 		 * frame */
 		int len = atoi(custom + 14);
-		if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
 			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
 				   "assoc_req/auth event length %d", len);
 			return;
 		}
 		atheros_raw_receive(drv, NULL,
-				    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 	} else if (strncmp(custom, "Manage.auth ", 12) == 0) {
 		/* Format: "Manage.auth <frame len>" | zero padding | frame
 		 */
 		int len = atoi(custom + 12);
-		if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
 			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
 				   "assoc_req/auth event length %d", len);
 			return;
 		}
 		atheros_raw_receive(drv, NULL,
-				    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 #endif /* CONFIG_WPS or CONFIG_IEEE80211R */
 	}
 }
 
+/*
+* Handle size of data problem. WEXT only allows data of 256 bytes for custom
+* events, and p2p data can be much bigger. So the athr driver sends a small
+* event telling me to collect the big data with an ioctl.
+* On the first event, send all pending events to supplicant.
+*/
+static void fetch_pending_big_events(struct atheros_driver_data *drv)
+{
+	union wpa_event_data event;
+	const struct ieee80211_mgmt *mgmt;
+	u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */
+	u16 fc, stype;
+	struct iwreq iwr;
+	size_t data_len;
+	u32 freq, frame_type;
+
+	while (1) {
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+		iwr.u.data.pointer = (void *) tbuf;
+		iwr.u.data.length = sizeof(tbuf);
+		iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME;
+
+		if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr)
+		    < 0) {
+			if (errno == ENOSPC) {
+				wpa_printf(MSG_DEBUG, "%s:%d exit",
+					   __func__, __LINE__);
+				return;
+			}
+			wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM["
+				   "P2P_FETCH_FRAME] failed: %s",
+				   __func__, strerror(errno));
+			return;
+		}
+		data_len = iwr.u.data.length;
+		wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data",
+			    (u8 *) tbuf, data_len);
+		if (data_len < sizeof(freq) + sizeof(frame_type) + 24) {
+			wpa_printf(MSG_DEBUG, "athr: frame too short");
+			continue;
+		}
+		os_memcpy(&freq, tbuf, sizeof(freq));
+		os_memcpy(&frame_type, &tbuf[sizeof(freq)],
+			  sizeof(frame_type));
+		mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)];
+		data_len -= sizeof(freq) + sizeof(frame_type);
+
+		if (frame_type == IEEE80211_EV_RX_MGMT) {
+			fc = le_to_host16(mgmt->frame_control);
+			stype = WLAN_FC_GET_STYPE(fc);
+
+			wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u "
+				"freq=%u len=%u", stype, freq, (int) data_len);
+
+			if (stype == WLAN_FC_STYPE_ACTION) {
+				os_memset(&event, 0, sizeof(event));
+				event.rx_mgmt.frame = (const u8 *) mgmt;
+				event.rx_mgmt.frame_len = data_len;
+				wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT,
+						     &event);
+				continue;
+			}
+		} else {
+			wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
+				   __func__, frame_type);
+			continue;
+		}
+	}
+}
+
+static void
+atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
+				      int opcode, char *buf, int len)
+{
+	switch (opcode) {
+	case IEEE80211_EV_RX_MGMT:
+		wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
+		fetch_pending_big_events(drv);
+		break;
+	default:
+		break;
+	}
+}
+
 static void
 atheros_wireless_event_wireless(struct atheros_driver_data *drv,
 				char *data, int len)
@@ -1274,8 +1460,15 @@
 				return;		/* XXX */
 			memcpy(buf, custom, iwe->u.data.length);
 			buf[iwe->u.data.length] = '\0';
-			atheros_wireless_event_wireless_custom(
-				drv, buf, buf + iwe->u.data.length);
+
+			if (iwe->u.data.flags != 0) {
+				atheros_wireless_event_atheros_custom(
+					drv, (int) iwe->u.data.flags,
+					buf, len);
+			} else {
+				atheros_wireless_event_wireless_custom(
+					drv, buf, buf + iwe->u.data.length);
+			}
 			free(buf);
 			break;
 		}
@@ -1709,6 +1902,221 @@
 #endif /* CONFIG_IEEE80211R */
 
 
+/* Use only to set a big param, get will not work. */
+static int
+set80211big(struct atheros_driver_data *drv, int op, const void *data, int len)
+{
+	struct iwreq iwr;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+	iwr.u.data.pointer = (void *) data;
+	iwr.u.data.length = len;
+	iwr.u.data.flags = op;
+	wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x",
+		   __func__, op, op, athr_get_param_name(op), len);
+
+	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d "
+			   "value=0x%x,0x%x failed: %d (%s)",
+			   __func__, op, athr_get_ioctl_name(op), iwr.u.mode,
+			   iwr.u.mode, iwr.u.data.length,
+			   iwr.u.data.flags, errno, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+
+static int atheros_send_action(void *priv, unsigned int freq,
+			       unsigned int wait,
+			       const u8 *dst, const u8 *src,
+			       const u8 *bssid,
+			       const u8 *data, size_t data_len, int no_cck)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211_p2p_send_action *act;
+	int res;
+
+	act = os_zalloc(sizeof(*act) + data_len);
+	if (act == NULL)
+		return -1;
+	act->freq = freq;
+	os_memcpy(act->dst_addr, dst, ETH_ALEN);
+	os_memcpy(act->src_addr, src, ETH_ALEN);
+	os_memcpy(act->bssid, bssid, ETH_ALEN);
+	os_memcpy(act + 1, data, data_len);
+	wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src="
+		   MACSTR ", bssid=" MACSTR,
+		   __func__, act->freq, wait, MAC2STR(act->dst_addr),
+		   MAC2STR(act->src_addr), MAC2STR(act->bssid));
+	wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act));
+	wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len);
+
+	res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION,
+			  act, sizeof(*act) + data_len);
+	os_free(act);
+	return res;
+}
+
+
+#ifdef CONFIG_IEEE80211V
+static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
+			u8 *ie, u16 *len, enum wnm_oper oper)
+{
+#define IEEE80211_APPIE_MAX    1024 /* max appie buffer size */
+	u8 buf[IEEE80211_APPIE_MAX];
+	struct ieee80211req_getset_appiebuf *tfs_ie;
+	u16 val;
+
+	wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
+		   drv->iface, oper, MAC2STR(peer));
+
+	switch (oper) {
+	case WNM_SLEEP_TFS_REQ_IE_SET:
+		if (*len > IEEE80211_APPIE_MAX -
+		    sizeof(struct ieee80211req_getset_appiebuf)) {
+			wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
+			return -1;
+		}
+		tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+		tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+		tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
+
+		/* Command header for driver */
+		os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+		val = oper;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+		val = *len;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+		/* copy the ie */
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
+
+		if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+				 IEEE80211_APPIE_MAX)) {
+			wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+				   "%s", __func__, strerror(errno));
+			return -1;
+		}
+		break;
+	case WNM_SLEEP_TFS_RESP_IE_ADD:
+		tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+		tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+		tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+			sizeof(struct ieee80211req_getset_appiebuf);
+		/* Command header for driver */
+		os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+		val = oper;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+		val = 0;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+		if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
+				 IEEE80211_APPIE_MAX)) {
+			wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
+				   "%s", __func__, strerror(errno));
+			return -1;
+		}
+
+		*len = tfs_ie->app_buflen;
+		os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
+		wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
+			   *len);
+		break;
+	case WNM_SLEEP_TFS_RESP_IE_NONE:
+		*len = 0;
+		break;
+	case WNM_SLEEP_TFS_IE_DEL:
+		tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+		tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+		tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+			sizeof(struct ieee80211req_getset_appiebuf);
+		/* Command header for driver */
+		os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+		val = oper;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+		val = 0;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+		if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+				 IEEE80211_APPIE_MAX)) {
+			wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+				   "%s", __func__, strerror(errno));
+			return -1;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int atheros_wnm_sleep(struct atheros_driver_data *drv,
+			     const u8 *peer, enum wnm_oper oper)
+{
+	u8 *data, *pos;
+	size_t dlen;
+	int ret;
+	u16 val;
+
+	wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
+		   oper, MAC2STR(peer));
+
+	dlen = ETH_ALEN + 2 + 2;
+	data = os_malloc(dlen);
+	if (data == NULL)
+		return -1;
+
+	/* Command header for driver */
+	pos = data;
+	os_memcpy(pos, peer, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	val = oper;
+	os_memcpy(pos, &val, 2);
+	pos += 2;
+
+	val = 0;
+	os_memcpy(pos, &val, 2);
+
+	ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
+
+	os_free(data);
+
+	return ret;
+}
+
+
+static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
+			    u8 *buf, u16 *buf_len)
+{
+	struct atheros_driver_data *drv = priv;
+
+	switch (oper) {
+	case WNM_SLEEP_ENTER_CONFIRM:
+	case WNM_SLEEP_ENTER_FAIL:
+	case WNM_SLEEP_EXIT_CONFIRM:
+	case WNM_SLEEP_EXIT_FAIL:
+		return atheros_wnm_sleep(drv, peer, oper);
+	case WNM_SLEEP_TFS_REQ_IE_SET:
+	case WNM_SLEEP_TFS_RESP_IE_ADD:
+	case WNM_SLEEP_TFS_RESP_IE_NONE:
+	case WNM_SLEEP_TFS_IE_DEL:
+		return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
+	default:
+		wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
+			   oper);
+		return -1;
+	}
+}
+#endif /* CONFIG_IEEE80211V */
+
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
 	.name			= "atheros",
 	.hapd_init		= atheros_init,
@@ -1739,4 +2147,8 @@
 	.add_tspec      	= atheros_add_tspec,
 	.add_sta_node    	= atheros_add_sta_node,
 #endif /* CONFIG_IEEE80211R */
+	.send_action		= atheros_send_action,
+#ifdef CONFIG_IEEE80211V
+	.wnm_oper		= atheros_wnm_oper,
+#endif /* CONFIG_IEEE80211V */
 };
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 67abb67..a2b34c1 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1328,8 +1328,8 @@
 
 	result->ie_len = pos - (u8 *)(result + 1);
 
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
 	if (tmp == NULL) {
 		os_free(result);
 		return;
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 81856aa..418cf1a 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -78,6 +78,7 @@
 	E2S(DRIVER_CLIENT_POLL_OK);
 	E2S(EAPOL_TX_STATUS);
 	E2S(CH_SWITCH);
+	E2S(WNM);
 	}
 
 	return "UNKNOWN";
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 185ed4f..b9e096c 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -858,7 +858,7 @@
 		os_free(b);
 		return NULL;
 	}
-	results->res = os_zalloc(count * sizeof(struct wpa_scan_res *));
+	results->res = os_calloc(count, sizeof(struct wpa_scan_res *));
 	if (results->res == NULL) {
 		os_free(results);
 		os_free(b);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b9503f1..eeec609 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2386,7 +2386,7 @@
 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 	struct wiphy_info_data *info = arg;
 	int p2p_go_supported = 0, p2p_client_supported = 0;
-	int p2p_concurrent = 0;
+	int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
 	int auth_supported = 0, connect_supported = 0;
 	struct wpa_driver_capa *capa = info->capa;
 	static struct nla_policy
@@ -2487,6 +2487,8 @@
 
 			if (combination_has_p2p && combination_has_mgd) {
 				p2p_concurrent = 1;
+				if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+					p2p_multichan_concurrent = 1;
 				break;
 			}
 
@@ -2554,6 +2556,13 @@
 			   "interface (driver advertised support)");
 		capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+
+		if (p2p_multichan_concurrent) {
+			wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+				   "concurrent (driver advertised support)");
+			capa->flags |=
+				WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+		}
 	}
 
 	if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
@@ -2646,9 +2655,16 @@
 	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
 	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
 
-	if (!info.device_ap_sme)
+	if (!info.device_ap_sme) {
 		drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
 
+		/*
+		 * No AP SME is currently assumed to also indicate no AP MLME
+		 * in the driver/firmware.
+		 */
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+	}
+
 	drv->device_ap_sme = info.device_ap_sme;
 	drv->poll_command_supported = info.poll_command_supported;
 	drv->data_tx_status = info.data_tx_status;
@@ -3485,6 +3501,83 @@
 }
 
 
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+		    struct wpa_driver_scan_params *params)
+{
+	struct nl_msg *msg;
+	int err;
+	size_t i;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NULL;
+
+	nl80211_cmd(drv, msg, 0, cmd);
+
+	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
+		goto fail;
+
+	if (params->num_ssids) {
+		struct nl_msg *ssids = nlmsg_alloc();
+		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);
+				goto fail;
+			}
+		}
+		err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+		nlmsg_free(ssids);
+		if (err < 0)
+			goto fail;
+	}
+
+	if (params->extra_ies) {
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+			    params->extra_ies, params->extra_ies_len);
+		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+			    params->extra_ies) < 0)
+			goto fail;
+	}
+
+	if (params->freqs) {
+		struct nl_msg *freqs = nlmsg_alloc();
+		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);
+				goto fail;
+			}
+		}
+		err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
+				     freqs);
+		nlmsg_free(freqs);
+		if (err < 0)
+			goto fail;
+	}
+
+	os_free(drv->filter_ssids);
+	drv->filter_ssids = params->filter_ssids;
+	params->filter_ssids = NULL;
+	drv->num_filter_ssids = params->num_filter_ssids;
+
+	return msg;
+
+fail:
+	nlmsg_free(msg);
+	return NULL;
+}
+
+
 /**
  * wpa_driver_nl80211_scan - Request the driver to initiate scan
  * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
@@ -3496,62 +3589,22 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = 0, timeout;
-	struct nl_msg *msg, *ssids, *freqs, *rates;
-	size_t i;
+	int ret = -1, timeout;
+	struct nl_msg *msg, *rates = NULL;
 
 	drv->scan_for_auth = 0;
 
-	msg = nlmsg_alloc();
-	ssids = nlmsg_alloc();
-	freqs = nlmsg_alloc();
-	rates = nlmsg_alloc();
-	if (!msg || !ssids || !freqs || !rates) {
-		nlmsg_free(msg);
-		nlmsg_free(ssids);
-		nlmsg_free(freqs);
-		nlmsg_free(rates);
+	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+	if (!msg)
 		return -1;
-	}
-
-	os_free(drv->filter_ssids);
-	drv->filter_ssids = params->filter_ssids;
-	params->filter_ssids = NULL;
-	drv->num_filter_ssids = params->num_filter_ssids;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	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);
-		NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
-			params->ssids[i].ssid);
-	}
-	if (params->num_ssids)
-		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
-	if (params->extra_ies) {
-		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-			    params->extra_ies, params->extra_ies_len);
-		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
-			params->extra_ies);
-	}
-
-	if (params->freqs) {
-		for (i = 0; params->freqs[i]; i++) {
-			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
-				   "MHz", params->freqs[i]);
-			NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
-		}
-		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
-	}
 
 	if (params->p2p_probe) {
 		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
 
+		rates = nlmsg_alloc();
+		if (rates == NULL)
+			goto nla_put_failure;
+
 		/*
 		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
 		 * by masking out everything else apart from the OFDM rates 6,
@@ -3560,7 +3613,9 @@
 		 */
 		NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
 			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-		nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+		if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
+		    0)
+			goto nla_put_failure;
 
 		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
 	}
@@ -3613,9 +3668,7 @@
 			       drv, drv->ctx);
 
 nla_put_failure:
-	nlmsg_free(ssids);
 	nlmsg_free(msg);
-	nlmsg_free(freqs);
 	nlmsg_free(rates);
 	return ret;
 }
@@ -3634,8 +3687,10 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = 0;
-	struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+	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;
 
 #ifdef ANDROID
@@ -3643,30 +3698,18 @@
 		return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-	msg = nlmsg_alloc();
-	ssids = nlmsg_alloc();
-	freqs = nlmsg_alloc();
-	if (!msg || !ssids || !freqs) {
-		nlmsg_free(msg);
-		nlmsg_free(ssids);
-		nlmsg_free(freqs);
-		return -1;
-	}
-
-	os_free(drv->filter_ssids);
-	drv->filter_ssids = params->filter_ssids;
-	params->filter_ssids = NULL;
-	drv->num_filter_ssids = params->num_filter_ssids;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+	if (!msg)
+		goto nla_put_failure;
 
 	NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
 
-	if (drv->num_filter_ssids &&
-	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
+	if ((drv->num_filter_ssids &&
+	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+	    params->filter_rssi) {
 		match_sets = nlmsg_alloc();
+		if (match_sets == NULL)
+			goto nla_put_failure;
 
 		for (i = 0; i < drv->num_filter_ssids; i++) {
 			wpa_hexdump_ascii(MSG_MSGDUMP,
@@ -3675,45 +3718,35 @@
 					  drv->filter_ssids[i].ssid_len);
 
 			match_set_ssid = nlmsg_alloc();
-			nla_put(match_set_ssid,
+			if (match_set_ssid == NULL)
+				goto nla_put_failure;
+			NLA_PUT(match_set_ssid,
 				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
 				drv->filter_ssids[i].ssid_len,
 				drv->filter_ssids[i].ssid);
 
-			nla_put_nested(match_sets, i + 1, match_set_ssid);
-
-			nlmsg_free(match_set_ssid);
+			if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
+			    0)
+				goto nla_put_failure;
 		}
 
-		nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-			       match_sets);
-		nlmsg_free(match_sets);
-	}
-
-	for (i = 0; i < params->num_ssids; i++) {
-		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
-				  params->ssids[i].ssid,
-				  params->ssids[i].ssid_len);
-		NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
-			params->ssids[i].ssid);
-	}
-	if (params->num_ssids)
-		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
-	if (params->extra_ies) {
-		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
-				  params->extra_ies, params->extra_ies_len);
-		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
-			params->extra_ies);
-	}
-
-	if (params->freqs) {
-		for (i = 0; params->freqs[i]; i++) {
-			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
-				   "MHz", params->freqs[i]);
-			NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+		if (params->filter_rssi) {
+			match_set_rssi = nlmsg_alloc();
+			if (match_set_rssi == NULL)
+				goto nla_put_failure;
+			NLA_PUT_U32(match_set_rssi,
+				    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_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+
+		if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+				   match_sets) < 0)
+			goto nla_put_failure;
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3731,9 +3764,10 @@
 		   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-	nlmsg_free(ssids);
+	nlmsg_free(match_set_ssid);
+	nlmsg_free(match_sets);
+	nlmsg_free(match_set_rssi);
 	nlmsg_free(msg);
-	nlmsg_free(freqs);
 	return ret;
 }
 
@@ -3981,8 +4015,8 @@
 		return NL_SKIP;
 	}
 
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
 	if (tmp == NULL) {
 		os_free(r);
 		return NL_SKIP;
@@ -4185,6 +4219,10 @@
 			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
 				    WLAN_CIPHER_SUITE_CCMP);
 			break;
+		case WPA_ALG_GCMP:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_GCMP);
+			break;
 		case WPA_ALG_IGTK:
 			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
 				    WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4325,6 +4363,9 @@
 	case WPA_ALG_CCMP:
 		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
 		break;
+	case WPA_ALG_GCMP:
+		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
+		break;
 	case WPA_ALG_IGTK:
 		NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
 			    WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4777,7 +4818,9 @@
 		return NL_SKIP;
 
 	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
-		mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
+		mode = os_realloc_array(phy_info->modes,
+					*phy_info->num_modes + 1,
+					sizeof(*mode));
 		if (!mode)
 			return NL_SKIP;
 		phy_info->modes = mode;
@@ -4836,7 +4879,8 @@
 			mode->num_channels++;
 		}
 
-		mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
+		mode->channels = os_calloc(mode->num_channels,
+					   sizeof(struct hostapd_channel_data));
 		if (!mode->channels)
 			return NL_SKIP;
 
@@ -4898,7 +4942,7 @@
 			mode->num_rates++;
 		}
 
-		mode->rates = os_zalloc(mode->num_rates * sizeof(int));
+		mode->rates = os_calloc(mode->num_rates, sizeof(int));
 		if (!mode->rates)
 			return NL_SKIP;
 
@@ -4943,7 +4987,7 @@
 	if (mode11g_idx < 0)
 		return modes; /* 2.4 GHz band not supported at all */
 
-	nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+	nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
 	if (nmodes == NULL)
 		return modes; /* Could not add 802.11b mode */
 
@@ -5457,6 +5501,8 @@
 	num_suites = 0;
 	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
 		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+	if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
 	if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
 		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
 	if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
@@ -5473,6 +5519,10 @@
 		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
 			    WLAN_CIPHER_SUITE_CCMP);
 		break;
+	case WPA_CIPHER_GCMP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_GCMP);
+		break;
 	case WPA_CIPHER_TKIP:
 		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
 			    WLAN_CIPHER_SUITE_TKIP);
@@ -5643,7 +5693,8 @@
 		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
 				(params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
 				WMM_QOSINFO_STA_SP_MASK);
-		nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+		if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
+			goto nla_put_failure;
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6746,6 +6797,9 @@
 		case CIPHER_CCMP:
 			cipher = WLAN_CIPHER_SUITE_CCMP;
 			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
 		case CIPHER_TKIP:
 		default:
 			cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6767,6 +6821,9 @@
 		case CIPHER_CCMP:
 			cipher = WLAN_CIPHER_SUITE_CCMP;
 			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
 		case CIPHER_TKIP:
 		default:
 			cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6909,6 +6966,9 @@
 		case CIPHER_CCMP:
 			cipher = WLAN_CIPHER_SUITE_CCMP;
 			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
 		case CIPHER_TKIP:
 		default:
 			cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6931,6 +6991,9 @@
 		case CIPHER_CCMP:
 			cipher = WLAN_CIPHER_SUITE_CCMP;
 			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
 		case CIPHER_TKIP:
 		default:
 			cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7084,6 +7147,11 @@
 		return ret;
 	}
 
+	if (is_p2p_interface(nlmode))
+		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+	else if (drv->disabled_11b_rates)
+		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
 	if (is_ap_interface(nlmode)) {
 		nl80211_mgmt_unsubscribe(bss, "start AP");
 		/* Setup additional AP mode functionality if needed */
@@ -7336,7 +7404,6 @@
 		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
 		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
 		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
 	};
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -7372,9 +7439,6 @@
 	if (stats[NL80211_STA_INFO_TX_PACKETS])
 		data->tx_packets =
 			nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
-	if (stats[NL80211_STA_INFO_TX_FAILED])
-		data->tx_retry_failed =
-			nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
 
 	return NL_SKIP;
 }
@@ -7586,8 +7650,8 @@
 	else
 		old = NULL;
 
-	drv->if_indices = os_realloc(old,
-				     sizeof(int) * (drv->num_if_indices + 1));
+	drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+					   sizeof(int));
 	if (!drv->if_indices) {
 		if (!old)
 			drv->if_indices = drv->default_if_indices;
@@ -7651,7 +7715,10 @@
 					    bridge_ifname, name) < 0)
 				return -1;
 		}
-		linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
+		if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+				   "interface %s up", name);
+		}
 		return i802_set_sta_vlan(priv, addr, name, 0);
 	} else {
 		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -8377,7 +8444,9 @@
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
-	}
+	} else
+		drv->disabled_11b_rates = disabled;
+
 	return ret;
 
 nla_put_failure:
@@ -8470,6 +8539,7 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg, *cqm = NULL;
+	int ret = -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
 		   "hysteresis=%d", threshold, hysteresis);
@@ -8484,20 +8554,20 @@
 
 	cqm = nlmsg_alloc();
 	if (cqm == NULL)
-		return -1;
+		goto nla_put_failure;
 
 	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
 	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-	nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
+	if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
+		goto nla_put_failure;
 
-	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
-		return 0;
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 
 nla_put_failure:
 	nlmsg_free(cqm);
 	nlmsg_free(msg);
-	return -1;
+	return ret;
 }
 
 
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index c8916f0..9481cbf 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -152,7 +152,7 @@
 		return NULL;
 	}
 
-	results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
+	results->res = os_calloc(num, sizeof(struct wpa_scan_res *));
 	if (results->res == NULL) {
 		os_free(results);
 		os_free(buf);
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index f011651..e7bf195 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1478,7 +1478,7 @@
 	if (res == NULL)
 		return NULL;
 
-	res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
+	res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
 	if (res->res == NULL) {
 		os_free(res);
 		return NULL;
@@ -2570,15 +2570,14 @@
 
 	*num_modes = 3;
 	*flags = 0;
-	modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+	modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes));
 	if (modes == NULL)
 		return NULL;
 	modes[0].mode = HOSTAPD_MODE_IEEE80211G;
 	modes[0].num_channels = 11;
 	modes[0].num_rates = 12;
-	modes[0].channels =
-		os_zalloc(11 * sizeof(struct hostapd_channel_data));
-	modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
+	modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+	modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int));
 	if (modes[0].channels == NULL || modes[0].rates == NULL)
 		goto fail;
 	for (i = 0; i < 11; i++) {
@@ -2602,9 +2601,8 @@
 	modes[1].mode = HOSTAPD_MODE_IEEE80211B;
 	modes[1].num_channels = 11;
 	modes[1].num_rates = 4;
-	modes[1].channels =
-		os_zalloc(11 * sizeof(struct hostapd_channel_data));
-	modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int));
+	modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+	modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int));
 	if (modes[1].channels == NULL || modes[1].rates == NULL)
 		goto fail;
 	for (i = 0; i < 11; i++) {
@@ -2620,8 +2618,8 @@
 	modes[2].mode = HOSTAPD_MODE_IEEE80211A;
 	modes[2].num_channels = 1;
 	modes[2].num_rates = 8;
-	modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
-	modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int));
+	modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data));
+	modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int));
 	if (modes[2].channels == NULL || modes[2].rates == NULL)
 		goto fail;
 	modes[2].channels[0].chan = 60;
@@ -2822,17 +2820,19 @@
 
 static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
 	if (!drv->p2p)
 		return -1;
-	return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL);
+	return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0);
 }
 
 
 static int wpa_driver_test_p2p_stop_find(void *priv)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s", __func__);
 	if (!drv->p2p)
 		return -1;
@@ -2843,7 +2843,8 @@
 
 static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
 	if (!drv->p2p)
 		return -1;
@@ -2857,7 +2858,8 @@
 				       unsigned int force_freq,
 				       int persistent_group)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d "
 		   "go_intent=%d "
 		   "own_interface_addr=" MACSTR " force_freq=%u "
@@ -2874,7 +2876,8 @@
 
 static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")",
 		   __func__, MAC2STR(peer_addr));
 	if (!drv->p2p)
@@ -2886,7 +2889,8 @@
 
 static int wpa_driver_test_p2p_group_formation_failed(void *priv)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s", __func__);
 	if (!drv->p2p)
 		return -1;
@@ -2898,7 +2902,8 @@
 static int wpa_driver_test_p2p_set_params(void *priv,
 					  const struct p2p_params *params)
 {
-	struct wpa_driver_test_data *drv = priv;
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
 	wpa_printf(MSG_DEBUG, "%s", __func__);
 	if (!drv->p2p)
 		return -1;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 068e416..bd37ca1 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -40,10 +40,7 @@
 static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
 static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
 static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
-#ifdef ANDROID
-extern int wpa_driver_wext_combo_scan(void *priv,
-					struct wpa_driver_scan_params *params);
-#endif
+
 
 int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
 				   int idx, u32 value)
@@ -481,19 +478,10 @@
 				drv->assoc_req_ies = NULL;
 				os_free(drv->assoc_resp_ies);
 				drv->assoc_resp_ies = NULL;
-#ifdef ANDROID
-				if (!drv->skip_disconnect) {
-					drv->skip_disconnect = 1;
-#endif
 				wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
 						     NULL);
-#ifdef ANDROID
-				}
-#endif
+			
 			} else {
-#ifdef ANDROID
-				drv->skip_disconnect = 0;
-#endif
 				wpa_driver_wext_event_assoc_ies(drv);
 				wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
 						     NULL);
@@ -875,7 +863,6 @@
 #ifdef ANDROID
 	drv->errors = 0;
 	drv->driver_is_started = TRUE;
-	drv->skip_disconnect = 0;
 	drv->bgscan_enabled = 0;
 #endif /* ANDROID */
 
@@ -1039,13 +1026,6 @@
 	const u8 *ssid = params->ssids[0].ssid;
 	size_t ssid_len = params->ssids[0].ssid_len;
 
-#ifdef ANDROID
-	if (drv->capa.max_scan_ssids > 1) {
-		ret = wpa_driver_wext_combo_scan(priv, params);
-		goto scan_out;
-	}
-#endif
-
 	if (ssid_len > IW_ESSID_MAX_SIZE) {
 		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
 			   __FUNCTION__, (unsigned long) ssid_len);
@@ -1071,9 +1051,6 @@
 		ret = -1;
 	}
 
-#ifdef ANDROID
-scan_out:
-#endif
 	/* Not all drivers generate "scan completed" wireless event, so try to
 	 * read results after a timeout. */
 	timeout = 10;
@@ -1437,8 +1414,8 @@
 	if (data->ie)
 		os_memcpy(pos, data->ie, data->ie_len);
 
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
 	if (tmp == NULL) {
 		os_free(r);
 		return;
@@ -1608,11 +1585,7 @@
 		drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
 			WPA_DRIVER_AUTH_SHARED |
 			WPA_DRIVER_AUTH_LEAP;
-#ifdef ANDROID
-		drv->capa.max_scan_ssids = WEXT_CSCAN_AMOUNT;
-#else
 		drv->capa.max_scan_ssids = 1;
-#endif
 
 		wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x "
 			   "flags 0x%x",
@@ -2084,9 +2057,7 @@
 	int value;
 
 	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-#ifdef ANDROID
-	drv->skip_disconnect = 0;
-#endif
+
 	if (drv->cfg80211) {
 		/*
 		 * Stop cfg80211 from trying to associate before we are done
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index 7e0b28b..c4a5bc9 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -48,7 +48,6 @@
 #ifdef ANDROID
 	int errors;
 	int driver_is_started;
-	int skip_disconnect;
 	int bgscan_enabled;
 #endif /* ANDROID */
 };
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 0cc81f9..c7a98d3 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -30,7 +30,7 @@
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20
+  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
 else
   ifdef CONFIG_LIBNL_TINY
     DRV_LIBS += -lnl-tiny
@@ -142,6 +142,28 @@
 DRV_OBJS += ../src/drivers/rfkill.o
 endif
 
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_LIBS += -lnl-route-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_LIBS += -lnl-route
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+endif
 
 ##### COMMON VARS
 DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 1d7129c..23fcbb7 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -30,7 +30,7 @@
 ifdef CONFIG_LIBNL32
   DRV_LIBS += -lnl-3
   DRV_LIBS += -lnl-genl-3
-  DRV_CFLAGS += -DCONFIG_LIBNL20
+  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
 else
   ifdef CONFIG_LIBNL_TINY
     DRV_LIBS += -lnl-tiny
@@ -146,6 +146,29 @@
 DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
 endif
 
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_LIBS += -lnl-route-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_LIBS += -lnl-route
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+endif
+
 ##### COMMON VARS
 DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
 DRV_WPA_CFLAGS += $(DRV_CFLAGS)
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 940b69a..4380428 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -45,8 +45,9 @@
 
 	if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
 		ret = errno ? -errno : -999;
-		wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
-			   ifname, strerror(errno));
+		wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
+			   "%s",
+			   ifname, dev_up ? "UP" : "DOWN", strerror(errno));
 		return ret;
 	}
 
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 74cc55c..2f38788 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -771,6 +771,9 @@
  * @NL80211_ATTR_IFNAME: network interface name
  * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
  *
+ * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices
+ *	that don't have a netdev (u64)
+ *
  * @NL80211_ATTR_MAC: MAC address (various uses)
  *
  * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
@@ -1242,6 +1245,12 @@
  * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
  *      or 0 to disable background scan.
  *
+ * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from
+ *	userspace. If unset it is assumed the hint comes directly from
+ *	a user. If set code could specify exactly what type of source
+ *	was used to provide the hint. For the different types of
+ *	allowed user regulatory hints see nl80211_user_reg_hint_type.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1493,6 +1502,10 @@
 
 	NL80211_ATTR_BG_SCAN_PERIOD,
 
+	NL80211_ATTR_WDEV,
+
+	NL80211_ATTR_USER_REG_HINT_TYPE,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1545,6 +1558,8 @@
 /* default RSSI threshold for scan results if none specified. */
 #define NL80211_SCAN_RSSI_THOLD_OFF		-300
 
+#define NL80211_CQM_TXE_MAX_INTVL		1800
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -1638,12 +1653,20 @@
  *
  * These attribute types are used with %NL80211_STA_INFO_TXRATE
  * when getting information about the bitrate of a station.
+ * There are 2 attributes for bitrate, a legacy one that represents
+ * a 16-bit value, and new one that represents a 32-bit value.
+ * If the rate value fits into 16 bit, both attributes are reported
+ * with the same value. If the rate is too high to fit into 16 bits
+ * (>6.5535Gbps) only 32-bit attribute is included.
+ * User space tools encouraged to use the 32-bit attribute and fall
+ * back to the 16-bit one for compatibility with older kernels.
  *
  * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
  * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
  * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
  * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
  * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
@@ -1653,6 +1676,7 @@
 	NL80211_RATE_INFO_MCS,
 	NL80211_RATE_INFO_40_MHZ_WIDTH,
 	NL80211_RATE_INFO_SHORT_GI,
+	NL80211_RATE_INFO_BITRATE32,
 
 	/* keep last */
 	__NL80211_RATE_INFO_AFTER_LAST,
@@ -2045,6 +2069,26 @@
 };
 
 /**
+ * enum nl80211_user_reg_hint_type - type of user regulatory hint
+ *
+ * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always
+ *	assumed if the attribute is not set.
+ * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular
+ *	base station. Device drivers that have been tested to work
+ *	properly to support this type of hint can enable these hints
+ *	by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature
+ *	capability on the struct wiphy. The wireless core will
+ *	ignore all cell base station hints until at least one device
+ *	present has been registered with the wireless core that
+ *	has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
+ *	supported feature.
+ */
+enum nl80211_user_reg_hint_type {
+	NL80211_USER_REG_HINT_USER	= 0,
+	NL80211_USER_REG_HINT_CELL_BASE = 1,
+};
+
+/**
  * enum nl80211_survey_info - survey information
  *
  * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
@@ -2575,6 +2619,17 @@
  * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
  * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
  *	consecutive packets were not acknowledged by the peer
+ * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures
+ *	during the given %NL80211_ATTR_CQM_TXE_INTVL before an
+ *	%NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and
+ *	%NL80211_ATTR_CQM_TXE_PKTS is generated.
+ * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given
+ *	%NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is
+ *	checked.
+ * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic
+ *	interval in which %NL80211_ATTR_CQM_TXE_PKTS and
+ *	%NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
+ *	%NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -2584,6 +2639,9 @@
 	NL80211_ATTR_CQM_RSSI_HYST,
 	NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
 	NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+	NL80211_ATTR_CQM_TXE_RATE,
+	NL80211_ATTR_CQM_TXE_PKTS,
+	NL80211_ATTR_CQM_TXE_INTVL,
 
 	/* keep last */
 	__NL80211_ATTR_CQM_AFTER_LAST,
@@ -2933,11 +2991,15 @@
  * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
  * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
  *	the connected inactive stations in AP mode.
+ * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
+ *	to work properly to suppport receiving regulatory hints from
+ *	cellular base stations.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS	= 1 << 0,
 	NL80211_FEATURE_HT_IBSS		= 1 << 1,
 	NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
+	NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
 };
 
 /**