Cumulative patch from commit c0333c8dd59b9e254d3fc725c984b1c0cd3d496a

c0333c8 Check rx_mgmt::frame more consistently against NULL
d6c6b1f Make sta NULL-check easier for static analyzers
0bceb8d Make dl_list_first() and dl_list_last() uses easier for static analyzers
5f693cb WPS HTTP: Remove unused assignment
ee4fefc Remove duplicated variable zeroing
4a9d0eb Make PMKID check easier for static analyzers
06df2aa Remove floating constant suffix 'd' from test coee
9670f87 ACS: Clean up ifdef CONFIG_ACS to avoid unreachable code
ece88f7 Make last_scan_res update easier for static analyzers
d06e9ac P2P: Verify operating channel validity for NFC connection handover
13a524a nl80211: Remove unnecessary wpa_driver_nl80211_set_freq() wrapper
e87ef75 nl80211: Add support for changing AP mode channel bandwidth
3057518 Sync with mac80211-next.git nl80211.h
5f0bca7 Retry initial 20/40 MHz co-ex scan if the driver is busy
587d60d Add AP mode support for HT 20/40 co-ex Action frame
9c47f6a hostapd: Extend support for HT 20/40 coexistence feature
196c9c7 Make channel parameters available in set_ap() driver operation
b7a6702 Indicate disconnection event on interface disabled
b89962b Fix wpa_config_read() with existing config block
27b4187 WPS: Print setsockopt() failure in debug log
52cb207 trace: Replace demangle.h with internal defines
0e80ea2 nl80211: Fix some coding style issues
a26582c Make qca-vendor.h independent of other header files
4a64d5a nl80211: Allocate QCA vendor subcmd for extended statistics

Change-Id: Ibabee77b2b87f04f99d6b1ca0f1ac741cb9222c0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 0a143d3..9680817 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -174,11 +174,11 @@
 	conf->ap_table_expiration_time = 60;
 
 #ifdef CONFIG_TESTING_OPTIONS
-	conf->ignore_probe_probability = 0.0d;
-	conf->ignore_auth_probability = 0.0d;
-	conf->ignore_assoc_probability = 0.0d;
-	conf->ignore_reassoc_probability = 0.0d;
-	conf->corrupt_gtk_rekey_mic_probability = 0.0d;
+	conf->ignore_probe_probability = 0.0;
+	conf->ignore_auth_probability = 0.0;
+	conf->ignore_assoc_probability = 0.0;
+	conf->ignore_reassoc_probability = 0.0;
+	conf->corrupt_gtk_rekey_mic_probability = 0.0;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_ACS
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 56df318..27525dc 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -645,7 +645,7 @@
 	 * with AP configuration */
 
 #ifdef CONFIG_TESTING_OPTIONS
