Cumulative patch from commit 39a5800f7c2a9de743c673a78929ac46a099b1a4

39a5800 wpa_supplicant: Allow disabling LDPC
7230040 Interworking: Read IMSI if not read at supplicant start
62f736d Interworking: Init scard when a credential requires SIM access
729897a Interworking: Fix incorrect compile PCSC flag
21611ea edit: Increase buffer size to 4096 bytes
0b2c59e OSU server: Add example scripts for Hotspot 2.0 PKI
0f27c20 HS 2.0R2: Add example OSU SPP server implementation
1e03c6c XML: Remove forgotten, unused definition of debug_print_func
5cfc87b Make hs20_wan_metrics parser error print more helpful
4be20bf Fix validation of anqp_3gpp_cell_net configuration parameter
23587e3 Remove duplicated vht_capab parser entry
18a8e55 Notify STA of disconnection based on ACL change
8943cc9 RADIUS server: Add support for MAC ACL
dc87541 Clean up debug print for PSK file search
bbbacbf DFS: Print CAC info in ctrl_iface STATUS command
ace0fbd P2P: Fix segfault when PBC overlap is detected
cf15b15 Add writing of network block ocsp parameter
5c9da16 nl80211: Set all BSS interfaces down when tearing down AP in MBSS mode
f1c4dbf wpa_supplicant: Remove pending sme-connect radio work
4f560cd wpa_supplicant: Override HT A-MPDU size if VHT A-MPDU was overridden
3ae8b7b hostapd: Add vendor command support
782e2f7 P2P: Do not initiate scan on P2P Device when enabled
74a1319 Fix issue with incorrect secondary_channel in HT40/HT80
96ecea5 Pass TDLS peer capability information in tdls_mgmt
78cd7e6 Sync with wireless-testing.git include/uapi/linux/nl80211.h
b36935b nl80211: Fix EAPOL frames not being delivered
6997f8b nl80211: Set interface address even if using old interface
9b4d9c8 nl80211: Print if_indices list in debug log
762c41a eloop: Add assert() on negative fd when using select() code path
978c673 Add a note on using 'iw list' to determine multi-BSS support

Change-Id: I89af7f8d92ed706c8909ed3cc9c49d6e1277a2b0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 5a8e67e..0a143d3 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -651,12 +651,11 @@
 	struct hostapd_wpa_psk *psk;
 	int next_ok = prev_psk == NULL;
 
-	if (p2p_dev_addr) {
+	if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
 		wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
 			   " p2p_dev_addr=" MACSTR " prev_psk=%p",
 			   MAC2STR(addr), MAC2STR(p2p_dev_addr), prev_psk);
-		if (!is_zero_ether_addr(p2p_dev_addr))
-			addr = NULL; /* Use P2P Device Address for matching */
+		addr = NULL; /* Use P2P Device Address for matching */
 	} else {
 		wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
 			   " prev_psk=%p",
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 25eb490..dfbe626 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -127,6 +127,7 @@
 	unsigned int password_hash:1; /* whether password is hashed with
 				       * nt_password_hash() */
 	unsigned int remediation:1;
+	unsigned int macacl:1;
 	int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
 	struct hostapd_radius_attr *accept_attr;
 };
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 9abcd7c..6d3ae5a 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -774,8 +774,10 @@
 	}
 
 	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
-	if (!res)
+	if (!res) {
 		iface->cac_started = 1;
+		os_get_reltime(&iface->dfs_cac_start);
+	}
 
 	return res;
 }
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 9edaf7d..7cc9d7d 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -280,4 +280,15 @@
 	return hapd->driver->status(hapd->drv_priv, buf, buflen);
 }
 
+static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
+					 int vendor_id, int subcmd,
+					 const u8 *data, size_t data_len,
+					 struct wpabuf *buf)
+{
+	if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
+		return -1;
+	return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
+					data_len, buf);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 6e3decd..86f1cbe 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -79,6 +79,7 @@
 		user->password_hash = eap_user->password_hash;
 	}
 	user->force_version = eap_user->force_version;
+	user->macacl = eap_user->macacl;
 	user->ttls_auth = eap_user->ttls_auth;
 	user->remediation = eap_user->remediation;
 	user->accept_attr = eap_user->accept_attr;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index e1020a6..9760933 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -423,6 +423,28 @@
 		return len;
 	len += ret;
 
