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 1426431149 Lines: 385 509 75.6 %
Date: 2015-03-15 Functions: 23 26 88.5 %

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

Generated by: LCOV version 1.10