-	if (hapd->iconf->ignore_probe_probability > 0.0d &&
+	if (hapd->iconf->ignore_probe_probability > 0.0 &&
 	    drand48() < hapd->iconf->ignore_probe_probability) {
 		wpa_printf(MSG_INFO,
 			   "TESTING: ignoring probe request from " MACSTR,
@@ -951,6 +951,9 @@
 int ieee802_11_set_beacon(struct hostapd_data *hapd)
 {
 	struct wpa_driver_ap_params params;
+	struct hostapd_freq_params freq;
+	struct hostapd_iface *iface = hapd->iface;
+	struct hostapd_config *iconf = iface->conf;
 	struct wpabuf *beacon, *proberesp, *assocresp;
 	int res, ret = -1;
 
@@ -972,6 +975,17 @@
 	params.proberesp_ies = proberesp;
 	params.assocresp_ies = assocresp;
 
+	if (iface->current_mode &&
+	    hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+				    iconf->channel, iconf->ieee80211n,
+				    iconf->ieee80211ac,
+				    iconf->secondary_channel,
+				    iconf->vht_oper_chwidth,
+				    iconf->vht_oper_centr_freq_seg0_idx,
+				    iconf->vht_oper_centr_freq_seg1_idx,
+				    iface->current_mode->vht_capab) == 0)
+		params.freq = &freq;
+
 	res = hostapd_drv_set_ap(hapd, &params);
 	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 	if (res)
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9760933..ccbbab5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -405,6 +405,7 @@
 			  "num_sta_ht_no_gf=%d\n"
 			  "num_sta_no_ht=%d\n"
 			  "num_sta_ht_20_mhz=%d\n"
+			  "num_sta_ht40_intolerant=%d\n"
 			  "olbc_ht=%d\n"
 			  "ht_op_mode=0x%x\n",
 			  hostapd_state_text(iface->state),
@@ -417,6 +418,7 @@
 			  iface->num_sta_ht_no_gf,
 			  iface->num_sta_no_ht,
 			  iface->num_sta_ht_20mhz,
+			  iface->num_sta_ht40_intolerant,
 			  iface->olbc_ht,
 			  iface->ht_op_mode);
 	if (ret < 0 || (size_t) ret >= buflen - len)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index a8c24eb..fb095ef 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/eloop.h"
 #include "radius/radius.h"
 #include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
@@ -30,6 +31,7 @@
 #include "ap_config.h"
 #include "hw_features.h"
 #include "dfs.h"
+#include "beacon.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -121,6 +123,24 @@
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+	if (elems.ht_capabilities &&
+	    elems.ht_capabilities_len >=
+	    sizeof(struct ieee80211_ht_capabilities) &&
+	    (hapd->iface->conf->ht_capab &
+	     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+		struct ieee80211_ht_capabilities *ht_cap =
+			(struct ieee80211_ht_capabilities *)
+			elems.ht_capabilities;
+
+		if (le_to_host16(ht_cap->ht_capabilities_info) &
+		    HT_CAP_INFO_40MHZ_INTOLERANT)
+			ht40_intolerant_add(hapd->iface, sta);
+	}
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
+
 #ifdef CONFIG_INTERWORKING
 	if (elems.ext_capab && elems.ext_capab_len > 4) {
 		if (elems.ext_capab[4] & 0x01)
@@ -981,6 +1001,8 @@
 		break;
 #endif /* NEED_AP_MLME */
 	case EVENT_RX_MGMT:
+		if (!data->rx_mgmt.frame)
+			break;
 #ifdef NEED_AP_MLME
 		if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
 			break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 614a5bf..391d774 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -33,6 +33,7 @@
 #include "p2p_hostapd.h"
 #include "gas_serv.h"
 #include "dfs.h"
+#include "ieee802_11.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -1352,6 +1353,12 @@
 	if (iface == NULL)
 		return;
 
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+	hostapd_stop_setup_timers(iface);
+	eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
 	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
 	iface->wait_channel_update = 0;
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 090544d..bd85c54 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -327,6 +327,9 @@
 	/* Number of HT associated stations 20 MHz */
 	int num_sta_ht_20mhz;
 
+	/* Number of HT40 intolerant stations */
+	int num_sta_ht40_intolerant;
+
 	/* Overlapping BSS information */
 	int olbc_ht;
 
@@ -351,11 +354,16 @@
 	unsigned int dfs_cac_ms;
 	struct os_reltime dfs_cac_start;
 
+	/* Latched with the actual secondary channel information and will be
+	 * used while juggling between HT20 and HT40 modes. */
+	int secondary_ch;
+
 #ifdef CONFIG_ACS
 	unsigned int acs_num_completed_scans;
 #endif /* CONFIG_ACS */
 
 	void (*scan_cb)(struct hostapd_iface *iface);
+	int num_ht40_scan_tries;
 };
 
 /* hostapd.c */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d47a366..b361834 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -19,6 +19,8 @@
 #include "ap_config.h"
 #include "ap_drv_ops.h"
 #include "acs.h"
+#include "ieee802_11.h"
+#include "beacon.h"
 #include "hw_features.h"
 
 
@@ -414,6 +416,7 @@
 		int pri = bss->freq;
 		int sec = pri;
 		int sec_chan, pri_chan;
+		struct ieee802_11_elems elems;
 
 		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
 
@@ -445,7 +448,23 @@
 			}
 		}
 
-		/* TODO: 40 MHz intolerant */
+		ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+				       0);
+		if (elems.ht_capabilities &&
+		    elems.ht_capabilities_len >=
+		    sizeof(struct ieee80211_ht_capabilities)) {
+			struct ieee80211_ht_capabilities *ht_cap =
+				(struct ieee80211_ht_capabilities *)
+				elems.ht_capabilities;
+
+			if (le_to_host16(ht_cap->ht_capabilities_info) &
+			    HT_CAP_INFO_40MHZ_INTOLERANT) {
+				wpa_printf(MSG_DEBUG,
+					   "40 MHz Intolerant is set on channel %d in BSS "
+					   MACSTR, pri, MAC2STR(bss->bssid));
+				return 0;
+			}
+		}
 	}
 
 	return 1;
@@ -475,6 +494,7 @@
 		oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
 	wpa_scan_results_free(scan_res);
 
+	iface->secondary_ch = iface->conf->secondary_channel;
 	if (!oper40) {
 		wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
 			   "channel pri=%d sec=%d based on overlapping BSSes",
@@ -482,9 +502,21 @@
 			   iface->conf->channel +
 			   iface->conf->secondary_channel * 4);
 		iface->conf->secondary_channel = 0;
+		if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
+			/*
+			 * TODO: Could consider scheduling another scan to check
+			 * if channel width can be changed if no coex reports
+			 * are received from associating stations.
+			 */
+		}
 	}
 
 	res = ieee80211n_allowed_ht40_channel_pair(iface);
+	if (!res) {
+		iface->conf->secondary_channel = 0;
+		wpa_printf(MSG_INFO, "Fallback to 20 MHz");
+	}
+
 	hostapd_setup_interface_complete(iface, !res);
 }
 
@@ -570,9 +602,55 @@
 }
 
 