+	if (!iface->cac_started || !iface->dfs_cac_ms) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "cac_time_seconds=%d\n"
+				  "cac_time_left_seconds=N/A\n",
+				  iface->dfs_cac_ms / 1000);
+	} else {
+		/* CAC started and CAC time set - calculate remaining time */
+		struct os_reltime now;
+		unsigned int left_time;
+
+		os_reltime_age(&iface->dfs_cac_start, &now);
+		left_time = iface->dfs_cac_ms / 1000 - now.sec;
+		ret = os_snprintf(buf + len, buflen - len,
+				  "cac_time_seconds=%u\n"
+				  "cac_time_left_seconds=%u\n",
+				  iface->dfs_cac_ms / 1000,
+				  left_time);
+	}
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
 	ret = os_snprintf(buf + len, buflen - len,
 			  "channel=%u\n"
 			  "secondary_channel=%d\n"
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 0f262ce..3fb1881 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -573,6 +573,28 @@
 }
 
 
+static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+				     int start_chan_idx, int n_chans)
+{
+	struct hostapd_channel_data *channel;
+	struct hostapd_hw_modes *mode;
+	int i;
+	unsigned int cac_time_ms = 0;
+
+	mode = iface->current_mode;
+
+	for (i = 0; i < n_chans; i++) {
+		channel = &mode->channels[start_chan_idx + i];
+		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
+			continue;
+		if (channel->dfs_cac_ms > cac_time_ms)
+			cac_time_ms = channel->dfs_cac_ms;
+	}
+
+	return cac_time_ms;
+}
+
+
 /*
  * Main DFS handler
  * 1 - continue channel/ap setup
@@ -596,6 +618,10 @@
 		/* Get number of used channels, depend on width */
 		n_chans = dfs_get_used_n_chans(iface);
 
+		/* Setup CAC time */
+		iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
+						     n_chans);
+
 		/* Check if any of configured channels require DFS */
 		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
 		wpa_printf(MSG_DEBUG,
@@ -640,12 +666,13 @@
 	hostapd_set_state(iface, HAPD_IFACE_DFS);
 	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
-		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d",
+		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
 		iface->freq,
 		iface->conf->channel, iface->conf->secondary_channel,
 		iface->conf->vht_oper_chwidth,
 		iface->conf->vht_oper_centr_freq_seg0_idx,
-		iface->conf->vht_oper_centr_freq_seg1_idx);
+		iface->conf->vht_oper_centr_freq_seg1_idx,
+		iface->dfs_cac_ms / 1000);
 
 	res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
 				    iface->freq,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ed2226c..614a5bf 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -172,6 +172,7 @@
 		hapd = iface->bss[j];
 		hapd->iconf = newconf;
 		hapd->iconf->channel = oldconf->channel;
+		hapd->iconf->secondary_channel = oldconf->secondary_channel;
 		hapd->iconf->ieee80211n = oldconf->ieee80211n;
 		hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
 		hapd->iconf->ht_capab = oldconf->ht_capab;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 9a705a4..090544d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -348,6 +348,9 @@
 	unsigned int cs_c_off_proberesp;
 	int csa_in_progress;
 
+	unsigned int dfs_cac_ms;
+	struct os_reltime dfs_cac_start;
+
 #ifdef CONFIG_ACS
 	unsigned int acs_num_completed_scans;
 #endif /* CONFIG_ACS */
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index b12c9d6..035415f 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1787,6 +1787,7 @@
 		user->password_hash = eap_user->password_hash;
 	}
 	user->force_version = eap_user->force_version;
+	user->macacl = eap_user->macacl;
 	user->ttls_auth = eap_user->ttls_auth;
 	user->remediation = eap_user->remediation;
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 5935273..02ade12 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -93,6 +93,9 @@
 	 */
 	long double interference_factor;
 #endif /* CONFIG_ACS */
+
+	/* DFS CAC time in milliseconds */
+	unsigned int dfs_cac_ms;
 };
 
 #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
@@ -1269,6 +1272,13 @@
 	u16 counter_offset_presp;
 };
 
