LCOV - code coverage report
Current view: top level - src/ap - dfs.c (source / functions) Hit Total Coverage
Test: hostapd hwsim test run 1388338050 Lines: 38 373 10.2 %
Date: 2013-12-29 Functions: 4 20 20.0 %
Branches: 16 173 9.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * DFS - Dynamic Frequency Selection
       3                 :            :  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
       4                 :            :  * Copyright (c) 2013, Qualcomm Atheros, Inc.
       5                 :            :  *
       6                 :            :  * This software may be distributed under the terms of the BSD license.
       7                 :            :  * See README for more details.
       8                 :            :  */
       9                 :            : 
      10                 :            : #include "utils/includes.h"
      11                 :            : 
      12                 :            : #include "utils/common.h"
      13                 :            : #include "common/ieee802_11_defs.h"
      14                 :            : #include "common/wpa_ctrl.h"
      15                 :            : #include "hostapd.h"
      16                 :            : #include "ap_drv_ops.h"
      17                 :            : #include "drivers/driver.h"
      18                 :            : #include "dfs.h"
      19                 :            : 
      20                 :            : 
      21                 :        183 : static int dfs_get_used_n_chans(struct hostapd_iface *iface)
      22                 :            : {
      23                 :        183 :         int n_chans = 1;
      24                 :            : 
      25 [ +  - ][ +  + ]:        183 :         if (iface->conf->ieee80211n && iface->conf->secondary_channel)
      26                 :          4 :                 n_chans = 2;
      27                 :            : 
      28         [ -  + ]:        183 :         if (iface->conf->ieee80211ac) {
      29   [ #  #  #  # ]:          0 :                 switch (iface->conf->vht_oper_chwidth) {
      30                 :            :                 case VHT_CHANWIDTH_USE_HT:
      31                 :          0 :                         break;
      32                 :            :                 case VHT_CHANWIDTH_80MHZ:
      33                 :          0 :                         n_chans = 4;
      34                 :          0 :                         break;
      35                 :            :                 case VHT_CHANWIDTH_160MHZ:
      36                 :          0 :                         n_chans = 8;
      37                 :          0 :                         break;
      38                 :            :                 default:
      39                 :          0 :                         break;
      40                 :            :                 }
      41                 :            :         }
      42                 :            : 
      43                 :        183 :         return n_chans;
      44                 :            : }
      45                 :            : 
      46                 :            : 
      47                 :          0 : static int dfs_channel_available(struct hostapd_channel_data *chan,
      48                 :            :                                  int skip_radar)
      49                 :            : {
      50                 :            :         /*
      51                 :            :          * When radar detection happens, CSA is performed. However, there's no
      52                 :            :          * time for CAC, so radar channels must be skipped when finding a new
      53                 :            :          * channel for CSA.
      54                 :            :          */
      55 [ #  # ][ #  # ]:          0 :         if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
      56                 :          0 :                 return 0;
      57                 :            : 
      58         [ #  # ]:          0 :         if (chan->flag & HOSTAPD_CHAN_DISABLED)
      59                 :          0 :                 return 0;
      60 [ #  # ][ #  # ]:          0 :         if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
      61                 :          0 :             ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
      62                 :            :              HOSTAPD_CHAN_DFS_UNAVAILABLE))
      63                 :          0 :                 return 0;
      64                 :          0 :         return 1;
      65                 :            : }
      66                 :            : 
      67                 :            : 
      68                 :          0 : static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
      69                 :            : {
      70                 :            :         /*
      71                 :            :          * The tables contain first valid channel number based on channel width.
      72                 :            :          * We will also choose this first channel as the control one.
      73                 :            :          */
      74                 :          0 :         int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
      75                 :            :                              184, 192 };
      76                 :            :         /*
      77                 :            :          * VHT80, valid channels based on center frequency:
      78                 :            :          * 42, 58, 106, 122, 138, 155
      79                 :            :          */
      80                 :          0 :         int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
      81                 :          0 :         int *allowed = allowed_40;
      82                 :          0 :         unsigned int i, allowed_no = 0;
      83                 :            : 
      84      [ #  #  # ]:          0 :         switch (n_chans) {
      85                 :            :         case 2:
      86                 :          0 :                 allowed = allowed_40;
      87                 :          0 :                 allowed_no = ARRAY_SIZE(allowed_40);
      88                 :          0 :                 break;
      89                 :            :         case 4:
      90                 :          0 :                 allowed = allowed_80;
      91                 :          0 :                 allowed_no = ARRAY_SIZE(allowed_80);
      92                 :          0 :                 break;
      93                 :            :         default:
      94                 :          0 :                 wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
      95                 :          0 :                 break;
      96                 :            :         }
      97                 :            : 
      98         [ #  # ]:          0 :         for (i = 0; i < allowed_no; i++) {
      99         [ #  # ]:          0 :                 if (chan->chan == allowed[i])
     100                 :          0 :                         return 1;
     101                 :            :         }
     102                 :            : 
     103                 :          0 :         return 0;
     104                 :            : }
     105                 :            : 
     106                 :            : 
     107                 :          0 : static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
     108                 :            :                                     int first_chan_idx, int num_chans,
     109                 :            :                                     int skip_radar)
     110                 :            : {
     111                 :            :         struct hostapd_channel_data *first_chan, *chan;
     112                 :            :         int i;
     113                 :            : 
     114         [ #  # ]:          0 :         if (first_chan_idx + num_chans >= mode->num_channels)
     115                 :          0 :                 return 0;
     116                 :            : 
     117                 :          0 :         first_chan = &mode->channels[first_chan_idx];
     118                 :            : 
     119         [ #  # ]:          0 :         for (i = 0; i < num_chans; i++) {
     120                 :          0 :                 chan = &mode->channels[first_chan_idx + i];
     121                 :            : 
     122         [ #  # ]:          0 :                 if (first_chan->freq + i * 20 != chan->freq)
     123                 :          0 :                         return 0;
     124                 :            : 
     125         [ #  # ]:          0 :                 if (!dfs_channel_available(chan, skip_radar))
     126                 :          0 :                         return 0;
     127                 :            :         }
     128                 :            : 
     129                 :          0 :         return 1;
     130                 :            : }
     131                 :            : 
     132                 :            : 
     133                 :            : /*
     134                 :            :  * The function assumes HT40+ operation.
     135                 :            :  * Make sure to adjust the following variables after calling this:
     136                 :            :  *  - hapd->secondary_channel
     137                 :            :  *  - hapd->vht_oper_centr_freq_seg0_idx
     138                 :            :  *  - hapd->vht_oper_centr_freq_seg1_idx
     139                 :            :  */
     140                 :          0 : static int dfs_find_channel(struct hostapd_iface *iface,
     141                 :            :                             struct hostapd_channel_data **ret_chan,
     142                 :            :                             int idx, int skip_radar)
     143                 :            : {
     144                 :            :         struct hostapd_hw_modes *mode;
     145                 :            :         struct hostapd_channel_data *chan;
     146                 :          0 :         int i, channel_idx = 0, n_chans;
     147                 :            : 
     148                 :          0 :         mode = iface->current_mode;
     149                 :          0 :         n_chans = dfs_get_used_n_chans(iface);
     150                 :            : 
     151                 :          0 :         wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
     152         [ #  # ]:          0 :         for (i = 0; i < mode->num_channels; i++) {
     153                 :          0 :                 chan = &mode->channels[i];
     154                 :            : 
     155                 :            :                 /* Skip HT40/VHT incompatible channels */
     156 [ #  # ][ #  # ]:          0 :                 if (iface->conf->ieee80211n &&
     157         [ #  # ]:          0 :                     iface->conf->secondary_channel &&
     158                 :          0 :                     !dfs_is_chan_allowed(chan, n_chans))
     159                 :          0 :                         continue;
     160                 :            : 
     161                 :            :                 /* Skip incompatible chandefs */
     162         [ #  # ]:          0 :                 if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
     163                 :          0 :                         continue;
     164                 :            : 
     165 [ #  # ][ #  # ]:          0 :                 if (ret_chan && idx == channel_idx) {
     166                 :          0 :                         wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
     167                 :          0 :                         *ret_chan = chan;
     168                 :          0 :                         return idx;
     169                 :            :                 }
     170                 :          0 :                 wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
     171                 :          0 :                 channel_idx++;
     172                 :            :         }
     173                 :          0 :         return channel_idx;
     174                 :            : }
     175                 :            : 
     176                 :            : 
     177                 :          0 : static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
     178                 :            :                                        struct hostapd_channel_data *chan,
     179                 :            :                                        u8 *vht_oper_centr_freq_seg0_idx,
     180                 :            :                                        u8 *vht_oper_centr_freq_seg1_idx)
     181                 :            : {
     182         [ #  # ]:          0 :         if (!iface->conf->ieee80211ac)
     183                 :          0 :                 return;
     184                 :            : 
     185         [ #  # ]:          0 :         if (!chan)
     186                 :          0 :                 return;
     187                 :            : 
     188                 :          0 :         *vht_oper_centr_freq_seg1_idx = 0;
     189                 :            : 
     190   [ #  #  #  # ]:          0 :         switch (iface->conf->vht_oper_chwidth) {
     191                 :            :         case VHT_CHANWIDTH_USE_HT:
     192         [ #  # ]:          0 :                 if (iface->conf->secondary_channel == 1)
     193                 :          0 :                         *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
     194         [ #  # ]:          0 :                 else if (iface->conf->secondary_channel == -1)
     195                 :          0 :                         *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
     196                 :            :                 else
     197                 :          0 :                         *vht_oper_centr_freq_seg0_idx = chan->chan;
     198                 :          0 :                 break;
     199                 :            :         case VHT_CHANWIDTH_80MHZ:
     200                 :          0 :                 *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
     201                 :          0 :                 break;
     202                 :            :         case VHT_CHANWIDTH_160MHZ:
     203                 :          0 :                 *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
     204                 :          0 :                 break;
     205                 :            :         default:
     206                 :          0 :                 wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
     207                 :          0 :                 break;
     208                 :            :         }
     209                 :            : 
     210                 :          0 :         wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
     211                 :          0 :                    *vht_oper_centr_freq_seg0_idx,
     212                 :          0 :                    *vht_oper_centr_freq_seg1_idx);
     213                 :            : }
     214                 :            : 
     215                 :            : 
     216                 :            : /* Return start channel idx we will use for mode->channels[idx] */
     217                 :        183 : static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
     218                 :            : {
     219                 :            :         struct hostapd_hw_modes *mode;
     220                 :            :         struct hostapd_channel_data *chan;
     221                 :        183 :         int channel_no = iface->conf->channel;
     222                 :        183 :         int res = -1, i;
     223                 :            : 
     224                 :            :         /* HT40- */
     225 [ +  - ][ +  + ]:        183 :         if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
     226                 :          1 :                 channel_no -= 4;
     227                 :            : 
     228                 :            :         /* VHT */
     229         [ -  + ]:        183 :         if (iface->conf->ieee80211ac) {
     230   [ #  #  #  # ]:          0 :                 switch (iface->conf->vht_oper_chwidth) {
     231                 :            :                 case VHT_CHANWIDTH_USE_HT:
     232                 :          0 :                         break;
     233                 :            :                 case VHT_CHANWIDTH_80MHZ:
     234                 :          0 :                         channel_no =
     235                 :          0 :                                 iface->conf->vht_oper_centr_freq_seg0_idx - 6;
     236                 :          0 :                         break;
     237                 :            :                 case VHT_CHANWIDTH_160MHZ:
     238                 :          0 :                         channel_no =
     239                 :          0 :                                 iface->conf->vht_oper_centr_freq_seg0_idx - 14;
     240                 :          0 :                         break;
     241                 :            :                 default:
     242                 :          0 :                         wpa_printf(MSG_INFO,
     243                 :            :                                    "DFS only VHT20/40/80/160 is supported now");
     244                 :          0 :                         channel_no = -1;
     245                 :          0 :                         break;
     246                 :            :                 }
     247                 :            :         }
     248                 :            : 
     249                 :            :         /* Get idx */
     250                 :        183 :         mode = iface->current_mode;
     251         [ +  - ]:        183 :         for (i = 0; i < mode->num_channels; i++) {
     252                 :        183 :                 chan = &mode->channels[i];
     253         [ +  - ]:        183 :                 if (chan->chan == channel_no) {
     254                 :        183 :                         res = i;
     255                 :        183 :                         break;
     256                 :            :                 }
     257                 :            :         }
     258                 :            : 
     259         [ -  + ]:        183 :         if (res == -1)
     260                 :          0 :                 wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1");
     261                 :            : 
     262                 :        183 :         return res;
     263                 :            : }
     264                 :            : 
     265                 :            : 
     266                 :            : /* At least one channel have radar flag */
     267                 :        183 : static int dfs_check_chans_radar(struct hostapd_iface *iface,
     268                 :            :                                  int start_chan_idx, int n_chans)
     269                 :            : {
     270                 :            :         struct hostapd_channel_data *channel;
     271                 :            :         struct hostapd_hw_modes *mode;
     272                 :        183 :         int i, res = 0;
     273                 :            : 
     274                 :        183 :         mode = iface->current_mode;
     275                 :            : 
     276         [ +  + ]:        370 :         for (i = 0; i < n_chans; i++) {
     277                 :        187 :                 channel = &mode->channels[start_chan_idx + i];
     278         [ -  + ]:        187 :                 if (channel->flag & HOSTAPD_CHAN_RADAR)
     279                 :          0 :                         res++;
     280                 :            :         }
     281                 :            : 
     282                 :        183 :         return res;
     283                 :            : }
     284                 :            : 
     285                 :            : 
     286                 :            : /* All channels available */
     287                 :          0 : static int dfs_check_chans_available(struct hostapd_iface *iface,
     288                 :            :                                      int start_chan_idx, int n_chans)
     289                 :            : {
     290                 :            :         struct hostapd_channel_data *channel;
     291                 :            :         struct hostapd_hw_modes *mode;
     292                 :            :         int i;
     293                 :            : 
     294                 :          0 :         mode = iface->current_mode;
     295                 :            : 
     296         [ #  # ]:          0 :         for(i = 0; i < n_chans; i++) {
     297                 :          0 :                 channel = &mode->channels[start_chan_idx + i];
     298         [ #  # ]:          0 :                 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
     299                 :            :                     HOSTAPD_CHAN_DFS_AVAILABLE)
     300                 :          0 :                         break;
     301                 :            :         }
     302                 :            : 
     303                 :          0 :         return i == n_chans;
     304                 :            : }
     305                 :            : 
     306                 :            : 
     307                 :            : /* At least one channel unavailable */
     308                 :          0 : static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
     309                 :            :                                        int start_chan_idx,
     310                 :            :                                        int n_chans)
     311                 :            : {
     312                 :            :         struct hostapd_channel_data *channel;
     313                 :            :         struct hostapd_hw_modes *mode;
     314                 :          0 :         int i, res = 0;
     315                 :            : 
     316                 :          0 :         mode = iface->current_mode;
     317                 :            : 
     318         [ #  # ]:          0 :         for(i = 0; i < n_chans; i++) {
     319                 :          0 :                 channel = &mode->channels[start_chan_idx + i];
     320         [ #  # ]:          0 :                 if (channel->flag & HOSTAPD_CHAN_DISABLED)
     321                 :          0 :                         res++;
     322         [ #  # ]:          0 :                 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
     323                 :            :                     HOSTAPD_CHAN_DFS_UNAVAILABLE)
     324                 :          0 :                         res++;
     325                 :            :         }
     326                 :            : 
     327                 :          0 :         return res;
     328                 :            : }
     329                 :            : 
     330                 :            : 
     331                 :            : static struct hostapd_channel_data *
     332                 :          0 : dfs_get_valid_channel(struct hostapd_iface *iface,
     333                 :            :                       int *secondary_channel,
     334                 :            :                       u8 *vht_oper_centr_freq_seg0_idx,
     335                 :            :                       u8 *vht_oper_centr_freq_seg1_idx,
     336                 :            :                       int skip_radar)
     337                 :            : {
     338                 :            :         struct hostapd_hw_modes *mode;
     339                 :          0 :         struct hostapd_channel_data *chan = NULL;
     340                 :            :         int num_available_chandefs;
     341                 :            :         int chan_idx;
     342                 :            :         u32 _rand;
     343                 :            : 
     344                 :          0 :         wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
     345                 :            : 
     346         [ #  # ]:          0 :         if (iface->current_mode == NULL)
     347                 :          0 :                 return NULL;
     348                 :            : 
     349                 :          0 :         mode = iface->current_mode;
     350         [ #  # ]:          0 :         if (mode->mode != HOSTAPD_MODE_IEEE80211A)
     351                 :          0 :                 return NULL;
     352                 :            : 
     353                 :            :         /* Get the count first */
     354                 :          0 :         num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
     355         [ #  # ]:          0 :         if (num_available_chandefs == 0)
     356                 :          0 :                 return NULL;
     357                 :            : 
     358                 :          0 :         os_get_random((u8 *) &_rand, sizeof(_rand));
     359                 :          0 :         chan_idx = _rand % num_available_chandefs;
     360                 :          0 :         dfs_find_channel(iface, &chan, chan_idx, skip_radar);
     361                 :            : 
     362                 :            :         /* dfs_find_channel() calculations assume HT40+ */
     363         [ #  # ]:          0 :         if (iface->conf->secondary_channel)
     364                 :          0 :                 *secondary_channel = 1;
     365                 :            :         else
     366                 :          0 :                 *secondary_channel = 0;
     367                 :            : 
     368                 :          0 :         dfs_adjust_vht_center_freq(iface, chan,
     369                 :            :                                    vht_oper_centr_freq_seg0_idx,
     370                 :            :                                    vht_oper_centr_freq_seg1_idx);
     371                 :            : 
     372                 :          0 :         return chan;
     373                 :            : }
     374                 :            : 
     375                 :            : 
     376                 :          0 : static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
     377                 :            : {
     378                 :            :         struct hostapd_hw_modes *mode;
     379                 :          0 :         struct hostapd_channel_data *chan = NULL;
     380                 :            :         int i;
     381                 :            : 
     382                 :          0 :         mode = iface->current_mode;
     383         [ #  # ]:          0 :         if (mode == NULL)
     384                 :          0 :                 return 0;
     385                 :            : 
     386                 :          0 :         wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
     387         [ #  # ]:          0 :         for (i = 0; i < iface->current_mode->num_channels; i++) {
     388                 :          0 :                 chan = &iface->current_mode->channels[i];
     389         [ #  # ]:          0 :                 if (chan->freq == freq) {
     390         [ #  # ]:          0 :                         if (chan->flag & HOSTAPD_CHAN_RADAR) {
     391                 :          0 :                                 chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
     392                 :          0 :                                 chan->flag |= state;
     393                 :          0 :                                 return 1; /* Channel found */
     394                 :            :                         }
     395                 :            :                 }
     396                 :            :         }
     397                 :          0 :         wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
     398                 :          0 :         return 0;
     399                 :            : }
     400                 :            : 
     401                 :            : 
     402                 :          0 : static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
     403                 :            :                          int chan_offset, int chan_width, int cf1,
     404                 :            :                          int cf2, u32 state)
     405                 :            : {
     406                 :          0 :         int n_chans = 1, i;
     407                 :            :         struct hostapd_hw_modes *mode;
     408                 :          0 :         int frequency = freq;
     409                 :          0 :         int ret = 0;
     410                 :            : 
     411                 :          0 :         mode = iface->current_mode;
     412         [ #  # ]:          0 :         if (mode == NULL)
     413                 :          0 :                 return 0;
     414                 :            : 
     415         [ #  # ]:          0 :         if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
     416                 :          0 :                 wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
     417                 :          0 :                 return 0;
     418                 :            :         }
     419                 :            : 
     420                 :            :         /* Seems cf1 and chan_width is enough here */
     421   [ #  #  #  #  :          0 :         switch (chan_width) {
                      # ]
     422                 :            :         case CHAN_WIDTH_20_NOHT:
     423                 :            :         case CHAN_WIDTH_20:
     424                 :          0 :                 n_chans = 1;
     425         [ #  # ]:          0 :                 if (frequency == 0)
     426                 :          0 :                         frequency = cf1;
     427                 :          0 :                 break;
     428                 :            :         case CHAN_WIDTH_40:
     429                 :          0 :                 n_chans = 2;
     430                 :          0 :                 frequency = cf1 - 10;
     431                 :          0 :                 break;
     432                 :            :         case CHAN_WIDTH_80:
     433                 :          0 :                 n_chans = 4;
     434                 :          0 :                 frequency = cf1 - 30;
     435                 :          0 :                 break;
     436                 :            :         case CHAN_WIDTH_160:
     437                 :          0 :                 n_chans = 8;
     438                 :          0 :                 frequency = cf1 - 70;
     439                 :          0 :                 break;
     440                 :            :         default:
     441                 :          0 :                 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
     442                 :            :                            chan_width);
     443                 :          0 :                 break;
     444                 :            :         }
     445                 :            : 
     446                 :          0 :         wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
     447                 :            :                    n_chans);
     448         [ #  # ]:          0 :         for (i = 0; i < n_chans; i++) {
     449                 :          0 :                 ret += set_dfs_state_freq(iface, frequency, state);
     450                 :          0 :                 frequency = frequency + 20;
     451                 :            :         }
     452                 :            : 
     453                 :          0 :         return ret;
     454                 :            : }
     455                 :            : 
     456                 :            : 
     457                 :          0 : static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
     458                 :            :                                        int chan_width, int cf1, int cf2)
     459                 :            : {
     460                 :            :         int start_chan_idx;
     461                 :            :         struct hostapd_hw_modes *mode;
     462                 :            :         struct hostapd_channel_data *chan;
     463                 :          0 :         int n_chans, i, j, frequency = freq, radar_n_chans = 1;
     464                 :            :         u8 radar_chan;
     465                 :          0 :         int res = 0;
     466                 :            : 
     467                 :            :         /* Our configuration */
     468                 :          0 :         mode = iface->current_mode;
     469                 :          0 :         start_chan_idx = dfs_get_start_chan_idx(iface);
     470                 :          0 :         n_chans = dfs_get_used_n_chans(iface);
     471                 :            : 
     472                 :            :         /* Check we are on DFS channel(s) */
     473         [ #  # ]:          0 :         if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
     474                 :          0 :                 return 0;
     475                 :            : 
     476                 :            :         /* Reported via radar event */
     477   [ #  #  #  #  :          0 :         switch (chan_width) {
                      # ]
     478                 :            :         case CHAN_WIDTH_20_NOHT:
     479                 :            :         case CHAN_WIDTH_20:
     480                 :          0 :                 radar_n_chans = 1;
     481         [ #  # ]:          0 :                 if (frequency == 0)
     482                 :          0 :                         frequency = cf1;
     483                 :          0 :                 break;
     484                 :            :         case CHAN_WIDTH_40:
     485                 :          0 :                 radar_n_chans = 2;
     486                 :          0 :                 frequency = cf1 - 10;
     487                 :          0 :                 break;
     488                 :            :         case CHAN_WIDTH_80:
     489                 :          0 :                 radar_n_chans = 4;
     490                 :          0 :                 frequency = cf1 - 30;
     491                 :          0 :                 break;
     492                 :            :         case CHAN_WIDTH_160:
     493                 :          0 :                 radar_n_chans = 8;
     494                 :          0 :                 frequency = cf1 - 70;
     495                 :          0 :                 break;
     496                 :            :         default:
     497                 :          0 :                 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
     498                 :            :                            chan_width);
     499                 :          0 :                 break;
     500                 :            :         }
     501                 :            : 
     502                 :          0 :         ieee80211_freq_to_chan(frequency, &radar_chan);
     503                 :            : 
     504         [ #  # ]:          0 :         for (i = 0; i < n_chans; i++) {
     505                 :          0 :                 chan = &mode->channels[start_chan_idx + i];
     506         [ #  # ]:          0 :                 if (!(chan->flag & HOSTAPD_CHAN_RADAR))
     507                 :          0 :                         continue;
     508         [ #  # ]:          0 :                 for (j = 0; j < radar_n_chans; j++) {
     509                 :          0 :                         wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
     510                 :          0 :                                    chan->chan, radar_chan + j * 4);
     511         [ #  # ]:          0 :                         if (chan->chan == radar_chan + j * 4)
     512                 :          0 :                                 res++;
     513                 :            :                 }
     514                 :            :         }
     515                 :            : 
     516                 :          0 :         wpa_printf(MSG_DEBUG, "overlapped: %d", res);
     517                 :            : 
     518                 :          0 :         return res;
     519                 :            : }
     520                 :            : 
     521                 :            : 
     522                 :            : /*
     523                 :            :  * Main DFS handler
     524                 :            :  * 1 - continue channel/ap setup
     525                 :            :  * 0 - channel/ap setup will be continued after CAC
     526                 :            :  * -1 - hit critical error
     527                 :            :  */
     528                 :        183 : int hostapd_handle_dfs(struct hostapd_iface *iface)
     529                 :            : {
     530                 :            :         struct hostapd_channel_data *channel;
     531                 :            :         int res, n_chans, start_chan_idx;
     532                 :        183 :         int skip_radar = 0;
     533                 :            : 
     534                 :        183 :         iface->cac_started = 0;
     535                 :            : 
     536                 :            :         do {
     537                 :            :                 /* Get start (first) channel for current configuration */
     538                 :        183 :                 start_chan_idx = dfs_get_start_chan_idx(iface);
     539         [ -  + ]:        183 :                 if (start_chan_idx == -1)
     540                 :          0 :                         return -1;
     541                 :            : 
     542                 :            :                 /* Get number of used channels, depend on width */
     543                 :        183 :                 n_chans = dfs_get_used_n_chans(iface);
     544                 :            : 
     545                 :            :                 /* Check if any of configured channels require DFS */
     546                 :        183 :                 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
     547                 :        183 :                 wpa_printf(MSG_DEBUG,
     548                 :            :                            "DFS %d channels required radar detection",
     549                 :            :                            res);
     550         [ +  - ]:        183 :                 if (!res)
     551                 :        183 :                         return 1;
     552                 :            : 
     553                 :            :                 /* Check if all channels are DFS available */
     554                 :          0 :                 res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
     555         [ #  # ]:          0 :                 wpa_printf(MSG_DEBUG,
     556                 :            :                            "DFS all channels available, (SKIP CAC): %s",
     557                 :            :                            res ? "yes" : "no");
     558         [ #  # ]:          0 :                 if (res)
     559                 :          0 :                         return 1;
     560                 :            : 
     561                 :            :                 /* Check if any of configured channels is unavailable */
     562                 :          0 :                 res = dfs_check_chans_unavailable(iface, start_chan_idx,
     563                 :            :                                                   n_chans);
     564         [ #  # ]:          0 :                 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
     565                 :            :                            res, res ? "yes": "no");
     566         [ #  # ]:          0 :                 if (res) {
     567                 :            :                         int sec;
     568                 :            :                         u8 cf1, cf2;
     569                 :            : 
     570                 :          0 :                         channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
     571                 :            :                                                         skip_radar);
     572         [ #  # ]:          0 :                         if (!channel) {
     573                 :          0 :                                 wpa_printf(MSG_ERROR, "could not get valid channel");
     574                 :          0 :                                 return -1;
     575                 :            :                         }
     576                 :            : 
     577                 :          0 :                         iface->freq = channel->freq;
     578                 :          0 :                         iface->conf->channel = channel->chan;
     579                 :          0 :                         iface->conf->secondary_channel = sec;
     580                 :          0 :                         iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
     581                 :          0 :                         iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
     582                 :            :                 }
     583         [ #  # ]:          0 :         } while (res);
     584                 :            : 
     585                 :            :         /* Finally start CAC */
     586                 :          0 :         hostapd_set_state(iface, HAPD_IFACE_DFS);
     587                 :          0 :         wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
     588                 :          0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
     589                 :            :                 "freq=%d chan=%d sec_chan=%d",
     590                 :            :                 iface->freq,
     591                 :          0 :                 iface->conf->channel, iface->conf->secondary_channel);
     592         [ #  # ]:          0 :         if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
     593                 :            :                                   iface->freq,
     594                 :          0 :                                   iface->conf->channel,
     595                 :          0 :                                   iface->conf->ieee80211n,
     596                 :          0 :                                   iface->conf->ieee80211ac,
     597                 :          0 :                                   iface->conf->secondary_channel,
     598                 :          0 :                                   iface->conf->vht_oper_chwidth,
     599                 :          0 :                                   iface->conf->vht_oper_centr_freq_seg0_idx,
     600                 :          0 :                                   iface->conf->vht_oper_centr_freq_seg1_idx)) {
     601                 :          0 :                 wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
     602                 :          0 :                 return -1;
     603                 :            :         }
     604                 :            : 
     605                 :        183 :         return 0;
     606                 :            : }
     607                 :            : 
     608                 :            : 
     609                 :          0 : int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
     610                 :            :                              int ht_enabled, int chan_offset, int chan_width,
     611                 :            :                              int cf1, int cf2)
     612                 :            : {
     613                 :          0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
     614                 :            :                 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
     615                 :            :                 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
     616                 :            : 
     617         [ #  # ]:          0 :         if (success) {
     618                 :            :                 /* Complete iface/ap configuration */
     619                 :          0 :                 set_dfs_state(iface, freq, ht_enabled, chan_offset,
     620                 :            :                               chan_width, cf1, cf2,
     621                 :            :                               HOSTAPD_CHAN_DFS_AVAILABLE);
     622                 :          0 :                 iface->cac_started = 0;
     623                 :          0 :                 hostapd_setup_interface_complete(iface, 0);
     624                 :            :         }
     625                 :            : 
     626                 :          0 :         return 0;
     627                 :            : }
     628                 :            : 
     629                 :            : 
     630                 :          0 : static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
     631                 :            : {
     632                 :            :         struct hostapd_channel_data *channel;
     633                 :            :         int secondary_channel;
     634                 :            :         u8 vht_oper_centr_freq_seg0_idx;
     635                 :            :         u8 vht_oper_centr_freq_seg1_idx;
     636                 :          0 :         int skip_radar = 0;
     637                 :          0 :         int err = 1;
     638                 :            : 
     639                 :            :         /* Radar detected during active CAC */
     640                 :          0 :         iface->cac_started = 0;
     641                 :          0 :         channel = dfs_get_valid_channel(iface, &secondary_channel,
     642                 :            :                                         &vht_oper_centr_freq_seg0_idx,
     643                 :            :                                         &vht_oper_centr_freq_seg1_idx,
     644                 :            :                                         skip_radar);
     645                 :            : 
     646         [ #  # ]:          0 :         if (!channel) {
     647                 :          0 :                 wpa_printf(MSG_ERROR, "No valid channel available");
     648                 :          0 :                 hostapd_setup_interface_complete(iface, err);
     649                 :          0 :                 return err;
     650                 :            :         }
     651                 :            : 
     652                 :          0 :         wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
     653                 :          0 :                    channel->chan);
     654                 :          0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
     655                 :            :                 "freq=%d chan=%d sec_chan=%d", channel->freq,
     656                 :          0 :                 channel->chan, secondary_channel);
     657                 :            : 
     658                 :          0 :         iface->freq = channel->freq;
     659                 :          0 :         iface->conf->channel = channel->chan;
     660                 :          0 :         iface->conf->secondary_channel = secondary_channel;
     661                 :          0 :         iface->conf->vht_oper_centr_freq_seg0_idx =
     662                 :            :                 vht_oper_centr_freq_seg0_idx;
     663                 :          0 :         iface->conf->vht_oper_centr_freq_seg1_idx =
     664                 :            :                 vht_oper_centr_freq_seg1_idx;
     665                 :          0 :         err = 0;
     666                 :            : 
     667                 :          0 :         hostapd_setup_interface_complete(iface, err);
     668                 :          0 :         return err;
     669                 :            : }
     670                 :            : 
     671                 :            : 
     672                 :          0 : static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
     673                 :            : {
     674                 :            :         struct hostapd_channel_data *channel;
     675                 :            :         int secondary_channel;
     676                 :            :         u8 vht_oper_centr_freq_seg0_idx;
     677                 :            :         u8 vht_oper_centr_freq_seg1_idx;
     678                 :          0 :         int skip_radar = 1;
     679                 :            :         struct csa_settings csa_settings;
     680                 :          0 :         struct hostapd_data *hapd = iface->bss[0];
     681                 :          0 :         int err = 1;
     682                 :            : 
     683         [ #  # ]:          0 :         wpa_printf(MSG_DEBUG, "%s called (CAC active: %s)", __func__,
     684                 :          0 :                    iface->cac_started ? "yes" : "no");
     685                 :            : 
     686                 :            :         /* Check if active CAC */
     687         [ #  # ]:          0 :         if (iface->cac_started)
     688                 :          0 :                 return hostapd_dfs_start_channel_switch_cac(iface);
     689                 :            : 
     690                 :            : 
     691                 :            :         /* Perform channel switch/CSA */
     692                 :          0 :         channel = dfs_get_valid_channel(iface, &secondary_channel,
     693                 :            :                                         &vht_oper_centr_freq_seg0_idx,
     694                 :            :                                         &vht_oper_centr_freq_seg1_idx,
     695                 :            :                                         skip_radar);
     696                 :            : 
     697         [ #  # ]:          0 :         if (!channel) {
     698                 :            :                 /* FIXME: Wait for channel(s) to become available */
     699                 :          0 :                 hostapd_disable_iface(iface);
     700                 :          0 :                 return err;
     701                 :            :         }
     702                 :            : 
     703                 :          0 :         wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
     704                 :          0 :                    channel->chan);
     705                 :          0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
     706                 :            :                 "freq=%d chan=%d sec_chan=%d", channel->freq,
     707                 :          0 :                 channel->chan, secondary_channel);
     708                 :            : 
     709                 :            :         /* Setup CSA request */
     710                 :          0 :         os_memset(&csa_settings, 0, sizeof(csa_settings));
     711                 :          0 :         csa_settings.cs_count = 5;
     712                 :          0 :         csa_settings.block_tx = 1;
     713                 :          0 :         err = hostapd_set_freq_params(&csa_settings.freq_params,
     714                 :          0 :                                       iface->conf->hw_mode,
     715                 :            :                                       channel->freq,
     716                 :          0 :                                       channel->chan,
     717                 :          0 :                                       iface->conf->ieee80211n,
     718                 :          0 :                                       iface->conf->ieee80211ac,
     719                 :            :                                       secondary_channel,
     720                 :          0 :                                       iface->conf->vht_oper_chwidth,
     721                 :            :                                       vht_oper_centr_freq_seg0_idx,
     722                 :            :                                       vht_oper_centr_freq_seg1_idx,
     723                 :          0 :                                       iface->current_mode->vht_capab);
     724                 :            : 
     725         [ #  # ]:          0 :         if (err) {
     726                 :          0 :                 wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
     727                 :          0 :                 hostapd_disable_iface(iface);
     728                 :          0 :                 return err;
     729                 :            :         }
     730                 :            : 
     731                 :          0 :         err = hostapd_switch_channel(hapd, &csa_settings);
     732         [ #  # ]:          0 :         if (err) {
     733                 :          0 :                 wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
     734                 :            :                            err);
     735                 :          0 :                 iface->freq = channel->freq;
     736                 :          0 :                 iface->conf->channel = channel->chan;
     737                 :          0 :                 iface->conf->secondary_channel = secondary_channel;
     738                 :          0 :                 iface->conf->vht_oper_centr_freq_seg0_idx =
     739                 :            :                         vht_oper_centr_freq_seg0_idx;
     740                 :          0 :                 iface->conf->vht_oper_centr_freq_seg1_idx =
     741                 :            :                         vht_oper_centr_freq_seg1_idx;
     742                 :            : 
     743                 :          0 :                 hostapd_disable_iface(iface);
     744                 :          0 :                 hostapd_enable_iface(iface);
     745                 :          0 :                 return 0;
     746                 :            :         }
     747                 :            : 
     748                 :            :         /* Channel configuration will be updated once CSA completes and
     749                 :            :          * ch_switch_notify event is received */
     750                 :            : 
     751                 :          0 :         wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
     752                 :          0 :         return 0;
     753                 :            : }
     754                 :            : 
     755                 :            : 
     756                 :          0 : int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
     757                 :            :                                int ht_enabled, int chan_offset, int chan_width,
     758                 :            :                                int cf1, int cf2)
     759                 :            : {
     760                 :            :         int res;
     761                 :            : 
     762         [ #  # ]:          0 :         if (!iface->conf->ieee80211h)
     763                 :          0 :                 return 0;
     764                 :            : 
     765                 :          0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
     766                 :            :                 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
     767                 :            :                 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
     768                 :            : 
     769                 :            :         /* mark radar frequency as invalid */
     770                 :          0 :         res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
     771                 :            :                             chan_width, cf1, cf2,
     772                 :            :                             HOSTAPD_CHAN_DFS_UNAVAILABLE);
     773                 :            : 
     774                 :            :         /* Skip if reported radar event not overlapped our channels */
     775                 :          0 :         res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
     776         [ #  # ]:          0 :         if (!res)
     777                 :          0 :                 return 0;
     778                 :            : 
     779                 :            :         /* radar detected while operating, switch the channel. */
     780                 :          0 :         res = hostapd_dfs_start_channel_switch(iface);
     781                 :            : 
     782                 :          0 :         return res;
     783                 :            : }
     784                 :            : 
     785                 :            : 
     786                 :          0 : int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
     787                 :            :                              int ht_enabled, int chan_offset, int chan_width,
     788                 :            :                              int cf1, int cf2)
     789                 :            : {
     790                 :          0 :         wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
     791                 :            :                 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
     792                 :            :                 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
     793                 :            :         /* TODO add correct implementation here */
     794                 :          0 :         set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
     795                 :            :                       cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
     796                 :          0 :         return 0;
     797                 :            : }

Generated by: LCOV version 1.9