+static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
+{
+#define HT2040_COEX_SCAN_RETRY 15
+	struct hostapd_iface *iface = eloop_data;
+	struct wpa_driver_scan_params params;
+	int ret;
+
+	os_memset(&params, 0, sizeof(params));
+	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		ieee80211n_scan_channels_2g4(iface, &params);
+	else
+		ieee80211n_scan_channels_5g(iface, &params);
+
+	ret = hostapd_driver_scan(iface->bss[0], &params);
+	iface->num_ht40_scan_tries++;
+	os_free(params.freqs);
+
+	if (ret == -EBUSY &&
+	    iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
+			   ret, strerror(-ret), iface->num_ht40_scan_tries);
+		eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+		return;
+	}
+
+	if (ret == 0) {
+		iface->scan_cb = ieee80211n_check_scan;
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "Failed to request a scan in device, bringing up in HT20 mode");
+	iface->conf->secondary_channel = 0;
+	iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+	hostapd_setup_interface_complete(iface, 0);
+}
+
+
+void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+	eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+}
+
+
 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
 {
 	struct wpa_driver_scan_params params;
+	int ret;
 
 	if (!iface->conf->secondary_channel)
 		return 0; /* HT40 not used */
@@ -585,13 +663,26 @@
 		ieee80211n_scan_channels_2g4(iface, &params);
 	else
 		ieee80211n_scan_channels_5g(iface, &params);
-	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to request a scan of "
-			   "neighboring BSSes");
-		os_free(params.freqs);
+
+	ret = hostapd_driver_scan(iface->bss[0], &params);
+	os_free(params.freqs);
+
+	if (ret == -EBUSY) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
+			   ret, strerror(-ret));
+		iface->num_ht40_scan_tries = 1;
+		eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+		eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+		return 1;
+	}
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to request a scan of neighboring BSSes ret=%d (%s)",
+			   ret, strerror(-ret));
 		return -1;
 	}
-	os_free(params.freqs);
 
 	iface->scan_cb = ieee80211n_check_scan;
 	return 1;
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 783ae5e..0f67ab8 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -23,6 +23,7 @@
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
 int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode);
+void hostapd_stop_setup_timers(struct hostapd_iface *iface);
 #else /* NEED_AP_MLME */
 static inline void
 hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -61,6 +62,10 @@
 	return 0;
 }
 
+static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+}
+
 #endif /* NEED_AP_MLME */
 
 #endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 14fb567..ca8db8f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -62,7 +62,6 @@
 	}
 
 	*pos++ = num;
-	count = 0;
 	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
 	     i++) {
 		count++;
@@ -105,7 +104,6 @@
 
 	*pos++ = WLAN_EID_EXT_SUPP_RATES;
 	*pos++ = num;
-	count = 0;
 	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
 	     i++) {
 		count++;
@@ -565,7 +563,7 @@
 	}
 
 #ifdef CONFIG_TESTING_OPTIONS