+/* TDLS peer capabilities for send_tdls_mgmt() */
+enum tdls_peer_capability {
+	TDLS_PEER_HT = BIT(0),
+	TDLS_PEER_VHT = BIT(1),
+	TDLS_PEER_WMM = BIT(2),
+};
+
 /**
  * struct wpa_driver_ops - Driver interface API definition
  *
@@ -2449,6 +2459,7 @@
 	 * @action_code: TDLS action code for the mssage
 	 * @dialog_token: Dialog Token to use in the message (if needed)
 	 * @status_code: Status Code or Reason Code to use (if needed)
+	 * @peer_capab: TDLS peer capability (TDLS_PEER_* bitfield)
 	 * @buf: TDLS IEs to add to the message
 	 * @len: Length of buf in octets
 	 * Returns: 0 on success, negative (<0) on failure
@@ -2457,7 +2468,7 @@
 	 * responsible for receiving and sending all TDLS packets.
 	 */
 	int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
-			      u8 dialog_token, u16 status_code,
+			      u8 dialog_token, u16 status_code, u32 peer_capab,
 			      const u8 *buf, size_t len);
 
 	/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 3ecce19..27b4c48 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6200,6 +6200,7 @@
 	u8 channel;
 	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
 	chan->flag = 0;
+	chan->dfs_cac_ms = 0;
 	if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
 		chan->chan = channel;
 
@@ -6226,6 +6227,11 @@
 			break;
 		}
 	}
+
+	if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
+		chan->dfs_cac_ms = nla_get_u32(
+			tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
+	}
 }
 
 
@@ -7660,6 +7666,16 @@
 		if (use_existing) {
 			wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
 				   ifname);
+			if (addr && iftype != NL80211_IFTYPE_MONITOR &&
+			    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+					       addr) < 0 &&
+			    (linux_set_iface_flags(drv->global->ioctl_sock,
+						   ifname, 0) < 0 ||
+			     linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+						addr) < 0 ||
+			     linux_set_iface_flags(drv->global->ioctl_sock,
+						   ifname, 1) < 0))
+					return -1;
 			return -ENFILE;
 		}
 		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
@@ -9446,6 +9462,29 @@
 }
 
 
+static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
+{
+	char buf[200], *pos, *end;
+	int i, res;
+
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (!drv->if_indices[i])
+			continue;
+		res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
+		if (res < 0 || res >= end - pos)
+			break;
+		pos += res;
+	}
+	*pos = '\0';
+
+	wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
+		   drv->num_if_indices, buf);
+}
+
+
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
 	int i;
@@ -9453,9 +9492,15 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
 		   ifidx);
+	if (have_ifidx(drv, ifidx)) {
+		wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
+			   ifidx);
+		return;
+	}
 	for (i = 0; i < drv->num_if_indices; i++) {
 		if (drv->if_indices[i] == 0) {
 			drv->if_indices[i] = ifidx;
+			dump_ifidx(drv);
 			return;
 		}
 	}
@@ -9481,6 +9526,7 @@
 			  sizeof(drv->default_if_indices));
 	drv->if_indices[drv->num_if_indices] = ifidx;
 	drv->num_if_indices++;
+	dump_ifidx(drv);
 }
 
 
@@ -9494,6 +9540,7 @@
 			break;
 		}
 	}
+	dump_ifidx(drv);
 }
 
 
@@ -9929,6 +9976,9 @@
 	if (drv->global)
 		drv->global->if_add_ifindex = ifidx;
 
+	if (ifidx > 0)
+		add_ifidx(drv, ifidx);
+
 	return 0;
 }
 
@@ -9944,6 +9994,8 @@
 		   __func__, type, ifname, ifindex, bss->added_if);
 	if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
 		nl80211_remove_iface(drv, ifindex);
+	else if (ifindex > 0 && !bss->added_if)
+		del_ifidx(drv, ifindex);
 
 	if (type != WPA_IF_AP_BSS)
 		return 0;
@@ -9972,6 +10024,8 @@
 				/* Unsubscribe management frames */
 				nl80211_teardown_ap(bss);
 				nl80211_destroy_bss(bss);
+				if (!bss->added_if)
+					i802_set_iface_flags(bss, 0);
 				os_free(bss);
 				bss = NULL;
 				break;
