blob: a11b2cf805cd123c0431a2c5cfca31ae24ed7d9c [file] [log] [blame]
Dmitry Shmidt051af732013-10-22 13:52:46 -07001/*
2 * DFS - Dynamic Frequency Selection
3 * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2013, Qualcomm Atheros, Inc.
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
11
12#include "utils/common.h"
13#include "common/ieee802_11_defs.h"
Dmitry Shmidtcce06662013-11-04 18:44:24 -080014#include "common/wpa_ctrl.h"
Dmitry Shmidt051af732013-10-22 13:52:46 -070015#include "hostapd.h"
16#include "ap_drv_ops.h"
17#include "drivers/driver.h"
18#include "dfs.h"
19
20
Dmitry Shmidtcce06662013-11-04 18:44:24 -080021static int dfs_get_used_n_chans(struct hostapd_iface *iface)
Dmitry Shmidt051af732013-10-22 13:52:46 -070022{
23 int n_chans = 1;
24
Dmitry Shmidtcce06662013-11-04 18:44:24 -080025 if (iface->conf->ieee80211n && iface->conf->secondary_channel)
Dmitry Shmidt051af732013-10-22 13:52:46 -070026 n_chans = 2;
27
Dmitry Shmidtcce06662013-11-04 18:44:24 -080028 if (iface->conf->ieee80211ac) {
29 switch (iface->conf->vht_oper_chwidth) {
Dmitry Shmidt051af732013-10-22 13:52:46 -070030 case VHT_CHANWIDTH_USE_HT:
31 break;
32 case VHT_CHANWIDTH_80MHZ:
33 n_chans = 4;
34 break;
35 case VHT_CHANWIDTH_160MHZ:
36 n_chans = 8;
37 break;
38 default:
39 break;
40 }
41 }
42
43 return n_chans;
44}
45
46
Dmitry Shmidt04f534e2013-12-09 15:50:16 -080047static int dfs_channel_available(struct hostapd_channel_data *chan,
48 int skip_radar)
Dmitry Shmidt051af732013-10-22 13:52:46 -070049{
Dmitry Shmidt04f534e2013-12-09 15:50:16 -080050 /*
51 * When radar detection happens, CSA is performed. However, there's no
52 * time for CAC, so radar channels must be skipped when finding a new
Dmitry Shmidt98660862014-03-11 17:26:21 -070053 * channel for CSA, unless they are available for immediate use.
Dmitry Shmidt04f534e2013-12-09 15:50:16 -080054 */
Dmitry Shmidt98660862014-03-11 17:26:21 -070055 if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
56 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
57 HOSTAPD_CHAN_DFS_AVAILABLE))
Dmitry Shmidt04f534e2013-12-09 15:50:16 -080058 return 0;
59
Dmitry Shmidt051af732013-10-22 13:52:46 -070060 if (chan->flag & HOSTAPD_CHAN_DISABLED)
61 return 0;
62 if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
63 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
64 HOSTAPD_CHAN_DFS_UNAVAILABLE))
65 return 0;
66 return 1;
67}
68
69
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -070070static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
Dmitry Shmidt051af732013-10-22 13:52:46 -070071{
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -070072 /*
73 * The tables contain first valid channel number based on channel width.
74 * We will also choose this first channel as the control one.
75 */
76 int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
77 184, 192 };
78 /*
79 * VHT80, valid channels based on center frequency:
80 * 42, 58, 106, 122, 138, 155
81 */
82 int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080083 /*
84 * VHT160 valid channels based on center frequency:
85 * 50, 114
86 */
87 int allowed_160[] = { 36, 100 };
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -070088 int *allowed = allowed_40;
89 unsigned int i, allowed_no = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -070090
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -070091 switch (n_chans) {
92 case 2:
93 allowed = allowed_40;
94 allowed_no = ARRAY_SIZE(allowed_40);
95 break;
96 case 4:
97 allowed = allowed_80;
98 allowed_no = ARRAY_SIZE(allowed_80);
99 break;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800100 case 8:
101 allowed = allowed_160;
102 allowed_no = ARRAY_SIZE(allowed_160);
103 break;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700104 default:
105 wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
106 break;
107 }
108
109 for (i = 0; i < allowed_no; i++) {
Dmitry Shmidt051af732013-10-22 13:52:46 -0700110 if (chan->chan == allowed[i])
111 return 1;
112 }
113
114 return 0;
115}
116
117
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800118static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800119 int first_chan_idx, int num_chans,
120 int skip_radar)
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800121{
122 struct hostapd_channel_data *first_chan, *chan;
123 int i;
124
125 if (first_chan_idx + num_chans >= mode->num_channels)
126 return 0;
127
128 first_chan = &mode->channels[first_chan_idx];
129
130 for (i = 0; i < num_chans; i++) {
131 chan = &mode->channels[first_chan_idx + i];
132
133 if (first_chan->freq + i * 20 != chan->freq)
134 return 0;
135
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800136 if (!dfs_channel_available(chan, skip_radar))
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800137 return 0;
138 }
139
140 return 1;
141}
142
143
Dmitry Shmidt98660862014-03-11 17:26:21 -0700144static int is_in_chanlist(struct hostapd_iface *iface,
145 struct hostapd_channel_data *chan)
146{
147 int *entry;
148
149 if (!iface->conf->chanlist)
150 return 1;
151
152 for (entry = iface->conf->chanlist; *entry != -1; entry++) {
153 if (*entry == chan->chan)
154 return 1;
155 }
156 return 0;
157}
158
159
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800160/*
161 * The function assumes HT40+ operation.
162 * Make sure to adjust the following variables after calling this:
163 * - hapd->secondary_channel
164 * - hapd->vht_oper_centr_freq_seg0_idx
165 * - hapd->vht_oper_centr_freq_seg1_idx
166 */
167static int dfs_find_channel(struct hostapd_iface *iface,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700168 struct hostapd_channel_data **ret_chan,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800169 int idx, int skip_radar)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700170{
171 struct hostapd_hw_modes *mode;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800172 struct hostapd_channel_data *chan;
173 int i, channel_idx = 0, n_chans;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700174
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800175 mode = iface->current_mode;
176 n_chans = dfs_get_used_n_chans(iface);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700177
178 wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
179 for (i = 0; i < mode->num_channels; i++) {
180 chan = &mode->channels[i];
181
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800182 /* Skip HT40/VHT incompatible channels */
183 if (iface->conf->ieee80211n &&
184 iface->conf->secondary_channel &&
185 !dfs_is_chan_allowed(chan, n_chans))
Dmitry Shmidt051af732013-10-22 13:52:46 -0700186 continue;
187
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800188 /* Skip incompatible chandefs */
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800189 if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800190 continue;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700191
Dmitry Shmidt98660862014-03-11 17:26:21 -0700192 if (!is_in_chanlist(iface, chan))
193 continue;
194
Dmitry Shmidt051af732013-10-22 13:52:46 -0700195 if (ret_chan && idx == channel_idx) {
196 wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
197 *ret_chan = chan;
198 return idx;
199 }
200 wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
201 channel_idx++;
202 }
203 return channel_idx;
204}
205
206
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800207static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
208 struct hostapd_channel_data *chan,
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800209 int secondary_channel,
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800210 u8 *vht_oper_centr_freq_seg0_idx,
211 u8 *vht_oper_centr_freq_seg1_idx)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700212{
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800213 if (!iface->conf->ieee80211ac)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700214 return;
215
216 if (!chan)
217 return;
218
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800219 *vht_oper_centr_freq_seg1_idx = 0;
220
221 switch (iface->conf->vht_oper_chwidth) {
Dmitry Shmidt051af732013-10-22 13:52:46 -0700222 case VHT_CHANWIDTH_USE_HT:
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800223 if (secondary_channel == 1)
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800224 *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800225 else if (secondary_channel == -1)
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800226 *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700227 else
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800228 *vht_oper_centr_freq_seg0_idx = chan->chan;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700229 break;
230 case VHT_CHANWIDTH_80MHZ:
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800231 *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700232 break;
233 case VHT_CHANWIDTH_160MHZ:
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800234 *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700235 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700236 default:
237 wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800238 *vht_oper_centr_freq_seg0_idx = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700239 break;
240 }
241
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800242 wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
243 *vht_oper_centr_freq_seg0_idx,
244 *vht_oper_centr_freq_seg1_idx);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700245}
246
247
248/* Return start channel idx we will use for mode->channels[idx] */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800249static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700250{
251 struct hostapd_hw_modes *mode;
252 struct hostapd_channel_data *chan;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800253 int channel_no = iface->conf->channel;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700254 int res = -1, i;
255
256 /* HT40- */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800257 if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700258 channel_no -= 4;
259
260 /* VHT */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800261 if (iface->conf->ieee80211ac) {
262 switch (iface->conf->vht_oper_chwidth) {
Dmitry Shmidt051af732013-10-22 13:52:46 -0700263 case VHT_CHANWIDTH_USE_HT:
264 break;
265 case VHT_CHANWIDTH_80MHZ:
266 channel_no =
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800267 iface->conf->vht_oper_centr_freq_seg0_idx - 6;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700268 break;
269 case VHT_CHANWIDTH_160MHZ:
270 channel_no =
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800271 iface->conf->vht_oper_centr_freq_seg0_idx - 14;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700272 break;
273 default:
274 wpa_printf(MSG_INFO,
275 "DFS only VHT20/40/80/160 is supported now");
276 channel_no = -1;
277 break;
278 }
279 }
280
281 /* Get idx */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800282 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700283 for (i = 0; i < mode->num_channels; i++) {
284 chan = &mode->channels[i];
285 if (chan->chan == channel_no) {
286 res = i;
287 break;
288 }
289 }
290
Dmitry Shmidt98660862014-03-11 17:26:21 -0700291 if (res == -1) {
292 wpa_printf(MSG_DEBUG,
293 "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
294 mode->num_channels, channel_no, iface->conf->channel,
295 iface->conf->ieee80211n,
296 iface->conf->secondary_channel,
297 iface->conf->vht_oper_chwidth);
298
299 for (i = 0; i < mode->num_channels; i++) {
300 wpa_printf(MSG_DEBUG, "Available channel: %d",
301 mode->channels[i].chan);
302 }
303 }
Dmitry Shmidt051af732013-10-22 13:52:46 -0700304
305 return res;
306}
307
308
309/* At least one channel have radar flag */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800310static int dfs_check_chans_radar(struct hostapd_iface *iface,
311 int start_chan_idx, int n_chans)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700312{
313 struct hostapd_channel_data *channel;
314 struct hostapd_hw_modes *mode;
315 int i, res = 0;
316
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800317 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700318
319 for (i = 0; i < n_chans; i++) {
320 channel = &mode->channels[start_chan_idx + i];
321 if (channel->flag & HOSTAPD_CHAN_RADAR)
322 res++;
323 }
324
325 return res;
326}
327
328
329/* All channels available */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800330static int dfs_check_chans_available(struct hostapd_iface *iface,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700331 int start_chan_idx, int n_chans)
332{
333 struct hostapd_channel_data *channel;
334 struct hostapd_hw_modes *mode;
335 int i;
336
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800337 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700338
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800339 for (i = 0; i < n_chans; i++) {
Dmitry Shmidt051af732013-10-22 13:52:46 -0700340 channel = &mode->channels[start_chan_idx + i];
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800341
342 if (channel->flag & HOSTAPD_CHAN_DISABLED)
343 break;
344
345 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
346 continue;
347
Dmitry Shmidt051af732013-10-22 13:52:46 -0700348 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
349 HOSTAPD_CHAN_DFS_AVAILABLE)
350 break;
351 }
352
353 return i == n_chans;
354}
355
356
357/* At least one channel unavailable */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800358static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700359 int start_chan_idx,
360 int n_chans)
361{
362 struct hostapd_channel_data *channel;
363 struct hostapd_hw_modes *mode;
364 int i, res = 0;
365
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800366 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700367
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800368 for (i = 0; i < n_chans; i++) {
Dmitry Shmidt051af732013-10-22 13:52:46 -0700369 channel = &mode->channels[start_chan_idx + i];
370 if (channel->flag & HOSTAPD_CHAN_DISABLED)
371 res++;
372 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
373 HOSTAPD_CHAN_DFS_UNAVAILABLE)
374 res++;
375 }
376
377 return res;
378}
379
380
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800381static struct hostapd_channel_data *
382dfs_get_valid_channel(struct hostapd_iface *iface,
383 int *secondary_channel,
384 u8 *vht_oper_centr_freq_seg0_idx,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800385 u8 *vht_oper_centr_freq_seg1_idx,
386 int skip_radar)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700387{
388 struct hostapd_hw_modes *mode;
389 struct hostapd_channel_data *chan = NULL;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800390 int num_available_chandefs;
391 int chan_idx;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700392 u32 _rand;
393
394 wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -0800395 *secondary_channel = 0;
396 *vht_oper_centr_freq_seg0_idx = 0;
397 *vht_oper_centr_freq_seg1_idx = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700398
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800399 if (iface->current_mode == NULL)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700400 return NULL;
401
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800402 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700403 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
404 return NULL;
405
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800406 /* Get the count first */
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800407 num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800408 if (num_available_chandefs == 0)
409 return NULL;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700410
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800411 os_get_random((u8 *) &_rand, sizeof(_rand));
412 chan_idx = _rand % num_available_chandefs;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800413 dfs_find_channel(iface, &chan, chan_idx, skip_radar);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800414
415 /* dfs_find_channel() calculations assume HT40+ */
416 if (iface->conf->secondary_channel)
417 *secondary_channel = 1;
418 else
419 *secondary_channel = 0;
420
421 dfs_adjust_vht_center_freq(iface, chan,
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800422 *secondary_channel,
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800423 vht_oper_centr_freq_seg0_idx,
424 vht_oper_centr_freq_seg1_idx);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700425
426 return chan;
427}
428
429
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800430static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700431{
432 struct hostapd_hw_modes *mode;
433 struct hostapd_channel_data *chan = NULL;
434 int i;
435
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800436 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700437 if (mode == NULL)
438 return 0;
439
440 wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800441 for (i = 0; i < iface->current_mode->num_channels; i++) {
442 chan = &iface->current_mode->channels[i];
Dmitry Shmidt051af732013-10-22 13:52:46 -0700443 if (chan->freq == freq) {
444 if (chan->flag & HOSTAPD_CHAN_RADAR) {
445 chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
446 chan->flag |= state;
447 return 1; /* Channel found */
448 }
449 }
450 }
451 wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
452 return 0;
453}
454
455
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800456static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700457 int chan_offset, int chan_width, int cf1,
458 int cf2, u32 state)
459{
460 int n_chans = 1, i;
461 struct hostapd_hw_modes *mode;
462 int frequency = freq;
463 int ret = 0;
464
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800465 mode = iface->current_mode;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700466 if (mode == NULL)
467 return 0;
468
469 if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
470 wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
471 return 0;
472 }
473
474 /* Seems cf1 and chan_width is enough here */
475 switch (chan_width) {
476 case CHAN_WIDTH_20_NOHT:
477 case CHAN_WIDTH_20:
478 n_chans = 1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800479 if (frequency == 0)
480 frequency = cf1;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700481 break;
482 case CHAN_WIDTH_40:
483 n_chans = 2;
484 frequency = cf1 - 10;
485 break;
486 case CHAN_WIDTH_80:
487 n_chans = 4;
488 frequency = cf1 - 30;
489 break;
490 case CHAN_WIDTH_160:
491 n_chans = 8;
492 frequency = cf1 - 70;
493 break;
494 default:
495 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
496 chan_width);
497 break;
498 }
499
500 wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
501 n_chans);
502 for (i = 0; i < n_chans; i++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800503 ret += set_dfs_state_freq(iface, frequency, state);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700504 frequency = frequency + 20;
505 }
506
507 return ret;
508}
509
510
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800511static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700512 int chan_width, int cf1, int cf2)
513{
514 int start_chan_idx;
515 struct hostapd_hw_modes *mode;
516 struct hostapd_channel_data *chan;
517 int n_chans, i, j, frequency = freq, radar_n_chans = 1;
518 u8 radar_chan;
519 int res = 0;
520
Dmitry Shmidt051af732013-10-22 13:52:46 -0700521 /* Our configuration */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800522 mode = iface->current_mode;
523 start_chan_idx = dfs_get_start_chan_idx(iface);
524 n_chans = dfs_get_used_n_chans(iface);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700525
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700526 /* Check we are on DFS channel(s) */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800527 if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700528 return 0;
529
Dmitry Shmidt051af732013-10-22 13:52:46 -0700530 /* Reported via radar event */
531 switch (chan_width) {
532 case CHAN_WIDTH_20_NOHT:
533 case CHAN_WIDTH_20:
534 radar_n_chans = 1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800535 if (frequency == 0)
536 frequency = cf1;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700537 break;
538 case CHAN_WIDTH_40:
539 radar_n_chans = 2;
540 frequency = cf1 - 10;
541 break;
542 case CHAN_WIDTH_80:
543 radar_n_chans = 4;
544 frequency = cf1 - 30;
545 break;
546 case CHAN_WIDTH_160:
547 radar_n_chans = 8;
548 frequency = cf1 - 70;
549 break;
550 default:
551 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
552 chan_width);
553 break;
554 }
555
556 ieee80211_freq_to_chan(frequency, &radar_chan);
557
558 for (i = 0; i < n_chans; i++) {
559 chan = &mode->channels[start_chan_idx + i];
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700560 if (!(chan->flag & HOSTAPD_CHAN_RADAR))
561 continue;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700562 for (j = 0; j < radar_n_chans; j++) {
563 wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
564 chan->chan, radar_chan + j * 4);
565 if (chan->chan == radar_chan + j * 4)
566 res++;
567 }
568 }
569
570 wpa_printf(MSG_DEBUG, "overlapped: %d", res);
571
572 return res;
573}
574
575
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700576static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
577 int start_chan_idx, int n_chans)
578{
579 struct hostapd_channel_data *channel;
580 struct hostapd_hw_modes *mode;
581 int i;
582 unsigned int cac_time_ms = 0;
583
584 mode = iface->current_mode;
585
586 for (i = 0; i < n_chans; i++) {
587 channel = &mode->channels[start_chan_idx + i];
588 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
589 continue;
590 if (channel->dfs_cac_ms > cac_time_ms)
591 cac_time_ms = channel->dfs_cac_ms;
592 }
593
594 return cac_time_ms;
595}
596
597
Dmitry Shmidt051af732013-10-22 13:52:46 -0700598/*
599 * Main DFS handler
600 * 1 - continue channel/ap setup
601 * 0 - channel/ap setup will be continued after CAC
602 * -1 - hit critical error
603 */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800604int hostapd_handle_dfs(struct hostapd_iface *iface)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700605{
606 struct hostapd_channel_data *channel;
607 int res, n_chans, start_chan_idx;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800608 int skip_radar = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700609
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800610 iface->cac_started = 0;
611
Dmitry Shmidt051af732013-10-22 13:52:46 -0700612 do {
613 /* Get start (first) channel for current configuration */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800614 start_chan_idx = dfs_get_start_chan_idx(iface);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700615 if (start_chan_idx == -1)
616 return -1;
617
618 /* Get number of used channels, depend on width */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800619 n_chans = dfs_get_used_n_chans(iface);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700620
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700621 /* Setup CAC time */
622 iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
623 n_chans);
624
Dmitry Shmidt051af732013-10-22 13:52:46 -0700625 /* Check if any of configured channels require DFS */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800626 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700627 wpa_printf(MSG_DEBUG,
628 "DFS %d channels required radar detection",
629 res);
630 if (!res)
631 return 1;
632
633 /* Check if all channels are DFS available */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800634 res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700635 wpa_printf(MSG_DEBUG,
636 "DFS all channels available, (SKIP CAC): %s",
637 res ? "yes" : "no");
638 if (res)
639 return 1;
640
641 /* Check if any of configured channels is unavailable */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800642 res = dfs_check_chans_unavailable(iface, start_chan_idx,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700643 n_chans);
644 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
645 res, res ? "yes": "no");
646 if (res) {
Dmitry Shmidt96be6222014-02-13 10:16:51 -0800647 int sec = 0;
648 u8 cf1 = 0, cf2 = 0;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800649
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800650 channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
651 skip_radar);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700652 if (!channel) {
653 wpa_printf(MSG_ERROR, "could not get valid channel");
654 return -1;
655 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800656
657 iface->freq = channel->freq;
658 iface->conf->channel = channel->chan;
659 iface->conf->secondary_channel = sec;
660 iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
661 iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700662 }
663 } while (res);
664
665 /* Finally start CAC */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800666 hostapd_set_state(iface, HAPD_IFACE_DFS);
667 wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
668 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700669 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800670 iface->freq,
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800671 iface->conf->channel, iface->conf->secondary_channel,
672 iface->conf->vht_oper_chwidth,
673 iface->conf->vht_oper_centr_freq_seg0_idx,
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -0700674 iface->conf->vht_oper_centr_freq_seg1_idx,
675 iface->dfs_cac_ms / 1000);
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800676
677 res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
678 iface->freq,
679 iface->conf->channel,
680 iface->conf->ieee80211n,
681 iface->conf->ieee80211ac,
682 iface->conf->secondary_channel,
683 iface->conf->vht_oper_chwidth,
684 iface->conf->vht_oper_centr_freq_seg0_idx,
685 iface->conf->vht_oper_centr_freq_seg1_idx);
686
687 if (res) {
688 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700689 return -1;
690 }
691
692 return 0;
693}
694
695
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800696int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700697 int ht_enabled, int chan_offset, int chan_width,
698 int cf1, int cf2)
699{
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800700 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
701 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
702 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
703
Dmitry Shmidt051af732013-10-22 13:52:46 -0700704 if (success) {
705 /* Complete iface/ap configuration */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800706 set_dfs_state(iface, freq, ht_enabled, chan_offset,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700707 chan_width, cf1, cf2,
708 HOSTAPD_CHAN_DFS_AVAILABLE);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800709 iface->cac_started = 0;
710 hostapd_setup_interface_complete(iface, 0);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700711 }
712
713 return 0;
714}
715
716
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800717static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700718{
719 struct hostapd_channel_data *channel;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800720 int secondary_channel;
Dmitry Shmidt96be6222014-02-13 10:16:51 -0800721 u8 vht_oper_centr_freq_seg0_idx = 0;
722 u8 vht_oper_centr_freq_seg1_idx = 0;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800723 int skip_radar = 0;
724 int err = 1;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700725
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800726 /* Radar detected during active CAC */
727 iface->cac_started = 0;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800728 channel = dfs_get_valid_channel(iface, &secondary_channel,
729 &vht_oper_centr_freq_seg0_idx,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800730 &vht_oper_centr_freq_seg1_idx,
731 skip_radar);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800732
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800733 if (!channel) {
734 wpa_printf(MSG_ERROR, "No valid channel available");
735 hostapd_setup_interface_complete(iface, err);
736 return err;
737 }
738
739 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
740 channel->chan);
741 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
742 "freq=%d chan=%d sec_chan=%d", channel->freq,
743 channel->chan, secondary_channel);
744
745 iface->freq = channel->freq;
746 iface->conf->channel = channel->chan;
747 iface->conf->secondary_channel = secondary_channel;
748 iface->conf->vht_oper_centr_freq_seg0_idx =
749 vht_oper_centr_freq_seg0_idx;
750 iface->conf->vht_oper_centr_freq_seg1_idx =
751 vht_oper_centr_freq_seg1_idx;
752 err = 0;
753
754 hostapd_setup_interface_complete(iface, err);
755 return err;
756}
757
758
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700759static int hostapd_csa_in_progress(struct hostapd_iface *iface)
760{
761 unsigned int i;
762 for (i = 0; i < iface->num_bss; i++)
763 if (iface->bss[i]->csa_in_progress)
764 return 1;
765 return 0;
766}
767
768
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800769static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
770{
771 struct hostapd_channel_data *channel;
772 int secondary_channel;
773 u8 vht_oper_centr_freq_seg0_idx;
774 u8 vht_oper_centr_freq_seg1_idx;
775 int skip_radar = 1;
776 struct csa_settings csa_settings;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700777 unsigned int i;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800778 int err = 1;
779
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800780 wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
781 __func__, iface->cac_started ? "yes" : "no",
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700782 hostapd_csa_in_progress(iface) ? "yes" : "no");
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800783
784 /* Check if CSA in progress */
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700785 if (hostapd_csa_in_progress(iface))
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800786 return 0;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800787
788 /* Check if active CAC */
789 if (iface->cac_started)
790 return hostapd_dfs_start_channel_switch_cac(iface);
791
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800792 /* Perform channel switch/CSA */
793 channel = dfs_get_valid_channel(iface, &secondary_channel,
794 &vht_oper_centr_freq_seg0_idx,
795 &vht_oper_centr_freq_seg1_idx,
796 skip_radar);
797
798 if (!channel) {
Dmitry Shmidt98660862014-03-11 17:26:21 -0700799 /*
800 * If there is no channel to switch immediately to, check if
801 * there is another channel where we can switch even if it
802 * requires to perform a CAC first.
803 */
804 skip_radar = 0;
805 channel = dfs_get_valid_channel(iface, &secondary_channel,
806 &vht_oper_centr_freq_seg0_idx,
807 &vht_oper_centr_freq_seg1_idx,
808 skip_radar);
809 if (!channel) {
810 /* FIXME: Wait for channel(s) to become available */
811 hostapd_disable_iface(iface);
812 return err;
813 }
814
815 iface->freq = channel->freq;
816 iface->conf->channel = channel->chan;
817 iface->conf->secondary_channel = secondary_channel;
818 iface->conf->vht_oper_centr_freq_seg0_idx =
819 vht_oper_centr_freq_seg0_idx;
820 iface->conf->vht_oper_centr_freq_seg1_idx =
821 vht_oper_centr_freq_seg1_idx;
822
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800823 hostapd_disable_iface(iface);
Dmitry Shmidt98660862014-03-11 17:26:21 -0700824 hostapd_enable_iface(iface);
825 return 0;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800826 }
827
828 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
829 channel->chan);
830 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
831 "freq=%d chan=%d sec_chan=%d", channel->freq,
832 channel->chan, secondary_channel);
833
834 /* Setup CSA request */
835 os_memset(&csa_settings, 0, sizeof(csa_settings));
836 csa_settings.cs_count = 5;
837 csa_settings.block_tx = 1;
838 err = hostapd_set_freq_params(&csa_settings.freq_params,
839 iface->conf->hw_mode,
840 channel->freq,
841 channel->chan,
842 iface->conf->ieee80211n,
843 iface->conf->ieee80211ac,
844 secondary_channel,
845 iface->conf->vht_oper_chwidth,
846 vht_oper_centr_freq_seg0_idx,
847 vht_oper_centr_freq_seg1_idx,
848 iface->current_mode->vht_capab);
849
850 if (err) {
851 wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
852 hostapd_disable_iface(iface);
853 return err;
854 }
855
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700856 for (i = 0; i < iface->num_bss; i++) {
857 err = hostapd_switch_channel(iface->bss[i], &csa_settings);
858 if (err)
859 break;
860 }
861
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800862 if (err) {
863 wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
864 err);
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800865 iface->freq = channel->freq;
866 iface->conf->channel = channel->chan;
867 iface->conf->secondary_channel = secondary_channel;
868 iface->conf->vht_oper_centr_freq_seg0_idx =
869 vht_oper_centr_freq_seg0_idx;
870 iface->conf->vht_oper_centr_freq_seg1_idx =
871 vht_oper_centr_freq_seg1_idx;
Dmitry Shmidt051af732013-10-22 13:52:46 -0700872
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800873 hostapd_disable_iface(iface);
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800874 hostapd_enable_iface(iface);
875 return 0;
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800876 }
877
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800878 /* Channel configuration will be updated once CSA completes and
879 * ch_switch_notify event is received */
880
881 wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
Dmitry Shmidt051af732013-10-22 13:52:46 -0700882 return 0;
883}
884
885
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800886int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700887 int ht_enabled, int chan_offset, int chan_width,
888 int cf1, int cf2)
889{
890 int res;
891
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800892 if (!iface->conf->ieee80211h)
Dmitry Shmidt051af732013-10-22 13:52:46 -0700893 return 0;
894
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800895 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
896 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
897 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
898
Dmitry Shmidt051af732013-10-22 13:52:46 -0700899 /* mark radar frequency as invalid */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800900 res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700901 chan_width, cf1, cf2,
902 HOSTAPD_CHAN_DFS_UNAVAILABLE);
903
904 /* Skip if reported radar event not overlapped our channels */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800905 res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700906 if (!res)
907 return 0;
908
Dmitry Shmidt051af732013-10-22 13:52:46 -0700909 /* radar detected while operating, switch the channel. */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800910 res = hostapd_dfs_start_channel_switch(iface);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700911
912 return res;
913}
914
915
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800916int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
Dmitry Shmidt051af732013-10-22 13:52:46 -0700917 int ht_enabled, int chan_offset, int chan_width,
918 int cf1, int cf2)
919{
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800920 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
921 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
922 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700923 /* TODO add correct implementation here */
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800924 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
925 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
Dmitry Shmidt051af732013-10-22 13:52:46 -0700926 return 0;
927}
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800928
929
930int hostapd_is_dfs_required(struct hostapd_iface *iface)
931{
932 int n_chans, start_chan_idx;
933
Dmitry Shmidt61593f02014-04-21 16:27:35 -0700934 if (!iface->conf->ieee80211h || !iface->current_mode ||
935 iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
936 return 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800937
938 /* Get start (first) channel for current configuration */
939 start_chan_idx = dfs_get_start_chan_idx(iface);
940 if (start_chan_idx == -1)
941 return -1;
942
943 /* Get number of used channels, depend on width */
944 n_chans = dfs_get_used_n_chans(iface);
945
946 /* Check if any of configured channels require DFS */
947 return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
948}