-	if (hapd->iconf->ignore_auth_probability > 0.0d &&
+	if (hapd->iconf->ignore_auth_probability > 0.0 &&
 	    drand48() < hapd->iconf->ignore_auth_probability) {
 		wpa_printf(MSG_INFO,
 			   "TESTING: ignoring auth frame from " MACSTR,
@@ -1291,7 +1289,7 @@
 
 #ifdef CONFIG_TESTING_OPTIONS
 	if (reassoc) {
-		if (hapd->iconf->ignore_reassoc_probability > 0.0d &&
+		if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
 		    drand48() < hapd->iconf->ignore_reassoc_probability) {
 			wpa_printf(MSG_INFO,
 				   "TESTING: ignoring reassoc request from "
@@ -1299,7 +1297,7 @@
 			return;
 		}
 	} else {
-		if (hapd->iconf->ignore_assoc_probability > 0.0d &&
+		if (hapd->iconf->ignore_assoc_probability > 0.0 &&
 		    drand48() < hapd->iconf->ignore_assoc_probability) {
 			wpa_printf(MSG_INFO,
 				   "TESTING: ignoring assoc request from "
@@ -1628,7 +1626,8 @@
 	switch (mgmt->u.action.category) {
 #ifdef CONFIG_IEEE80211R
 	case WLAN_ACTION_FT:
-		if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+		if (!sta ||
+		    wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
 				     len - IEEE80211_HDRLEN))
 			break;
 		return 1;
@@ -1647,6 +1646,15 @@
 #endif /* CONFIG_WNM */
 	case WLAN_ACTION_PUBLIC:
 	case WLAN_ACTION_PROTECTED_DUAL:
+#ifdef CONFIG_IEEE80211N
+		if (mgmt->u.action.u.public_action.action ==
+		    WLAN_PA_20_40_BSS_COEX) {
+			wpa_printf(MSG_DEBUG,
+				   "HT20/40 coex mgmt frame received from STA "
+				   MACSTR, MAC2STR(mgmt->sa));
+			hostapd_2040_coex_action(hapd, mgmt, len);
+		}
+#endif /* CONFIG_IEEE80211N */
 		if (hapd->public_action_cb) {
 			hapd->public_action_cb(hapd->public_action_cb_ctx,
 					       (u8 *) mgmt, len,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 809b4ca..cf0d3f2 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,11 +14,14 @@
 struct sta_info;
 struct hostapd_frame_info;
 struct ieee80211_ht_capabilities;
+struct ieee80211_mgmt;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 		    struct hostapd_frame_info *fi);
 void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
 			u16 stype, int ok);
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+			      const struct ieee80211_mgmt *mgmt, size_t len);
 #ifdef NEED_AP_MLME
 int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
 int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
@@ -39,6 +42,7 @@
 #endif /* NEED_AP_MLME */
 u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
 			   int probe);
+void ap_ht2040_timeout(void *eloop_data, void *user_data);
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
@@ -59,6 +63,8 @@
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		      const u8 *ht_capab, size_t ht_capab_len);
 void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *vht_capab, size_t vht_capab_len);
 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 1d64748..c0a7cd4 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -10,12 +10,15 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "sta_info.h"
 #include "beacon.h"
 #include "ieee802_11.h"
+#include "hw_features.h"
+#include "ap_drv_ops.h"
 
 
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
@@ -172,6 +175,117 @@
 }
 
 
+static int is_40_allowed(struct hostapd_iface *iface, int channel)
+{
+	int pri_freq, sec_freq;
+	int affected_start, affected_end;
+	int pri = 2407 + 5 * channel;
+
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return 1;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+	if ((pri < affected_start || pri > affected_end))
+		return 1; /* not within affected channel range */
+
+	wpa_printf(MSG_ERROR, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+	wpa_printf(MSG_ERROR, "Neighboring BSS: freq=%d", pri);
+	return 0;
+}
+
+
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+			      const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	struct ieee80211_2040_bss_coex_ie *bc_ie;
+	struct ieee80211_2040_intol_chan_report *ic_report;
+	int is_ht_allowed = 1;
+	int i;
+	const u8 *data = (const u8 *) &mgmt->u.action.u.public_action.action;
+	size_t hdr_len;
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
+		       mgmt->u.action.u.public_action.action);
+
+	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+		return;
+
+	hdr_len = data - (u8 *) mgmt;
+	if (hdr_len > len)
+		return;
+	data++;
+
+	bc_ie = (struct ieee80211_2040_bss_coex_ie *) &data[0];
+	ic_report = (struct ieee80211_2040_intol_chan_report *)
+		(&data[0] + sizeof(*bc_ie));
+
+	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+		hostapd_logger(hapd, mgmt->sa,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "20 MHz BSS width request bit is set in BSS coexistence information field");
+		is_ht_allowed = 0;
+	}
+
+	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+		hostapd_logger(hapd, mgmt->sa,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "40 MHz intolerant bit is set in BSS coexistence information field");
+		is_ht_allowed = 0;
+	}
+
+	if (ic_report &&
+	    (ic_report->element_id == WLAN_EID_20_40_BSS_INTOLERANT)) {
+		/* Go through the channel report to find any BSS there in the
+		 * affected channel range */
+		for (i = 0; i < ic_report->length - 1; i++) {
+			if (is_40_allowed(iface, ic_report->variable[i]))
+				continue;
+			hostapd_logger(hapd, mgmt->sa,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "20_40_INTOLERANT channel %d reported",
+				       ic_report->variable[i]);
+			is_ht_allowed = 0;
+			break;
+		}
+	}
+
+	if (!is_ht_allowed &&
+	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+		if (iface->conf->secondary_channel) {
+			hostapd_logger(hapd, mgmt->sa,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_INFO,
+				       "Switching to 20 MHz operation");
+			iface->conf->secondary_channel = 0;
+			ieee802_11_set_beacons(iface);
+		}
+		if (!iface->num_sta_ht40_intolerant) {
+			unsigned int delay_time;
+			delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+				iface->conf->obss_interval;
+			eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
+					     NULL);
+			eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+					       hapd->iface, NULL);
+		}
+	}
+}
+
+
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 		      const u8 *ht_capab, size_t ht_capab_len)
 {
@@ -200,6 +314,52 @@
 }
 
 
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta)
+{
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return;
+
+	wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR
+		   " in Association Request", MAC2STR(sta->addr));
+
+	if (sta->ht40_intolerant_set)
+		return;
+
+	sta->ht40_intolerant_set = 1;
+	iface->num_sta_ht40_intolerant++;
+	eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+
+	if (iface->conf->secondary_channel &&
+	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+		iface->conf->secondary_channel = 0;
+		ieee802_11_set_beacons(iface);
+	}
+}
+
+
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta)
+{
+	if (!sta->ht40_intolerant_set)
+		return;
+
+	sta->ht40_intolerant_set = 0;
+	iface->num_sta_ht40_intolerant--;
+
+	if (iface->num_sta_ht40_intolerant == 0 &&
+	    (iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+		unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+			iface->conf->obss_interval;
+		wpa_printf(MSG_DEBUG,
+			   "HT: Start 20->40 MHz transition timer (%d seconds)",
+			   delay_time);
+		eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+		eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+				       iface, NULL);
+	}
+}
+
+
 static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	u16 ht_capab;