@@ -11176,7 +11230,7 @@
 
 static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
 				  u8 dialog_token, u16 status_code,
-				  const u8 *buf, size_t len)
+				  u32 peer_capab, const u8 *buf, size_t len)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -11198,6 +11252,15 @@
 	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
 	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
 	NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+	if (peer_capab) {
+		/*
+		 * The internal enum tdls_peer_capability definition is
+		 * currently identical with the nl80211 enum
+		 * nl80211_tdls_peer_capability, so no conversion is needed
+		 * here.
+		 */
+		NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab);
+	}
 	NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index a12e6ca..1ba9d62 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -303,8 +303,9 @@
  *	passed, all channels allowed for the current regulatory domain
  *	are used.  Extra IEs can also be passed from the userspace by
  *	using the %NL80211_ATTR_IE attribute.
- * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
- *	if scheduled scan is not running.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
+ *	scheduled scan is not running. The caller may assume that as soon
+ *	as the call returns, it is safe to start a new scheduled scan again.
  * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
  *	results available.
  * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
@@ -1575,6 +1576,9 @@
  *	advertise values that cannot always be met. In such cases, an attempt
  *	to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
  *
+ * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
+ *	As specified in the &enum nl80211_tdls_peer_capability.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1908,6 +1912,8 @@
 
 	NL80211_ATTR_MAX_AP_ASSOC_STA,
 
+	NL80211_ATTR_TDLS_PEER_CAPABILITY,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2329,6 +2335,7 @@
  * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
  *	using this channel as the primary or any of the secondary channels
  *	isn't possible
+ * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
  * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
  *	currently defined
  * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -2347,6 +2354,7 @@
 	NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
 	NL80211_FREQUENCY_ATTR_NO_80MHZ,
 	NL80211_FREQUENCY_ATTR_NO_160MHZ,
+	NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
 
 	/* keep last */
 	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2437,15 +2445,14 @@
  * 	in KHz. This is not a center a frequency but an actual regulatory
  * 	band edge.
  * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
- *	frequency range, in KHz. If not present or 0, maximum available
- *	bandwidth should be calculated base on contiguous rules and wider
- *	channels will be allowed to cross multiple contiguous/overlapping
- *	frequency ranges.
+ *	frequency range, in KHz.
  * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
  * 	for a given frequency range. The value is in mBi (100 * dBi).
  * 	If you don't have one then don't send this.
  * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
  * 	a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
+ *	If not present or 0 default CAC time will be used.
  * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
  *	currently defined
  * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
@@ -2461,6 +2468,8 @@
 	NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
 	NL80211_ATTR_POWER_RULE_MAX_EIRP,
 
+	NL80211_ATTR_DFS_CAC_TIME,
+
 	/* keep last */
 	__NL80211_REG_RULE_ATTR_AFTER_LAST,
 	NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
@@ -2511,6 +2520,9 @@
  * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
  * 	this includes probe requests or modes of operation that require
  * 	beaconing.
+ * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
+ *	base on contiguous rules and wider channels will be allowed to cross
+ *	multiple contiguous/overlapping frequency ranges.
  */
 enum nl80211_reg_rule_flags {
 	NL80211_RRF_NO_OFDM		= 1<<0,
@@ -2522,6 +2534,7 @@
 	NL80211_RRF_PTMP_ONLY		= 1<<6,
 	NL80211_RRF_NO_IR		= 1<<7,
 	__NL80211_RRF_NO_IBSS		= 1<<8,
+	NL80211_RRF_AUTO_BW		= 1<<11,
 };
 
 #define NL80211_RRF_PASSIVE_SCAN	NL80211_RRF_NO_IR
@@ -3843,11 +3856,6 @@
  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
  *	to work properly to suppport receiving regulatory hints from
  *	cellular base stations.
- * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
- *	P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
- *	in the interface combinations, even when it's only used for scan
- *	and remain-on-channel. This could be due to, for example, the
- *	remain-on-channel implementation requiring a channel context.
  * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
  *	equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
  *	mode
