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 1393793999 Lines: 49 400 12.2 %
Date: 2014-03-02 Functions: 5 21 23.8 %
Branches: 26 186 14.0 %

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

Generated by: LCOV version 1.9