]>
Commit | Line | Data |
---|---|---|
e76da505 JD |
1 | /* |
2 | * DFS - Dynamic Frequency Selection | |
3 | * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> | |
58b73e3d | 4 | * Copyright (c) 2013, Qualcomm Atheros, Inc. |
e76da505 JD |
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" | |
14 | #include "hostapd.h" | |
e76da505 JD |
15 | #include "ap_drv_ops.h" |
16 | #include "drivers/driver.h" | |
17 | #include "dfs.h" | |
18 | ||
19 | ||
58b73e3d JD |
20 | static int dfs_get_used_n_chans(struct hostapd_data *hapd) |
21 | { | |
22 | int n_chans = 1; | |
23 | ||
24 | if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel) | |
25 | n_chans = 2; | |
26 | ||
27 | if (hapd->iconf->ieee80211ac) { | |
28 | switch (hapd->iconf->vht_oper_chwidth) { | |
29 | case VHT_CHANWIDTH_USE_HT: | |
30 | break; | |
31 | case VHT_CHANWIDTH_80MHZ: | |
32 | n_chans = 4; | |
33 | break; | |
899cc14e JD |
34 | case VHT_CHANWIDTH_160MHZ: |
35 | n_chans = 8; | |
36 | break; | |
58b73e3d JD |
37 | default: |
38 | break; | |
39 | } | |
40 | } | |
41 | ||
42 | return n_chans; | |
43 | } | |
44 | ||
45 | ||
46 | static int dfs_channel_available(struct hostapd_channel_data *chan) | |
47 | { | |
48 | if (chan->flag & HOSTAPD_CHAN_DISABLED) | |
49 | return 0; | |
50 | if ((chan->flag & HOSTAPD_CHAN_RADAR) && | |
51 | ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == | |
52 | HOSTAPD_CHAN_DFS_UNAVAILABLE)) | |
53 | return 0; | |
54 | return 1; | |
55 | } | |
56 | ||
57 | ||
58 | static int dfs_is_ht40_allowed(struct hostapd_channel_data *chan) | |
59 | { | |
60 | int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, | |
61 | 184, 192 }; | |
62 | unsigned int i; | |
63 | ||
64 | for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++) { | |
65 | if (chan->chan == allowed[i]) | |
66 | return 1; | |
67 | } | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | ||
6de0e0c9 JD |
73 | static int dfs_find_channel(struct hostapd_data *hapd, |
74 | struct hostapd_channel_data **ret_chan, | |
75 | int idx) | |
e76da505 JD |
76 | { |
77 | struct hostapd_hw_modes *mode; | |
58b73e3d JD |
78 | struct hostapd_channel_data *chan, *next_chan; |
79 | int i, j, channel_idx = 0, n_chans; | |
e76da505 JD |
80 | |
81 | mode = hapd->iface->current_mode; | |
58b73e3d | 82 | n_chans = dfs_get_used_n_chans(hapd); |
e76da505 | 83 | |
58b73e3d | 84 | wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); |
e76da505 JD |
85 | for (i = 0; i < mode->num_channels; i++) { |
86 | chan = &mode->channels[i]; | |
87 | ||
58b73e3d JD |
88 | /* Skip not available channels */ |
89 | if (!dfs_channel_available(chan)) | |
e76da505 JD |
90 | continue; |
91 | ||
58b73e3d JD |
92 | /* Skip HT40/VHT uncompatible channels */ |
93 | if (hapd->iconf->ieee80211n && | |
94 | hapd->iconf->secondary_channel) { | |
95 | if (!dfs_is_ht40_allowed(chan)) | |
96 | continue; | |
97 | ||
98 | for (j = 1; j < n_chans; j++) { | |
99 | next_chan = &mode->channels[i + j]; | |
100 | if (!dfs_channel_available(next_chan)) | |
101 | break; | |
102 | } | |
103 | if (j != n_chans) | |
104 | continue; | |
105 | ||
106 | /* Set HT40+ */ | |
107 | hapd->iconf->secondary_channel = 1; | |
108 | } | |
e76da505 JD |
109 | |
110 | if (ret_chan && idx == channel_idx) { | |
111 | wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); | |
112 | *ret_chan = chan; | |
113 | return idx; | |
114 | } | |
58b73e3d | 115 | wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); |
e76da505 JD |
116 | channel_idx++; |
117 | } | |
118 | return channel_idx; | |
119 | } | |
120 | ||
121 | ||
58b73e3d JD |
122 | static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd, |
123 | struct hostapd_channel_data *chan) | |
124 | { | |
125 | if (!hapd->iconf->ieee80211ac) | |
126 | return; | |
127 | ||
128 | if (!chan) | |
129 | return; | |
130 | ||
131 | switch (hapd->iconf->vht_oper_chwidth) { | |
132 | case VHT_CHANWIDTH_USE_HT: | |
133 | hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 2; | |
134 | break; | |
135 | case VHT_CHANWIDTH_80MHZ: | |
136 | hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6; | |
137 | break; | |
899cc14e JD |
138 | case VHT_CHANWIDTH_160MHZ: |
139 | hapd->iconf->vht_oper_centr_freq_seg0_idx = | |
140 | chan->chan + 14; | |
35f83637 | 141 | break; |
58b73e3d | 142 | default: |
899cc14e | 143 | wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); |
58b73e3d JD |
144 | break; |
145 | } | |
146 | ||
147 | wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d", | |
148 | hapd->iconf->vht_oper_centr_freq_seg0_idx); | |
149 | } | |
150 | ||
151 | ||
152 | /* Return start channel idx we will use for mode->channels[idx] */ | |
153 | static int dfs_get_start_chan_idx(struct hostapd_data *hapd) | |
154 | { | |
155 | struct hostapd_hw_modes *mode; | |
156 | struct hostapd_channel_data *chan; | |
157 | int channel_no = hapd->iconf->channel; | |
158 | int res = -1, i; | |
159 | ||
160 | /* HT40- */ | |
161 | if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel == -1) | |
162 | channel_no -= 4; | |
163 | ||
164 | /* VHT */ | |
165 | if (hapd->iconf->ieee80211ac) { | |
166 | switch (hapd->iconf->vht_oper_chwidth) { | |
167 | case VHT_CHANWIDTH_USE_HT: | |
168 | break; | |
169 | case VHT_CHANWIDTH_80MHZ: | |
170 | channel_no = | |
171 | hapd->iconf->vht_oper_centr_freq_seg0_idx - 6; | |
172 | break; | |
899cc14e JD |
173 | case VHT_CHANWIDTH_160MHZ: |
174 | channel_no = | |
175 | hapd->iconf->vht_oper_centr_freq_seg0_idx - 14; | |
176 | break; | |
58b73e3d JD |
177 | default: |
178 | wpa_printf(MSG_INFO, | |
899cc14e | 179 | "DFS only VHT20/40/80/160 is supported now"); |
58b73e3d JD |
180 | channel_no = -1; |
181 | break; | |
182 | } | |
183 | } | |
184 | ||
185 | /* Get idx */ | |
186 | mode = hapd->iface->current_mode; | |
187 | for (i = 0; i < mode->num_channels; i++) { | |
188 | chan = &mode->channels[i]; | |
189 | if (chan->chan == channel_no) { | |
190 | res = i; | |
191 | break; | |
192 | } | |
193 | } | |
194 | ||
195 | if (res == -1) | |
196 | wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); | |
197 | ||
198 | return res; | |
199 | } | |
200 | ||
201 | ||
202 | /* At least one channel have radar flag */ | |
203 | static int dfs_check_chans_radar(struct hostapd_data *hapd, int start_chan_idx, | |
204 | int n_chans) | |
205 | { | |
206 | struct hostapd_channel_data *channel; | |
207 | struct hostapd_hw_modes *mode; | |
208 | int i, res = 0; | |
209 | ||
210 | mode = hapd->iface->current_mode; | |
211 | ||
212 | for (i = 0; i < n_chans; i++) { | |
213 | channel = &mode->channels[start_chan_idx + i]; | |
214 | if (channel->flag & HOSTAPD_CHAN_RADAR) | |
215 | res++; | |
216 | } | |
217 | ||
218 | return res; | |
219 | } | |
220 | ||
221 | ||
222 | /* All channels available */ | |
223 | static int dfs_check_chans_available(struct hostapd_data *hapd, | |
224 | int start_chan_idx, int n_chans) | |
225 | { | |
226 | struct hostapd_channel_data *channel; | |
227 | struct hostapd_hw_modes *mode; | |
228 | int i; | |
229 | ||
230 | mode = hapd->iface->current_mode; | |
231 | ||
232 | for(i = 0; i < n_chans; i++) { | |
233 | channel = &mode->channels[start_chan_idx + i]; | |
234 | if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != | |
235 | HOSTAPD_CHAN_DFS_AVAILABLE) | |
236 | break; | |
237 | } | |
238 | ||
239 | return i == n_chans; | |
240 | } | |
241 | ||
242 | ||
243 | /* At least one channel unavailable */ | |
244 | static int dfs_check_chans_unavailable(struct hostapd_data *hapd, | |
245 | int start_chan_idx, | |
246 | int n_chans) | |
247 | { | |
248 | struct hostapd_channel_data *channel; | |
249 | struct hostapd_hw_modes *mode; | |
250 | int i, res = 0; | |
251 | ||
252 | mode = hapd->iface->current_mode; | |
253 | ||
254 | for(i = 0; i < n_chans; i++) { | |
255 | channel = &mode->channels[start_chan_idx + i]; | |
256 | if (channel->flag & HOSTAPD_CHAN_DISABLED) | |
257 | res++; | |
258 | if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == | |
259 | HOSTAPD_CHAN_DFS_UNAVAILABLE) | |
260 | res++; | |
261 | } | |
262 | ||
263 | return res; | |
264 | } | |
265 | ||
266 | ||
6de0e0c9 | 267 | static struct hostapd_channel_data * dfs_get_valid_channel( |
e76da505 JD |
268 | struct hostapd_data *hapd) |
269 | { | |
270 | struct hostapd_hw_modes *mode; | |
271 | struct hostapd_channel_data *chan = NULL; | |
272 | int channel_idx, new_channel_idx; | |
273 | u32 _rand; | |
274 | ||
275 | wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); | |
276 | ||
277 | if (hapd->iface->current_mode == NULL) | |
278 | return NULL; | |
279 | ||
280 | mode = hapd->iface->current_mode; | |
281 | if (mode->mode != HOSTAPD_MODE_IEEE80211A) | |
282 | return NULL; | |
283 | ||
284 | /* get random available channel */ | |
6de0e0c9 | 285 | channel_idx = dfs_find_channel(hapd, NULL, 0); |
e76da505 JD |
286 | if (channel_idx > 0) { |
287 | os_get_random((u8 *) &_rand, sizeof(_rand)); | |
288 | new_channel_idx = _rand % channel_idx; | |
6de0e0c9 | 289 | dfs_find_channel(hapd, &chan, new_channel_idx); |
e76da505 JD |
290 | } |
291 | ||
58b73e3d JD |
292 | /* VHT */ |
293 | dfs_adjust_vht_center_freq(hapd, chan); | |
294 | ||
e76da505 JD |
295 | return chan; |
296 | } | |
297 | ||
298 | ||
58b73e3d | 299 | static int set_dfs_state_freq(struct hostapd_data *hapd, int freq, u32 state) |
e76da505 JD |
300 | { |
301 | struct hostapd_hw_modes *mode; | |
302 | struct hostapd_channel_data *chan = NULL; | |
303 | int i; | |
304 | ||
305 | mode = hapd->iface->current_mode; | |
306 | if (mode == NULL) | |
307 | return 0; | |
308 | ||
58b73e3d | 309 | wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); |
e76da505 JD |
310 | for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { |
311 | chan = &hapd->iface->current_mode->channels[i]; | |
312 | if (chan->freq == freq) { | |
313 | if (chan->flag & HOSTAPD_CHAN_RADAR) { | |
314 | chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; | |
315 | chan->flag |= state; | |
316 | return 1; /* Channel found */ | |
317 | } | |
318 | } | |
319 | } | |
320 | wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); | |
321 | return 0; | |
322 | } | |
323 | ||
324 | ||
58b73e3d JD |
325 | static int set_dfs_state(struct hostapd_data *hapd, int freq, int ht_enabled, |
326 | int chan_offset, int chan_width, int cf1, | |
327 | int cf2, u32 state) | |
328 | { | |
329 | int n_chans = 1, i; | |
330 | struct hostapd_hw_modes *mode; | |
331 | int frequency = freq; | |
332 | int ret = 0; | |
333 | ||
334 | mode = hapd->iface->current_mode; | |
335 | if (mode == NULL) | |
336 | return 0; | |
337 | ||
338 | if (mode->mode != HOSTAPD_MODE_IEEE80211A) { | |
339 | wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | /* Seems cf1 and chan_width is enough here */ | |
344 | switch (chan_width) { | |
345 | case CHAN_WIDTH_20_NOHT: | |
346 | case CHAN_WIDTH_20: | |
347 | n_chans = 1; | |
348 | frequency = cf1; | |
349 | break; | |
350 | case CHAN_WIDTH_40: | |
351 | n_chans = 2; | |
352 | frequency = cf1 - 10; | |
353 | break; | |
354 | case CHAN_WIDTH_80: | |
355 | n_chans = 4; | |
356 | frequency = cf1 - 30; | |
357 | break; | |
899cc14e JD |
358 | case CHAN_WIDTH_160: |
359 | n_chans = 8; | |
360 | frequency = cf1 - 70; | |
361 | break; | |
58b73e3d JD |
362 | default: |
363 | wpa_printf(MSG_INFO, "DFS chan_width %d not supported", | |
364 | chan_width); | |
365 | break; | |
366 | } | |
367 | ||
368 | wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, | |
369 | n_chans); | |
370 | for (i = 0; i < n_chans; i++) { | |
371 | ret += set_dfs_state_freq(hapd, frequency, state); | |
372 | frequency = frequency + 20; | |
373 | } | |
374 | ||
375 | return ret; | |
376 | } | |
377 | ||
378 | ||
379 | static int dfs_are_channels_overlapped(struct hostapd_data *hapd, int freq, | |
380 | int chan_width, int cf1, int cf2) | |
381 | { | |
382 | int start_chan_idx; | |
383 | struct hostapd_hw_modes *mode; | |
384 | struct hostapd_channel_data *chan; | |
385 | int n_chans, i, j, frequency = freq, radar_n_chans = 1; | |
386 | u8 radar_chan; | |
387 | int res = 0; | |
388 | ||
389 | if (hapd->iface->freq == freq) | |
390 | res++; | |
391 | ||
392 | /* Our configuration */ | |
393 | mode = hapd->iface->current_mode; | |
394 | start_chan_idx = dfs_get_start_chan_idx(hapd); | |
395 | n_chans = dfs_get_used_n_chans(hapd); | |
396 | ||
397 | /* Reported via radar event */ | |
398 | switch (chan_width) { | |
399 | case CHAN_WIDTH_20_NOHT: | |
400 | case CHAN_WIDTH_20: | |
401 | radar_n_chans = 1; | |
402 | frequency = cf1; | |
403 | break; | |
404 | case CHAN_WIDTH_40: | |
405 | radar_n_chans = 2; | |
406 | frequency = cf1 - 10; | |
407 | break; | |
408 | case CHAN_WIDTH_80: | |
409 | radar_n_chans = 4; | |
410 | frequency = cf1 - 30; | |
411 | break; | |
899cc14e JD |
412 | case CHAN_WIDTH_160: |
413 | radar_n_chans = 8; | |
414 | frequency = cf1 - 70; | |
415 | break; | |
58b73e3d JD |
416 | default: |
417 | wpa_printf(MSG_INFO, "DFS chan_width %d not supported", | |
418 | chan_width); | |
419 | break; | |
420 | } | |
421 | ||
422 | ieee80211_freq_to_chan(frequency, &radar_chan); | |
423 | ||
424 | for (i = 0; i < n_chans; i++) { | |
425 | chan = &mode->channels[start_chan_idx + i]; | |
426 | for (j = 0; j < radar_n_chans; j++) { | |
427 | wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", | |
428 | chan->chan, radar_chan + j * 4); | |
429 | if (chan->chan == radar_chan + j * 4) | |
430 | res++; | |
431 | } | |
432 | } | |
433 | ||
434 | wpa_printf(MSG_DEBUG, "overlapped: %d", res); | |
435 | ||
436 | return res; | |
437 | } | |
438 | ||
439 | ||
e76da505 JD |
440 | /* |
441 | * Main DFS handler | |
442 | * 1 - continue channel/ap setup | |
443 | * 0 - channel/ap setup will be continued after CAC | |
444 | * -1 - hit critical error | |
445 | */ | |
446 | int hostapd_handle_dfs(struct hostapd_data *hapd) | |
447 | { | |
e76da505 | 448 | struct hostapd_channel_data *channel; |
58b73e3d JD |
449 | int res, n_chans, start_chan_idx; |
450 | ||
451 | do { | |
452 | /* Get start (first) channel for current configuration */ | |
453 | start_chan_idx = dfs_get_start_chan_idx(hapd); | |
454 | if (start_chan_idx == -1) | |
455 | return -1; | |
456 | ||
457 | /* Get number of used channels, depend on width */ | |
458 | n_chans = dfs_get_used_n_chans(hapd); | |
459 | ||
460 | /* Check if any of configured channels require DFS */ | |
461 | res = dfs_check_chans_radar(hapd, start_chan_idx, n_chans); | |
462 | wpa_printf(MSG_DEBUG, | |
463 | "DFS %d channels required radar detection", | |
464 | res); | |
465 | if (!res) | |
466 | return 1; | |
467 | ||
468 | /* Check if all channels are DFS available */ | |
469 | res = dfs_check_chans_available(hapd, start_chan_idx, n_chans); | |
470 | wpa_printf(MSG_DEBUG, | |
471 | "DFS all channels available, (SKIP CAC): %s", | |
472 | res ? "yes" : "no"); | |
473 | if (res) | |
474 | return 1; | |
475 | ||
476 | /* Check if any of configured channels is unavailable */ | |
477 | res = dfs_check_chans_unavailable(hapd, start_chan_idx, | |
478 | n_chans); | |
479 | wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", | |
480 | res, res ? "yes": "no"); | |
481 | if (res) { | |
6de0e0c9 | 482 | channel = dfs_get_valid_channel(hapd); |
e76da505 JD |
483 | if (!channel) { |
484 | wpa_printf(MSG_ERROR, "could not get valid channel"); | |
485 | return -1; | |
486 | } | |
487 | hapd->iconf->channel = channel->chan; | |
488 | hapd->iface->freq = channel->freq; | |
e76da505 | 489 | } |
58b73e3d JD |
490 | } while (res); |
491 | ||
492 | /* Finally start CAC */ | |
493 | wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", hapd->iface->freq); | |
494 | if (hostapd_start_dfs_cac(hapd, hapd->iconf->hw_mode, | |
495 | hapd->iface->freq, | |
496 | hapd->iconf->channel, | |
497 | hapd->iconf->ieee80211n, | |
498 | hapd->iconf->ieee80211ac, | |
499 | hapd->iconf->secondary_channel, | |
500 | hapd->iconf->vht_oper_chwidth, | |
501 | hapd->iconf->vht_oper_centr_freq_seg0_idx, | |
502 | hapd->iconf->vht_oper_centr_freq_seg1_idx)) { | |
503 | wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); | |
504 | return -1; | |
e76da505 JD |
505 | } |
506 | ||
58b73e3d | 507 | return 0; |
e76da505 JD |
508 | } |
509 | ||
510 | ||
58b73e3d JD |
511 | int hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq, |
512 | int ht_enabled, int chan_offset, int chan_width, | |
513 | int cf1, int cf2) | |
e76da505 JD |
514 | { |
515 | struct hostapd_channel_data *channel; | |
516 | int err = 1; | |
517 | ||
518 | if (success) { | |
519 | /* Complete iface/ap configuration */ | |
58b73e3d JD |
520 | set_dfs_state(hapd, freq, ht_enabled, chan_offset, |
521 | chan_width, cf1, cf2, | |
522 | HOSTAPD_CHAN_DFS_AVAILABLE); | |
e76da505 JD |
523 | hostapd_setup_interface_complete(hapd->iface, 0); |
524 | } else { | |
525 | /* Switch to new channel */ | |
58b73e3d JD |
526 | set_dfs_state(hapd, freq, ht_enabled, chan_offset, |
527 | chan_width, cf1, cf2, | |
528 | HOSTAPD_CHAN_DFS_UNAVAILABLE); | |
6de0e0c9 | 529 | channel = dfs_get_valid_channel(hapd); |
e76da505 JD |
530 | if (channel) { |
531 | hapd->iconf->channel = channel->chan; | |
532 | hapd->iface->freq = channel->freq; | |
533 | err = 0; | |
534 | } else | |
535 | wpa_printf(MSG_ERROR, "No valid channel available"); | |
536 | ||
537 | hostapd_setup_interface_complete(hapd->iface, err); | |
538 | } | |
539 | ||
540 | return 0; | |
541 | } | |
542 | ||
543 | ||
6de0e0c9 | 544 | static int hostapd_dfs_start_channel_switch(struct hostapd_data *hapd) |
e76da505 JD |
545 | { |
546 | struct hostapd_channel_data *channel; | |
547 | int err = 1; | |
548 | ||
549 | wpa_printf(MSG_DEBUG, "%s called", __func__); | |
6de0e0c9 | 550 | channel = dfs_get_valid_channel(hapd); |
e76da505 JD |
551 | if (channel) { |
552 | hapd->iconf->channel = channel->chan; | |
553 | hapd->iface->freq = channel->freq; | |
554 | err = 0; | |
555 | } | |
556 | ||
557 | hapd->driver->stop_ap(hapd->drv_priv); | |
558 | ||
559 | hostapd_setup_interface_complete(hapd->iface, err); | |
560 | return 0; | |
561 | } | |
58b73e3d JD |
562 | |
563 | ||
564 | int hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq, | |
565 | int ht_enabled, int chan_offset, int chan_width, | |
566 | int cf1, int cf2) | |
567 | { | |
568 | int res; | |
569 | ||
570 | if (!hapd->iconf->ieee80211h) | |
571 | return 0; | |
572 | ||
573 | /* mark radar frequency as invalid */ | |
574 | res = set_dfs_state(hapd, freq, ht_enabled, chan_offset, | |
575 | chan_width, cf1, cf2, | |
576 | HOSTAPD_CHAN_DFS_UNAVAILABLE); | |
577 | ||
578 | /* Skip if reported radar event not overlapped our channels */ | |
579 | res = dfs_are_channels_overlapped(hapd, freq, chan_width, cf1, cf2); | |
580 | if (!res) | |
581 | return 0; | |
582 | ||
583 | /* we are working on non-DFS channel - skip event */ | |
584 | if (res == 0) | |
585 | return 0; | |
586 | ||
587 | /* radar detected while operating, switch the channel. */ | |
6de0e0c9 | 588 | res = hostapd_dfs_start_channel_switch(hapd); |
58b73e3d JD |
589 | |
590 | return res; | |
591 | } | |
592 | ||
593 | ||
594 | int hostapd_dfs_nop_finished(struct hostapd_data *hapd, int freq, | |
595 | int ht_enabled, int chan_offset, int chan_width, | |
596 | int cf1, int cf2) | |
597 | { | |
598 | /* TODO add correct implementation here */ | |
599 | set_dfs_state(hapd, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, | |
600 | HOSTAPD_CHAN_DFS_USABLE); | |
601 | return 0; | |
602 | } |