@@ -3889,7 +3897,7 @@
 	NL80211_FEATURE_HT_IBSS				= 1 << 1,
 	NL80211_FEATURE_INACTIVITY_TIMER		= 1 << 2,
 	NL80211_FEATURE_CELL_BASE_REG_HINTS		= 1 << 3,
-	NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL	= 1 << 4,
+	/* bit 4 is reserved - don't use */
 	NL80211_FEATURE_SAE				= 1 << 5,
 	NL80211_FEATURE_LOW_PRIORITY_SCAN		= 1 << 6,
 	NL80211_FEATURE_SCAN_FLUSH			= 1 << 7,
@@ -4079,4 +4087,20 @@
 	__u32 subcmd;
 };
 
+/**
+ * enum nl80211_tdls_peer_capability - TDLS peer flags.
+ *
+ * Used by tdls_mgmt() to determine which conditional elements need
+ * to be added to TDLS Setup frames.
+ *
+ * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
+ * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
+ * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
+ */
+enum nl80211_tdls_peer_capability {
+	NL80211_TDLS_PEER_HT = 1<<0,
+	NL80211_TDLS_PEER_VHT = 1<<1,
+	NL80211_TDLS_PEER_WMM = 1<<2,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 698a5ac..1253bd6 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -33,6 +33,7 @@
 	int phase2;
 	int force_version;
 	unsigned int remediation:1;
+	unsigned int macacl:1;
 	int ttls_auth; /* bitfield of
 			* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
 	struct hostapd_radius_attr *accept_attr;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 370b517..47b4f8a 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1247,30 +1247,28 @@
 }
 
 
-/* Add User-Password attribute to a RADIUS message and encrypt it as specified
- * in RFC 2865, Chap. 5.2 */
-struct radius_attr_hdr *
-radius_msg_add_attr_user_password(struct radius_msg *msg,
-				  const u8 *data, size_t data_len,
-				  const u8 *secret, size_t secret_len)
+int radius_user_password_hide(struct radius_msg *msg,
+			      const u8 *data, size_t data_len,
+			      const u8 *secret, size_t secret_len,
+			      u8 *buf, size_t buf_len)
 {
-	u8 buf[128];
-	size_t padlen, i, buf_len, pos;
+	size_t padlen, i, pos;
 	const u8 *addr[2];
 	size_t len[2];
 	u8 hash[16];
 
-	if (data_len > 128)
-		return NULL;
+	if (data_len + 16 > buf_len)
+		return -1;
 
 	os_memcpy(buf, data, data_len);
-	buf_len = data_len;
 
 	padlen = data_len % 16;
-	if (padlen && data_len < sizeof(buf)) {
+	if (padlen && data_len < buf_len) {
 		padlen = 16 - padlen;
 		os_memset(buf + data_len, 0, padlen);
-		buf_len += padlen;
+		buf_len = data_len + padlen;
+	} else {
+		buf_len = data_len;
 	}
 
 	addr[0] = secret;
@@ -1296,8 +1294,27 @@
 		pos += 16;
 	}
 
+	return buf_len;
+}
+
+
+/* Add User-Password attribute to a RADIUS message and encrypt it as specified
+ * in RFC 2865, Chap. 5.2 */
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  const u8 *data, size_t data_len,
+				  const u8 *secret, size_t secret_len)
+{
+	u8 buf[128];
+	int res;
+
+	res = radius_user_password_hide(msg, data, data_len,
+					secret, secret_len, buf, sizeof(buf));
+	if (res < 0)
+		return NULL;
+
 	return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
-				   buf, buf_len);
+				   buf, res);
 }
 
 
diff --git a/src/radius/radius.h b/src/radius/radius.h
index d8bf21e..d388f71 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -251,6 +251,10 @@
 			     const u8 *recv_key, size_t recv_key_len);
 int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
 		       size_t len);
+int radius_user_password_hide(struct radius_msg *msg,
+			      const u8 *data, size_t data_len,
+			      const u8 *secret, size_t secret_len,
+			      u8 *buf, size_t buf_len);
 struct radius_attr_hdr *
 radius_msg_add_attr_user_password(struct radius_msg *msg,
 				  const u8 *data, size_t data_len,
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index f2ea393..bd358ae 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -86,6 +86,7 @@
 	u8 last_authenticator[16];
 
 	unsigned int remediation:1;
+	unsigned int macacl:1;
 
 	struct hostapd_radius_attr *accept_attr;
 };
