LCOV - code coverage report
Current view: top level - src/ap - dfs.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 386 511 75.5 %
Date: 2015-09-27 Functions: 24 27 88.9 %

          Line data    Source code
       1             : /*
       2             :  * DFS - Dynamic Frequency Selection
       3             :  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
       4             :  * Copyright (c) 2013-2015, 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"
      14             : #include "common/hw_features_common.h"
      15             : #include "common/wpa_ctrl.h"
      16             : #include "hostapd.h"
      17             : #include "ap_drv_ops.h"
      18             : #include "drivers/driver.h"
      19             : #include "dfs.h"
      20             : 
      21             : 
      22        2107 : static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
      23             : {
      24        2107 :         int n_chans = 1;
      25             : 
      26        2107 :         *seg1 = 0;
      27             : 
      28        2107 :         if (iface->conf->ieee80211n && iface->conf->secondary_channel)
      29          93 :                 n_chans = 2;
      30             : 
      31        2107 :         if (iface->conf->ieee80211ac) {
      32          48 :                 switch (iface->conf->vht_oper_chwidth) {
      33             :                 case VHT_CHANWIDTH_USE_HT:
      34          14 :                         break;
      35             :                 case VHT_CHANWIDTH_80MHZ:
      36          18 :                         n_chans = 4;
      37          18 :                         break;
      38             :                 case VHT_CHANWIDTH_160MHZ:
      39          14 :                         n_chans = 8;
      40          14 :                         break;
      41             :                 case VHT_CHANWIDTH_80P80MHZ:
      42           2 :                         n_chans = 4;
      43           2 :                         *seg1 = 4;
      44           2 :                         break;
      45             :                 default:
      46           0 :                         break;
      47             :                 }
      48             :         }
      49             : 
      50        2107 :         return n_chans;
      51             : }
      52             : 
      53             : 
      54         193 : static int dfs_channel_available(struct hostapd_channel_data *chan,
      55             :                                  int skip_radar)
      56             : {
      57             :         /*
      58             :          * When radar detection happens, CSA is performed. However, there's no
      59             :          * time for CAC, so radar channels must be skipped when finding a new
      60             :          * channel for CSA, unless they are available for immediate use.
      61             :          */
      62         215 :         if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
      63          22 :             ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
      64             :              HOSTAPD_CHAN_DFS_AVAILABLE))
      65          22 :                 return 0;
      66             : 
      67         171 :         if (chan->flag & HOSTAPD_CHAN_DISABLED)
      68          30 :                 return 0;
      69         231 :         if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
      70          90 :             ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
      71             :              HOSTAPD_CHAN_DFS_UNAVAILABLE))
      72           7 :                 return 0;
      73         134 :         return 1;
      74             : }
      75             : 
      76             : 
      77          75 : static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
      78             : {
      79             :         /*
      80             :          * The tables contain first valid channel number based on channel width.
      81             :          * We will also choose this first channel as the control one.
      82             :          */
      83          75 :         int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
      84             :                              184, 192 };
      85             :         /*
      86             :          * VHT80, valid channels based on center frequency:
      87             :          * 42, 58, 106, 122, 138, 155
      88             :          */
      89          75 :         int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
      90             :         /*
      91             :          * VHT160 valid channels based on center frequency:
      92             :          * 50, 114
      93             :          */
      94          75 :         int allowed_160[] = { 36, 100 };
      95          75 :         int *allowed = allowed_40;
      96          75 :         unsigned int i, allowed_no = 0;
      97             : 
      98          75 :         switch (n_chans) {
      99             :         case 2:
     100          50 :                 allowed = allowed_40;
     101          50 :                 allowed_no = ARRAY_SIZE(allowed_40);
     102          50 :                 break;
     103             :         case 4:
     104          25 :                 allowed = allowed_80;
     105          25 :                 allowed_no = ARRAY_SIZE(allowed_80);
     106          25 :                 break;
     107             :         case 8:
     108           0 :                 allowed = allowed_160;
     109           0 :                 allowed_no = ARRAY_SIZE(allowed_160);
     110           0 :                 break;
     111             :         default:
     112           0 :                 wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
     113           0 :                 break;
     114             :         }
     115             : 
     116         646 :         for (i = 0; i < allowed_no; i++) {
     117         602 :                 if (chan->chan == allowed[i])
     118          31 :                         return 1;
     119             :         }
     120             : 
     121          44 :         return 0;
     122             : }
     123             : 
     124             : 
     125             : static struct hostapd_channel_data *
     126         194 : dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
     127             : {
     128             :         int i;
     129             : 
     130         241 :         for (i = first_chan_idx; i < mode->num_channels; i++) {
     131         240 :                 if (mode->channels[i].freq == freq)
     132         193 :                         return &mode->channels[i];
     133             :         }
     134             : 
     135           1 :         return NULL;
     136             : }
     137             : 
     138             : 
     139         167 : static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
     140             :                                     int first_chan_idx, int num_chans,
     141             :                                     int skip_radar)
     142             : {
     143             :         struct hostapd_channel_data *first_chan, *chan;
     144             :         int i;
     145             : 
     146         167 :         if (first_chan_idx + num_chans > mode->num_channels)
     147           0 :                 return 0;
     148             : 
     149         167 :         first_chan = &mode->channels[first_chan_idx];
     150             : 
     151         301 :         for (i = 0; i < num_chans; i++) {
     152         194 :                 chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
     153             :                                          first_chan_idx);
     154         194 :                 if (!chan)
     155           1 :                         return 0;
     156             : 
     157         193 :                 if (!dfs_channel_available(chan, skip_radar))
     158          59 :                         return 0;
     159             :         }
     160             : 
     161         107 :         return 1;
     162             : }
     163             : 
     164             : 
     165         107 : static int is_in_chanlist(struct hostapd_iface *iface,
     166             :                           struct hostapd_channel_data *chan)
     167             : {
     168         107 :         if (!iface->conf->acs_ch_list.num)
     169          36 :                 return 1;
     170             : 
     171          71 :         return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
     172             : }
     173             : 
     174             : 
     175             : /*
     176             :  * The function assumes HT40+ operation.
     177             :  * Make sure to adjust the following variables after calling this:
     178             :  *  - hapd->secondary_channel
     179             :  *  - hapd->vht_oper_centr_freq_seg0_idx
     180             :  *  - hapd->vht_oper_centr_freq_seg1_idx
     181             :  */
     182          16 : static int dfs_find_channel(struct hostapd_iface *iface,
     183             :                             struct hostapd_channel_data **ret_chan,
     184             :                             int idx, int skip_radar)
     185             : {
     186             :         struct hostapd_hw_modes *mode;
     187             :         struct hostapd_channel_data *chan;
     188          16 :         int i, channel_idx = 0, n_chans, n_chans1;
     189             : 
     190          16 :         mode = iface->current_mode;
     191          16 :         n_chans = dfs_get_used_n_chans(iface, &n_chans1);
     192             : 
     193          16 :         wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
     194         219 :         for (i = 0; i < mode->num_channels; i++) {
     195         211 :                 chan = &mode->channels[i];
     196             : 
     197             :                 /* Skip HT40/VHT incompatible channels */
     198         397 :                 if (iface->conf->ieee80211n &&
     199         261 :                     iface->conf->secondary_channel &&
     200          75 :                     !dfs_is_chan_allowed(chan, n_chans))
     201          44 :                         continue;
     202             : 
     203             :                 /* Skip incompatible chandefs */
     204         167 :                 if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
     205          60 :                         continue;
     206             : 
     207         107 :                 if (!is_in_chanlist(iface, chan))
     208          60 :                         continue;
     209             : 
     210          47 :                 if (ret_chan && idx == channel_idx) {
     211           8 :                         wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
     212           8 :                         *ret_chan = chan;
     213           8 :                         return idx;
     214             :                 }
     215          39 :                 wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
     216          39 :                 channel_idx++;
     217             :         }
     218           8 :         return channel_idx;
     219             : }
     220             : 
     221             : 
     222           8 : static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
     223             :                                        struct hostapd_channel_data *chan,
     224             :                                        int secondary_channel,
     225             :                                        u8 *vht_oper_centr_freq_seg0_idx,
     226             :                                        u8 *vht_oper_centr_freq_seg1_idx)
     227             : {
     228           8 :         if (!iface->conf->ieee80211ac)
     229           6 :                 return;
     230             : 
     231           2 :         if (!chan)
     232           0 :                 return;
     233             : 
     234           2 :         *vht_oper_centr_freq_seg1_idx = 0;
     235             : 
     236           2 :         switch (iface->conf->vht_oper_chwidth) {
     237             :         case VHT_CHANWIDTH_USE_HT:
     238           1 :                 if (secondary_channel == 1)
     239           0 :                         *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
     240           1 :                 else if (secondary_channel == -1)
     241           0 :                         *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
     242             :                 else
     243           1 :                         *vht_oper_centr_freq_seg0_idx = chan->chan;
     244           1 :                 break;
     245             :         case VHT_CHANWIDTH_80MHZ:
     246           1 :                 *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
     247           1 :                 break;
     248             :         case VHT_CHANWIDTH_160MHZ:
     249           0 :                 *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
     250           0 :                 break;
     251             :         default:
     252           0 :                 wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
     253           0 :                 *vht_oper_centr_freq_seg0_idx = 0;
     254           0 :                 break;
     255             :         }
     256             : 
     257           4 :         wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
     258           2 :                    *vht_oper_centr_freq_seg0_idx,
     259           2 :                    *vht_oper_centr_freq_seg1_idx);
     260             : }
     261             : 
     262             : 
     263             : /* Return start channel idx we will use for mode->channels[idx] */
     264        2091 : static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
     265             : {
     266             :         struct hostapd_hw_modes *mode;
     267             :         struct hostapd_channel_data *chan;
     268        2091 :         int channel_no = iface->conf->channel;
     269        2091 :         int res = -1, i;
     270        2091 :         int chan_seg1 = -1;
     271             : 
     272        2091 :         *seg1_start = -1;
     273             : 
     274             :         /* HT40- */
     275        2091 :         if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
     276          23 :                 channel_no -= 4;
     277             : 
     278             :         /* VHT */
     279        2091 :         if (iface->conf->ieee80211ac) {
     280          44 :                 switch (iface->conf->vht_oper_chwidth) {
     281             :                 case VHT_CHANWIDTH_USE_HT:
     282          12 :                         break;
     283             :                 case VHT_CHANWIDTH_80MHZ:
     284          16 :                         channel_no =
     285          16 :                                 iface->conf->vht_oper_centr_freq_seg0_idx - 6;
     286          16 :                         break;
     287             :                 case VHT_CHANWIDTH_160MHZ:
     288          14 :                         channel_no =
     289          14 :                                 iface->conf->vht_oper_centr_freq_seg0_idx - 14;
     290          14 :                         break;
     291             :                 case VHT_CHANWIDTH_80P80MHZ:
     292           2 :                         channel_no =
     293           2 :                                 iface->conf->vht_oper_centr_freq_seg0_idx - 6;
     294           2 :                         chan_seg1 =
     295           2 :                                 iface->conf->vht_oper_centr_freq_seg1_idx - 6;
     296           2 :                         break;
     297             :                 default:
     298           0 :                         wpa_printf(MSG_INFO,
     299             :                                    "DFS only VHT20/40/80/160/80+80 is supported now");
     300           0 :                         channel_no = -1;
     301           0 :                         break;
     302             :                 }
     303             :         }
     304             : 
     305             :         /* Get idx */
     306        2091 :         mode = iface->current_mode;
     307        3676 :         for (i = 0; i < mode->num_channels; i++) {
     308        3676 :                 chan = &mode->channels[i];
     309        3676 :                 if (chan->chan == channel_no) {
     310        2091 :                         res = i;
     311        2091 :                         break;
     312             :                 }
     313             :         }
     314             : 
     315        2091 :         if (res != -1 && chan_seg1 > -1) {
     316           2 :                 int found = 0;
     317             : 
     318             :                 /* Get idx for seg1 */
     319           2 :                 mode = iface->current_mode;
     320          40 :                 for (i = 0; i < mode->num_channels; i++) {
     321          40 :                         chan = &mode->channels[i];
     322          40 :                         if (chan->chan == chan_seg1) {
     323           2 :                                 *seg1_start = i;
     324           2 :                                 found = 1;
     325           2 :                                 break;
     326             :                         }
     327             :                 }
     328           2 :                 if (!found)
     329           0 :                         res = -1;
     330             :         }
     331             : 
     332        2091 :         if (res == -1) {
     333           0 :                 wpa_printf(MSG_DEBUG,
     334             :                            "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
     335           0 :                            mode->num_channels, channel_no, iface->conf->channel,
     336           0 :                            iface->conf->ieee80211n,
     337           0 :                            iface->conf->secondary_channel,
     338           0 :                            iface->conf->vht_oper_chwidth);
     339             : 
     340           0 :                 for (i = 0; i < mode->num_channels; i++) {
     341           0 :                         wpa_printf(MSG_DEBUG, "Available channel: %d",
     342           0 :                                    mode->channels[i].chan);
     343             :                 }
     344             :         }
     345             : 
     346        2091 :         return res;
     347             : }
     348             : 
     349             : 
     350             : /* At least one channel have radar flag */
     351        2091 : static int dfs_check_chans_radar(struct hostapd_iface *iface,
     352             :                                  int start_chan_idx, int n_chans)
     353             : {
     354             :         struct hostapd_channel_data *channel;
     355             :         struct hostapd_hw_modes *mode;
     356        2091 :         int i, res = 0;
     357             : 
     358        2091 :         mode = iface->current_mode;
     359             : 
     360        4389 :         for (i = 0; i < n_chans; i++) {
     361        2298 :                 channel = &mode->channels[start_chan_idx + i];
     362        2298 :                 if (channel->flag & HOSTAPD_CHAN_RADAR)
     363         154 :                         res++;
     364             :         }
     365             : 
     366        2091 :         return res;
     367             : }
     368             : 
     369             : 
     370             : /* All channels available */
     371          19 : static int dfs_check_chans_available(struct hostapd_iface *iface,
     372             :                                      int start_chan_idx, int n_chans)
     373             : {
     374             :         struct hostapd_channel_data *channel;
     375             :         struct hostapd_hw_modes *mode;
     376             :         int i;
     377             : 
     378          19 :         mode = iface->current_mode;
     379             : 
     380          44 :         for (i = 0; i < n_chans; i++) {
     381          38 :                 channel = &mode->channels[start_chan_idx + i];
     382             : 
     383          38 :                 if (channel->flag & HOSTAPD_CHAN_DISABLED)
     384           0 :                         break;
     385             : 
     386          38 :                 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
     387           8 :                         continue;
     388             : 
     389          30 :                 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
     390             :                     HOSTAPD_CHAN_DFS_AVAILABLE)
     391          13 :                         break;
     392             :         }
     393             : 
     394          19 :         return i == n_chans;
     395             : }
     396             : 
     397             : 
     398             : /* At least one channel unavailable */
     399          13 : static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
     400             :                                        int start_chan_idx,
     401             :                                        int n_chans)
     402             : {
     403             :         struct hostapd_channel_data *channel;
     404             :         struct hostapd_hw_modes *mode;
     405          13 :         int i, res = 0;
     406             : 
     407          13 :         mode = iface->current_mode;
     408             : 
     409          48 :         for (i = 0; i < n_chans; i++) {
     410          35 :                 channel = &mode->channels[start_chan_idx + i];
     411          35 :                 if (channel->flag & HOSTAPD_CHAN_DISABLED)
     412           0 :                         res++;
     413          35 :                 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
     414             :                     HOSTAPD_CHAN_DFS_UNAVAILABLE)
     415           0 :                         res++;
     416             :         }
     417             : 
     418          13 :         return res;
     419             : }
     420             : 
     421             : 
     422             : static struct hostapd_channel_data *
     423           8 : dfs_get_valid_channel(struct hostapd_iface *iface,
     424             :                       int *secondary_channel,
     425             :                       u8 *vht_oper_centr_freq_seg0_idx,
     426             :                       u8 *vht_oper_centr_freq_seg1_idx,
     427             :                       int skip_radar)
     428             : {
     429             :         struct hostapd_hw_modes *mode;
     430           8 :         struct hostapd_channel_data *chan = NULL;
     431             :         int num_available_chandefs;
     432             :         int chan_idx;
     433             :         u32 _rand;
     434             : 
     435           8 :         wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
     436           8 :         *secondary_channel = 0;
     437           8 :         *vht_oper_centr_freq_seg0_idx = 0;
     438           8 :         *vht_oper_centr_freq_seg1_idx = 0;
     439             : 
     440           8 :         if (iface->current_mode == NULL)
     441           0 :                 return NULL;
     442             : 
     443           8 :         mode = iface->current_mode;
     444           8 :         if (mode->mode != HOSTAPD_MODE_IEEE80211A)
     445           0 :                 return NULL;
     446             : 
     447             :         /* Get the count first */
     448           8 :         num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
     449           8 :         if (num_available_chandefs == 0)
     450           0 :                 return NULL;
     451             : 
     452           8 :         if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
     453           0 :                 _rand = os_random();
     454           8 :         chan_idx = _rand % num_available_chandefs;
     455           8 :         dfs_find_channel(iface, &chan, chan_idx, skip_radar);
     456             : 
     457             :         /* dfs_find_channel() calculations assume HT40+ */
     458           8 :         if (iface->conf->secondary_channel)
     459           3 :                 *secondary_channel = 1;
     460             :         else
     461           5 :                 *secondary_channel = 0;
     462             : 
     463           8 :         dfs_adjust_vht_center_freq(iface, chan,
     464             :                                    *secondary_channel,
     465             :                                    vht_oper_centr_freq_seg0_idx,
     466             :                                    vht_oper_centr_freq_seg1_idx);
     467             : 
     468           8 :         return chan;
     469             : }
     470             : 
     471             : 
     472          34 : static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
     473             : {
     474             :         struct hostapd_hw_modes *mode;
     475          34 :         struct hostapd_channel_data *chan = NULL;
     476             :         int i;
     477             : 
     478          34 :         mode = iface->current_mode;
     479          34 :         if (mode == NULL)
     480           0 :                 return 0;
     481             : 
     482          34 :         wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
     483         329 :         for (i = 0; i < iface->current_mode->num_channels; i++) {
     484         325 :                 chan = &iface->current_mode->channels[i];
     485         325 :                 if (chan->freq == freq) {
     486          34 :                         if (chan->flag & HOSTAPD_CHAN_RADAR) {
     487          30 :                                 chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
     488          30 :                                 chan->flag |= state;
     489          30 :                                 return 1; /* Channel found */
     490             :                         }
     491             :                 }
     492             :         }
     493           4 :         wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
     494           4 :         return 0;
     495             : }
     496             : 
     497             : 
     498          14 : static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
     499             :                          int chan_offset, int chan_width, int cf1,
     500             :                          int cf2, u32 state)
     501             : {
     502          14 :         int n_chans = 1, i;
     503             :         struct hostapd_hw_modes *mode;
     504          14 :         int frequency = freq;
     505          14 :         int ret = 0;
     506             : 
     507          14 :         mode = iface->current_mode;
     508          14 :         if (mode == NULL)
     509           0 :                 return 0;
     510             : 
     511          14 :         if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
     512           0 :                 wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
     513           0 :                 return 0;
     514             :         }
     515             : 
     516             :         /* Seems cf1 and chan_width is enough here */
     517          14 :         switch (chan_width) {
     518             :         case CHAN_WIDTH_20_NOHT:
     519             :         case CHAN_WIDTH_20:
     520           8 :                 n_chans = 1;
     521           8 :                 if (frequency == 0)
     522           0 :                         frequency = cf1;
     523           8 :                 break;
     524             :         case CHAN_WIDTH_40:
     525           3 :                 n_chans = 2;
     526           3 :                 frequency = cf1 - 10;
     527           3 :                 break;
     528             :         case CHAN_WIDTH_80:
     529           1 :                 n_chans = 4;
     530           1 :                 frequency = cf1 - 30;
     531           1 :                 break;
     532             :         case CHAN_WIDTH_160:
     533           2 :                 n_chans = 8;
     534           2 :                 frequency = cf1 - 70;
     535           2 :                 break;
     536             :         default:
     537           0 :                 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
     538             :                            chan_width);
     539           0 :                 break;
     540             :         }
     541             : 
     542          14 :         wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
     543             :                    n_chans);
     544          48 :         for (i = 0; i < n_chans; i++) {
     545          34 :                 ret += set_dfs_state_freq(iface, frequency, state);
     546          34 :                 frequency = frequency + 20;
     547             :         }
     548             : 
     549          14 :         return ret;
     550             : }
     551             : 
     552             : 
     553           8 : static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
     554             :                                        int chan_width, int cf1, int cf2)
     555             : {
     556             :         int start_chan_idx, start_chan_idx1;
     557             :         struct hostapd_hw_modes *mode;
     558             :         struct hostapd_channel_data *chan;
     559           8 :         int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
     560             :         u8 radar_chan;
     561           8 :         int res = 0;
     562             : 
     563             :         /* Our configuration */
     564           8 :         mode = iface->current_mode;
     565           8 :         start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
     566           8 :         n_chans = dfs_get_used_n_chans(iface, &n_chans1);
     567             : 
     568             :         /* Check we are on DFS channel(s) */
     569           8 :         if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
     570           0 :                 return 0;
     571             : 
     572             :         /* Reported via radar event */
     573           8 :         switch (chan_width) {
     574             :         case CHAN_WIDTH_20_NOHT:
     575             :         case CHAN_WIDTH_20:
     576           5 :                 radar_n_chans = 1;
     577           5 :                 if (frequency == 0)
     578           0 :                         frequency = cf1;
     579           5 :                 break;
     580             :         case CHAN_WIDTH_40:
     581           2 :                 radar_n_chans = 2;
     582           2 :                 frequency = cf1 - 10;
     583           2 :                 break;
     584             :         case CHAN_WIDTH_80:
     585           1 :                 radar_n_chans = 4;
     586           1 :                 frequency = cf1 - 30;
     587           1 :                 break;
     588             :         case CHAN_WIDTH_160:
     589           0 :                 radar_n_chans = 8;
     590           0 :                 frequency = cf1 - 70;
     591           0 :                 break;
     592             :         default:
     593           0 :                 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
     594             :                            chan_width);
     595           0 :                 break;
     596             :         }
     597             : 
     598           8 :         ieee80211_freq_to_chan(frequency, &radar_chan);
     599             : 
     600          21 :         for (i = 0; i < n_chans; i++) {
     601          13 :                 chan = &mode->channels[start_chan_idx + i];
     602          13 :                 if (!(chan->flag & HOSTAPD_CHAN_RADAR))
     603           0 :                         continue;
     604          42 :                 for (j = 0; j < radar_n_chans; j++) {
     605          87 :                         wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
     606          58 :                                    chan->chan, radar_chan + j * 4);
     607          29 :                         if (chan->chan == radar_chan + j * 4)
     608          13 :                                 res++;
     609             :                 }
     610             :         }
     611             : 
     612           8 :         wpa_printf(MSG_DEBUG, "overlapped: %d", res);
     613             : 
     614           8 :         return res;
     615             : }
     616             : 
     617             : 
     618        2013 : static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
     619             :                                      int start_chan_idx, int n_chans)
     620             : {
     621             :         struct hostapd_channel_data *channel;
     622             :         struct hostapd_hw_modes *mode;
     623             :         int i;
     624        2013 :         unsigned int cac_time_ms = 0;
     625             : 
     626        2013 :         mode = iface->current_mode;
     627             : 
     628        4128 :         for (i = 0; i < n_chans; i++) {
     629        2115 :                 channel = &mode->channels[start_chan_idx + i];
     630        2115 :                 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
     631        2067 :                         continue;
     632          48 :                 if (channel->dfs_cac_ms > cac_time_ms)
     633          19 :                         cac_time_ms = channel->dfs_cac_ms;
     634             :         }
     635             : 
     636        2013 :         return cac_time_ms;
     637             : }
     638             : 
     639             : 
     640             : /*
     641             :  * Main DFS handler
     642             :  * 1 - continue channel/ap setup
     643             :  * 0 - channel/ap setup will be continued after CAC
     644             :  * -1 - hit critical error
     645             :  */
     646        2013 : int hostapd_handle_dfs(struct hostapd_iface *iface)
     647             : {
     648             :         struct hostapd_channel_data *channel;
     649             :         int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
     650        2013 :         int skip_radar = 0;
     651             : 
     652        2013 :         if (!iface->current_mode) {
     653             :                 /*
     654             :                  * This can happen with drivers that do not provide mode
     655             :                  * information and as such, cannot really use hostapd for DFS.
     656             :                  */
     657           0 :                 wpa_printf(MSG_DEBUG,
     658             :                            "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
     659           0 :                 return 1;
     660             :         }
     661             : 
     662        2013 :         iface->cac_started = 0;
     663             : 
     664             :         do {
     665             :                 /* Get start (first) channel for current configuration */
     666        2013 :                 start_chan_idx = dfs_get_start_chan_idx(iface,
     667             :                                                         &start_chan_idx1);
     668        2013 :                 if (start_chan_idx == -1)
     669           0 :                         return -1;
     670             : 
     671             :                 /* Get number of used channels, depend on width */
     672        2013 :                 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
     673             : 
     674             :                 /* Setup CAC time */
     675        2013 :                 iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
     676             :                                                      n_chans);
     677             : 
     678             :                 /* Check if any of configured channels require DFS */
     679        2013 :                 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
     680        2013 :                 wpa_printf(MSG_DEBUG,
     681             :                            "DFS %d channels required radar detection",
     682             :                            res);
     683        2013 :                 if (!res)
     684        1994 :                         return 1;
     685             : 
     686             :                 /* Check if all channels are DFS available */
     687          19 :                 res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
     688          19 :                 wpa_printf(MSG_DEBUG,
     689             :                            "DFS all channels available, (SKIP CAC): %s",
     690             :                            res ? "yes" : "no");
     691          19 :                 if (res)
     692           6 :                         return 1;
     693             : 
     694             :                 /* Check if any of configured channels is unavailable */
     695          13 :                 res = dfs_check_chans_unavailable(iface, start_chan_idx,
     696             :                                                   n_chans);
     697          13 :                 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
     698             :                            res, res ? "yes": "no");
     699          13 :                 if (res) {
     700           0 :                         int sec = 0;
     701           0 :                         u8 cf1 = 0, cf2 = 0;
     702             : 
     703           0 :                         channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
     704             :                                                         skip_radar);
     705           0 :                         if (!channel) {
     706           0 :                                 wpa_printf(MSG_ERROR, "could not get valid channel");
     707           0 :                                 return -1;
     708             :                         }
     709             : 
     710           0 :                         iface->freq = channel->freq;
     711           0 :                         iface->conf->channel = channel->chan;
     712           0 :                         iface->conf->secondary_channel = sec;
     713           0 :                         iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
     714           0 :                         iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
     715             :                 }
     716          13 :         } while (res);
     717             : 
     718             :         /* Finally start CAC */
     719          13 :         hostapd_set_state(iface, HAPD_IFACE_DFS);
     720          13 :         wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
     721          78 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
     722             :                 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
     723             :                 iface->freq,
     724          26 :                 iface->conf->channel, iface->conf->secondary_channel,
     725          13 :                 iface->conf->vht_oper_chwidth,
     726          13 :                 iface->conf->vht_oper_centr_freq_seg0_idx,
     727          13 :                 iface->conf->vht_oper_centr_freq_seg1_idx,
     728          13 :                 iface->dfs_cac_ms / 1000);
     729             : 
     730          91 :         res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
     731             :                                     iface->freq,
     732          13 :                                     iface->conf->channel,
     733          13 :                                     iface->conf->ieee80211n,
     734          13 :                                     iface->conf->ieee80211ac,
     735          13 :                                     iface->conf->secondary_channel,
     736          13 :                                     iface->conf->vht_oper_chwidth,
     737          13 :                                     iface->conf->vht_oper_centr_freq_seg0_idx,
     738          13 :                                     iface->conf->vht_oper_centr_freq_seg1_idx);
     739             : 
     740          13 :         if (res) {
     741           1 :                 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
     742           1 :                 return -1;
     743             :         }
     744             : 
     745          12 :         return 0;
     746             : }
     747             : 
     748             : 
     749          12 : int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
     750             :                              int ht_enabled, int chan_offset, int chan_width,
     751             :                              int cf1, int cf2)
     752             : {
     753          12 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
     754             :                 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
     755             :                 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
     756             : 
     757          12 :         if (success) {
     758             :                 /* Complete iface/ap configuration */
     759           6 :                 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
     760             :                         /* Complete AP configuration for the first bring up. */
     761           0 :                         if (iface->state != HAPD_IFACE_ENABLED)
     762           0 :                                 hostapd_setup_interface_complete(iface, 0);
     763             :                         else
     764           0 :                                 iface->cac_started = 0;
     765             :                 } else {
     766           6 :                         set_dfs_state(iface, freq, ht_enabled, chan_offset,
     767             :                                       chan_width, cf1, cf2,
     768             :                                       HOSTAPD_CHAN_DFS_AVAILABLE);
     769           6 :                         iface->cac_started = 0;
     770           6 :                         hostapd_setup_interface_complete(iface, 0);
     771             :                 }
     772             :         }
     773             : 
     774          12 :         return 0;
     775             : }
     776             : 
     777             : 
     778           6 : static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
     779             : {
     780             :         struct hostapd_channel_data *channel;
     781             :         int secondary_channel;
     782           6 :         u8 vht_oper_centr_freq_seg0_idx = 0;
     783           6 :         u8 vht_oper_centr_freq_seg1_idx = 0;
     784           6 :         int skip_radar = 0;
     785           6 :         int err = 1;
     786             : 
     787             :         /* Radar detected during active CAC */
     788           6 :         iface->cac_started = 0;
     789           6 :         channel = dfs_get_valid_channel(iface, &secondary_channel,
     790             :                                         &vht_oper_centr_freq_seg0_idx,
     791             :                                         &vht_oper_centr_freq_seg1_idx,
     792             :                                         skip_radar);
     793             : 
     794           6 :         if (!channel) {
     795           0 :                 wpa_printf(MSG_ERROR, "No valid channel available");
     796           0 :                 hostapd_setup_interface_complete(iface, err);
     797           0 :                 return err;
     798             :         }
     799             : 
     800           6 :         wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
     801           6 :                    channel->chan);
     802          12 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
     803             :                 "freq=%d chan=%d sec_chan=%d", channel->freq,
     804           6 :                 channel->chan, secondary_channel);
     805             : 
     806           6 :         iface->freq = channel->freq;
     807           6 :         iface->conf->channel = channel->chan;
     808           6 :         iface->conf->secondary_channel = secondary_channel;
     809           6 :         iface->conf->vht_oper_centr_freq_seg0_idx =
     810             :                 vht_oper_centr_freq_seg0_idx;
     811           6 :         iface->conf->vht_oper_centr_freq_seg1_idx =
     812             :                 vht_oper_centr_freq_seg1_idx;
     813           6 :         err = 0;
     814             : 
     815           6 :         hostapd_setup_interface_complete(iface, err);
     816           6 :         return err;
     817             : }
     818             : 
     819             : 
     820          16 : static int hostapd_csa_in_progress(struct hostapd_iface *iface)
     821             : {
     822             :         unsigned int i;
     823          32 :         for (i = 0; i < iface->num_bss; i++)
     824          16 :                 if (iface->bss[i]->csa_in_progress)
     825           0 :                         return 1;
     826          16 :         return 0;
     827             : }
     828             : 
     829             : 
     830           8 : static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
     831             : {
     832             :         struct hostapd_channel_data *channel;
     833             :         int secondary_channel;
     834             :         u8 vht_oper_centr_freq_seg0_idx;
     835             :         u8 vht_oper_centr_freq_seg1_idx;
     836           8 :         int skip_radar = 1;
     837             :         struct csa_settings csa_settings;
     838             :         unsigned int i;
     839           8 :         int err = 1;
     840             : 
     841          16 :         wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
     842           8 :                    __func__, iface->cac_started ? "yes" : "no",
     843           8 :                    hostapd_csa_in_progress(iface) ? "yes" : "no");
     844             : 
     845             :         /* Check if CSA in progress */
     846           8 :         if (hostapd_csa_in_progress(iface))
     847           0 :                 return 0;
     848             : 
     849             :         /* Check if active CAC */
     850           8 :         if (iface->cac_started)
     851           6 :                 return hostapd_dfs_start_channel_switch_cac(iface);
     852             : 
     853             :         /* Perform channel switch/CSA */
     854           2 :         channel = dfs_get_valid_channel(iface, &secondary_channel,
     855             :                                         &vht_oper_centr_freq_seg0_idx,
     856             :                                         &vht_oper_centr_freq_seg1_idx,
     857             :                                         skip_radar);
     858             : 
     859           2 :         if (!channel) {
     860             :                 /*
     861             :                  * If there is no channel to switch immediately to, check if
     862             :                  * there is another channel where we can switch even if it
     863             :                  * requires to perform a CAC first.
     864             :                  */
     865           0 :                 skip_radar = 0;
     866           0 :                 channel = dfs_get_valid_channel(iface, &secondary_channel,
     867             :                                                 &vht_oper_centr_freq_seg0_idx,
     868             :                                                 &vht_oper_centr_freq_seg1_idx,
     869             :                                                 skip_radar);
     870           0 :                 if (!channel) {
     871             :                         /* FIXME: Wait for channel(s) to become available */
     872           0 :                         hostapd_disable_iface(iface);
     873           0 :                         return err;
     874             :                 }
     875             : 
     876           0 :                 iface->freq = channel->freq;
     877           0 :                 iface->conf->channel = channel->chan;
     878           0 :                 iface->conf->secondary_channel = secondary_channel;
     879           0 :                 iface->conf->vht_oper_centr_freq_seg0_idx =
     880             :                         vht_oper_centr_freq_seg0_idx;
     881           0 :                 iface->conf->vht_oper_centr_freq_seg1_idx =
     882             :                         vht_oper_centr_freq_seg1_idx;
     883             : 
     884           0 :                 hostapd_disable_iface(iface);
     885           0 :                 hostapd_enable_iface(iface);
     886           0 :                 return 0;
     887             :         }
     888             : 
     889           2 :         wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
     890           2 :                    channel->chan);
     891           4 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
     892             :                 "freq=%d chan=%d sec_chan=%d", channel->freq,
     893           2 :                 channel->chan, secondary_channel);
     894             : 
     895             :         /* Setup CSA request */
     896           2 :         os_memset(&csa_settings, 0, sizeof(csa_settings));
     897           2 :         csa_settings.cs_count = 5;
     898           2 :         csa_settings.block_tx = 1;
     899          12 :         err = hostapd_set_freq_params(&csa_settings.freq_params,
     900           2 :                                       iface->conf->hw_mode,
     901             :                                       channel->freq,
     902           2 :                                       channel->chan,
     903           2 :                                       iface->conf->ieee80211n,
     904           2 :                                       iface->conf->ieee80211ac,
     905             :                                       secondary_channel,
     906           2 :                                       iface->conf->vht_oper_chwidth,
     907             :                                       vht_oper_centr_freq_seg0_idx,
     908             :                                       vht_oper_centr_freq_seg1_idx,
     909           2 :                                       iface->current_mode->vht_capab);
     910             : 
     911           2 :         if (err) {
     912           0 :                 wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
     913           0 :                 hostapd_disable_iface(iface);
     914           0 :                 return err;
     915             :         }
     916             : 
     917           4 :         for (i = 0; i < iface->num_bss; i++) {
     918           2 :                 err = hostapd_switch_channel(iface->bss[i], &csa_settings);
     919           2 :                 if (err)
     920           0 :                         break;
     921             :         }
     922             : 
     923           2 :         if (err) {
     924           0 :                 wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
     925             :                            err);
     926           0 :                 iface->freq = channel->freq;
     927           0 :                 iface->conf->channel = channel->chan;
     928           0 :                 iface->conf->secondary_channel = secondary_channel;
     929           0 :                 iface->conf->vht_oper_centr_freq_seg0_idx =
     930             :                         vht_oper_centr_freq_seg0_idx;
     931           0 :                 iface->conf->vht_oper_centr_freq_seg1_idx =
     932             :                         vht_oper_centr_freq_seg1_idx;
     933             : 
     934           0 :                 hostapd_disable_iface(iface);
     935           0 :                 hostapd_enable_iface(iface);
     936           0 :                 return 0;
     937             :         }
     938             : 
     939             :         /* Channel configuration will be updated once CSA completes and
     940             :          * ch_switch_notify event is received */
     941             : 
     942           2 :         wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
     943           2 :         return 0;
     944             : }
     945             : 
     946             : 
     947          10 : int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
     948             :                                int ht_enabled, int chan_offset, int chan_width,
     949             :                                int cf1, int cf2)
     950             : {
     951             :         int res;
     952             : 
     953          10 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
     954             :                 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
     955             :                 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
     956             : 
     957             :         /* Proceed only if DFS is not offloaded to the driver */
     958          10 :         if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
     959           0 :                 return 0;
     960             : 
     961          10 :         if (!iface->conf->ieee80211h)
     962           2 :                 return 0;
     963             : 
     964             :         /* mark radar frequency as invalid */
     965           8 :         set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
     966             :                       cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
     967             : 
     968             :         /* Skip if reported radar event not overlapped our channels */
     969           8 :         res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
     970           8 :         if (!res)
     971           0 :                 return 0;
     972             : 
     973             :         /* radar detected while operating, switch the channel. */
     974           8 :         res = hostapd_dfs_start_channel_switch(iface);
     975             : 
     976           8 :         return res;
     977             : }
     978             : 
     979             : 
     980           0 : int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
     981             :                              int ht_enabled, int chan_offset, int chan_width,
     982             :                              int cf1, int cf2)
     983             : {
     984           0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
     985             :                 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
     986             :                 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
     987             : 
     988             :         /* Proceed only if DFS is not offloaded to the driver */
     989           0 :         if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
     990           0 :                 return 0;
     991             : 
     992             :         /* TODO add correct implementation here */
     993           0 :         set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
     994             :                       cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
     995           0 :         return 0;
     996             : }
     997             : 
     998             : 
     999       11930 : int hostapd_is_dfs_required(struct hostapd_iface *iface)
    1000             : {
    1001             :         int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
    1002             : 
    1003       12000 :         if (!iface->conf->ieee80211h || !iface->current_mode ||
    1004          70 :             iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
    1005       11860 :                 return 0;
    1006             : 
    1007             :         /* Get start (first) channel for current configuration */
    1008          70 :         start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
    1009          70 :         if (start_chan_idx == -1)
    1010           0 :                 return -1;
    1011             : 
    1012             :         /* Get number of used channels, depend on width */
    1013          70 :         n_chans = dfs_get_used_n_chans(iface, &n_chans1);
    1014             : 
    1015             :         /* Check if any of configured channels require DFS */
    1016          70 :         res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
    1017          70 :         if (res)
    1018          37 :                 return res;
    1019          33 :         if (start_chan_idx1 >= 0 && n_chans1 > 0)
    1020           0 :                 res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
    1021          33 :         return res;
    1022             : }
    1023             : 
    1024             : 
    1025           0 : int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
    1026             :                           int ht_enabled, int chan_offset, int chan_width,
    1027             :                           int cf1, int cf2)
    1028             : {
    1029           0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
    1030             :                 "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
    1031             :                 "seg1=%d cac_time=%ds",
    1032           0 :                 freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
    1033           0 :         iface->cac_started = 1;
    1034           0 :         return 0;
    1035             : }
    1036             : 
    1037             : 
    1038             : /*
    1039             :  * Main DFS handler for offloaded case.
    1040             :  * 2 - continue channel/AP setup for non-DFS channel
    1041             :  * 1 - continue channel/AP setup for DFS channel
    1042             :  * 0 - channel/AP setup will be continued after CAC
    1043             :  * -1 - hit critical error
    1044             :  */
    1045           0 : int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
    1046             : {
    1047           0 :         wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
    1048           0 :                    __func__, iface->cac_started);
    1049             : 
    1050             :         /*
    1051             :          * If DFS has already been started, then we are being called from a
    1052             :          * callback to continue AP/channel setup. Reset the CAC start flag and
    1053             :          * return.
    1054             :          */
    1055           0 :         if (iface->cac_started) {
    1056           0 :                 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
    1057           0 :                            __func__, iface->cac_started);
    1058           0 :                 iface->cac_started = 0;
    1059           0 :                 return 1;
    1060             :         }
    1061             : 
    1062           0 :         if (ieee80211_is_dfs(iface->freq)) {
    1063           0 :                 wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
    1064             :                            __func__, iface->freq);
    1065           0 :                 return 0;
    1066             :         }
    1067             : 
    1068           0 :         wpa_printf(MSG_DEBUG,
    1069             :                    "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
    1070             :                    __func__, iface->freq);
    1071           0 :         return 2;
    1072             : }

Generated by: LCOV version 1.10