xref: /aosp_15_r20/external/wpa_supplicant_8/src/ap/dfs.c (revision 03f9172ca588f91df233974f4258bab95191f931)
1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker  * DFS - Dynamic Frequency Selection
3*03f9172cSAndroid Build Coastguard Worker  * Copyright (c) 2002-2013, Jouni Malinen <[email protected]>
4*03f9172cSAndroid Build Coastguard Worker  * Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
5*03f9172cSAndroid Build Coastguard Worker  *
6*03f9172cSAndroid Build Coastguard Worker  * This software may be distributed under the terms of the BSD license.
7*03f9172cSAndroid Build Coastguard Worker  * See README for more details.
8*03f9172cSAndroid Build Coastguard Worker  */
9*03f9172cSAndroid Build Coastguard Worker 
10*03f9172cSAndroid Build Coastguard Worker #include "utils/includes.h"
11*03f9172cSAndroid Build Coastguard Worker 
12*03f9172cSAndroid Build Coastguard Worker #include "utils/common.h"
13*03f9172cSAndroid Build Coastguard Worker #include "common/ieee802_11_defs.h"
14*03f9172cSAndroid Build Coastguard Worker #include "common/hw_features_common.h"
15*03f9172cSAndroid Build Coastguard Worker #include "common/wpa_ctrl.h"
16*03f9172cSAndroid Build Coastguard Worker #include "hostapd.h"
17*03f9172cSAndroid Build Coastguard Worker #include "beacon.h"
18*03f9172cSAndroid Build Coastguard Worker #include "ap_drv_ops.h"
19*03f9172cSAndroid Build Coastguard Worker #include "drivers/driver.h"
20*03f9172cSAndroid Build Coastguard Worker #include "dfs.h"
21*03f9172cSAndroid Build Coastguard Worker 
22*03f9172cSAndroid Build Coastguard Worker 
23*03f9172cSAndroid Build Coastguard Worker enum dfs_channel_type {
24*03f9172cSAndroid Build Coastguard Worker 	DFS_ANY_CHANNEL,
25*03f9172cSAndroid Build Coastguard Worker 	DFS_AVAILABLE, /* non-radar or radar-available */
26*03f9172cSAndroid Build Coastguard Worker 	DFS_NO_CAC_YET, /* radar-not-yet-available */
27*03f9172cSAndroid Build Coastguard Worker };
28*03f9172cSAndroid Build Coastguard Worker 
29*03f9172cSAndroid Build Coastguard Worker static struct hostapd_channel_data *
30*03f9172cSAndroid Build Coastguard Worker dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
31*03f9172cSAndroid Build Coastguard Worker 			u8 *oper_centr_freq_seg0_idx,
32*03f9172cSAndroid Build Coastguard Worker 			u8 *oper_centr_freq_seg1_idx,
33*03f9172cSAndroid Build Coastguard Worker 			enum dfs_channel_type *channel_type);
34*03f9172cSAndroid Build Coastguard Worker 
35*03f9172cSAndroid Build Coastguard Worker 
dfs_use_radar_background(struct hostapd_iface * iface)36*03f9172cSAndroid Build Coastguard Worker static bool dfs_use_radar_background(struct hostapd_iface *iface)
37*03f9172cSAndroid Build Coastguard Worker {
38*03f9172cSAndroid Build Coastguard Worker 	return (iface->drv_flags2 & WPA_DRIVER_FLAGS2_RADAR_BACKGROUND) &&
39*03f9172cSAndroid Build Coastguard Worker 		iface->conf->enable_background_radar;
40*03f9172cSAndroid Build Coastguard Worker }
41*03f9172cSAndroid Build Coastguard Worker 
42*03f9172cSAndroid Build Coastguard Worker 
dfs_get_used_n_chans(struct hostapd_iface * iface,int * seg1)43*03f9172cSAndroid Build Coastguard Worker static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
44*03f9172cSAndroid Build Coastguard Worker {
45*03f9172cSAndroid Build Coastguard Worker 	int n_chans = 1;
46*03f9172cSAndroid Build Coastguard Worker 
47*03f9172cSAndroid Build Coastguard Worker 	*seg1 = 0;
48*03f9172cSAndroid Build Coastguard Worker 
49*03f9172cSAndroid Build Coastguard Worker 	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
50*03f9172cSAndroid Build Coastguard Worker 		n_chans = 2;
51*03f9172cSAndroid Build Coastguard Worker 
52*03f9172cSAndroid Build Coastguard Worker 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
53*03f9172cSAndroid Build Coastguard Worker 		switch (hostapd_get_oper_chwidth(iface->conf)) {
54*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_USE_HT:
55*03f9172cSAndroid Build Coastguard Worker 			break;
56*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_80MHZ:
57*03f9172cSAndroid Build Coastguard Worker 			n_chans = 4;
58*03f9172cSAndroid Build Coastguard Worker 			break;
59*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_160MHZ:
60*03f9172cSAndroid Build Coastguard Worker 			n_chans = 8;
61*03f9172cSAndroid Build Coastguard Worker 			break;
62*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_80P80MHZ:
63*03f9172cSAndroid Build Coastguard Worker 			n_chans = 4;
64*03f9172cSAndroid Build Coastguard Worker 			*seg1 = 4;
65*03f9172cSAndroid Build Coastguard Worker 			break;
66*03f9172cSAndroid Build Coastguard Worker 		default:
67*03f9172cSAndroid Build Coastguard Worker 			break;
68*03f9172cSAndroid Build Coastguard Worker 		}
69*03f9172cSAndroid Build Coastguard Worker 	}
70*03f9172cSAndroid Build Coastguard Worker 
71*03f9172cSAndroid Build Coastguard Worker 	return n_chans;
72*03f9172cSAndroid Build Coastguard Worker }
73*03f9172cSAndroid Build Coastguard Worker 
74*03f9172cSAndroid Build Coastguard Worker 
75*03f9172cSAndroid Build Coastguard Worker /* dfs_channel_available: select new channel according to type parameter */
dfs_channel_available(struct hostapd_channel_data * chan,enum dfs_channel_type type)76*03f9172cSAndroid Build Coastguard Worker static int dfs_channel_available(struct hostapd_channel_data *chan,
77*03f9172cSAndroid Build Coastguard Worker 				 enum dfs_channel_type type)
78*03f9172cSAndroid Build Coastguard Worker {
79*03f9172cSAndroid Build Coastguard Worker 	if (type == DFS_NO_CAC_YET) {
80*03f9172cSAndroid Build Coastguard Worker 		/* Select only radar channel where CAC has not been
81*03f9172cSAndroid Build Coastguard Worker 		 * performed yet
82*03f9172cSAndroid Build Coastguard Worker 		 */
83*03f9172cSAndroid Build Coastguard Worker 		if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
84*03f9172cSAndroid Build Coastguard Worker 		    (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
85*03f9172cSAndroid Build Coastguard Worker 		     HOSTAPD_CHAN_DFS_USABLE)
86*03f9172cSAndroid Build Coastguard Worker 			return 1;
87*03f9172cSAndroid Build Coastguard Worker 		return 0;
88*03f9172cSAndroid Build Coastguard Worker 	}
89*03f9172cSAndroid Build Coastguard Worker 
90*03f9172cSAndroid Build Coastguard Worker 	/*
91*03f9172cSAndroid Build Coastguard Worker 	 * When radar detection happens, CSA is performed. However, there's no
92*03f9172cSAndroid Build Coastguard Worker 	 * time for CAC, so radar channels must be skipped when finding a new
93*03f9172cSAndroid Build Coastguard Worker 	 * channel for CSA, unless they are available for immediate use.
94*03f9172cSAndroid Build Coastguard Worker 	 */
95*03f9172cSAndroid Build Coastguard Worker 	if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
96*03f9172cSAndroid Build Coastguard Worker 	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
97*03f9172cSAndroid Build Coastguard Worker 	     HOSTAPD_CHAN_DFS_AVAILABLE))
98*03f9172cSAndroid Build Coastguard Worker 		return 0;
99*03f9172cSAndroid Build Coastguard Worker 
100*03f9172cSAndroid Build Coastguard Worker 	if (chan->flag & HOSTAPD_CHAN_DISABLED)
101*03f9172cSAndroid Build Coastguard Worker 		return 0;
102*03f9172cSAndroid Build Coastguard Worker 	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
103*03f9172cSAndroid Build Coastguard Worker 	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
104*03f9172cSAndroid Build Coastguard Worker 	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
105*03f9172cSAndroid Build Coastguard Worker 		return 0;
106*03f9172cSAndroid Build Coastguard Worker 	return 1;
107*03f9172cSAndroid Build Coastguard Worker }
108*03f9172cSAndroid Build Coastguard Worker 
109*03f9172cSAndroid Build Coastguard Worker 
dfs_is_chan_allowed(struct hostapd_channel_data * chan,int n_chans)110*03f9172cSAndroid Build Coastguard Worker static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
111*03f9172cSAndroid Build Coastguard Worker {
112*03f9172cSAndroid Build Coastguard Worker 	/*
113*03f9172cSAndroid Build Coastguard Worker 	 * The tables contain first valid channel number based on channel width.
114*03f9172cSAndroid Build Coastguard Worker 	 * We will also choose this first channel as the control one.
115*03f9172cSAndroid Build Coastguard Worker 	 */
116*03f9172cSAndroid Build Coastguard Worker 	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
117*03f9172cSAndroid Build Coastguard Worker 			     165, 173, 184, 192 };
118*03f9172cSAndroid Build Coastguard Worker 	/*
119*03f9172cSAndroid Build Coastguard Worker 	 * VHT80, valid channels based on center frequency:
120*03f9172cSAndroid Build Coastguard Worker 	 * 42, 58, 106, 122, 138, 155, 171
121*03f9172cSAndroid Build Coastguard Worker 	 */
122*03f9172cSAndroid Build Coastguard Worker 	int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
123*03f9172cSAndroid Build Coastguard Worker 	/*
124*03f9172cSAndroid Build Coastguard Worker 	 * VHT160 valid channels based on center frequency:
125*03f9172cSAndroid Build Coastguard Worker 	 * 50, 114, 163
126*03f9172cSAndroid Build Coastguard Worker 	 */
127*03f9172cSAndroid Build Coastguard Worker 	int allowed_160[] = { 36, 100, 149 };
128*03f9172cSAndroid Build Coastguard Worker 	int *allowed = allowed_40;
129*03f9172cSAndroid Build Coastguard Worker 	unsigned int i, allowed_no = 0;
130*03f9172cSAndroid Build Coastguard Worker 
131*03f9172cSAndroid Build Coastguard Worker 	switch (n_chans) {
132*03f9172cSAndroid Build Coastguard Worker 	case 2:
133*03f9172cSAndroid Build Coastguard Worker 		allowed = allowed_40;
134*03f9172cSAndroid Build Coastguard Worker 		allowed_no = ARRAY_SIZE(allowed_40);
135*03f9172cSAndroid Build Coastguard Worker 		break;
136*03f9172cSAndroid Build Coastguard Worker 	case 4:
137*03f9172cSAndroid Build Coastguard Worker 		allowed = allowed_80;
138*03f9172cSAndroid Build Coastguard Worker 		allowed_no = ARRAY_SIZE(allowed_80);
139*03f9172cSAndroid Build Coastguard Worker 		break;
140*03f9172cSAndroid Build Coastguard Worker 	case 8:
141*03f9172cSAndroid Build Coastguard Worker 		allowed = allowed_160;
142*03f9172cSAndroid Build Coastguard Worker 		allowed_no = ARRAY_SIZE(allowed_160);
143*03f9172cSAndroid Build Coastguard Worker 		break;
144*03f9172cSAndroid Build Coastguard Worker 	default:
145*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
146*03f9172cSAndroid Build Coastguard Worker 		break;
147*03f9172cSAndroid Build Coastguard Worker 	}
148*03f9172cSAndroid Build Coastguard Worker 
149*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < allowed_no; i++) {
150*03f9172cSAndroid Build Coastguard Worker 		if (chan->chan == allowed[i])
151*03f9172cSAndroid Build Coastguard Worker 			return 1;
152*03f9172cSAndroid Build Coastguard Worker 	}
153*03f9172cSAndroid Build Coastguard Worker 
154*03f9172cSAndroid Build Coastguard Worker 	return 0;
155*03f9172cSAndroid Build Coastguard Worker }
156*03f9172cSAndroid Build Coastguard Worker 
157*03f9172cSAndroid Build Coastguard Worker 
158*03f9172cSAndroid Build Coastguard Worker static struct hostapd_channel_data *
dfs_get_chan_data(struct hostapd_hw_modes * mode,int freq,int first_chan_idx)159*03f9172cSAndroid Build Coastguard Worker dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
160*03f9172cSAndroid Build Coastguard Worker {
161*03f9172cSAndroid Build Coastguard Worker 	int i;
162*03f9172cSAndroid Build Coastguard Worker 
163*03f9172cSAndroid Build Coastguard Worker 	for (i = first_chan_idx; i < mode->num_channels; i++) {
164*03f9172cSAndroid Build Coastguard Worker 		if (mode->channels[i].freq == freq)
165*03f9172cSAndroid Build Coastguard Worker 			return &mode->channels[i];
166*03f9172cSAndroid Build Coastguard Worker 	}
167*03f9172cSAndroid Build Coastguard Worker 
168*03f9172cSAndroid Build Coastguard Worker 	return NULL;
169*03f9172cSAndroid Build Coastguard Worker }
170*03f9172cSAndroid Build Coastguard Worker 
171*03f9172cSAndroid Build Coastguard Worker 
dfs_chan_range_available(struct hostapd_hw_modes * mode,int first_chan_idx,int num_chans,enum dfs_channel_type type)172*03f9172cSAndroid Build Coastguard Worker static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
173*03f9172cSAndroid Build Coastguard Worker 				    int first_chan_idx, int num_chans,
174*03f9172cSAndroid Build Coastguard Worker 				    enum dfs_channel_type type)
175*03f9172cSAndroid Build Coastguard Worker {
176*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *first_chan, *chan;
177*03f9172cSAndroid Build Coastguard Worker 	int i;
178*03f9172cSAndroid Build Coastguard Worker 	u32 bw = num_chan_to_bw(num_chans);
179*03f9172cSAndroid Build Coastguard Worker 
180*03f9172cSAndroid Build Coastguard Worker 	if (first_chan_idx + num_chans > mode->num_channels) {
181*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG,
182*03f9172cSAndroid Build Coastguard Worker 			   "DFS: some channels in range not defined");
183*03f9172cSAndroid Build Coastguard Worker 		return 0;
184*03f9172cSAndroid Build Coastguard Worker 	}
185*03f9172cSAndroid Build Coastguard Worker 
186*03f9172cSAndroid Build Coastguard Worker 	first_chan = &mode->channels[first_chan_idx];
187*03f9172cSAndroid Build Coastguard Worker 
188*03f9172cSAndroid Build Coastguard Worker 	/* hostapd DFS implementation assumes the first channel as primary.
189*03f9172cSAndroid Build Coastguard Worker 	 * If it's not allowed to use the first channel as primary, decline the
190*03f9172cSAndroid Build Coastguard Worker 	 * whole channel range. */
191*03f9172cSAndroid Build Coastguard Worker 	if (!chan_pri_allowed(first_chan)) {
192*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "DFS: primary channel not allowed");
193*03f9172cSAndroid Build Coastguard Worker 		return 0;
194*03f9172cSAndroid Build Coastguard Worker 	}
195*03f9172cSAndroid Build Coastguard Worker 
196*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < num_chans; i++) {
197*03f9172cSAndroid Build Coastguard Worker 		chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
198*03f9172cSAndroid Build Coastguard Worker 					 first_chan_idx);
199*03f9172cSAndroid Build Coastguard Worker 		if (!chan) {
200*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
201*03f9172cSAndroid Build Coastguard Worker 				   first_chan->freq + i * 20);
202*03f9172cSAndroid Build Coastguard Worker 			return 0;
203*03f9172cSAndroid Build Coastguard Worker 		}
204*03f9172cSAndroid Build Coastguard Worker 
205*03f9172cSAndroid Build Coastguard Worker 		/* HT 40 MHz secondary channel availability checked only for
206*03f9172cSAndroid Build Coastguard Worker 		 * primary channel */
207*03f9172cSAndroid Build Coastguard Worker 		if (!chan_bw_allowed(chan, bw, 1, !i)) {
208*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
209*03f9172cSAndroid Build Coastguard Worker 				   first_chan->freq + i * 20);
210*03f9172cSAndroid Build Coastguard Worker 			return 0;
211*03f9172cSAndroid Build Coastguard Worker 		}
212*03f9172cSAndroid Build Coastguard Worker 
213*03f9172cSAndroid Build Coastguard Worker 		if (!dfs_channel_available(chan, type)) {
214*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
215*03f9172cSAndroid Build Coastguard Worker 				   first_chan->freq + i * 20);
216*03f9172cSAndroid Build Coastguard Worker 			return 0;
217*03f9172cSAndroid Build Coastguard Worker 		}
218*03f9172cSAndroid Build Coastguard Worker 	}
219*03f9172cSAndroid Build Coastguard Worker 
220*03f9172cSAndroid Build Coastguard Worker 	return 1;
221*03f9172cSAndroid Build Coastguard Worker }
222*03f9172cSAndroid Build Coastguard Worker 
223*03f9172cSAndroid Build Coastguard Worker 
is_in_chanlist(struct hostapd_iface * iface,struct hostapd_channel_data * chan)224*03f9172cSAndroid Build Coastguard Worker static int is_in_chanlist(struct hostapd_iface *iface,
225*03f9172cSAndroid Build Coastguard Worker 			  struct hostapd_channel_data *chan)
226*03f9172cSAndroid Build Coastguard Worker {
227*03f9172cSAndroid Build Coastguard Worker 	if (!iface->conf->acs_ch_list.num)
228*03f9172cSAndroid Build Coastguard Worker 		return 1;
229*03f9172cSAndroid Build Coastguard Worker 
230*03f9172cSAndroid Build Coastguard Worker 	return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
231*03f9172cSAndroid Build Coastguard Worker }
232*03f9172cSAndroid Build Coastguard Worker 
233*03f9172cSAndroid Build Coastguard Worker 
234*03f9172cSAndroid Build Coastguard Worker /*
235*03f9172cSAndroid Build Coastguard Worker  * The function assumes HT40+ operation.
236*03f9172cSAndroid Build Coastguard Worker  * Make sure to adjust the following variables after calling this:
237*03f9172cSAndroid Build Coastguard Worker  *  - hapd->secondary_channel
238*03f9172cSAndroid Build Coastguard Worker  *  - hapd->vht/he_oper_centr_freq_seg0_idx
239*03f9172cSAndroid Build Coastguard Worker  *  - hapd->vht/he_oper_centr_freq_seg1_idx
240*03f9172cSAndroid Build Coastguard Worker  */
dfs_find_channel(struct hostapd_iface * iface,struct hostapd_channel_data ** ret_chan,int idx,enum dfs_channel_type type)241*03f9172cSAndroid Build Coastguard Worker static int dfs_find_channel(struct hostapd_iface *iface,
242*03f9172cSAndroid Build Coastguard Worker 			    struct hostapd_channel_data **ret_chan,
243*03f9172cSAndroid Build Coastguard Worker 			    int idx, enum dfs_channel_type type)
244*03f9172cSAndroid Build Coastguard Worker {
245*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
246*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan;
247*03f9172cSAndroid Build Coastguard Worker 	int i, channel_idx = 0, n_chans, n_chans1;
248*03f9172cSAndroid Build Coastguard Worker 
249*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
250*03f9172cSAndroid Build Coastguard Worker 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
251*03f9172cSAndroid Build Coastguard Worker 
252*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
253*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < mode->num_channels; i++) {
254*03f9172cSAndroid Build Coastguard Worker 		chan = &mode->channels[i];
255*03f9172cSAndroid Build Coastguard Worker 
256*03f9172cSAndroid Build Coastguard Worker 		if (!chan_in_current_hw_info(iface->current_hw_info, chan)) {
257*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG,
258*03f9172cSAndroid Build Coastguard Worker 				   "DFS: channel %d (%d) is not under current hardware index",
259*03f9172cSAndroid Build Coastguard Worker 				   chan->freq, chan->chan);
260*03f9172cSAndroid Build Coastguard Worker 			continue;
261*03f9172cSAndroid Build Coastguard Worker 		}
262*03f9172cSAndroid Build Coastguard Worker 
263*03f9172cSAndroid Build Coastguard Worker 		/* Skip HT40/VHT incompatible channels */
264*03f9172cSAndroid Build Coastguard Worker 		if (iface->conf->ieee80211n &&
265*03f9172cSAndroid Build Coastguard Worker 		    iface->conf->secondary_channel &&
266*03f9172cSAndroid Build Coastguard Worker 		    (!dfs_is_chan_allowed(chan, n_chans) ||
267*03f9172cSAndroid Build Coastguard Worker 		     !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
268*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG,
269*03f9172cSAndroid Build Coastguard Worker 				   "DFS: channel %d (%d) is incompatible",
270*03f9172cSAndroid Build Coastguard Worker 				   chan->freq, chan->chan);
271*03f9172cSAndroid Build Coastguard Worker 			continue;
272*03f9172cSAndroid Build Coastguard Worker 		}
273*03f9172cSAndroid Build Coastguard Worker 
274*03f9172cSAndroid Build Coastguard Worker 		/* Skip incompatible chandefs */
275*03f9172cSAndroid Build Coastguard Worker 		if (!dfs_chan_range_available(mode, i, n_chans, type)) {
276*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG,
277*03f9172cSAndroid Build Coastguard Worker 				   "DFS: range not available for %d (%d)",
278*03f9172cSAndroid Build Coastguard Worker 				   chan->freq, chan->chan);
279*03f9172cSAndroid Build Coastguard Worker 			continue;
280*03f9172cSAndroid Build Coastguard Worker 		}
281*03f9172cSAndroid Build Coastguard Worker 
282*03f9172cSAndroid Build Coastguard Worker 		if (!is_in_chanlist(iface, chan)) {
283*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG,
284*03f9172cSAndroid Build Coastguard Worker 				   "DFS: channel %d (%d) not in chanlist",
285*03f9172cSAndroid Build Coastguard Worker 				   chan->freq, chan->chan);
286*03f9172cSAndroid Build Coastguard Worker 			continue;
287*03f9172cSAndroid Build Coastguard Worker 		}
288*03f9172cSAndroid Build Coastguard Worker 
289*03f9172cSAndroid Build Coastguard Worker 		if (chan->max_tx_power < iface->conf->min_tx_power)
290*03f9172cSAndroid Build Coastguard Worker 			continue;
291*03f9172cSAndroid Build Coastguard Worker 
292*03f9172cSAndroid Build Coastguard Worker 		if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
293*03f9172cSAndroid Build Coastguard Worker 		    iface->conf->country[2] == 0x4f)
294*03f9172cSAndroid Build Coastguard Worker 			continue;
295*03f9172cSAndroid Build Coastguard Worker 
296*03f9172cSAndroid Build Coastguard Worker 		if (ret_chan && idx == channel_idx) {
297*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
298*03f9172cSAndroid Build Coastguard Worker 				   chan->freq, chan->chan);
299*03f9172cSAndroid Build Coastguard Worker 			*ret_chan = chan;
300*03f9172cSAndroid Build Coastguard Worker 			return idx;
301*03f9172cSAndroid Build Coastguard Worker 		}
302*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
303*03f9172cSAndroid Build Coastguard Worker 			   chan->freq, chan->chan);
304*03f9172cSAndroid Build Coastguard Worker 		channel_idx++;
305*03f9172cSAndroid Build Coastguard Worker 	}
306*03f9172cSAndroid Build Coastguard Worker 	return channel_idx;
307*03f9172cSAndroid Build Coastguard Worker }
308*03f9172cSAndroid Build Coastguard Worker 
309*03f9172cSAndroid Build Coastguard Worker 
dfs_adjust_center_freq(struct hostapd_iface * iface,struct hostapd_channel_data * chan,int secondary_channel,int sec_chan_idx_80p80,u8 * oper_centr_freq_seg0_idx,u8 * oper_centr_freq_seg1_idx)310*03f9172cSAndroid Build Coastguard Worker static void dfs_adjust_center_freq(struct hostapd_iface *iface,
311*03f9172cSAndroid Build Coastguard Worker 				   struct hostapd_channel_data *chan,
312*03f9172cSAndroid Build Coastguard Worker 				   int secondary_channel,
313*03f9172cSAndroid Build Coastguard Worker 				   int sec_chan_idx_80p80,
314*03f9172cSAndroid Build Coastguard Worker 				   u8 *oper_centr_freq_seg0_idx,
315*03f9172cSAndroid Build Coastguard Worker 				   u8 *oper_centr_freq_seg1_idx)
316*03f9172cSAndroid Build Coastguard Worker {
317*03f9172cSAndroid Build Coastguard Worker 	if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
318*03f9172cSAndroid Build Coastguard Worker 		return;
319*03f9172cSAndroid Build Coastguard Worker 
320*03f9172cSAndroid Build Coastguard Worker 	if (!chan)
321*03f9172cSAndroid Build Coastguard Worker 		return;
322*03f9172cSAndroid Build Coastguard Worker 
323*03f9172cSAndroid Build Coastguard Worker 	*oper_centr_freq_seg1_idx = 0;
324*03f9172cSAndroid Build Coastguard Worker 
325*03f9172cSAndroid Build Coastguard Worker 	switch (hostapd_get_oper_chwidth(iface->conf)) {
326*03f9172cSAndroid Build Coastguard Worker 	case CONF_OPER_CHWIDTH_USE_HT:
327*03f9172cSAndroid Build Coastguard Worker 		if (secondary_channel == 1)
328*03f9172cSAndroid Build Coastguard Worker 			*oper_centr_freq_seg0_idx = chan->chan + 2;
329*03f9172cSAndroid Build Coastguard Worker 		else if (secondary_channel == -1)
330*03f9172cSAndroid Build Coastguard Worker 			*oper_centr_freq_seg0_idx = chan->chan - 2;
331*03f9172cSAndroid Build Coastguard Worker 		else
332*03f9172cSAndroid Build Coastguard Worker 			*oper_centr_freq_seg0_idx = chan->chan;
333*03f9172cSAndroid Build Coastguard Worker 		break;
334*03f9172cSAndroid Build Coastguard Worker 	case CONF_OPER_CHWIDTH_80MHZ:
335*03f9172cSAndroid Build Coastguard Worker 		*oper_centr_freq_seg0_idx = chan->chan + 6;
336*03f9172cSAndroid Build Coastguard Worker 		break;
337*03f9172cSAndroid Build Coastguard Worker 	case CONF_OPER_CHWIDTH_160MHZ:
338*03f9172cSAndroid Build Coastguard Worker 		*oper_centr_freq_seg0_idx = chan->chan + 14;
339*03f9172cSAndroid Build Coastguard Worker 		break;
340*03f9172cSAndroid Build Coastguard Worker 	case CONF_OPER_CHWIDTH_80P80MHZ:
341*03f9172cSAndroid Build Coastguard Worker 		*oper_centr_freq_seg0_idx = chan->chan + 6;
342*03f9172cSAndroid Build Coastguard Worker 		*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
343*03f9172cSAndroid Build Coastguard Worker 		break;
344*03f9172cSAndroid Build Coastguard Worker 
345*03f9172cSAndroid Build Coastguard Worker 	default:
346*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO,
347*03f9172cSAndroid Build Coastguard Worker 			   "DFS: Unsupported channel width configuration");
348*03f9172cSAndroid Build Coastguard Worker 		*oper_centr_freq_seg0_idx = 0;
349*03f9172cSAndroid Build Coastguard Worker 		break;
350*03f9172cSAndroid Build Coastguard Worker 	}
351*03f9172cSAndroid Build Coastguard Worker 
352*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
353*03f9172cSAndroid Build Coastguard Worker 		   *oper_centr_freq_seg0_idx,
354*03f9172cSAndroid Build Coastguard Worker 		   *oper_centr_freq_seg1_idx);
355*03f9172cSAndroid Build Coastguard Worker }
356*03f9172cSAndroid Build Coastguard Worker 
357*03f9172cSAndroid Build Coastguard Worker 
358*03f9172cSAndroid Build Coastguard Worker /* Return start channel idx we will use for mode->channels[idx] */
dfs_get_start_chan_idx(struct hostapd_iface * iface,int * seg1_start)359*03f9172cSAndroid Build Coastguard Worker static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
360*03f9172cSAndroid Build Coastguard Worker {
361*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
362*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan;
363*03f9172cSAndroid Build Coastguard Worker 	int channel_no = iface->conf->channel;
364*03f9172cSAndroid Build Coastguard Worker 	int res = -1, i;
365*03f9172cSAndroid Build Coastguard Worker 	int chan_seg1 = -1;
366*03f9172cSAndroid Build Coastguard Worker 
367*03f9172cSAndroid Build Coastguard Worker 	*seg1_start = -1;
368*03f9172cSAndroid Build Coastguard Worker 
369*03f9172cSAndroid Build Coastguard Worker 	/* HT40- */
370*03f9172cSAndroid Build Coastguard Worker 	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
371*03f9172cSAndroid Build Coastguard Worker 		channel_no -= 4;
372*03f9172cSAndroid Build Coastguard Worker 
373*03f9172cSAndroid Build Coastguard Worker 	/* VHT/HE/EHT */
374*03f9172cSAndroid Build Coastguard Worker 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
375*03f9172cSAndroid Build Coastguard Worker 	    iface->conf->ieee80211be) {
376*03f9172cSAndroid Build Coastguard Worker 		switch (hostapd_get_oper_chwidth(iface->conf)) {
377*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_USE_HT:
378*03f9172cSAndroid Build Coastguard Worker 			break;
379*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_80MHZ:
380*03f9172cSAndroid Build Coastguard Worker 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
381*03f9172cSAndroid Build Coastguard Worker 				iface->conf) - 6;
382*03f9172cSAndroid Build Coastguard Worker 			break;
383*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_160MHZ:
384*03f9172cSAndroid Build Coastguard Worker 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
385*03f9172cSAndroid Build Coastguard Worker 				iface->conf) - 14;
386*03f9172cSAndroid Build Coastguard Worker 			break;
387*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_80P80MHZ:
388*03f9172cSAndroid Build Coastguard Worker 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
389*03f9172cSAndroid Build Coastguard Worker 				iface->conf) - 6;
390*03f9172cSAndroid Build Coastguard Worker 			chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
391*03f9172cSAndroid Build Coastguard Worker 				iface->conf) - 6;
392*03f9172cSAndroid Build Coastguard Worker 			break;
393*03f9172cSAndroid Build Coastguard Worker 		case CONF_OPER_CHWIDTH_320MHZ:
394*03f9172cSAndroid Build Coastguard Worker 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
395*03f9172cSAndroid Build Coastguard Worker 				iface->conf) - 30;
396*03f9172cSAndroid Build Coastguard Worker 			break;
397*03f9172cSAndroid Build Coastguard Worker 		default:
398*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_INFO,
399*03f9172cSAndroid Build Coastguard Worker 				   "DFS only EHT20/40/80/160/80+80/320 is supported now");
400*03f9172cSAndroid Build Coastguard Worker 			channel_no = -1;
401*03f9172cSAndroid Build Coastguard Worker 			break;
402*03f9172cSAndroid Build Coastguard Worker 		}
403*03f9172cSAndroid Build Coastguard Worker 	}
404*03f9172cSAndroid Build Coastguard Worker 
405*03f9172cSAndroid Build Coastguard Worker 	/* Get idx */
406*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
407*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < mode->num_channels; i++) {
408*03f9172cSAndroid Build Coastguard Worker 		chan = &mode->channels[i];
409*03f9172cSAndroid Build Coastguard Worker 		if (chan->chan == channel_no) {
410*03f9172cSAndroid Build Coastguard Worker 			res = i;
411*03f9172cSAndroid Build Coastguard Worker 			break;
412*03f9172cSAndroid Build Coastguard Worker 		}
413*03f9172cSAndroid Build Coastguard Worker 	}
414*03f9172cSAndroid Build Coastguard Worker 
415*03f9172cSAndroid Build Coastguard Worker 	if (res != -1 && chan_seg1 > -1) {
416*03f9172cSAndroid Build Coastguard Worker 		int found = 0;
417*03f9172cSAndroid Build Coastguard Worker 
418*03f9172cSAndroid Build Coastguard Worker 		/* Get idx for seg1 */
419*03f9172cSAndroid Build Coastguard Worker 		mode = iface->current_mode;
420*03f9172cSAndroid Build Coastguard Worker 		for (i = 0; i < mode->num_channels; i++) {
421*03f9172cSAndroid Build Coastguard Worker 			chan = &mode->channels[i];
422*03f9172cSAndroid Build Coastguard Worker 			if (chan->chan == chan_seg1) {
423*03f9172cSAndroid Build Coastguard Worker 				*seg1_start = i;
424*03f9172cSAndroid Build Coastguard Worker 				found = 1;
425*03f9172cSAndroid Build Coastguard Worker 				break;
426*03f9172cSAndroid Build Coastguard Worker 			}
427*03f9172cSAndroid Build Coastguard Worker 		}
428*03f9172cSAndroid Build Coastguard Worker 		if (!found)
429*03f9172cSAndroid Build Coastguard Worker 			res = -1;
430*03f9172cSAndroid Build Coastguard Worker 	}
431*03f9172cSAndroid Build Coastguard Worker 
432*03f9172cSAndroid Build Coastguard Worker 	if (res == -1) {
433*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG,
434*03f9172cSAndroid Build Coastguard Worker 			   "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
435*03f9172cSAndroid Build Coastguard Worker 			   mode->num_channels, channel_no, iface->conf->channel,
436*03f9172cSAndroid Build Coastguard Worker 			   iface->conf->ieee80211n,
437*03f9172cSAndroid Build Coastguard Worker 			   iface->conf->secondary_channel,
438*03f9172cSAndroid Build Coastguard Worker 			   hostapd_get_oper_chwidth(iface->conf));
439*03f9172cSAndroid Build Coastguard Worker 
440*03f9172cSAndroid Build Coastguard Worker 		for (i = 0; i < mode->num_channels; i++) {
441*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "Available channel: %d",
442*03f9172cSAndroid Build Coastguard Worker 				   mode->channels[i].chan);
443*03f9172cSAndroid Build Coastguard Worker 		}
444*03f9172cSAndroid Build Coastguard Worker 	}
445*03f9172cSAndroid Build Coastguard Worker 
446*03f9172cSAndroid Build Coastguard Worker 	return res;
447*03f9172cSAndroid Build Coastguard Worker }
448*03f9172cSAndroid Build Coastguard Worker 
449*03f9172cSAndroid Build Coastguard Worker 
450*03f9172cSAndroid Build Coastguard Worker /* At least one channel have radar flag */
dfs_check_chans_radar(struct hostapd_iface * iface,int start_chan_idx,int n_chans)451*03f9172cSAndroid Build Coastguard Worker static int dfs_check_chans_radar(struct hostapd_iface *iface,
452*03f9172cSAndroid Build Coastguard Worker 				 int start_chan_idx, int n_chans)
453*03f9172cSAndroid Build Coastguard Worker {
454*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
455*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
456*03f9172cSAndroid Build Coastguard Worker 	int i, res = 0;
457*03f9172cSAndroid Build Coastguard Worker 
458*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
459*03f9172cSAndroid Build Coastguard Worker 
460*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < n_chans; i++) {
461*03f9172cSAndroid Build Coastguard Worker 		if (start_chan_idx + i >= mode->num_channels)
462*03f9172cSAndroid Build Coastguard Worker 			break;
463*03f9172cSAndroid Build Coastguard Worker 		channel = &mode->channels[start_chan_idx + i];
464*03f9172cSAndroid Build Coastguard Worker 		if (channel->flag & HOSTAPD_CHAN_RADAR)
465*03f9172cSAndroid Build Coastguard Worker 			res++;
466*03f9172cSAndroid Build Coastguard Worker 	}
467*03f9172cSAndroid Build Coastguard Worker 
468*03f9172cSAndroid Build Coastguard Worker 	return res;
469*03f9172cSAndroid Build Coastguard Worker }
470*03f9172cSAndroid Build Coastguard Worker 
471*03f9172cSAndroid Build Coastguard Worker 
472*03f9172cSAndroid Build Coastguard Worker /* All channels available */
dfs_check_chans_available(struct hostapd_iface * iface,int start_chan_idx,int n_chans)473*03f9172cSAndroid Build Coastguard Worker static int dfs_check_chans_available(struct hostapd_iface *iface,
474*03f9172cSAndroid Build Coastguard Worker 				     int start_chan_idx, int n_chans)
475*03f9172cSAndroid Build Coastguard Worker {
476*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
477*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
478*03f9172cSAndroid Build Coastguard Worker 	int i;
479*03f9172cSAndroid Build Coastguard Worker 
480*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
481*03f9172cSAndroid Build Coastguard Worker 
482*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < n_chans; i++) {
483*03f9172cSAndroid Build Coastguard Worker 		channel = &mode->channels[start_chan_idx + i];
484*03f9172cSAndroid Build Coastguard Worker 
485*03f9172cSAndroid Build Coastguard Worker 		if (channel->flag & HOSTAPD_CHAN_DISABLED)
486*03f9172cSAndroid Build Coastguard Worker 			break;
487*03f9172cSAndroid Build Coastguard Worker 
488*03f9172cSAndroid Build Coastguard Worker 		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
489*03f9172cSAndroid Build Coastguard Worker 			continue;
490*03f9172cSAndroid Build Coastguard Worker 
491*03f9172cSAndroid Build Coastguard Worker 		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
492*03f9172cSAndroid Build Coastguard Worker 		    HOSTAPD_CHAN_DFS_AVAILABLE)
493*03f9172cSAndroid Build Coastguard Worker 			break;
494*03f9172cSAndroid Build Coastguard Worker 	}
495*03f9172cSAndroid Build Coastguard Worker 
496*03f9172cSAndroid Build Coastguard Worker 	return i == n_chans;
497*03f9172cSAndroid Build Coastguard Worker }
498*03f9172cSAndroid Build Coastguard Worker 
499*03f9172cSAndroid Build Coastguard Worker 
500*03f9172cSAndroid Build Coastguard Worker /* At least one channel unavailable */
dfs_check_chans_unavailable(struct hostapd_iface * iface,int start_chan_idx,int n_chans)501*03f9172cSAndroid Build Coastguard Worker static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
502*03f9172cSAndroid Build Coastguard Worker 				       int start_chan_idx,
503*03f9172cSAndroid Build Coastguard Worker 				       int n_chans)
504*03f9172cSAndroid Build Coastguard Worker {
505*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
506*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
507*03f9172cSAndroid Build Coastguard Worker 	int i, res = 0;
508*03f9172cSAndroid Build Coastguard Worker 
509*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
510*03f9172cSAndroid Build Coastguard Worker 
511*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < n_chans; i++) {
512*03f9172cSAndroid Build Coastguard Worker 		channel = &mode->channels[start_chan_idx + i];
513*03f9172cSAndroid Build Coastguard Worker 		if (channel->flag & HOSTAPD_CHAN_DISABLED)
514*03f9172cSAndroid Build Coastguard Worker 			res++;
515*03f9172cSAndroid Build Coastguard Worker 		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
516*03f9172cSAndroid Build Coastguard Worker 		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
517*03f9172cSAndroid Build Coastguard Worker 			res++;
518*03f9172cSAndroid Build Coastguard Worker 	}
519*03f9172cSAndroid Build Coastguard Worker 
520*03f9172cSAndroid Build Coastguard Worker 	return res;
521*03f9172cSAndroid Build Coastguard Worker }
522*03f9172cSAndroid Build Coastguard Worker 
523*03f9172cSAndroid Build Coastguard Worker 
524*03f9172cSAndroid Build Coastguard Worker static struct hostapd_channel_data *
dfs_get_valid_channel(struct hostapd_iface * iface,int * secondary_channel,u8 * oper_centr_freq_seg0_idx,u8 * oper_centr_freq_seg1_idx,enum dfs_channel_type type)525*03f9172cSAndroid Build Coastguard Worker dfs_get_valid_channel(struct hostapd_iface *iface,
526*03f9172cSAndroid Build Coastguard Worker 		      int *secondary_channel,
527*03f9172cSAndroid Build Coastguard Worker 		      u8 *oper_centr_freq_seg0_idx,
528*03f9172cSAndroid Build Coastguard Worker 		      u8 *oper_centr_freq_seg1_idx,
529*03f9172cSAndroid Build Coastguard Worker 		      enum dfs_channel_type type)
530*03f9172cSAndroid Build Coastguard Worker {
531*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
532*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan = NULL;
533*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan2 = NULL;
534*03f9172cSAndroid Build Coastguard Worker 	int num_available_chandefs;
535*03f9172cSAndroid Build Coastguard Worker 	int chan_idx, chan_idx2;
536*03f9172cSAndroid Build Coastguard Worker 	int sec_chan_idx_80p80 = -1;
537*03f9172cSAndroid Build Coastguard Worker 	int i;
538*03f9172cSAndroid Build Coastguard Worker 	u32 _rand;
539*03f9172cSAndroid Build Coastguard Worker 
540*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
541*03f9172cSAndroid Build Coastguard Worker 	*secondary_channel = 0;
542*03f9172cSAndroid Build Coastguard Worker 	*oper_centr_freq_seg0_idx = 0;
543*03f9172cSAndroid Build Coastguard Worker 	*oper_centr_freq_seg1_idx = 0;
544*03f9172cSAndroid Build Coastguard Worker 
545*03f9172cSAndroid Build Coastguard Worker 	if (iface->current_mode == NULL)
546*03f9172cSAndroid Build Coastguard Worker 		return NULL;
547*03f9172cSAndroid Build Coastguard Worker 
548*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
549*03f9172cSAndroid Build Coastguard Worker 	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
550*03f9172cSAndroid Build Coastguard Worker 		return NULL;
551*03f9172cSAndroid Build Coastguard Worker 
552*03f9172cSAndroid Build Coastguard Worker 	/* Get the count first */
553*03f9172cSAndroid Build Coastguard Worker 	num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
554*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
555*03f9172cSAndroid Build Coastguard Worker 		   num_available_chandefs);
556*03f9172cSAndroid Build Coastguard Worker 	if (num_available_chandefs == 0)
557*03f9172cSAndroid Build Coastguard Worker 		return NULL;
558*03f9172cSAndroid Build Coastguard Worker 
559*03f9172cSAndroid Build Coastguard Worker 	if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
560*03f9172cSAndroid Build Coastguard Worker 		return NULL;
561*03f9172cSAndroid Build Coastguard Worker 	chan_idx = _rand % num_available_chandefs;
562*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS: Picked random entry from the list: %d/%d",
563*03f9172cSAndroid Build Coastguard Worker 		   chan_idx, num_available_chandefs);
564*03f9172cSAndroid Build Coastguard Worker 	dfs_find_channel(iface, &chan, chan_idx, type);
565*03f9172cSAndroid Build Coastguard Worker 	if (!chan) {
566*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "DFS: no random channel found");
567*03f9172cSAndroid Build Coastguard Worker 		return NULL;
568*03f9172cSAndroid Build Coastguard Worker 	}
569*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
570*03f9172cSAndroid Build Coastguard Worker 		   chan->freq, chan->chan);
571*03f9172cSAndroid Build Coastguard Worker 
572*03f9172cSAndroid Build Coastguard Worker 	/* dfs_find_channel() calculations assume HT40+ */
573*03f9172cSAndroid Build Coastguard Worker 	if (iface->conf->secondary_channel)
574*03f9172cSAndroid Build Coastguard Worker 		*secondary_channel = 1;
575*03f9172cSAndroid Build Coastguard Worker 	else
576*03f9172cSAndroid Build Coastguard Worker 		*secondary_channel = 0;
577*03f9172cSAndroid Build Coastguard Worker 
578*03f9172cSAndroid Build Coastguard Worker 	/* Get secondary channel for HT80P80 */
579*03f9172cSAndroid Build Coastguard Worker 	if (hostapd_get_oper_chwidth(iface->conf) ==
580*03f9172cSAndroid Build Coastguard Worker 	    CONF_OPER_CHWIDTH_80P80MHZ) {
581*03f9172cSAndroid Build Coastguard Worker 		if (num_available_chandefs <= 1) {
582*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_ERROR,
583*03f9172cSAndroid Build Coastguard Worker 				   "only 1 valid chan, can't support 80+80");
584*03f9172cSAndroid Build Coastguard Worker 			return NULL;
585*03f9172cSAndroid Build Coastguard Worker 		}
586*03f9172cSAndroid Build Coastguard Worker 
587*03f9172cSAndroid Build Coastguard Worker 		/*
588*03f9172cSAndroid Build Coastguard Worker 		 * Loop all channels except channel1 to find a valid channel2
589*03f9172cSAndroid Build Coastguard Worker 		 * that is not adjacent to channel1.
590*03f9172cSAndroid Build Coastguard Worker 		 */
591*03f9172cSAndroid Build Coastguard Worker 		for (i = 0; i < num_available_chandefs - 1; i++) {
592*03f9172cSAndroid Build Coastguard Worker 			/* start from chan_idx + 1, end when chan_idx - 1 */
593*03f9172cSAndroid Build Coastguard Worker 			chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
594*03f9172cSAndroid Build Coastguard Worker 			dfs_find_channel(iface, &chan2, chan_idx2, type);
595*03f9172cSAndroid Build Coastguard Worker 			if (chan2 && abs(chan2->chan - chan->chan) > 12) {
596*03f9172cSAndroid Build Coastguard Worker 				/* two channels are not adjacent */
597*03f9172cSAndroid Build Coastguard Worker 				sec_chan_idx_80p80 = chan2->chan;
598*03f9172cSAndroid Build Coastguard Worker 				wpa_printf(MSG_DEBUG,
599*03f9172cSAndroid Build Coastguard Worker 					   "DFS: got second chan: %d (%d)",
600*03f9172cSAndroid Build Coastguard Worker 					   chan2->freq, chan2->chan);
601*03f9172cSAndroid Build Coastguard Worker 				break;
602*03f9172cSAndroid Build Coastguard Worker 			}
603*03f9172cSAndroid Build Coastguard Worker 		}
604*03f9172cSAndroid Build Coastguard Worker 
605*03f9172cSAndroid Build Coastguard Worker 		/* Check if we got a valid secondary channel which is not
606*03f9172cSAndroid Build Coastguard Worker 		 * adjacent to the first channel.
607*03f9172cSAndroid Build Coastguard Worker 		 */
608*03f9172cSAndroid Build Coastguard Worker 		if (sec_chan_idx_80p80 == -1) {
609*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_INFO,
610*03f9172cSAndroid Build Coastguard Worker 				   "DFS: failed to get chan2 for 80+80");
611*03f9172cSAndroid Build Coastguard Worker 			return NULL;
612*03f9172cSAndroid Build Coastguard Worker 		}
613*03f9172cSAndroid Build Coastguard Worker 	}
614*03f9172cSAndroid Build Coastguard Worker 
615*03f9172cSAndroid Build Coastguard Worker 	dfs_adjust_center_freq(iface, chan,
616*03f9172cSAndroid Build Coastguard Worker 			       *secondary_channel,
617*03f9172cSAndroid Build Coastguard Worker 			       sec_chan_idx_80p80,
618*03f9172cSAndroid Build Coastguard Worker 			       oper_centr_freq_seg0_idx,
619*03f9172cSAndroid Build Coastguard Worker 			       oper_centr_freq_seg1_idx);
620*03f9172cSAndroid Build Coastguard Worker 
621*03f9172cSAndroid Build Coastguard Worker 	return chan;
622*03f9172cSAndroid Build Coastguard Worker }
623*03f9172cSAndroid Build Coastguard Worker 
624*03f9172cSAndroid Build Coastguard Worker 
dfs_set_valid_channel(struct hostapd_iface * iface,int skip_radar)625*03f9172cSAndroid Build Coastguard Worker static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
626*03f9172cSAndroid Build Coastguard Worker {
627*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
628*03f9172cSAndroid Build Coastguard Worker 	u8 cf1 = 0, cf2 = 0;
629*03f9172cSAndroid Build Coastguard Worker 	int sec = 0;
630*03f9172cSAndroid Build Coastguard Worker 
631*03f9172cSAndroid Build Coastguard Worker 	channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
632*03f9172cSAndroid Build Coastguard Worker 					skip_radar ? DFS_AVAILABLE :
633*03f9172cSAndroid Build Coastguard Worker 					DFS_ANY_CHANNEL);
634*03f9172cSAndroid Build Coastguard Worker 	if (!channel) {
635*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_ERROR, "could not get valid channel");
636*03f9172cSAndroid Build Coastguard Worker 		return -1;
637*03f9172cSAndroid Build Coastguard Worker 	}
638*03f9172cSAndroid Build Coastguard Worker 
639*03f9172cSAndroid Build Coastguard Worker 	iface->freq = channel->freq;
640*03f9172cSAndroid Build Coastguard Worker 	iface->conf->channel = channel->chan;
641*03f9172cSAndroid Build Coastguard Worker 	iface->conf->secondary_channel = sec;
642*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
643*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
644*03f9172cSAndroid Build Coastguard Worker 
645*03f9172cSAndroid Build Coastguard Worker 	return 0;
646*03f9172cSAndroid Build Coastguard Worker }
647*03f9172cSAndroid Build Coastguard Worker 
648*03f9172cSAndroid Build Coastguard Worker 
set_dfs_state_freq(struct hostapd_iface * iface,int freq,u32 state)649*03f9172cSAndroid Build Coastguard Worker static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
650*03f9172cSAndroid Build Coastguard Worker {
651*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
652*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan = NULL;
653*03f9172cSAndroid Build Coastguard Worker 	int i;
654*03f9172cSAndroid Build Coastguard Worker 
655*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
656*03f9172cSAndroid Build Coastguard Worker 	if (mode == NULL)
657*03f9172cSAndroid Build Coastguard Worker 		return 0;
658*03f9172cSAndroid Build Coastguard Worker 
659*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
660*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < iface->current_mode->num_channels; i++) {
661*03f9172cSAndroid Build Coastguard Worker 		chan = &iface->current_mode->channels[i];
662*03f9172cSAndroid Build Coastguard Worker 		if (chan->freq == freq) {
663*03f9172cSAndroid Build Coastguard Worker 			if (chan->flag & HOSTAPD_CHAN_RADAR) {
664*03f9172cSAndroid Build Coastguard Worker 				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
665*03f9172cSAndroid Build Coastguard Worker 				chan->flag |= state;
666*03f9172cSAndroid Build Coastguard Worker 				return 1; /* Channel found */
667*03f9172cSAndroid Build Coastguard Worker 			}
668*03f9172cSAndroid Build Coastguard Worker 		}
669*03f9172cSAndroid Build Coastguard Worker 	}
670*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
671*03f9172cSAndroid Build Coastguard Worker 	return 0;
672*03f9172cSAndroid Build Coastguard Worker }
673*03f9172cSAndroid Build Coastguard Worker 
674*03f9172cSAndroid Build Coastguard Worker 
set_dfs_state(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2,u32 state)675*03f9172cSAndroid Build Coastguard Worker static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
676*03f9172cSAndroid Build Coastguard Worker 			 int chan_offset, int chan_width, int cf1,
677*03f9172cSAndroid Build Coastguard Worker 			 int cf2, u32 state)
678*03f9172cSAndroid Build Coastguard Worker {
679*03f9172cSAndroid Build Coastguard Worker 	int n_chans = 1, i;
680*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
681*03f9172cSAndroid Build Coastguard Worker 	int frequency = freq;
682*03f9172cSAndroid Build Coastguard Worker 	int frequency2 = 0;
683*03f9172cSAndroid Build Coastguard Worker 	int ret = 0;
684*03f9172cSAndroid Build Coastguard Worker 
685*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
686*03f9172cSAndroid Build Coastguard Worker 	if (mode == NULL)
687*03f9172cSAndroid Build Coastguard Worker 		return 0;
688*03f9172cSAndroid Build Coastguard Worker 
689*03f9172cSAndroid Build Coastguard Worker 	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
690*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
691*03f9172cSAndroid Build Coastguard Worker 		return 0;
692*03f9172cSAndroid Build Coastguard Worker 	}
693*03f9172cSAndroid Build Coastguard Worker 
694*03f9172cSAndroid Build Coastguard Worker 	/* Seems cf1 and chan_width is enough here */
695*03f9172cSAndroid Build Coastguard Worker 	switch (chan_width) {
696*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_20_NOHT:
697*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_20:
698*03f9172cSAndroid Build Coastguard Worker 		n_chans = 1;
699*03f9172cSAndroid Build Coastguard Worker 		if (frequency == 0)
700*03f9172cSAndroid Build Coastguard Worker 			frequency = cf1;
701*03f9172cSAndroid Build Coastguard Worker 		break;
702*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_40:
703*03f9172cSAndroid Build Coastguard Worker 		n_chans = 2;
704*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 10;
705*03f9172cSAndroid Build Coastguard Worker 		break;
706*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_80:
707*03f9172cSAndroid Build Coastguard Worker 		n_chans = 4;
708*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 30;
709*03f9172cSAndroid Build Coastguard Worker 		break;
710*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_80P80:
711*03f9172cSAndroid Build Coastguard Worker 		n_chans = 4;
712*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 30;
713*03f9172cSAndroid Build Coastguard Worker 		frequency2 = cf2 - 30;
714*03f9172cSAndroid Build Coastguard Worker 		break;
715*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_160:
716*03f9172cSAndroid Build Coastguard Worker 		n_chans = 8;
717*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 70;
718*03f9172cSAndroid Build Coastguard Worker 		break;
719*03f9172cSAndroid Build Coastguard Worker 	default:
720*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
721*03f9172cSAndroid Build Coastguard Worker 			   chan_width);
722*03f9172cSAndroid Build Coastguard Worker 		break;
723*03f9172cSAndroid Build Coastguard Worker 	}
724*03f9172cSAndroid Build Coastguard Worker 
725*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
726*03f9172cSAndroid Build Coastguard Worker 		   n_chans);
727*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < n_chans; i++) {
728*03f9172cSAndroid Build Coastguard Worker 		ret += set_dfs_state_freq(iface, frequency, state);
729*03f9172cSAndroid Build Coastguard Worker 		frequency = frequency + 20;
730*03f9172cSAndroid Build Coastguard Worker 
731*03f9172cSAndroid Build Coastguard Worker 		if (chan_width == CHAN_WIDTH_80P80) {
732*03f9172cSAndroid Build Coastguard Worker 			ret += set_dfs_state_freq(iface, frequency2, state);
733*03f9172cSAndroid Build Coastguard Worker 			frequency2 = frequency2 + 20;
734*03f9172cSAndroid Build Coastguard Worker 		}
735*03f9172cSAndroid Build Coastguard Worker 	}
736*03f9172cSAndroid Build Coastguard Worker 
737*03f9172cSAndroid Build Coastguard Worker 	return ret;
738*03f9172cSAndroid Build Coastguard Worker }
739*03f9172cSAndroid Build Coastguard Worker 
740*03f9172cSAndroid Build Coastguard Worker 
dfs_are_channels_overlapped(struct hostapd_iface * iface,int freq,int chan_width,int cf1,int cf2)741*03f9172cSAndroid Build Coastguard Worker static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
742*03f9172cSAndroid Build Coastguard Worker 				       int chan_width, int cf1, int cf2)
743*03f9172cSAndroid Build Coastguard Worker {
744*03f9172cSAndroid Build Coastguard Worker 	int start_chan_idx, start_chan_idx1;
745*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
746*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan;
747*03f9172cSAndroid Build Coastguard Worker 	int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
748*03f9172cSAndroid Build Coastguard Worker 	u8 radar_chan;
749*03f9172cSAndroid Build Coastguard Worker 	int res = 0;
750*03f9172cSAndroid Build Coastguard Worker 
751*03f9172cSAndroid Build Coastguard Worker 	/* Our configuration */
752*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
753*03f9172cSAndroid Build Coastguard Worker 	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
754*03f9172cSAndroid Build Coastguard Worker 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
755*03f9172cSAndroid Build Coastguard Worker 
756*03f9172cSAndroid Build Coastguard Worker 	/* Check we are on DFS channel(s) */
757*03f9172cSAndroid Build Coastguard Worker 	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
758*03f9172cSAndroid Build Coastguard Worker 		return 0;
759*03f9172cSAndroid Build Coastguard Worker 
760*03f9172cSAndroid Build Coastguard Worker 	/* Reported via radar event */
761*03f9172cSAndroid Build Coastguard Worker 	switch (chan_width) {
762*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_20_NOHT:
763*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_20:
764*03f9172cSAndroid Build Coastguard Worker 		radar_n_chans = 1;
765*03f9172cSAndroid Build Coastguard Worker 		if (frequency == 0)
766*03f9172cSAndroid Build Coastguard Worker 			frequency = cf1;
767*03f9172cSAndroid Build Coastguard Worker 		break;
768*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_40:
769*03f9172cSAndroid Build Coastguard Worker 		radar_n_chans = 2;
770*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 10;
771*03f9172cSAndroid Build Coastguard Worker 		break;
772*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_80:
773*03f9172cSAndroid Build Coastguard Worker 		radar_n_chans = 4;
774*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 30;
775*03f9172cSAndroid Build Coastguard Worker 		break;
776*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_160:
777*03f9172cSAndroid Build Coastguard Worker 		radar_n_chans = 8;
778*03f9172cSAndroid Build Coastguard Worker 		frequency = cf1 - 70;
779*03f9172cSAndroid Build Coastguard Worker 		break;
780*03f9172cSAndroid Build Coastguard Worker 	default:
781*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
782*03f9172cSAndroid Build Coastguard Worker 			   chan_width);
783*03f9172cSAndroid Build Coastguard Worker 		break;
784*03f9172cSAndroid Build Coastguard Worker 	}
785*03f9172cSAndroid Build Coastguard Worker 
786*03f9172cSAndroid Build Coastguard Worker 	ieee80211_freq_to_chan(frequency, &radar_chan);
787*03f9172cSAndroid Build Coastguard Worker 
788*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < n_chans; i++) {
789*03f9172cSAndroid Build Coastguard Worker 		chan = &mode->channels[start_chan_idx + i];
790*03f9172cSAndroid Build Coastguard Worker 		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
791*03f9172cSAndroid Build Coastguard Worker 			continue;
792*03f9172cSAndroid Build Coastguard Worker 		for (j = 0; j < radar_n_chans; j++) {
793*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
794*03f9172cSAndroid Build Coastguard Worker 				   chan->chan, radar_chan + j * 4);
795*03f9172cSAndroid Build Coastguard Worker 			if (chan->chan == radar_chan + j * 4)
796*03f9172cSAndroid Build Coastguard Worker 				res++;
797*03f9172cSAndroid Build Coastguard Worker 		}
798*03f9172cSAndroid Build Coastguard Worker 	}
799*03f9172cSAndroid Build Coastguard Worker 
800*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
801*03f9172cSAndroid Build Coastguard Worker 
802*03f9172cSAndroid Build Coastguard Worker 	return res;
803*03f9172cSAndroid Build Coastguard Worker }
804*03f9172cSAndroid Build Coastguard Worker 
805*03f9172cSAndroid Build Coastguard Worker 
dfs_get_cac_time(struct hostapd_iface * iface,int start_chan_idx,int n_chans)806*03f9172cSAndroid Build Coastguard Worker static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
807*03f9172cSAndroid Build Coastguard Worker 				     int start_chan_idx, int n_chans)
808*03f9172cSAndroid Build Coastguard Worker {
809*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
810*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode;
811*03f9172cSAndroid Build Coastguard Worker 	int i;
812*03f9172cSAndroid Build Coastguard Worker 	unsigned int cac_time_ms = 0;
813*03f9172cSAndroid Build Coastguard Worker 
814*03f9172cSAndroid Build Coastguard Worker 	mode = iface->current_mode;
815*03f9172cSAndroid Build Coastguard Worker 
816*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < n_chans; i++) {
817*03f9172cSAndroid Build Coastguard Worker 		if (start_chan_idx + i >= mode->num_channels)
818*03f9172cSAndroid Build Coastguard Worker 			break;
819*03f9172cSAndroid Build Coastguard Worker 		channel = &mode->channels[start_chan_idx + i];
820*03f9172cSAndroid Build Coastguard Worker 		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
821*03f9172cSAndroid Build Coastguard Worker 			continue;
822*03f9172cSAndroid Build Coastguard Worker 		if (channel->dfs_cac_ms > cac_time_ms)
823*03f9172cSAndroid Build Coastguard Worker 			cac_time_ms = channel->dfs_cac_ms;
824*03f9172cSAndroid Build Coastguard Worker 	}
825*03f9172cSAndroid Build Coastguard Worker 
826*03f9172cSAndroid Build Coastguard Worker 	return cac_time_ms;
827*03f9172cSAndroid Build Coastguard Worker }
828*03f9172cSAndroid Build Coastguard Worker 
829*03f9172cSAndroid Build Coastguard Worker 
830*03f9172cSAndroid Build Coastguard Worker /*
831*03f9172cSAndroid Build Coastguard Worker  * Main DFS handler
832*03f9172cSAndroid Build Coastguard Worker  * 1 - continue channel/ap setup
833*03f9172cSAndroid Build Coastguard Worker  * 0 - channel/ap setup will be continued after CAC
834*03f9172cSAndroid Build Coastguard Worker  * -1 - hit critical error
835*03f9172cSAndroid Build Coastguard Worker  */
hostapd_handle_dfs(struct hostapd_iface * iface)836*03f9172cSAndroid Build Coastguard Worker int hostapd_handle_dfs(struct hostapd_iface *iface)
837*03f9172cSAndroid Build Coastguard Worker {
838*03f9172cSAndroid Build Coastguard Worker 	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
839*03f9172cSAndroid Build Coastguard Worker 	int skip_radar = 0;
840*03f9172cSAndroid Build Coastguard Worker 
841*03f9172cSAndroid Build Coastguard Worker 	if (is_6ghz_freq(iface->freq))
842*03f9172cSAndroid Build Coastguard Worker 		return 1;
843*03f9172cSAndroid Build Coastguard Worker 
844*03f9172cSAndroid Build Coastguard Worker 	if (!iface->current_mode) {
845*03f9172cSAndroid Build Coastguard Worker 		/*
846*03f9172cSAndroid Build Coastguard Worker 		 * This can happen with drivers that do not provide mode
847*03f9172cSAndroid Build Coastguard Worker 		 * information and as such, cannot really use hostapd for DFS.
848*03f9172cSAndroid Build Coastguard Worker 		 */
849*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG,
850*03f9172cSAndroid Build Coastguard Worker 			   "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
851*03f9172cSAndroid Build Coastguard Worker 		return 1;
852*03f9172cSAndroid Build Coastguard Worker 	}
853*03f9172cSAndroid Build Coastguard Worker 
854*03f9172cSAndroid Build Coastguard Worker 	iface->cac_started = 0;
855*03f9172cSAndroid Build Coastguard Worker 
856*03f9172cSAndroid Build Coastguard Worker 	do {
857*03f9172cSAndroid Build Coastguard Worker 		/* Get start (first) channel for current configuration */
858*03f9172cSAndroid Build Coastguard Worker 		start_chan_idx = dfs_get_start_chan_idx(iface,
859*03f9172cSAndroid Build Coastguard Worker 							&start_chan_idx1);
860*03f9172cSAndroid Build Coastguard Worker 		if (start_chan_idx == -1)
861*03f9172cSAndroid Build Coastguard Worker 			return -1;
862*03f9172cSAndroid Build Coastguard Worker 
863*03f9172cSAndroid Build Coastguard Worker 		/* Get number of used channels, depend on width */
864*03f9172cSAndroid Build Coastguard Worker 		n_chans = dfs_get_used_n_chans(iface, &n_chans1);
865*03f9172cSAndroid Build Coastguard Worker 
866*03f9172cSAndroid Build Coastguard Worker 		/* Setup CAC time */
867*03f9172cSAndroid Build Coastguard Worker 		iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
868*03f9172cSAndroid Build Coastguard Worker 						     n_chans);
869*03f9172cSAndroid Build Coastguard Worker 
870*03f9172cSAndroid Build Coastguard Worker 		/* Check if any of configured channels require DFS */
871*03f9172cSAndroid Build Coastguard Worker 		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
872*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG,
873*03f9172cSAndroid Build Coastguard Worker 			   "DFS %d channels required radar detection",
874*03f9172cSAndroid Build Coastguard Worker 			   res);
875*03f9172cSAndroid Build Coastguard Worker 		if (!res)
876*03f9172cSAndroid Build Coastguard Worker 			return 1;
877*03f9172cSAndroid Build Coastguard Worker 
878*03f9172cSAndroid Build Coastguard Worker 		/* Check if all channels are DFS available */
879*03f9172cSAndroid Build Coastguard Worker 		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
880*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG,
881*03f9172cSAndroid Build Coastguard Worker 			   "DFS all channels available, (SKIP CAC): %s",
882*03f9172cSAndroid Build Coastguard Worker 			   res ? "yes" : "no");
883*03f9172cSAndroid Build Coastguard Worker 		if (res)
884*03f9172cSAndroid Build Coastguard Worker 			return 1;
885*03f9172cSAndroid Build Coastguard Worker 
886*03f9172cSAndroid Build Coastguard Worker 		/* Check if any of configured channels is unavailable */
887*03f9172cSAndroid Build Coastguard Worker 		res = dfs_check_chans_unavailable(iface, start_chan_idx,
888*03f9172cSAndroid Build Coastguard Worker 						  n_chans);
889*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
890*03f9172cSAndroid Build Coastguard Worker 			   res, res ? "yes": "no");
891*03f9172cSAndroid Build Coastguard Worker 		if (res) {
892*03f9172cSAndroid Build Coastguard Worker 			if (dfs_set_valid_channel(iface, skip_radar) < 0) {
893*03f9172cSAndroid Build Coastguard Worker 				hostapd_set_state(iface, HAPD_IFACE_DFS);
894*03f9172cSAndroid Build Coastguard Worker 				return 0;
895*03f9172cSAndroid Build Coastguard Worker 			}
896*03f9172cSAndroid Build Coastguard Worker 		}
897*03f9172cSAndroid Build Coastguard Worker 	} while (res);
898*03f9172cSAndroid Build Coastguard Worker 
899*03f9172cSAndroid Build Coastguard Worker 	/* Finally start CAC */
900*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_state(iface, HAPD_IFACE_DFS);
901*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
902*03f9172cSAndroid Build Coastguard Worker 		   dfs_use_radar_background(iface) ? " (background)" : "");
903*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
904*03f9172cSAndroid Build Coastguard Worker 		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
905*03f9172cSAndroid Build Coastguard Worker 		iface->freq,
906*03f9172cSAndroid Build Coastguard Worker 		iface->conf->channel, iface->conf->secondary_channel,
907*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_chwidth(iface->conf),
908*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
909*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
910*03f9172cSAndroid Build Coastguard Worker 		iface->dfs_cac_ms / 1000);
911*03f9172cSAndroid Build Coastguard Worker 
912*03f9172cSAndroid Build Coastguard Worker 	res = hostapd_start_dfs_cac(
913*03f9172cSAndroid Build Coastguard Worker 		iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
914*03f9172cSAndroid Build Coastguard Worker 		iface->conf->ieee80211n, iface->conf->ieee80211ac,
915*03f9172cSAndroid Build Coastguard Worker 		iface->conf->ieee80211ax, iface->conf->ieee80211be,
916*03f9172cSAndroid Build Coastguard Worker 		iface->conf->secondary_channel,
917*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_chwidth(iface->conf),
918*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
919*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
920*03f9172cSAndroid Build Coastguard Worker 		dfs_use_radar_background(iface));
921*03f9172cSAndroid Build Coastguard Worker 
922*03f9172cSAndroid Build Coastguard Worker 	if (res) {
923*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
924*03f9172cSAndroid Build Coastguard Worker 		return -1;
925*03f9172cSAndroid Build Coastguard Worker 	}
926*03f9172cSAndroid Build Coastguard Worker 
927*03f9172cSAndroid Build Coastguard Worker 	if (dfs_use_radar_background(iface)) {
928*03f9172cSAndroid Build Coastguard Worker 		/* Cache background radar parameters. */
929*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.channel = iface->conf->channel;
930*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.secondary_channel =
931*03f9172cSAndroid Build Coastguard Worker 			iface->conf->secondary_channel;
932*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.freq = iface->freq;
933*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.centr_freq_seg0_idx =
934*03f9172cSAndroid Build Coastguard Worker 			hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
935*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.centr_freq_seg1_idx =
936*03f9172cSAndroid Build Coastguard Worker 			hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
937*03f9172cSAndroid Build Coastguard Worker 
938*03f9172cSAndroid Build Coastguard Worker 		/*
939*03f9172cSAndroid Build Coastguard Worker 		 * Let's select a random channel according to the
940*03f9172cSAndroid Build Coastguard Worker 		 * regulations and perform CAC on dedicated radar chain.
941*03f9172cSAndroid Build Coastguard Worker 		 */
942*03f9172cSAndroid Build Coastguard Worker 		res = dfs_set_valid_channel(iface, 1);
943*03f9172cSAndroid Build Coastguard Worker 		if (res < 0)
944*03f9172cSAndroid Build Coastguard Worker 			return res;
945*03f9172cSAndroid Build Coastguard Worker 
946*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.temp_ch = 1;
947*03f9172cSAndroid Build Coastguard Worker 		return 1;
948*03f9172cSAndroid Build Coastguard Worker 	}
949*03f9172cSAndroid Build Coastguard Worker 
950*03f9172cSAndroid Build Coastguard Worker 	return 0;
951*03f9172cSAndroid Build Coastguard Worker }
952*03f9172cSAndroid Build Coastguard Worker 
953*03f9172cSAndroid Build Coastguard Worker 
hostapd_is_dfs_chan_available(struct hostapd_iface * iface)954*03f9172cSAndroid Build Coastguard Worker int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
955*03f9172cSAndroid Build Coastguard Worker {
956*03f9172cSAndroid Build Coastguard Worker 	int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
957*03f9172cSAndroid Build Coastguard Worker 
958*03f9172cSAndroid Build Coastguard Worker 	/* Get the start (first) channel for current configuration */
959*03f9172cSAndroid Build Coastguard Worker 	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
960*03f9172cSAndroid Build Coastguard Worker 	if (start_chan_idx < 0)
961*03f9172cSAndroid Build Coastguard Worker 		return 0;
962*03f9172cSAndroid Build Coastguard Worker 
963*03f9172cSAndroid Build Coastguard Worker 	/* Get the number of used channels, depending on width */
964*03f9172cSAndroid Build Coastguard Worker 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
965*03f9172cSAndroid Build Coastguard Worker 
966*03f9172cSAndroid Build Coastguard Worker 	/* Check if all channels are DFS available */
967*03f9172cSAndroid Build Coastguard Worker 	return dfs_check_chans_available(iface, start_chan_idx, n_chans);
968*03f9172cSAndroid Build Coastguard Worker }
969*03f9172cSAndroid Build Coastguard Worker 
970*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_request_channel_switch(struct hostapd_iface * iface,int channel,int freq,int secondary_channel,u8 current_vht_oper_chwidth,u8 oper_centr_freq_seg0_idx,u8 oper_centr_freq_seg1_idx)971*03f9172cSAndroid Build Coastguard Worker static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
972*03f9172cSAndroid Build Coastguard Worker 					      int channel, int freq,
973*03f9172cSAndroid Build Coastguard Worker 					      int secondary_channel,
974*03f9172cSAndroid Build Coastguard Worker 					      u8 current_vht_oper_chwidth,
975*03f9172cSAndroid Build Coastguard Worker 					      u8 oper_centr_freq_seg0_idx,
976*03f9172cSAndroid Build Coastguard Worker 					      u8 oper_centr_freq_seg1_idx)
977*03f9172cSAndroid Build Coastguard Worker {
978*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *cmode = iface->current_mode;
979*03f9172cSAndroid Build Coastguard Worker 	int ieee80211_mode = IEEE80211_MODE_AP, err;
980*03f9172cSAndroid Build Coastguard Worker 	struct csa_settings csa_settings;
981*03f9172cSAndroid Build Coastguard Worker 	u8 new_vht_oper_chwidth;
982*03f9172cSAndroid Build Coastguard Worker 	unsigned int i;
983*03f9172cSAndroid Build Coastguard Worker 	unsigned int num_err = 0;
984*03f9172cSAndroid Build Coastguard Worker 
985*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
986*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
987*03f9172cSAndroid Build Coastguard Worker 		"freq=%d chan=%d sec_chan=%d", freq, channel,
988*03f9172cSAndroid Build Coastguard Worker 		secondary_channel);
989*03f9172cSAndroid Build Coastguard Worker 
990*03f9172cSAndroid Build Coastguard Worker 	new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
991*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
992*03f9172cSAndroid Build Coastguard Worker 
993*03f9172cSAndroid Build Coastguard Worker 	/* Setup CSA request */
994*03f9172cSAndroid Build Coastguard Worker 	os_memset(&csa_settings, 0, sizeof(csa_settings));
995*03f9172cSAndroid Build Coastguard Worker 	csa_settings.cs_count = 5;
996*03f9172cSAndroid Build Coastguard Worker 	csa_settings.block_tx = 1;
997*03f9172cSAndroid Build Coastguard Worker 	csa_settings.link_id = -1;
998*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_IEEE80211BE
999*03f9172cSAndroid Build Coastguard Worker 	if (iface->bss[0]->conf->mld_ap)
1000*03f9172cSAndroid Build Coastguard Worker 		csa_settings.link_id = iface->bss[0]->mld_link_id;
1001*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_IEEE80211BE */
1002*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_MESH
1003*03f9172cSAndroid Build Coastguard Worker 	if (iface->mconf)
1004*03f9172cSAndroid Build Coastguard Worker 		ieee80211_mode = IEEE80211_MODE_MESH;
1005*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_MESH */
1006*03f9172cSAndroid Build Coastguard Worker 	err = hostapd_set_freq_params(&csa_settings.freq_params,
1007*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->hw_mode,
1008*03f9172cSAndroid Build Coastguard Worker 				      freq, channel,
1009*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->enable_edmg,
1010*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->edmg_channel,
1011*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->ieee80211n,
1012*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->ieee80211ac,
1013*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->ieee80211ax,
1014*03f9172cSAndroid Build Coastguard Worker 				      iface->conf->ieee80211be,
1015*03f9172cSAndroid Build Coastguard Worker 				      secondary_channel,
1016*03f9172cSAndroid Build Coastguard Worker 				      new_vht_oper_chwidth,
1017*03f9172cSAndroid Build Coastguard Worker 				      oper_centr_freq_seg0_idx,
1018*03f9172cSAndroid Build Coastguard Worker 				      oper_centr_freq_seg1_idx,
1019*03f9172cSAndroid Build Coastguard Worker 				      cmode->vht_capab,
1020*03f9172cSAndroid Build Coastguard Worker 				      &cmode->he_capab[ieee80211_mode],
1021*03f9172cSAndroid Build Coastguard Worker 				      &cmode->eht_capab[ieee80211_mode],
1022*03f9172cSAndroid Build Coastguard Worker 				      hostapd_get_punct_bitmap(iface->bss[0]));
1023*03f9172cSAndroid Build Coastguard Worker 
1024*03f9172cSAndroid Build Coastguard Worker 	if (err) {
1025*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_ERROR,
1026*03f9172cSAndroid Build Coastguard Worker 			   "DFS failed to calculate CSA freq params");
1027*03f9172cSAndroid Build Coastguard Worker 		hostapd_disable_iface(iface);
1028*03f9172cSAndroid Build Coastguard Worker 		return err;
1029*03f9172cSAndroid Build Coastguard Worker 	}
1030*03f9172cSAndroid Build Coastguard Worker 
1031*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < iface->num_bss; i++) {
1032*03f9172cSAndroid Build Coastguard Worker 		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
1033*03f9172cSAndroid Build Coastguard Worker 		if (err)
1034*03f9172cSAndroid Build Coastguard Worker 			num_err++;
1035*03f9172cSAndroid Build Coastguard Worker 	}
1036*03f9172cSAndroid Build Coastguard Worker 
1037*03f9172cSAndroid Build Coastguard Worker 	if (num_err == iface->num_bss) {
1038*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_WARNING,
1039*03f9172cSAndroid Build Coastguard Worker 			   "DFS failed to schedule CSA (%d) - trying fallback",
1040*03f9172cSAndroid Build Coastguard Worker 			   err);
1041*03f9172cSAndroid Build Coastguard Worker 		iface->freq = freq;
1042*03f9172cSAndroid Build Coastguard Worker 		iface->conf->channel = channel;
1043*03f9172cSAndroid Build Coastguard Worker 		iface->conf->secondary_channel = secondary_channel;
1044*03f9172cSAndroid Build Coastguard Worker 		hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
1045*03f9172cSAndroid Build Coastguard Worker 		hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1046*03f9172cSAndroid Build Coastguard Worker 						     oper_centr_freq_seg0_idx);
1047*03f9172cSAndroid Build Coastguard Worker 		hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1048*03f9172cSAndroid Build Coastguard Worker 						     oper_centr_freq_seg1_idx);
1049*03f9172cSAndroid Build Coastguard Worker 
1050*03f9172cSAndroid Build Coastguard Worker 		hostapd_disable_iface(iface);
1051*03f9172cSAndroid Build Coastguard Worker 		hostapd_enable_iface(iface);
1052*03f9172cSAndroid Build Coastguard Worker 
1053*03f9172cSAndroid Build Coastguard Worker 		return 0;
1054*03f9172cSAndroid Build Coastguard Worker 	}
1055*03f9172cSAndroid Build Coastguard Worker 
1056*03f9172cSAndroid Build Coastguard Worker 	/* Channel configuration will be updated once CSA completes and
1057*03f9172cSAndroid Build Coastguard Worker 	 * ch_switch_notify event is received */
1058*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
1059*03f9172cSAndroid Build Coastguard Worker 
1060*03f9172cSAndroid Build Coastguard Worker 	return 0;
1061*03f9172cSAndroid Build Coastguard Worker }
1062*03f9172cSAndroid Build Coastguard Worker 
1063*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_update_background_chain(struct hostapd_iface * iface)1064*03f9172cSAndroid Build Coastguard Worker static void hostapd_dfs_update_background_chain(struct hostapd_iface *iface)
1065*03f9172cSAndroid Build Coastguard Worker {
1066*03f9172cSAndroid Build Coastguard Worker 	int sec = 0;
1067*03f9172cSAndroid Build Coastguard Worker 	enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
1068*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
1069*03f9172cSAndroid Build Coastguard Worker 	u8 oper_centr_freq_seg0_idx = 0;
1070*03f9172cSAndroid Build Coastguard Worker 	u8 oper_centr_freq_seg1_idx = 0;
1071*03f9172cSAndroid Build Coastguard Worker 
1072*03f9172cSAndroid Build Coastguard Worker 	/*
1073*03f9172cSAndroid Build Coastguard Worker 	 * Allow selection of DFS channel in ETSI to comply with
1074*03f9172cSAndroid Build Coastguard Worker 	 * uniform spreading.
1075*03f9172cSAndroid Build Coastguard Worker 	 */
1076*03f9172cSAndroid Build Coastguard Worker 	if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
1077*03f9172cSAndroid Build Coastguard Worker 		channel_type = DFS_ANY_CHANNEL;
1078*03f9172cSAndroid Build Coastguard Worker 
1079*03f9172cSAndroid Build Coastguard Worker 	channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
1080*03f9172cSAndroid Build Coastguard Worker 					&oper_centr_freq_seg1_idx,
1081*03f9172cSAndroid Build Coastguard Worker 					channel_type);
1082*03f9172cSAndroid Build Coastguard Worker 	if (!channel ||
1083*03f9172cSAndroid Build Coastguard Worker 	    channel->chan == iface->conf->channel ||
1084*03f9172cSAndroid Build Coastguard Worker 	    channel->chan == iface->radar_background.channel)
1085*03f9172cSAndroid Build Coastguard Worker 		channel = dfs_downgrade_bandwidth(iface, &sec,
1086*03f9172cSAndroid Build Coastguard Worker 						  &oper_centr_freq_seg0_idx,
1087*03f9172cSAndroid Build Coastguard Worker 						  &oper_centr_freq_seg1_idx,
1088*03f9172cSAndroid Build Coastguard Worker 						  &channel_type);
1089*03f9172cSAndroid Build Coastguard Worker 	if (!channel ||
1090*03f9172cSAndroid Build Coastguard Worker 	    hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
1091*03f9172cSAndroid Build Coastguard Worker 				  channel->freq, channel->chan,
1092*03f9172cSAndroid Build Coastguard Worker 				  iface->conf->ieee80211n,
1093*03f9172cSAndroid Build Coastguard Worker 				  iface->conf->ieee80211ac,
1094*03f9172cSAndroid Build Coastguard Worker 				  iface->conf->ieee80211ax,
1095*03f9172cSAndroid Build Coastguard Worker 				  iface->conf->ieee80211be,
1096*03f9172cSAndroid Build Coastguard Worker 				  sec, hostapd_get_oper_chwidth(iface->conf),
1097*03f9172cSAndroid Build Coastguard Worker 				  oper_centr_freq_seg0_idx,
1098*03f9172cSAndroid Build Coastguard Worker 				  oper_centr_freq_seg1_idx, true)) {
1099*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
1100*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.channel = -1;
1101*03f9172cSAndroid Build Coastguard Worker 		return;
1102*03f9172cSAndroid Build Coastguard Worker 	}
1103*03f9172cSAndroid Build Coastguard Worker 
1104*03f9172cSAndroid Build Coastguard Worker 	iface->radar_background.channel = channel->chan;
1105*03f9172cSAndroid Build Coastguard Worker 	iface->radar_background.freq = channel->freq;
1106*03f9172cSAndroid Build Coastguard Worker 	iface->radar_background.secondary_channel = sec;
1107*03f9172cSAndroid Build Coastguard Worker 	iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
1108*03f9172cSAndroid Build Coastguard Worker 	iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
1109*03f9172cSAndroid Build Coastguard Worker 
1110*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG,
1111*03f9172cSAndroid Build Coastguard Worker 		   "%s: setting background chain to chan %d (%d MHz)",
1112*03f9172cSAndroid Build Coastguard Worker 		   __func__, channel->chan, channel->freq);
1113*03f9172cSAndroid Build Coastguard Worker }
1114*03f9172cSAndroid Build Coastguard Worker 
1115*03f9172cSAndroid Build Coastguard Worker 
1116*03f9172cSAndroid Build Coastguard Worker static bool
hostapd_dfs_is_background_event(struct hostapd_iface * iface,int freq)1117*03f9172cSAndroid Build Coastguard Worker hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
1118*03f9172cSAndroid Build Coastguard Worker {
1119*03f9172cSAndroid Build Coastguard Worker 	return dfs_use_radar_background(iface) &&
1120*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.channel != -1 &&
1121*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.freq == freq;
1122*03f9172cSAndroid Build Coastguard Worker }
1123*03f9172cSAndroid Build Coastguard Worker 
1124*03f9172cSAndroid Build Coastguard Worker 
1125*03f9172cSAndroid Build Coastguard Worker static int
hostapd_dfs_start_channel_switch_background(struct hostapd_iface * iface)1126*03f9172cSAndroid Build Coastguard Worker hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
1127*03f9172cSAndroid Build Coastguard Worker {
1128*03f9172cSAndroid Build Coastguard Worker 	u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1129*03f9172cSAndroid Build Coastguard Worker 
1130*03f9172cSAndroid Build Coastguard Worker 	iface->conf->channel = iface->radar_background.channel;
1131*03f9172cSAndroid Build Coastguard Worker 	iface->freq = iface->radar_background.freq;
1132*03f9172cSAndroid Build Coastguard Worker 	iface->conf->secondary_channel =
1133*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.secondary_channel;
1134*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_centr_freq_seg0_idx(
1135*03f9172cSAndroid Build Coastguard Worker 		iface->conf, iface->radar_background.centr_freq_seg0_idx);
1136*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_centr_freq_seg1_idx(
1137*03f9172cSAndroid Build Coastguard Worker 		iface->conf, iface->radar_background.centr_freq_seg1_idx);
1138*03f9172cSAndroid Build Coastguard Worker 
1139*03f9172cSAndroid Build Coastguard Worker 	hostapd_dfs_update_background_chain(iface);
1140*03f9172cSAndroid Build Coastguard Worker 
1141*03f9172cSAndroid Build Coastguard Worker 	return hostapd_dfs_request_channel_switch(
1142*03f9172cSAndroid Build Coastguard Worker 		iface, iface->conf->channel, iface->freq,
1143*03f9172cSAndroid Build Coastguard Worker 		iface->conf->secondary_channel, current_vht_oper_chwidth,
1144*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
1145*03f9172cSAndroid Build Coastguard Worker 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
1146*03f9172cSAndroid Build Coastguard Worker }
1147*03f9172cSAndroid Build Coastguard Worker 
1148*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_complete_cac(struct hostapd_iface * iface,int success,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1149*03f9172cSAndroid Build Coastguard Worker int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
1150*03f9172cSAndroid Build Coastguard Worker 			     int ht_enabled, int chan_offset, int chan_width,
1151*03f9172cSAndroid Build Coastguard Worker 			     int cf1, int cf2)
1152*03f9172cSAndroid Build Coastguard Worker {
1153*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
1154*03f9172cSAndroid Build Coastguard Worker 		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d",
1155*03f9172cSAndroid Build Coastguard Worker 		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
1156*03f9172cSAndroid Build Coastguard Worker 		iface->radar_detected);
1157*03f9172cSAndroid Build Coastguard Worker 
1158*03f9172cSAndroid Build Coastguard Worker 	if (success) {
1159*03f9172cSAndroid Build Coastguard Worker 		/* Complete iface/ap configuration */
1160*03f9172cSAndroid Build Coastguard Worker 		if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
1161*03f9172cSAndroid Build Coastguard Worker 			/* Complete AP configuration for the first bring up. If
1162*03f9172cSAndroid Build Coastguard Worker 			 * a radar was detected in this channel, interface setup
1163*03f9172cSAndroid Build Coastguard Worker 			 * will be handled in
1164*03f9172cSAndroid Build Coastguard Worker 			 * 1. hostapd_event_ch_switch() if switching to a
1165*03f9172cSAndroid Build Coastguard Worker 			 *    non-DFS channel
1166*03f9172cSAndroid Build Coastguard Worker 			 * 2. on next CAC complete event if switching to another
1167*03f9172cSAndroid Build Coastguard Worker 			 *    DFS channel.
1168*03f9172cSAndroid Build Coastguard Worker 			 */
1169*03f9172cSAndroid Build Coastguard Worker 			if (iface->state != HAPD_IFACE_ENABLED &&
1170*03f9172cSAndroid Build Coastguard Worker 			    !iface->radar_detected)
1171*03f9172cSAndroid Build Coastguard Worker 				hostapd_setup_interface_complete(iface, 0);
1172*03f9172cSAndroid Build Coastguard Worker 			else
1173*03f9172cSAndroid Build Coastguard Worker 				iface->cac_started = 0;
1174*03f9172cSAndroid Build Coastguard Worker 		} else {
1175*03f9172cSAndroid Build Coastguard Worker 			set_dfs_state(iface, freq, ht_enabled, chan_offset,
1176*03f9172cSAndroid Build Coastguard Worker 				      chan_width, cf1, cf2,
1177*03f9172cSAndroid Build Coastguard Worker 				      HOSTAPD_CHAN_DFS_AVAILABLE);
1178*03f9172cSAndroid Build Coastguard Worker 
1179*03f9172cSAndroid Build Coastguard Worker 			/*
1180*03f9172cSAndroid Build Coastguard Worker 			 * Radar event from background chain for the selected
1181*03f9172cSAndroid Build Coastguard Worker 			 * channel. Perform CSA, move the main chain to the
1182*03f9172cSAndroid Build Coastguard Worker 			 * selected channel and configure the background chain
1183*03f9172cSAndroid Build Coastguard Worker 			 * to a new DFS channel.
1184*03f9172cSAndroid Build Coastguard Worker 			 */
1185*03f9172cSAndroid Build Coastguard Worker 			if (hostapd_dfs_is_background_event(iface, freq)) {
1186*03f9172cSAndroid Build Coastguard Worker 				iface->radar_background.cac_started = 0;
1187*03f9172cSAndroid Build Coastguard Worker 				if (!iface->radar_background.temp_ch)
1188*03f9172cSAndroid Build Coastguard Worker 					return 0;
1189*03f9172cSAndroid Build Coastguard Worker 
1190*03f9172cSAndroid Build Coastguard Worker 				iface->radar_background.temp_ch = 0;
1191*03f9172cSAndroid Build Coastguard Worker 				return hostapd_dfs_start_channel_switch_background(iface);
1192*03f9172cSAndroid Build Coastguard Worker 			}
1193*03f9172cSAndroid Build Coastguard Worker 
1194*03f9172cSAndroid Build Coastguard Worker 			/*
1195*03f9172cSAndroid Build Coastguard Worker 			 * Just mark the channel available when CAC completion
1196*03f9172cSAndroid Build Coastguard Worker 			 * event is received in enabled state. CAC result could
1197*03f9172cSAndroid Build Coastguard Worker 			 * have been propagated from another radio having the
1198*03f9172cSAndroid Build Coastguard Worker 			 * same regulatory configuration. When CAC completion is
1199*03f9172cSAndroid Build Coastguard Worker 			 * received during non-HAPD_IFACE_ENABLED state, make
1200*03f9172cSAndroid Build Coastguard Worker 			 * sure the configured channel is available because this
1201*03f9172cSAndroid Build Coastguard Worker 			 * CAC completion event could have been propagated from
1202*03f9172cSAndroid Build Coastguard Worker 			 * another radio.
1203*03f9172cSAndroid Build Coastguard Worker 			 */
1204*03f9172cSAndroid Build Coastguard Worker 			if (iface->state != HAPD_IFACE_ENABLED &&
1205*03f9172cSAndroid Build Coastguard Worker 			    hostapd_is_dfs_chan_available(iface)) {
1206*03f9172cSAndroid Build Coastguard Worker 				hostapd_setup_interface_complete(iface, 0);
1207*03f9172cSAndroid Build Coastguard Worker 				iface->cac_started = 0;
1208*03f9172cSAndroid Build Coastguard Worker 			}
1209*03f9172cSAndroid Build Coastguard Worker 		}
1210*03f9172cSAndroid Build Coastguard Worker 	} else if (hostapd_dfs_is_background_event(iface, freq)) {
1211*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.cac_started = 0;
1212*03f9172cSAndroid Build Coastguard Worker 		hostapd_dfs_update_background_chain(iface);
1213*03f9172cSAndroid Build Coastguard Worker 	}
1214*03f9172cSAndroid Build Coastguard Worker 
1215*03f9172cSAndroid Build Coastguard Worker 	iface->radar_detected = false;
1216*03f9172cSAndroid Build Coastguard Worker 	return 0;
1217*03f9172cSAndroid Build Coastguard Worker }
1218*03f9172cSAndroid Build Coastguard Worker 
1219*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_pre_cac_expired(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1220*03f9172cSAndroid Build Coastguard Worker int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
1221*03f9172cSAndroid Build Coastguard Worker 				int ht_enabled, int chan_offset, int chan_width,
1222*03f9172cSAndroid Build Coastguard Worker 				int cf1, int cf2)
1223*03f9172cSAndroid Build Coastguard Worker {
1224*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
1225*03f9172cSAndroid Build Coastguard Worker 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1226*03f9172cSAndroid Build Coastguard Worker 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1227*03f9172cSAndroid Build Coastguard Worker 
1228*03f9172cSAndroid Build Coastguard Worker 	/* Proceed only if DFS is not offloaded to the driver */
1229*03f9172cSAndroid Build Coastguard Worker 	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1230*03f9172cSAndroid Build Coastguard Worker 		return 0;
1231*03f9172cSAndroid Build Coastguard Worker 
1232*03f9172cSAndroid Build Coastguard Worker 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1233*03f9172cSAndroid Build Coastguard Worker 		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
1234*03f9172cSAndroid Build Coastguard Worker 
1235*03f9172cSAndroid Build Coastguard Worker 	return 0;
1236*03f9172cSAndroid Build Coastguard Worker }
1237*03f9172cSAndroid Build Coastguard Worker 
1238*03f9172cSAndroid Build Coastguard Worker 
1239*03f9172cSAndroid Build Coastguard Worker static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface * iface,int * secondary_channel,u8 * oper_centr_freq_seg0_idx,u8 * oper_centr_freq_seg1_idx,enum dfs_channel_type * channel_type)1240*03f9172cSAndroid Build Coastguard Worker dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
1241*03f9172cSAndroid Build Coastguard Worker 			u8 *oper_centr_freq_seg0_idx,
1242*03f9172cSAndroid Build Coastguard Worker 			u8 *oper_centr_freq_seg1_idx,
1243*03f9172cSAndroid Build Coastguard Worker 			enum dfs_channel_type *channel_type)
1244*03f9172cSAndroid Build Coastguard Worker {
1245*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
1246*03f9172cSAndroid Build Coastguard Worker 
1247*03f9172cSAndroid Build Coastguard Worker 	for (;;) {
1248*03f9172cSAndroid Build Coastguard Worker 		channel = dfs_get_valid_channel(iface, secondary_channel,
1249*03f9172cSAndroid Build Coastguard Worker 						oper_centr_freq_seg0_idx,
1250*03f9172cSAndroid Build Coastguard Worker 						oper_centr_freq_seg1_idx,
1251*03f9172cSAndroid Build Coastguard Worker 						*channel_type);
1252*03f9172cSAndroid Build Coastguard Worker 		if (channel) {
1253*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
1254*03f9172cSAndroid Build Coastguard Worker 				   channel->chan);
1255*03f9172cSAndroid Build Coastguard Worker 			return channel;
1256*03f9172cSAndroid Build Coastguard Worker 		}
1257*03f9172cSAndroid Build Coastguard Worker 
1258*03f9172cSAndroid Build Coastguard Worker 		if (*channel_type != DFS_ANY_CHANNEL) {
1259*03f9172cSAndroid Build Coastguard Worker 			*channel_type = DFS_ANY_CHANNEL;
1260*03f9172cSAndroid Build Coastguard Worker 		} else {
1261*03f9172cSAndroid Build Coastguard Worker 			int oper_chwidth;
1262*03f9172cSAndroid Build Coastguard Worker 
1263*03f9172cSAndroid Build Coastguard Worker 			oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1264*03f9172cSAndroid Build Coastguard Worker 			if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
1265*03f9172cSAndroid Build Coastguard Worker 				break;
1266*03f9172cSAndroid Build Coastguard Worker 			*channel_type = DFS_AVAILABLE;
1267*03f9172cSAndroid Build Coastguard Worker 			hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
1268*03f9172cSAndroid Build Coastguard Worker 		}
1269*03f9172cSAndroid Build Coastguard Worker 	}
1270*03f9172cSAndroid Build Coastguard Worker 
1271*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_INFO,
1272*03f9172cSAndroid Build Coastguard Worker 		   "%s: no DFS channels left, waiting for NOP to finish",
1273*03f9172cSAndroid Build Coastguard Worker 		   __func__);
1274*03f9172cSAndroid Build Coastguard Worker 	return NULL;
1275*03f9172cSAndroid Build Coastguard Worker }
1276*03f9172cSAndroid Build Coastguard Worker 
1277*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_start_channel_switch_cac(struct hostapd_iface * iface)1278*03f9172cSAndroid Build Coastguard Worker static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
1279*03f9172cSAndroid Build Coastguard Worker {
1280*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
1281*03f9172cSAndroid Build Coastguard Worker 	int secondary_channel;
1282*03f9172cSAndroid Build Coastguard Worker 	u8 oper_centr_freq_seg0_idx = 0;
1283*03f9172cSAndroid Build Coastguard Worker 	u8 oper_centr_freq_seg1_idx = 0;
1284*03f9172cSAndroid Build Coastguard Worker 	enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
1285*03f9172cSAndroid Build Coastguard Worker 	int err = 1;
1286*03f9172cSAndroid Build Coastguard Worker 
1287*03f9172cSAndroid Build Coastguard Worker 	/* Radar detected during active CAC */
1288*03f9172cSAndroid Build Coastguard Worker 	iface->cac_started = 0;
1289*03f9172cSAndroid Build Coastguard Worker 	channel = dfs_get_valid_channel(iface, &secondary_channel,
1290*03f9172cSAndroid Build Coastguard Worker 					&oper_centr_freq_seg0_idx,
1291*03f9172cSAndroid Build Coastguard Worker 					&oper_centr_freq_seg1_idx,
1292*03f9172cSAndroid Build Coastguard Worker 					channel_type);
1293*03f9172cSAndroid Build Coastguard Worker 
1294*03f9172cSAndroid Build Coastguard Worker 	if (!channel) {
1295*03f9172cSAndroid Build Coastguard Worker 		channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
1296*03f9172cSAndroid Build Coastguard Worker 						  &oper_centr_freq_seg0_idx,
1297*03f9172cSAndroid Build Coastguard Worker 						  &oper_centr_freq_seg1_idx,
1298*03f9172cSAndroid Build Coastguard Worker 						  &channel_type);
1299*03f9172cSAndroid Build Coastguard Worker 		if (!channel) {
1300*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_ERROR, "No valid channel available");
1301*03f9172cSAndroid Build Coastguard Worker 			return err;
1302*03f9172cSAndroid Build Coastguard Worker 		}
1303*03f9172cSAndroid Build Coastguard Worker 	}
1304*03f9172cSAndroid Build Coastguard Worker 
1305*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
1306*03f9172cSAndroid Build Coastguard Worker 		   channel->chan);
1307*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
1308*03f9172cSAndroid Build Coastguard Worker 		"freq=%d chan=%d sec_chan=%d", channel->freq,
1309*03f9172cSAndroid Build Coastguard Worker 		channel->chan, secondary_channel);
1310*03f9172cSAndroid Build Coastguard Worker 
1311*03f9172cSAndroid Build Coastguard Worker 	iface->freq = channel->freq;
1312*03f9172cSAndroid Build Coastguard Worker 	iface->conf->channel = channel->chan;
1313*03f9172cSAndroid Build Coastguard Worker 	iface->conf->secondary_channel = secondary_channel;
1314*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1315*03f9172cSAndroid Build Coastguard Worker 					     oper_centr_freq_seg0_idx);
1316*03f9172cSAndroid Build Coastguard Worker 	hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1317*03f9172cSAndroid Build Coastguard Worker 					     oper_centr_freq_seg1_idx);
1318*03f9172cSAndroid Build Coastguard Worker 	err = 0;
1319*03f9172cSAndroid Build Coastguard Worker 
1320*03f9172cSAndroid Build Coastguard Worker 	hostapd_setup_interface_complete(iface, err);
1321*03f9172cSAndroid Build Coastguard Worker 	return err;
1322*03f9172cSAndroid Build Coastguard Worker }
1323*03f9172cSAndroid Build Coastguard Worker 
1324*03f9172cSAndroid Build Coastguard Worker 
1325*03f9172cSAndroid Build Coastguard Worker static int
hostapd_dfs_background_start_channel_switch(struct hostapd_iface * iface,int freq)1326*03f9172cSAndroid Build Coastguard Worker hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
1327*03f9172cSAndroid Build Coastguard Worker 					    int freq)
1328*03f9172cSAndroid Build Coastguard Worker {
1329*03f9172cSAndroid Build Coastguard Worker 	if (!dfs_use_radar_background(iface))
1330*03f9172cSAndroid Build Coastguard Worker 		return -1; /* Background radar chain not supported. */
1331*03f9172cSAndroid Build Coastguard Worker 
1332*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG,
1333*03f9172cSAndroid Build Coastguard Worker 		   "%s called (background CAC active: %s, CSA active: %s)",
1334*03f9172cSAndroid Build Coastguard Worker 		   __func__, iface->radar_background.cac_started ? "yes" : "no",
1335*03f9172cSAndroid Build Coastguard Worker 		   hostapd_csa_in_progress(iface) ? "yes" : "no");
1336*03f9172cSAndroid Build Coastguard Worker 
1337*03f9172cSAndroid Build Coastguard Worker 	/* Check if CSA in progress */
1338*03f9172cSAndroid Build Coastguard Worker 	if (hostapd_csa_in_progress(iface))
1339*03f9172cSAndroid Build Coastguard Worker 		return 0;
1340*03f9172cSAndroid Build Coastguard Worker 
1341*03f9172cSAndroid Build Coastguard Worker 	if (hostapd_dfs_is_background_event(iface, freq)) {
1342*03f9172cSAndroid Build Coastguard Worker 		/*
1343*03f9172cSAndroid Build Coastguard Worker 		 * Radar pattern is reported on the background chain.
1344*03f9172cSAndroid Build Coastguard Worker 		 * Just select a new random channel according to the
1345*03f9172cSAndroid Build Coastguard Worker 		 * regulations for monitoring.
1346*03f9172cSAndroid Build Coastguard Worker 		 */
1347*03f9172cSAndroid Build Coastguard Worker 		hostapd_dfs_update_background_chain(iface);
1348*03f9172cSAndroid Build Coastguard Worker 		return 0;
1349*03f9172cSAndroid Build Coastguard Worker 	}
1350*03f9172cSAndroid Build Coastguard Worker 
1351*03f9172cSAndroid Build Coastguard Worker 	/*
1352*03f9172cSAndroid Build Coastguard Worker 	 * If background radar detection is supported and the radar channel
1353*03f9172cSAndroid Build Coastguard Worker 	 * monitored by the background chain is available switch to it without
1354*03f9172cSAndroid Build Coastguard Worker 	 * waiting for the CAC.
1355*03f9172cSAndroid Build Coastguard Worker 	 */
1356*03f9172cSAndroid Build Coastguard Worker 	if (iface->radar_background.channel == -1)
1357*03f9172cSAndroid Build Coastguard Worker 		return -1; /* Background radar chain not available. */
1358*03f9172cSAndroid Build Coastguard Worker 
1359*03f9172cSAndroid Build Coastguard Worker 	if (iface->radar_background.cac_started) {
1360*03f9172cSAndroid Build Coastguard Worker 		/*
1361*03f9172cSAndroid Build Coastguard Worker 		 * Background channel not available yet. Perform CAC on the
1362*03f9172cSAndroid Build Coastguard Worker 		 * main chain.
1363*03f9172cSAndroid Build Coastguard Worker 		 */
1364*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.temp_ch = 1;
1365*03f9172cSAndroid Build Coastguard Worker 		return -1;
1366*03f9172cSAndroid Build Coastguard Worker 	}
1367*03f9172cSAndroid Build Coastguard Worker 
1368*03f9172cSAndroid Build Coastguard Worker 	return hostapd_dfs_start_channel_switch_background(iface);
1369*03f9172cSAndroid Build Coastguard Worker }
1370*03f9172cSAndroid Build Coastguard Worker 
1371*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_start_channel_switch(struct hostapd_iface * iface)1372*03f9172cSAndroid Build Coastguard Worker static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
1373*03f9172cSAndroid Build Coastguard Worker {
1374*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *channel;
1375*03f9172cSAndroid Build Coastguard Worker 	int secondary_channel;
1376*03f9172cSAndroid Build Coastguard Worker 	u8 oper_centr_freq_seg0_idx;
1377*03f9172cSAndroid Build Coastguard Worker 	u8 oper_centr_freq_seg1_idx;
1378*03f9172cSAndroid Build Coastguard Worker 	enum dfs_channel_type channel_type = DFS_AVAILABLE;
1379*03f9172cSAndroid Build Coastguard Worker 	u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1380*03f9172cSAndroid Build Coastguard Worker 
1381*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
1382*03f9172cSAndroid Build Coastguard Worker 		   __func__, iface->cac_started ? "yes" : "no",
1383*03f9172cSAndroid Build Coastguard Worker 		   hostapd_csa_in_progress(iface) ? "yes" : "no");
1384*03f9172cSAndroid Build Coastguard Worker 
1385*03f9172cSAndroid Build Coastguard Worker 	/* Check if CSA in progress */
1386*03f9172cSAndroid Build Coastguard Worker 	if (hostapd_csa_in_progress(iface))
1387*03f9172cSAndroid Build Coastguard Worker 		return 0;
1388*03f9172cSAndroid Build Coastguard Worker 
1389*03f9172cSAndroid Build Coastguard Worker 	/* Check if active CAC */
1390*03f9172cSAndroid Build Coastguard Worker 	if (iface->cac_started)
1391*03f9172cSAndroid Build Coastguard Worker 		return hostapd_dfs_start_channel_switch_cac(iface);
1392*03f9172cSAndroid Build Coastguard Worker 
1393*03f9172cSAndroid Build Coastguard Worker 	/*
1394*03f9172cSAndroid Build Coastguard Worker 	 * Allow selection of DFS channel in ETSI to comply with
1395*03f9172cSAndroid Build Coastguard Worker 	 * uniform spreading.
1396*03f9172cSAndroid Build Coastguard Worker 	 */
1397*03f9172cSAndroid Build Coastguard Worker 	if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
1398*03f9172cSAndroid Build Coastguard Worker 		channel_type = DFS_ANY_CHANNEL;
1399*03f9172cSAndroid Build Coastguard Worker 
1400*03f9172cSAndroid Build Coastguard Worker 	/* Perform channel switch/CSA */
1401*03f9172cSAndroid Build Coastguard Worker 	channel = dfs_get_valid_channel(iface, &secondary_channel,
1402*03f9172cSAndroid Build Coastguard Worker 					&oper_centr_freq_seg0_idx,
1403*03f9172cSAndroid Build Coastguard Worker 					&oper_centr_freq_seg1_idx,
1404*03f9172cSAndroid Build Coastguard Worker 					channel_type);
1405*03f9172cSAndroid Build Coastguard Worker 
1406*03f9172cSAndroid Build Coastguard Worker 	if (!channel) {
1407*03f9172cSAndroid Build Coastguard Worker 		/*
1408*03f9172cSAndroid Build Coastguard Worker 		 * If there is no channel to switch immediately to, check if
1409*03f9172cSAndroid Build Coastguard Worker 		 * there is another channel where we can switch even if it
1410*03f9172cSAndroid Build Coastguard Worker 		 * requires to perform a CAC first.
1411*03f9172cSAndroid Build Coastguard Worker 		 */
1412*03f9172cSAndroid Build Coastguard Worker 		channel_type = DFS_ANY_CHANNEL;
1413*03f9172cSAndroid Build Coastguard Worker 		channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
1414*03f9172cSAndroid Build Coastguard Worker 						  &oper_centr_freq_seg0_idx,
1415*03f9172cSAndroid Build Coastguard Worker 						  &oper_centr_freq_seg1_idx,
1416*03f9172cSAndroid Build Coastguard Worker 						  &channel_type);
1417*03f9172cSAndroid Build Coastguard Worker 		if (!channel) {
1418*03f9172cSAndroid Build Coastguard Worker 			/*
1419*03f9172cSAndroid Build Coastguard Worker 			 * Toggle interface state to enter DFS state
1420*03f9172cSAndroid Build Coastguard Worker 			 * until NOP is finished.
1421*03f9172cSAndroid Build Coastguard Worker 			 */
1422*03f9172cSAndroid Build Coastguard Worker 			hostapd_disable_iface(iface);
1423*03f9172cSAndroid Build Coastguard Worker 			hostapd_enable_iface(iface);
1424*03f9172cSAndroid Build Coastguard Worker 			return 0;
1425*03f9172cSAndroid Build Coastguard Worker 		}
1426*03f9172cSAndroid Build Coastguard Worker 
1427*03f9172cSAndroid Build Coastguard Worker 		if (channel_type == DFS_ANY_CHANNEL) {
1428*03f9172cSAndroid Build Coastguard Worker 			iface->freq = channel->freq;
1429*03f9172cSAndroid Build Coastguard Worker 			iface->conf->channel = channel->chan;
1430*03f9172cSAndroid Build Coastguard Worker 			iface->conf->secondary_channel = secondary_channel;
1431*03f9172cSAndroid Build Coastguard Worker 			hostapd_set_oper_centr_freq_seg0_idx(
1432*03f9172cSAndroid Build Coastguard Worker 				iface->conf, oper_centr_freq_seg0_idx);
1433*03f9172cSAndroid Build Coastguard Worker 			hostapd_set_oper_centr_freq_seg1_idx(
1434*03f9172cSAndroid Build Coastguard Worker 				iface->conf, oper_centr_freq_seg1_idx);
1435*03f9172cSAndroid Build Coastguard Worker 
1436*03f9172cSAndroid Build Coastguard Worker 			hostapd_disable_iface(iface);
1437*03f9172cSAndroid Build Coastguard Worker 			hostapd_enable_iface(iface);
1438*03f9172cSAndroid Build Coastguard Worker 			return 0;
1439*03f9172cSAndroid Build Coastguard Worker 		}
1440*03f9172cSAndroid Build Coastguard Worker 	}
1441*03f9172cSAndroid Build Coastguard Worker 
1442*03f9172cSAndroid Build Coastguard Worker 	return hostapd_dfs_request_channel_switch(iface, channel->chan,
1443*03f9172cSAndroid Build Coastguard Worker 						  channel->freq,
1444*03f9172cSAndroid Build Coastguard Worker 						  secondary_channel,
1445*03f9172cSAndroid Build Coastguard Worker 						  current_vht_oper_chwidth,
1446*03f9172cSAndroid Build Coastguard Worker 						  oper_centr_freq_seg0_idx,
1447*03f9172cSAndroid Build Coastguard Worker 						  oper_centr_freq_seg1_idx);
1448*03f9172cSAndroid Build Coastguard Worker }
1449*03f9172cSAndroid Build Coastguard Worker 
1450*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_radar_detected(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1451*03f9172cSAndroid Build Coastguard Worker int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
1452*03f9172cSAndroid Build Coastguard Worker 			       int ht_enabled, int chan_offset, int chan_width,
1453*03f9172cSAndroid Build Coastguard Worker 			       int cf1, int cf2)
1454*03f9172cSAndroid Build Coastguard Worker {
1455*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
1456*03f9172cSAndroid Build Coastguard Worker 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1457*03f9172cSAndroid Build Coastguard Worker 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1458*03f9172cSAndroid Build Coastguard Worker 
1459*03f9172cSAndroid Build Coastguard Worker 	iface->radar_detected = true;
1460*03f9172cSAndroid Build Coastguard Worker 
1461*03f9172cSAndroid Build Coastguard Worker 	/* Proceed only if DFS is not offloaded to the driver */
1462*03f9172cSAndroid Build Coastguard Worker 	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1463*03f9172cSAndroid Build Coastguard Worker 		return 0;
1464*03f9172cSAndroid Build Coastguard Worker 
1465*03f9172cSAndroid Build Coastguard Worker 	if (!iface->conf->ieee80211h)
1466*03f9172cSAndroid Build Coastguard Worker 		return 0;
1467*03f9172cSAndroid Build Coastguard Worker 
1468*03f9172cSAndroid Build Coastguard Worker 	/* mark radar frequency as invalid */
1469*03f9172cSAndroid Build Coastguard Worker 	if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1470*03f9172cSAndroid Build Coastguard Worker 			   cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
1471*03f9172cSAndroid Build Coastguard Worker 		return 0;
1472*03f9172cSAndroid Build Coastguard Worker 
1473*03f9172cSAndroid Build Coastguard Worker 	if (!hostapd_dfs_is_background_event(iface, freq)) {
1474*03f9172cSAndroid Build Coastguard Worker 		/* Skip if reported radar event not overlapped our channels */
1475*03f9172cSAndroid Build Coastguard Worker 		if (!dfs_are_channels_overlapped(iface, freq, chan_width,
1476*03f9172cSAndroid Build Coastguard Worker 						 cf1, cf2))
1477*03f9172cSAndroid Build Coastguard Worker 			return 0;
1478*03f9172cSAndroid Build Coastguard Worker 	}
1479*03f9172cSAndroid Build Coastguard Worker 
1480*03f9172cSAndroid Build Coastguard Worker 	if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
1481*03f9172cSAndroid Build Coastguard Worker 		/* Radar detected while operating, switch the channel. */
1482*03f9172cSAndroid Build Coastguard Worker 		return hostapd_dfs_start_channel_switch(iface);
1483*03f9172cSAndroid Build Coastguard Worker 	}
1484*03f9172cSAndroid Build Coastguard Worker 
1485*03f9172cSAndroid Build Coastguard Worker 	return 0;
1486*03f9172cSAndroid Build Coastguard Worker }
1487*03f9172cSAndroid Build Coastguard Worker 
1488*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_nop_finished(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1489*03f9172cSAndroid Build Coastguard Worker int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
1490*03f9172cSAndroid Build Coastguard Worker 			     int ht_enabled, int chan_offset, int chan_width,
1491*03f9172cSAndroid Build Coastguard Worker 			     int cf1, int cf2)
1492*03f9172cSAndroid Build Coastguard Worker {
1493*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
1494*03f9172cSAndroid Build Coastguard Worker 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1495*03f9172cSAndroid Build Coastguard Worker 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1496*03f9172cSAndroid Build Coastguard Worker 
1497*03f9172cSAndroid Build Coastguard Worker 	/* Proceed only if DFS is not offloaded to the driver */
1498*03f9172cSAndroid Build Coastguard Worker 	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1499*03f9172cSAndroid Build Coastguard Worker 		return 0;
1500*03f9172cSAndroid Build Coastguard Worker 
1501*03f9172cSAndroid Build Coastguard Worker 	/* TODO add correct implementation here */
1502*03f9172cSAndroid Build Coastguard Worker 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1503*03f9172cSAndroid Build Coastguard Worker 		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
1504*03f9172cSAndroid Build Coastguard Worker 
1505*03f9172cSAndroid Build Coastguard Worker 	if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
1506*03f9172cSAndroid Build Coastguard Worker 		/* Handle cases where all channels were initially unavailable */
1507*03f9172cSAndroid Build Coastguard Worker 		hostapd_handle_dfs(iface);
1508*03f9172cSAndroid Build Coastguard Worker 	} else if (dfs_use_radar_background(iface) &&
1509*03f9172cSAndroid Build Coastguard Worker 		   iface->radar_background.channel == -1) {
1510*03f9172cSAndroid Build Coastguard Worker 		/* Reset radar background chain if disabled */
1511*03f9172cSAndroid Build Coastguard Worker 		hostapd_dfs_update_background_chain(iface);
1512*03f9172cSAndroid Build Coastguard Worker 	}
1513*03f9172cSAndroid Build Coastguard Worker 
1514*03f9172cSAndroid Build Coastguard Worker 	return 0;
1515*03f9172cSAndroid Build Coastguard Worker }
1516*03f9172cSAndroid Build Coastguard Worker 
1517*03f9172cSAndroid Build Coastguard Worker 
hostapd_is_dfs_required(struct hostapd_iface * iface)1518*03f9172cSAndroid Build Coastguard Worker int hostapd_is_dfs_required(struct hostapd_iface *iface)
1519*03f9172cSAndroid Build Coastguard Worker {
1520*03f9172cSAndroid Build Coastguard Worker 	int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
1521*03f9172cSAndroid Build Coastguard Worker 
1522*03f9172cSAndroid Build Coastguard Worker 	if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
1523*03f9172cSAndroid Build Coastguard Worker 	     !iface->conf->ieee80211h) ||
1524*03f9172cSAndroid Build Coastguard Worker 	    !iface->current_mode ||
1525*03f9172cSAndroid Build Coastguard Worker 	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
1526*03f9172cSAndroid Build Coastguard Worker 		return 0;
1527*03f9172cSAndroid Build Coastguard Worker 
1528*03f9172cSAndroid Build Coastguard Worker 	/* Get start (first) channel for current configuration */
1529*03f9172cSAndroid Build Coastguard Worker 	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
1530*03f9172cSAndroid Build Coastguard Worker 	if (start_chan_idx == -1)
1531*03f9172cSAndroid Build Coastguard Worker 		return -1;
1532*03f9172cSAndroid Build Coastguard Worker 
1533*03f9172cSAndroid Build Coastguard Worker 	/* Get number of used channels, depend on width */
1534*03f9172cSAndroid Build Coastguard Worker 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
1535*03f9172cSAndroid Build Coastguard Worker 
1536*03f9172cSAndroid Build Coastguard Worker 	/* Check if any of configured channels require DFS */
1537*03f9172cSAndroid Build Coastguard Worker 	res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
1538*03f9172cSAndroid Build Coastguard Worker 	if (res)
1539*03f9172cSAndroid Build Coastguard Worker 		return res;
1540*03f9172cSAndroid Build Coastguard Worker 	if (start_chan_idx1 >= 0 && n_chans1 > 0)
1541*03f9172cSAndroid Build Coastguard Worker 		res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
1542*03f9172cSAndroid Build Coastguard Worker 	return res;
1543*03f9172cSAndroid Build Coastguard Worker }
1544*03f9172cSAndroid Build Coastguard Worker 
1545*03f9172cSAndroid Build Coastguard Worker 
hostapd_dfs_start_cac(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1546*03f9172cSAndroid Build Coastguard Worker int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
1547*03f9172cSAndroid Build Coastguard Worker 			  int ht_enabled, int chan_offset, int chan_width,
1548*03f9172cSAndroid Build Coastguard Worker 			  int cf1, int cf2)
1549*03f9172cSAndroid Build Coastguard Worker {
1550*03f9172cSAndroid Build Coastguard Worker 	if (hostapd_dfs_is_background_event(iface, freq)) {
1551*03f9172cSAndroid Build Coastguard Worker 		iface->radar_background.cac_started = 1;
1552*03f9172cSAndroid Build Coastguard Worker 	} else {
1553*03f9172cSAndroid Build Coastguard Worker 		/* This is called when the driver indicates that an offloaded
1554*03f9172cSAndroid Build Coastguard Worker 		 * DFS has started CAC. radar_detected might be set for previous
1555*03f9172cSAndroid Build Coastguard Worker 		 * DFS channel. Clear it for this new CAC process. */
1556*03f9172cSAndroid Build Coastguard Worker 		hostapd_set_state(iface, HAPD_IFACE_DFS);
1557*03f9172cSAndroid Build Coastguard Worker 		iface->cac_started = 1;
1558*03f9172cSAndroid Build Coastguard Worker 
1559*03f9172cSAndroid Build Coastguard Worker 		/* Clear radar_detected in case it is for the previous
1560*03f9172cSAndroid Build Coastguard Worker 		 * frequency. Also remove disabled link's information in RNR
1561*03f9172cSAndroid Build Coastguard Worker 		 * element from other links. */
1562*03f9172cSAndroid Build Coastguard Worker 		iface->radar_detected = false;
1563*03f9172cSAndroid Build Coastguard Worker 		if (iface->interfaces && iface->interfaces->count > 1)
1564*03f9172cSAndroid Build Coastguard Worker 			ieee802_11_set_beacons(iface);
1565*03f9172cSAndroid Build Coastguard Worker 	}
1566*03f9172cSAndroid Build Coastguard Worker 	/* TODO: How to check CAC time for ETSI weather channels? */
1567*03f9172cSAndroid Build Coastguard Worker 	iface->dfs_cac_ms = 60000;
1568*03f9172cSAndroid Build Coastguard Worker 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1569*03f9172cSAndroid Build Coastguard Worker 		"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
1570*03f9172cSAndroid Build Coastguard Worker 		"seg1=%d cac_time=%ds%s",
1571*03f9172cSAndroid Build Coastguard Worker 		freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
1572*03f9172cSAndroid Build Coastguard Worker 		iface->dfs_cac_ms / 1000,
1573*03f9172cSAndroid Build Coastguard Worker 		hostapd_dfs_is_background_event(iface, freq) ?
1574*03f9172cSAndroid Build Coastguard Worker 		" (background)" : "");
1575*03f9172cSAndroid Build Coastguard Worker 
1576*03f9172cSAndroid Build Coastguard Worker 	os_get_reltime(&iface->dfs_cac_start);
1577*03f9172cSAndroid Build Coastguard Worker 	return 0;
1578*03f9172cSAndroid Build Coastguard Worker }
1579*03f9172cSAndroid Build Coastguard Worker 
1580*03f9172cSAndroid Build Coastguard Worker 
1581*03f9172cSAndroid Build Coastguard Worker /*
1582*03f9172cSAndroid Build Coastguard Worker  * Main DFS handler for offloaded case.
1583*03f9172cSAndroid Build Coastguard Worker  * 2 - continue channel/AP setup for non-DFS channel
1584*03f9172cSAndroid Build Coastguard Worker  * 1 - continue channel/AP setup for DFS channel
1585*03f9172cSAndroid Build Coastguard Worker  * 0 - channel/AP setup will be continued after CAC
1586*03f9172cSAndroid Build Coastguard Worker  * -1 - hit critical error
1587*03f9172cSAndroid Build Coastguard Worker  */
hostapd_handle_dfs_offload(struct hostapd_iface * iface)1588*03f9172cSAndroid Build Coastguard Worker int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
1589*03f9172cSAndroid Build Coastguard Worker {
1590*03f9172cSAndroid Build Coastguard Worker 	int dfs_res;
1591*03f9172cSAndroid Build Coastguard Worker 
1592*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1593*03f9172cSAndroid Build Coastguard Worker 		   __func__, iface->cac_started);
1594*03f9172cSAndroid Build Coastguard Worker 
1595*03f9172cSAndroid Build Coastguard Worker 	/*
1596*03f9172cSAndroid Build Coastguard Worker 	 * If DFS has already been started, then we are being called from a
1597*03f9172cSAndroid Build Coastguard Worker 	 * callback to continue AP/channel setup. Reset the CAC start flag and
1598*03f9172cSAndroid Build Coastguard Worker 	 * return.
1599*03f9172cSAndroid Build Coastguard Worker 	 */
1600*03f9172cSAndroid Build Coastguard Worker 	if (iface->cac_started) {
1601*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1602*03f9172cSAndroid Build Coastguard Worker 			   __func__, iface->cac_started);
1603*03f9172cSAndroid Build Coastguard Worker 		iface->cac_started = 0;
1604*03f9172cSAndroid Build Coastguard Worker 		return 1;
1605*03f9172cSAndroid Build Coastguard Worker 	}
1606*03f9172cSAndroid Build Coastguard Worker 
1607*03f9172cSAndroid Build Coastguard Worker 	dfs_res = hostapd_is_dfs_required(iface);
1608*03f9172cSAndroid Build Coastguard Worker 	if (dfs_res > 0) {
1609*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG,
1610*03f9172cSAndroid Build Coastguard Worker 			   "%s: freq %d MHz requires DFS for %d chans",
1611*03f9172cSAndroid Build Coastguard Worker 			   __func__, iface->freq, dfs_res);
1612*03f9172cSAndroid Build Coastguard Worker 		return 0;
1613*03f9172cSAndroid Build Coastguard Worker 	}
1614*03f9172cSAndroid Build Coastguard Worker 
1615*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG,
1616*03f9172cSAndroid Build Coastguard Worker 		   "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
1617*03f9172cSAndroid Build Coastguard Worker 		   __func__, iface->freq);
1618*03f9172cSAndroid Build Coastguard Worker 	return 2;
1619*03f9172cSAndroid Build Coastguard Worker }
1620*03f9172cSAndroid Build Coastguard Worker 
1621*03f9172cSAndroid Build Coastguard Worker 
hostapd_is_dfs_overlap(struct hostapd_iface * iface,enum chan_width width,int center_freq)1622*03f9172cSAndroid Build Coastguard Worker int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
1623*03f9172cSAndroid Build Coastguard Worker 			   int center_freq)
1624*03f9172cSAndroid Build Coastguard Worker {
1625*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_channel_data *chan;
1626*03f9172cSAndroid Build Coastguard Worker 	struct hostapd_hw_modes *mode = iface->current_mode;
1627*03f9172cSAndroid Build Coastguard Worker 	int half_width;
1628*03f9172cSAndroid Build Coastguard Worker 	int res = 0;
1629*03f9172cSAndroid Build Coastguard Worker 	int i;
1630*03f9172cSAndroid Build Coastguard Worker 
1631*03f9172cSAndroid Build Coastguard Worker 	if (!iface->conf->ieee80211h || !mode ||
1632*03f9172cSAndroid Build Coastguard Worker 	    mode->mode != HOSTAPD_MODE_IEEE80211A)
1633*03f9172cSAndroid Build Coastguard Worker 		return 0;
1634*03f9172cSAndroid Build Coastguard Worker 
1635*03f9172cSAndroid Build Coastguard Worker 	switch (width) {
1636*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_20_NOHT:
1637*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_20:
1638*03f9172cSAndroid Build Coastguard Worker 		half_width = 10;
1639*03f9172cSAndroid Build Coastguard Worker 		break;
1640*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_40:
1641*03f9172cSAndroid Build Coastguard Worker 		half_width = 20;
1642*03f9172cSAndroid Build Coastguard Worker 		break;
1643*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_80:
1644*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_80P80:
1645*03f9172cSAndroid Build Coastguard Worker 		half_width = 40;
1646*03f9172cSAndroid Build Coastguard Worker 		break;
1647*03f9172cSAndroid Build Coastguard Worker 	case CHAN_WIDTH_160:
1648*03f9172cSAndroid Build Coastguard Worker 		half_width = 80;
1649*03f9172cSAndroid Build Coastguard Worker 		break;
1650*03f9172cSAndroid Build Coastguard Worker 	default:
1651*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
1652*03f9172cSAndroid Build Coastguard Worker 			   width);
1653*03f9172cSAndroid Build Coastguard Worker 		return 0;
1654*03f9172cSAndroid Build Coastguard Worker 	}
1655*03f9172cSAndroid Build Coastguard Worker 
1656*03f9172cSAndroid Build Coastguard Worker 	for (i = 0; i < mode->num_channels; i++) {
1657*03f9172cSAndroid Build Coastguard Worker 		chan = &mode->channels[i];
1658*03f9172cSAndroid Build Coastguard Worker 
1659*03f9172cSAndroid Build Coastguard Worker 		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
1660*03f9172cSAndroid Build Coastguard Worker 			continue;
1661*03f9172cSAndroid Build Coastguard Worker 
1662*03f9172cSAndroid Build Coastguard Worker 		if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
1663*03f9172cSAndroid Build Coastguard Worker 		    HOSTAPD_CHAN_DFS_AVAILABLE)
1664*03f9172cSAndroid Build Coastguard Worker 			continue;
1665*03f9172cSAndroid Build Coastguard Worker 
1666*03f9172cSAndroid Build Coastguard Worker 		if (center_freq - chan->freq < half_width &&
1667*03f9172cSAndroid Build Coastguard Worker 		    chan->freq - center_freq < half_width)
1668*03f9172cSAndroid Build Coastguard Worker 			res++;
1669*03f9172cSAndroid Build Coastguard Worker 	}
1670*03f9172cSAndroid Build Coastguard Worker 
1671*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
1672*03f9172cSAndroid Build Coastguard Worker 		   center_freq - half_width, center_freq + half_width,
1673*03f9172cSAndroid Build Coastguard Worker 		   res ? "yes" : "no");
1674*03f9172cSAndroid Build Coastguard Worker 
1675*03f9172cSAndroid Build Coastguard Worker 	return res;
1676*03f9172cSAndroid Build Coastguard Worker }
1677