@@ -636,6 +637,7 @@
 		return NULL;
 	}
 	sess->accept_attr = tmp.accept_attr;
+	sess->macacl = tmp.macacl;
 
 	sess->username = os_malloc(user_len * 2 + 1);
 	if (sess->username == NULL) {
@@ -823,6 +825,87 @@
 }
 
 
+static struct radius_msg *
+radius_server_macacl(struct radius_server_data *data,
+		     struct radius_client *client,
+		     struct radius_session *sess,
+		     struct radius_msg *request)
+{
+	struct radius_msg *msg;
+	int code;
+	struct radius_hdr *hdr = radius_msg_get_hdr(request);
+	u8 *pw;
+	size_t pw_len;
+
+	code = RADIUS_CODE_ACCESS_ACCEPT;
+
+	if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw,
+				    &pw_len, NULL) < 0) {
+		RADIUS_DEBUG("Could not get User-Password");
+		code = RADIUS_CODE_ACCESS_REJECT;
+	} else {
+		int res;
+		struct eap_user tmp;
+
+		os_memset(&tmp, 0, sizeof(tmp));
+		res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username,
+					 os_strlen(sess->username), 0, &tmp);
+		if (res || !tmp.macacl || tmp.password == NULL) {
+			RADIUS_DEBUG("No MAC ACL user entry");
+			os_free(tmp.password);
+			code = RADIUS_CODE_ACCESS_REJECT;
+		} else {
+			u8 buf[128];
+			res = radius_user_password_hide(
+				request, tmp.password, tmp.password_len,
+				(u8 *) client->shared_secret,
+				client->shared_secret_len,
+				buf, sizeof(buf));
+			os_free(tmp.password);
+
+			if (res < 0 || pw_len != (size_t) res ||
+			    os_memcmp(pw, buf, res) != 0) {
+				RADIUS_DEBUG("Incorrect User-Password");
+				code = RADIUS_CODE_ACCESS_REJECT;
+			}
+		}
+	}
+
+	msg = radius_msg_new(code, hdr->identifier);
+	if (msg == NULL) {
+		RADIUS_DEBUG("Failed to allocate reply message");
+		return NULL;
+	}
+
+	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
+		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
+		radius_msg_free(msg);
+		return NULL;
+	}
+
+	if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+		struct hostapd_radius_attr *attr;
+		for (attr = sess->accept_attr; attr; attr = attr->next) {
+			if (!radius_msg_add_attr(msg, attr->type,
+						 wpabuf_head(attr->val),
+						 wpabuf_len(attr->val))) {
+				wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+				radius_msg_free(msg);
+				return NULL;
+			}
+		}
+	}
+
+	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
+				  client->shared_secret_len,
+				  hdr->authenticator) < 0) {
+		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+	}
+
+	return msg;
+}
+
+
 static int radius_server_reject(struct radius_server_data *data,
 				struct radius_client *client,
 				struct radius_msg *request,
@@ -958,6 +1041,12 @@
 	}
 		      
 	eap = radius_msg_get_eap(msg);
+	if (eap == NULL && sess->macacl) {
+		reply = radius_server_macacl(data, client, sess, msg);
+		if (reply == NULL)
+			return -1;
+		goto send_reply;
+	}
 	if (eap == NULL) {
 		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
 			     from_addr);
@@ -1015,6 +1104,7 @@
 
 	reply = radius_server_encapsulate_eap(data, client, sess, msg);
 
+send_reply:
 	if (reply) {
 		struct wpabuf *buf;
 		struct radius_hdr *hdr;
@@ -1904,6 +1994,7 @@
 	if (ret == 0 && user) {
 		sess->accept_attr = user->accept_attr;
 		sess->remediation = user->remediation;
+		sess->macacl = user->macacl;
 	}
 	return ret;
 }
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 9b8ca6b..62a2a59 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -118,6 +118,7 @@
 		u8 action_code; /* TDLS frame type */
 		u8 dialog_token;
 		u16 status_code;
+		u32 peer_capab;
 		int buf_len;    /* length of TPK message for retransmission */
 		u8 *buf;        /* buffer for TPK message */
 	} sm_tmr;