@@ -227,6 +387,9 @@
 			   __func__, MAC2STR(sta->addr),
 			   hapd->iface->num_sta_ht_20mhz);
 	}
+
+	if (ht_capab & HT_CAP_INFO_40MHZ_INTOLERANT)
+		ht40_intolerant_add(hapd->iface, sta);
 }
 
 
@@ -288,3 +451,14 @@
 
 	neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
 }
+
+
+void ap_ht2040_timeout(void *eloop_data, void *user_data)
+{
+	struct hostapd_iface *iface = eloop_data;
+
+	wpa_printf(MSG_INFO, "Switching to 40 MHz operation");
+
+	iface->conf->secondary_channel = iface->secondary_ch;
+	ieee802_11_set_beacons(iface);
+}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f5417de..60f0768 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -206,6 +206,10 @@
 		hapd->iface->num_sta_ht_20mhz--;
 	}
 
+#ifdef CONFIG_IEEE80211N
+	ht40_intolerant_remove(hapd->iface, sta);
+#endif /* CONFIG_IEEE80211N */
+
 #ifdef CONFIG_P2P
 	if (sta->no_p2p_set) {
 		sta->no_p2p_set = 0;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 2dbdeb1..03db98f 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -54,6 +54,7 @@
 	unsigned int no_short_preamble_set:1;
 	unsigned int no_ht_gf_set:1;
 	unsigned int no_ht_set:1;
+	unsigned int ht40_intolerant_set:1;
 	unsigned int ht_20mhz_set:1;
 	unsigned int no_p2p_set:1;
 	unsigned int qos_map_enabled:1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 77e7858..d212610 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1421,7 +1421,7 @@
 				  key->key_mic);
 #ifdef CONFIG_TESTING_OPTIONS
 		if (!pairwise &&
-		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d &&
+		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
 		    drand48() <
 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index e957c6e..1e4defc 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -675,7 +675,7 @@
 			break;
 		}
 	}
-	if (sm->pmksa) {
+	if (sm->pmksa && pmkid) {
 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				 "PMKID found from PMKSA cache "
 				 "eap_type=%d vlan_id=%d",
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index cb70130..8fe2e4a 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -646,6 +646,7 @@
 #define ERP_INFO_USE_PROTECTION BIT(1)
 #define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
 
+#define OVERLAPPING_BSS_TRANS_DELAY_FACTOR 5
 
 /* HT Capabilities Info field within HT Capabilities element */
 #define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
diff --git a/src/common/qca-vendor-attr.h b/src/common/qca-vendor-attr.h
new file mode 100644
index 0000000..6f51803
--- /dev/null
+++ b/src/common/qca-vendor-attr.h
@@ -0,0 +1,28 @@
+/*
+ * Qualcomm Atheros vendor specific attribute definitions
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef QCA_VENDOR_ATTR_H
+#define QCA_VENDOR_ATTR_H
+
+/*
+ * This file defines some of the attributes used with Qualcomm Atheros OUI
+ * 00:13:74 in a way that is not suitable for qca-vendor.h, e.g., due to
+ * compiler dependencies.
+ */
+
+struct qca_avoid_freq_range {
+	u32 start_freq;
+	u32 end_freq;
+} __attribute__ ((packed));
+
+struct qca_avoid_freq_list {
+	u32 count;
+	struct qca_avoid_freq_range range[0];
+} __attribute__ ((packed));
+
+#endif /* QCA_VENDOR_ATTR_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0e292e6..1bc981b 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -51,25 +51,18 @@
 	QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
 	QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY =  11,
 	QCA_NL80211_VENDOR_SUBCMD_NAN =  12,
+	QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
 };
 
 
-struct qca_avoid_freq_range {
-	u32 start_freq;
-	u32 end_freq;
-} STRUCT_PACKED;
-
-struct qca_avoid_freq_list {
-	u32 count;
-	struct qca_avoid_freq_range range[0];
-} STRUCT_PACKED;
-
 enum qca_wlan_vendor_attr {
 	QCA_WLAN_VENDOR_ATTR_INVALID = 0,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
 	QCA_WLAN_VENDOR_ATTR_DFS     = 1,
 	/* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
 	QCA_WLAN_VENDOR_ATTR_NAN     = 2,
+	/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+	QCA_WLAN_VENDOR_ATTR_STATS_EXT     = 3,
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_MAX	= QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 13bf718..00565a7 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -868,6 +868,11 @@
 	 * osen - Whether OSEN security is enabled
 	 */
 	int osen;
+
+	/**
+	 * freq - Channel parameters for dynamic bandwidth changes
+	 */
+	struct hostapd_freq_params *freq;
 };
 
 /**
@@ -921,7 +926,8 @@
 #define WPA_DRIVER_FLAGS_AP		0x00000040
 /* Driver needs static WEP key setup after association has been completed */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
-/* unused: 0x00000100 */
+/* Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+#define WPA_DRIVER_FLAGS_HT_2040_COEX			0x00000100
 /* Driver supports concurrent P2P operations */
 #define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
 /*
@@ -2164,7 +2170,7 @@
 	 * @session_timeout: Session timeout for the station
 	 * Returns: 0 on success, -1 on failure
 	 */
-	int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, 
+	int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
 				   u32 session_timeout);
 
 	/**
@@ -2228,7 +2234,7 @@
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
-	                   const char *bridge_ifname, char *ifname_wds);
+			   const char *bridge_ifname, char *ifname_wds);
 
 	/**
 	 * send_action - Transmit an Action frame
@@ -2516,7 +2522,7 @@
 	 * signal_poll - Get current connection information
 	 * @priv: Private driver interface data
 	 * @signal_info: Connection info structure
-         */
+	 */
 	int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
 
 	/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 1300703..b0c8a35 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -29,6 +29,7 @@
 #include "eloop.h"
 #include "utils/list.h"
 #include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "l2_packet/l2_packet.h"
