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