@@ -142,6 +143,8 @@
 
 	u8 *supp_oper_classes;
 	size_t supp_oper_classes_len;
+
+	u8 wmm_capable;
 };
 
 
@@ -211,15 +214,16 @@
 
 static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
 				 u8 action_code, u8 dialog_token,
-				 u16 status_code, const u8 *buf, size_t len)
+				 u16 status_code, u32 peer_capab,
+				 const u8 *buf, size_t len)
 {
 	return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
-				     status_code, buf, len);
+				     status_code, peer_capab, buf, len);
 }
 
 
 static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
-			     u8 dialog_token, u16 status_code,
+			     u8 dialog_token, u16 status_code, u32 peer_capab,
 			     const u8 *msg, size_t msg_len)
 {
 	struct wpa_tdls_peer *peer;
@@ -230,7 +234,7 @@
 		   (unsigned int) msg_len);
 
 	if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
-				  status_code, msg, msg_len)) {
+				  status_code, peer_capab, msg, msg_len)) {
 		wpa_printf(MSG_INFO, "TDLS: Failed to send message "
 			   "(action_code=%u)", action_code);
 		return -1;
@@ -268,6 +272,7 @@
 	peer->sm_tmr.action_code = action_code;
 	peer->sm_tmr.dialog_token = dialog_token;
 	peer->sm_tmr.status_code = status_code;
+	peer->sm_tmr.peer_capab = peer_capab;
 	peer->sm_tmr.buf_len = msg_len;
 	os_free(peer->sm_tmr.buf);
 	peer->sm_tmr.buf = os_malloc(msg_len);
@@ -324,6 +329,7 @@
 					  peer->sm_tmr.action_code,
 					  peer->sm_tmr.dialog_token,
 					  peer->sm_tmr.status_code,
+					  peer->sm_tmr.peer_capab,
 					  peer->sm_tmr.buf,
 					  peer->sm_tmr.buf_len)) {
 			wpa_printf(MSG_INFO, "TDLS: Failed to retry "
@@ -645,6 +651,8 @@
 	peer->supp_oper_classes = NULL;
 	peer->rsnie_i_len = peer->rsnie_p_len = 0;
 	peer->cipher = 0;
+	peer->qos_info = 0;
+	peer->wmm_capable = 0;
 	peer->tpk_set = peer->tpk_success = 0;
 	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
 	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
@@ -747,7 +755,7 @@
 
 	/* request driver to send Teardown using this FTIE */
 	wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
-			  reason_code, rbuf, pos - rbuf);
+			  reason_code, 0, rbuf, pos - rbuf);
 	os_free(rbuf);
 
 	/* clear the Peerkey statemachine */
@@ -918,7 +926,7 @@
 		   " (action=%u status=%u)",
 		   MAC2STR(dst), tdls_action, status);
 	return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
-				 NULL, 0);
+				 0, NULL, 0);
 }
 
 
@@ -1124,7 +1132,7 @@
 		   MAC2STR(peer->addr));
 
 	status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST,
-				   1, 0, rbuf, pos - rbuf);
+				   1, 0, 0, rbuf, pos - rbuf);
 	os_free(rbuf);
 
 	return status;
@@ -1208,7 +1216,7 @@
 
 skip_ies:
 	status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
-				   dtoken, 0, rbuf, pos - rbuf);
+				   dtoken, 0, 0, rbuf, pos - rbuf);
 	os_free(rbuf);
 
 	return status;
@@ -1226,6 +1234,7 @@
 	struct wpa_tdls_timeoutie timeoutie;
 	u32 lifetime;
 	int status;
+	u32 peer_capab = 0;
 
 	buf_len = 0;
 	if (wpa_tdls_get_privacy(sm)) {
@@ -1288,9 +1297,16 @@
 	wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
 			  (u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
 
+	if (peer->vht_capabilities)
+		peer_capab |= TDLS_PEER_VHT;
+	else if (peer->ht_capabilities)
+		peer_capab |= TDLS_PEER_HT;
+	else if (peer->wmm_capable)
+		peer_capab |= TDLS_PEER_WMM;
+
 skip_ies:
 	status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
-				   dtoken, 0, rbuf, pos - rbuf);
+				   dtoken, 0, peer_capab, rbuf, pos - rbuf);
 	os_free(rbuf);
 
 	return status;