@@ -235,6 +236,7 @@
 	u8 addr[ETH_ALEN];
 
 	int freq;
+	int bandwidth;
 	int if_dynamic;
 
 	void *ctx;
@@ -385,8 +387,8 @@
 					enum wpa_driver_if_type type,
 					const char *ifname);
 
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-				       struct hostapd_freq_params *freq);
+static int nl80211_set_channel(struct i802_bss *bss,
+			       struct hostapd_freq_params *freq, int set_chan);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
 				     int ifindex, int disabled);
 
@@ -536,22 +538,22 @@
 
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
-	return (nlmode == NL80211_IFTYPE_AP ||
-		nlmode == NL80211_IFTYPE_P2P_GO);
+	return nlmode == NL80211_IFTYPE_AP ||
+		nlmode == NL80211_IFTYPE_P2P_GO;
 }
 
 
 static int is_sta_interface(enum nl80211_iftype nlmode)
 {
-	return (nlmode == NL80211_IFTYPE_STATION ||
-		nlmode == NL80211_IFTYPE_P2P_CLIENT);
+	return nlmode == NL80211_IFTYPE_STATION ||
+		nlmode == NL80211_IFTYPE_P2P_CLIENT;
 }
 
 
 static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
-	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
-		nlmode == NL80211_IFTYPE_P2P_GO);
+	return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+		nlmode == NL80211_IFTYPE_P2P_GO;
 }
 
 
@@ -3656,6 +3658,9 @@
 
 	if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
 		capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+
+	if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+		capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
 }
 
 
@@ -4522,7 +4527,7 @@
  * it isn't per interface ... maybe just dump the scan
  * results periodically for OLBC?
  */
-//		WLAN_FC_STYPE_BEACON,
+		/* WLAN_FC_STYPE_BEACON, */
 	};
 	unsigned int i;
 
@@ -7299,6 +7304,30 @@
 		nl80211_set_bss(bss, params->cts_protect, params->preamble,
 				params->short_slot_time, params->ht_opmode,
 				params->isolate, params->basic_rates);
+		if (beacon_set && params->freq &&
+		    params->freq->bandwidth != bss->bandwidth) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Update BSS %s bandwidth: %d -> %d",
+				   bss->ifname, bss->bandwidth,
+				   params->freq->bandwidth);
+			ret = nl80211_set_channel(bss, params->freq, 1);
+			if (ret) {
+				wpa_printf(MSG_DEBUG,
+					   "nl80211: Frequency set failed: %d (%s)",
+					   ret, strerror(-ret));
+			} else {
+				wpa_printf(MSG_DEBUG,
+					   "nl80211: Frequency set succeeded for ht2040 coex");
+				bss->bandwidth = params->freq->bandwidth;
+			}
+		} else if (!beacon_set) {
+			/*
+			 * cfg80211 updates the driver on frequence change in AP
+			 * mode only at the point when beaconing is started, so
+			 * set the initial value here.
+			 */
+			bss->bandwidth = params->freq->bandwidth;
+		}
 	}
 	return ret;
  nla_put_failure:
@@ -7363,8 +7392,8 @@
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-				       struct hostapd_freq_params *freq)
+static int nl80211_set_channel(struct i802_bss *bss,
+			       struct hostapd_freq_params *freq, int set_chan)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
@@ -7378,7 +7407,8 @@
 	if (!msg)
 		return -1;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+	nl80211_cmd(drv, msg, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+		    NL80211_CMD_SET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	if (nl80211_put_freq_params(msg, freq) < 0)
@@ -7841,7 +7871,7 @@
 		return;
 	}
 
-	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len, NULL)) {
+	if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
 		wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
 		return;
 	}
@@ -8395,7 +8425,7 @@
 		return -1;
 	}
 
