Cumulative patch from commit 99cd77a8c50413d44f1ebead917310468a8406de

99cd77a tests: Verify reassociate-to-same-BSS commands
e8d70a7 nl80211: Hide deauth event due to forced deauth-during-auth
0f44ec8 Add a reattach command for fast reassociate-back-to-same-BSS
cfc393a hostapd: Document interworking realm EAP Method types
7450c12 DFS: Add extra debugging messages
5d0d72a wpa_supplicant: Put upper bound on initial scan time delay
8c06db7 nl80211: Fix P2P Device handling when starting with RF-kill blocked
5e3ddf4 PNO: Change sched_scan_stopped event to handle pending PNO properly
737e7a0 PNO: Move and rename pno_start()/pno_stop()
1d91f50 hostapd: Process management frames only once per BSS
e070051 hostapd: Allow to switch to usable DFS channels
01b9999 hostapd: Allow to switch to DFS channels if available
70ee1be hostapd: Add config option chanlist for DFS channels
09eef14 Use internal FIPS 186-2 PRF if needed
3b9c517 Fix PTK derivation for CCMP-256 and GCMP-256
e6ef73f nl80211: Add debug print of KEY_DATA and KEY_SEQ
b465f5d Remove unused hostapd_wep_key_cmp()
4fb363c Fix error path handling on radius_accept_attr

Change-Id: I28ecac6cbcc6f71f19a051c12b54668ca6a66e2a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 92eda21..0f262ce 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -50,9 +50,11 @@
 	/*
 	 * When radar detection happens, CSA is performed. However, there's no
 	 * time for CAC, so radar channels must be skipped when finding a new
-	 * channel for CSA.
+	 * channel for CSA, unless they are available for immediate use.
 	 */
-	if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
+	if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
+	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
+	     HOSTAPD_CHAN_DFS_AVAILABLE))
 		return 0;
 
 	if (chan->flag & HOSTAPD_CHAN_DISABLED)
@@ -139,6 +141,22 @@
 }
 
 
+static int is_in_chanlist(struct hostapd_iface *iface,
+			  struct hostapd_channel_data *chan)
+{
+	int *entry;
+
+	if (!iface->conf->chanlist)
+		return 1;
+
+	for (entry = iface->conf->chanlist; *entry != -1; entry++) {
+		if (*entry == chan->chan)
+			return 1;
+	}
+	return 0;
+}
+
+
 /*
  * The function assumes HT40+ operation.
  * Make sure to adjust the following variables after calling this:
@@ -171,6 +189,9 @@
 		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
 			continue;
 
+		if (!is_in_chanlist(iface, chan))
+			continue;
+
 		if (ret_chan && idx == channel_idx) {
 			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
 			*ret_chan = chan;
@@ -267,8 +288,19 @@
 		}
 	}
 
-	if (res == -1)
-		wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1");
+	if (res == -1) {
+		wpa_printf(MSG_DEBUG,
+			   "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
+			   mode->num_channels, channel_no, iface->conf->channel,
+			   iface->conf->ieee80211n,
+			   iface->conf->secondary_channel,
+			   iface->conf->vht_oper_chwidth);
+
+		for (i = 0; i < mode->num_channels; i++) {
+			wpa_printf(MSG_DEBUG, "Available channel: %d",
+				   mode->channels[i].chan);
+		}
+	}
 
 	return res;
 }
@@ -727,9 +759,33 @@
 					skip_radar);
 
 	if (!channel) {
-		/* FIXME: Wait for channel(s) to become available */
+		/*
+		 * If there is no channel to switch immediately to, check if
+		 * there is another channel where we can switch even if it
+		 * requires to perform a CAC first.
+		 */
+		skip_radar = 0;
+		channel = dfs_get_valid_channel(iface, &secondary_channel,
+						&vht_oper_centr_freq_seg0_idx,
+						&vht_oper_centr_freq_seg1_idx,
+						skip_radar);
+		if (!channel) {
+			/* FIXME: Wait for channel(s) to become available */
+			hostapd_disable_iface(iface);
+			return err;
+		}
+
+		iface->freq = channel->freq;
+		iface->conf->channel = channel->chan;
+		iface->conf->secondary_channel = secondary_channel;
+		iface->conf->vht_oper_centr_freq_seg0_idx =
+			vht_oper_centr_freq_seg0_idx;
+		iface->conf->vht_oper_centr_freq_seg1_idx =
+			vht_oper_centr_freq_seg1_idx;
+
 		hostapd_disable_iface(iface);
-		return err;
+		hostapd_enable_iface(iface);
+		return 0;
 	}
 
 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",