@@ -1305,7 +1321,7 @@
 		   "(peer " MACSTR ")", MAC2STR(peer->addr));
 
 	return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
-				 dialog_token, 0, NULL, 0);
+				 dialog_token, 0, 0, NULL, 0);
 }
 
 
@@ -1366,7 +1382,7 @@
 	wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
 		   MACSTR, MAC2STR(addr));
 	return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
-				 1, 0, NULL, 0);
+				 1, 0, 0, NULL, 0);
 }
 
 
@@ -1484,6 +1500,8 @@
 	wmm = (struct wmm_information_element *) kde->wmm;
 	peer->qos_info = wmm->qos_info;
 
+	peer->wmm_capable = 1;
+
 	wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info);
 	return 0;
 }
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 20b3f62..df10342 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -54,7 +54,8 @@
 			     int *tdls_ext_setup);
 	int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
 			      u8 action_code, u8 dialog_token,
-			      u16 status_code, const u8 *buf, size_t len);
+			      u16 status_code, u32 peer_capab,
+			      const u8 *buf, size_t len);
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
 	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
 				u16 capability, const u8 *supp_rates,
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 75cfb47..f2fd285 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -267,13 +267,13 @@
 
 static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
 					u8 action_code, u8 dialog_token,
-					u16 status_code, const u8 *buf,
-					size_t len)
+					u16 status_code, u32 peer_capab,
+					const u8 *buf, size_t len)
 {
 	if (sm->ctx->send_tdls_mgmt)
 		return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
 					       dialog_token, status_code,
-					       buf, len);
+					       peer_capab, buf, len);
 	return -1;
 }
 
diff --git a/src/utils/edit.c b/src/utils/edit.c
index 177ecf4..d340bfa 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -14,7 +14,7 @@
 #include "list.h"
 #include "edit.h"
 
-#define CMD_BUF_LEN 256
+#define CMD_BUF_LEN 4096
 static char cmdbuf[CMD_BUF_LEN];
 static int cmdbuf_pos = 0;
 static int cmdbuf_len = 0;
diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c
index a095ea6..13173cb 100644
--- a/src/utils/edit_simple.c
+++ b/src/utils/edit_simple.c
@@ -13,7 +13,7 @@
 #include "edit.h"
 
 
-#define CMD_BUF_LEN 256
+#define CMD_BUF_LEN 4096
 static char cmdbuf[CMD_BUF_LEN];
 static int cmdbuf_pos = 0;
 static const char *ps2 = NULL;
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index f83a232..2667c8c 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -7,6 +7,7 @@
  */
 
 #include "includes.h"
+#include <assert.h>
 
 #include "common.h"
 #include "trace.h"
@@ -14,7 +15,6 @@
 #include "eloop.h"
 
 #ifdef CONFIG_ELOOP_POLL
-#include <assert.h>
 #include <poll.h>
 #endif /* CONFIG_ELOOP_POLL */
 
@@ -374,8 +374,10 @@
 	if (table->table == NULL)
 		return;
 
-	for (i = 0; i < table->count; i++)
+	for (i = 0; i < table->count; i++) {
+		assert(table->table[i].sock >= 0);
 		FD_SET(table->table[i].sock, fds);
+	}
 }
 
 
@@ -459,6 +461,7 @@
 {
 	struct eloop_sock_table *table;
 
+	assert(sock >= 0);
 	table = eloop_get_sock_table(type);
 	return eloop_sock_table_add_sock(table, sock, handler,
 					 eloop_data, user_data);
diff --git a/src/utils/xml-utils.h b/src/utils/xml-utils.h
index 0d8e0cb..fb6208c 100644
--- a/src/utils/xml-utils.h
+++ b/src/utils/xml-utils.h
@@ -73,9 +73,6 @@
 if (!xml_node_is_element(ctx, child)) \
 	continue
 
-typedef void (*debug_print_func)(void *ctx, int print, const char *fmt, ...)
-	__attribute__ ((format (printf, 3, 4)));
-
 
 struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx,
 					const void *env);