-	if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
+	if (nl80211_set_channel(drv->first_bss, &freq, 0)) {
 		if (old_mode != nlmode)
 			wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
 		nl80211_remove_monitor_interface(drv);
@@ -9121,7 +9151,7 @@
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
 	struct i802_bss *bss = priv;
-	return wpa_driver_nl80211_set_freq(bss, freq);
+	return nl80211_set_channel(bss, freq, 0);
 }
 
 
@@ -9620,7 +9650,7 @@
 
 
 static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
-                            const char *bridge_ifname, char *ifname_wds)
+			    const char *bridge_ifname, char *ifname_wds)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 1b13d3d..3608b52 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1906,7 +1906,7 @@
 
 	/* data: optional [ STA-addr | ' ' | IEs(hex) ] */
 
-	if (!drv->ibss)
+	if (bss == NULL || !drv->ibss)
 		return;
 
 	pos = buf;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 1ba9d62..406010d 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1579,6 +1579,10 @@
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  *	As specified in the &enum nl80211_tdls_peer_capability.
  *
+ * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ *	creation then the new interface will be owned by the netlink socket
+ *	that created it and will be destroyed when the socket is closed
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1914,6 +1918,8 @@
 
 	NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
+	NL80211_ATTR_IFACE_SOCKET_OWNER,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2336,9 +2342,34 @@
  *	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_INDOOR_ONLY: Only indoor use is permitted on this
+ *	channel. A channel that has the INDOOR_ONLY attribute can only be
+ *	used when there is a clear assessment that the device is operating in
+ *	an indoor surroundings, i.e., it is connected to AC power (and not
+ *	through portable DC inverters) or is under the control of a master
+ *	that is acting as an AP and is connected to AC power.
+ * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
+ *	channel if it's connected concurrently to a BSS on the same channel on
+ *	the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
+ *	band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
+ *	channel that has the GO_CONCURRENT attribute set can be done when there
+ *	is a clear assessment that the device is operating under the guidance of
+ *	an authorized master, i.e., setting up a GO while the device is also
+ *	connected to an AP with DFS and radar detection on the UNII band (it is
+ *	up to user-space, i.e., wpa_supplicant to perform the required
+ *	verifications)
+ * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
+ *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
+ *	on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
  *	currently defined
  * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+ *
+ * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
+ * for more information on the FCC description of the relaxations allowed
+ * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
+ * NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
  */
 enum nl80211_frequency_attr {
 	__NL80211_FREQUENCY_ATTR_INVALID,
@@ -2355,6 +2386,10 @@
 	NL80211_FREQUENCY_ATTR_NO_80MHZ,
 	NL80211_FREQUENCY_ATTR_NO_160MHZ,
 	NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
+	NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
+	NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
+	NL80211_FREQUENCY_ATTR_NO_20MHZ,
+	NL80211_FREQUENCY_ATTR_NO_10MHZ,
 
 	/* keep last */
 	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2573,10 +2608,13 @@
  *	present has been registered with the wireless core that
  *	has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
  *	supported feature.
+ * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
+ *	platform is operating in an indoor environment.
  */
 enum nl80211_user_reg_hint_type {
 	NL80211_USER_REG_HINT_USER	= 0,
 	NL80211_USER_REG_HINT_CELL_BASE = 1,
+	NL80211_USER_REG_HINT_INDOOR    = 2,
 };
 
 /**
@@ -3891,6 +3929,9 @@
  *	interface. An active monitor interface behaves like a normal monitor
  *	interface, but gets added to the driver. It ensures that incoming
  *	unicast packets directed at the configured interface address get ACKed.
+ * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic
+ *	channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the
+ *	lifetime of a BSS.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -3911,6 +3952,7 @@
 	NL80211_FEATURE_FULL_AP_CLIENT_STATE		= 1 << 15,
 	NL80211_FEATURE_USERSPACE_MPM			= 1 << 16,
 	NL80211_FEATURE_ACTIVE_MONITOR			= 1 << 17,
+	NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE	= 1 << 18,
 };
 
 /**
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index bcc7e64..b30ea56 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4210,7 +4210,7 @@
 				dev = dl_list_first(&dev->list,
 						    struct p2p_device,
 						    list);
-				if (&dev->list == &p2p->devices)
+				if (!dev || &dev->list == &p2p->devices)
 					return NULL;
 			} while (dev->flags & P2P_DEV_PROBE_REQ_ONLY);
 		}
@@ -4222,7 +4222,7 @@
 			dev = dl_list_first(&dev->list,
 					    struct p2p_device,
 					    list);
-			if (&dev->list == &p2p->devices)
+			if (!dev || &dev->list == &p2p->devices)
 				return NULL;
 		}
 	}
@@ -4463,12 +4463,24 @@
 	p2p_buf_add_device_info(buf, p2p, NULL);
 
 	if (p2p->num_groups > 0) {
+		int freq = p2p_group_get_freq(p2p->groups[0]);
 		role = P2P_GO_IN_A_GROUP;
-		p2p_freq_to_channel(p2p_group_get_freq(p2p->groups[0]),
-				    &op_class, &channel);
+		if (p2p_freq_to_channel(freq, &op_class, &channel) < 0) {
+			p2p_dbg(p2p,
+				"Unknown GO operating frequency %d MHz for NFC handover",
+				freq);
+			wpabuf_free(buf);
+			return NULL;
+		}
 	} else if (client_freq > 0) {
 		role = P2P_CLIENT_IN_A_GROUP;
-		p2p_freq_to_channel(client_freq, &op_class, &channel);
+		if (p2p_freq_to_channel(client_freq, &op_class, &channel) < 0) {
+			p2p_dbg(p2p,
+				"Unknown client operating frequency %d MHz for NFC handover",
+				client_freq);
+			wpabuf_free(buf);
+			return NULL;
+		}
 	}
 
 	p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class,
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 94440f2..6044f5f 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -18,11 +18,9 @@
 
 #ifdef WPA_TRACE_BFD
 #include <bfd.h>
-#ifdef __linux__
-#include <demangle.h>
-#else /* __linux__ */
-#include <libiberty/demangle.h>
-#endif /* __linux__ */
+
+#define DMGL_PARAMS      (1 << 0)
+#define DMGL_ANSI        (1 << 1)
 
 static char *prg_fname = NULL;
 static bfd *cached_abfd = NULL;
diff --git a/src/wps/http_server.c b/src/wps/http_server.c
index 06c8bee..ac088c4 100644
--- a/src/wps/http_server.c
+++ b/src/wps/http_server.c
@@ -244,7 +244,13 @@
 	if (srv->fd < 0)
 		goto fail;
 
-	setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+	if (setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+	{
+		wpa_printf(MSG_DEBUG,
+			   "HTTP: setsockopt(SO_REUSEADDR) failed: %s",
+			   strerror(errno));
+		/* try to continue anyway */
+	}
 
 	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
 		goto fail;
diff --git a/src/wps/httpread.c b/src/wps/httpread.c
index b51d975..6d2d11c 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -617,7 +617,6 @@
 		 * We do NOT support trailers except to skip them --
 		 * this is supported (generally) by the http spec.
 		 */
-		bbp = h->body + h->body_nbytes;
 		for (;;) {
 			int c;
 			if (nread <= 0)
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 416961c..098571c 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -134,6 +134,8 @@
 	*islast = 0;
 	iface = dl_list_first(&sm->interfaces,
 			      struct upnp_wps_device_interface, list);
+	if (!iface)
+		return NULL;
 	uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
 	msg = wpabuf_alloc(800); /* more than big enough */
 	if (msg == NULL)
@@ -587,6 +589,8 @@
 					&sm->interfaces,
 					struct upnp_wps_device_interface,
 					list);
+				if (!iface)
+					continue;
 				data += os_strlen("uuid:");
 				uuid_bin2str(iface->wps->uuid, uuid_string,
 					     sizeof(uuid_string));
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index 54c3658..b1cf571 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -179,15 +179,12 @@
 /* format_wps_device_xml -- produce content of "file" wps_device.xml
  * (UPNP_WPS_DEVICE_XML_FILE)
  */
-static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
+static void format_wps_device_xml(struct upnp_wps_device_interface *iface,
+				  struct upnp_wps_device_sm *sm,
 				  struct wpabuf *buf)
 {
 	const char *s;
 	char uuid_string[80];
-	struct upnp_wps_device_interface *iface;
-
-	iface = dl_list_first(&sm->interfaces,
-			      struct upnp_wps_device_interface, list);
 
 	wpabuf_put_str(buf, wps_device_xml_prefix);
 
@@ -319,6 +316,10 @@
 
 	iface = dl_list_first(&sm->interfaces,
 			      struct upnp_wps_device_interface, list);
+	if (iface == NULL) {
+		http_request_deinit(hreq);
+		return;
+	}
 
 	/*
 	 * It is not required that filenames be case insensitive but it is
@@ -391,7 +392,7 @@
 
 	switch (req) {
 	case GET_DEVICE_XML_FILE:
-		format_wps_device_xml(sm, buf);
+		format_wps_device_xml(iface, sm, buf);
 		break;
 	case GET_SCPD_XML_FILE:
 		wpabuf_put_str(buf, wps_scpd_xml);
@@ -419,13 +420,14 @@
 
 	iface = dl_list_first(&sm->interfaces,
 			      struct upnp_wps_device_interface, list);
-	peer = &iface->peer;
 
 	wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
 
-	if (iface->ctx->ap_pin == NULL)
+	if (!iface || iface->ctx->ap_pin == NULL)
 		return HTTP_INTERNAL_SERVER_ERROR;
 
+	peer = &iface->peer;
+
 	/*
 	 * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
 	 * registration over UPnP with the AP acting as an Enrollee. It should
@@ -473,6 +475,8 @@
 
 	iface = dl_list_first(&sm->interfaces,
 			      struct upnp_wps_device_interface, list);
+	if (!iface)
+		return HTTP_INTERNAL_SERVER_ERROR;
 
 	/*
 	 * PutMessage is used by external UPnP-based Registrar to perform WPS