LCOV - code coverage report
Current view: top level - src/ap - hw_features.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 364 474 76.8 %
Date: 2015-09-27 Functions: 27 28 96.4 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / Hardware feature query and different modes
       3             :  * Copyright 2002-2003, Instant802 Networks, Inc.
       4             :  * Copyright 2005-2006, Devicescape Software, Inc.
       5             :  * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
       6             :  *
       7             :  * This software may be distributed under the terms of the BSD license.
       8             :  * See README for more details.
       9             :  */
      10             : 
      11             : #include "utils/includes.h"
      12             : 
      13             : #include "utils/common.h"
      14             : #include "utils/eloop.h"
      15             : #include "common/ieee802_11_defs.h"
      16             : #include "common/ieee802_11_common.h"
      17             : #include "common/wpa_ctrl.h"
      18             : #include "common/hw_features_common.h"
      19             : #include "hostapd.h"
      20             : #include "ap_config.h"
      21             : #include "ap_drv_ops.h"
      22             : #include "acs.h"
      23             : #include "ieee802_11.h"
      24             : #include "beacon.h"
      25             : #include "hw_features.h"
      26             : 
      27             : 
      28        4246 : void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
      29             :                               size_t num_hw_features)
      30             : {
      31             :         size_t i;
      32             : 
      33        4246 :         if (hw_features == NULL)
      34        6481 :                 return;
      35             : 
      36        8044 :         for (i = 0; i < num_hw_features; i++) {
      37        6033 :                 os_free(hw_features[i].channels);
      38        6033 :                 os_free(hw_features[i].rates);
      39             :         }
      40             : 
      41        2011 :         os_free(hw_features);
      42             : }
      43             : 
      44             : 
      45             : #ifndef CONFIG_NO_STDOUT_DEBUG
      46         158 : static char * dfs_info(struct hostapd_channel_data *chan)
      47             : {
      48             :         static char info[256];
      49             :         char *state;
      50             : 
      51         158 :         switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
      52             :         case HOSTAPD_CHAN_DFS_UNKNOWN:
      53           0 :                 state = "unknown";
      54           0 :                 break;
      55             :         case HOSTAPD_CHAN_DFS_USABLE:
      56         158 :                 state = "usable";
      57         158 :                 break;
      58             :         case HOSTAPD_CHAN_DFS_UNAVAILABLE:
      59           0 :                 state = "unavailable";
      60           0 :                 break;
      61             :         case HOSTAPD_CHAN_DFS_AVAILABLE:
      62           0 :                 state = "available";
      63           0 :                 break;
      64             :         default:
      65           0 :                 return "";
      66             :         }
      67         158 :         os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
      68         158 :         info[sizeof(info) - 1] = '\0';
      69             : 
      70         158 :         return info;
      71             : }
      72             : #endif /* CONFIG_NO_STDOUT_DEBUG */
      73             : 
      74             : 
      75        2023 : int hostapd_get_hw_features(struct hostapd_iface *iface)
      76             : {
      77        2023 :         struct hostapd_data *hapd = iface->bss[0];
      78             :         int i, j;
      79             :         u16 num_modes, flags;
      80             :         struct hostapd_hw_modes *modes;
      81             : 
      82        2023 :         if (hostapd_drv_none(hapd))
      83          12 :                 return -1;
      84        2011 :         modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
      85        2011 :         if (modes == NULL) {
      86           0 :                 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
      87             :                                HOSTAPD_LEVEL_DEBUG,
      88             :                                "Fetching hardware channel/rate support not "
      89             :                                "supported.");
      90           0 :                 return -1;
      91             :         }
      92             : 
      93        2011 :         iface->hw_flags = flags;
      94             : 
      95        2011 :         hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
      96        2011 :         iface->hw_features = modes;
      97        2011 :         iface->num_hw_features = num_modes;
      98             : 
      99        8044 :         for (i = 0; i < num_modes; i++) {
     100        6033 :                 struct hostapd_hw_modes *feature = &modes[i];
     101        6069 :                 int dfs_enabled = hapd->iconf->ieee80211h &&
     102          36 :                         (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
     103             : 
     104             :                 /* set flag for channels we can use in current regulatory
     105             :                  * domain */
     106      110605 :                 for (j = 0; j < feature->num_channels; j++) {
     107      104572 :                         int dfs = 0;
     108             : 
     109             :                         /*
     110             :                          * Disable all channels that are marked not to allow
     111             :                          * to initiate radiation (a.k.a. passive scan and no
     112             :                          * IBSS).
     113             :                          * Use radar channels only if the driver supports DFS.
     114             :                          */
     115      104572 :                         if ((feature->channels[j].flag &
     116       30088 :                              HOSTAPD_CHAN_RADAR) && dfs_enabled) {
     117         180 :                                 dfs = 1;
     118      104392 :                         } else if (((feature->channels[j].flag &
     119       29908 :                                      HOSTAPD_CHAN_RADAR) &&
     120       29908 :                                     !(iface->drv_flags &
     121       74484 :                                       WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
     122       74484 :                                    (feature->channels[j].flag &
     123             :                                     HOSTAPD_CHAN_NO_IR)) {
     124       56691 :                                 feature->channels[j].flag |=
     125             :                                         HOSTAPD_CHAN_DISABLED;
     126             :                         }
     127             : 
     128      104572 :                         if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
     129       56837 :                                 continue;
     130             : 
     131      238833 :                         wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
     132             :                                    "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
     133       47735 :                                    feature->mode,
     134       47735 :                                    feature->channels[j].chan,
     135       47735 :                                    feature->channels[j].freq,
     136       47735 :                                    feature->channels[j].max_tx_power,
     137         158 :                                    dfs ? dfs_info(&feature->channels[j]) : "");
     138             :                 }
     139             :         }
     140             : 
     141        2011 :         return 0;
     142             : }
     143             : 
     144             : 
     145        2000 : int hostapd_prepare_rates(struct hostapd_iface *iface,
     146             :                           struct hostapd_hw_modes *mode)
     147             : {
     148        2000 :         int i, num_basic_rates = 0;
     149        2000 :         int basic_rates_a[] = { 60, 120, 240, -1 };
     150        2000 :         int basic_rates_b[] = { 10, 20, -1 };
     151        2000 :         int basic_rates_g[] = { 10, 20, 55, 110, -1 };
     152             :         int *basic_rates;
     153             : 
     154        2000 :         if (iface->conf->basic_rates)
     155         345 :                 basic_rates = iface->conf->basic_rates;
     156        1655 :         else switch (mode->mode) {
     157             :         case HOSTAPD_MODE_IEEE80211A:
     158         205 :                 basic_rates = basic_rates_a;
     159         205 :                 break;
     160             :         case HOSTAPD_MODE_IEEE80211B:
     161           8 :                 basic_rates = basic_rates_b;
     162           8 :                 break;
     163             :         case HOSTAPD_MODE_IEEE80211G:
     164        1442 :                 basic_rates = basic_rates_g;
     165        1442 :                 break;
     166             :         case HOSTAPD_MODE_IEEE80211AD:
     167           0 :                 return 0; /* No basic rates for 11ad */
     168             :         default:
     169           0 :                 return -1;
     170             :         }
     171             : 
     172        2000 :         i = 0;
     173       11575 :         while (basic_rates[i] >= 0)
     174        7575 :                 i++;
     175        2000 :         if (i)
     176        2000 :                 i++; /* -1 termination */
     177        2000 :         os_free(iface->basic_rates);
     178        2000 :         iface->basic_rates = os_malloc(i * sizeof(int));
     179        2000 :         if (iface->basic_rates)
     180        2000 :                 os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
     181             : 
     182        2000 :         os_free(iface->current_rates);
     183        2000 :         iface->num_rates = 0;
     184             : 
     185        2000 :         iface->current_rates =
     186        2000 :                 os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
     187        2000 :         if (!iface->current_rates) {
     188           0 :                 wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
     189             :                            "table.");
     190           0 :                 return -1;
     191             :         }
     192             : 
     193       25116 :         for (i = 0; i < mode->num_rates; i++) {
     194             :                 struct hostapd_rate_data *rate;
     195             : 
     196       26868 :                 if (iface->conf->supported_rates &&
     197        3752 :                     !hostapd_rate_found(iface->conf->supported_rates,
     198        3752 :                                         mode->rates[i]))
     199        1252 :                         continue;
     200             : 
     201       21864 :                 rate = &iface->current_rates[iface->num_rates];
     202       21864 :                 rate->rate = mode->rates[i];
     203       21864 :                 if (hostapd_rate_found(basic_rates, rate->rate)) {
     204        7571 :                         rate->flags |= HOSTAPD_RATE_BASIC;
     205        7571 :                         num_basic_rates++;
     206             :                 }
     207       21864 :                 wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
     208             :                            iface->num_rates, rate->rate, rate->flags);
     209       21864 :                 iface->num_rates++;
     210             :         }
     211             : 
     212        2001 :         if ((iface->num_rates == 0 || num_basic_rates == 0) &&
     213           2 :             (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
     214           0 :                 wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
     215             :                            "rate sets (%d,%d).",
     216             :                            iface->num_rates, num_basic_rates);
     217           0 :                 return -1;
     218             :         }
     219             : 
     220        2000 :         return 0;
     221             : }
     222             : 
     223             : 
     224             : #ifdef CONFIG_IEEE80211N
     225        1959 : static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
     226             : {
     227             :         int pri_chan, sec_chan;
     228             : 
     229        1959 :         if (!iface->conf->secondary_channel)
     230        1909 :                 return 1; /* HT40 not used */
     231             : 
     232          50 :         pri_chan = iface->conf->channel;
     233          50 :         sec_chan = pri_chan + iface->conf->secondary_channel * 4;
     234             : 
     235          50 :         return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
     236             :                                          sec_chan);
     237             : }
     238             : 
     239             : 
     240           2 : static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
     241             : {
     242           2 :         if (iface->conf->secondary_channel > 0) {
     243           0 :                 iface->conf->channel += 4;
     244           0 :                 iface->conf->secondary_channel = -1;
     245             :         } else {
     246           2 :                 iface->conf->channel -= 4;
     247           2 :                 iface->conf->secondary_channel = 1;
     248             :         }
     249           2 : }
     250             : 
     251             : 
     252          32 : static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
     253             :                                      struct wpa_scan_results *scan_res)
     254             : {
     255             :         int pri_chan, sec_chan;
     256             :         int res;
     257             : 
     258          32 :         pri_chan = iface->conf->channel;
     259          32 :         sec_chan = pri_chan + iface->conf->secondary_channel * 4;
     260             : 
     261          32 :         res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
     262             : 
     263          32 :         if (res == 2) {
     264           3 :                 if (iface->conf->no_pri_sec_switch) {
     265           1 :                         wpa_printf(MSG_DEBUG,
     266             :                                    "Cannot switch PRI/SEC channels due to local constraint");
     267             :                 } else {
     268           2 :                         ieee80211n_switch_pri_sec(iface);
     269             :                 }
     270             :         }
     271             : 
     272          32 :         return !!res;
     273             : }
     274             : 
     275             : 
     276          23 : static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
     277             :                                       struct wpa_scan_results *scan_res)
     278             : {
     279             :         int pri_chan, sec_chan;
     280             : 
     281          23 :         pri_chan = iface->conf->channel;
     282          23 :         sec_chan = pri_chan + iface->conf->secondary_channel * 4;
     283             : 
     284          23 :         return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan,
     285             :                                sec_chan);
     286             : }
     287             : 
     288             : 
     289          55 : static void ieee80211n_check_scan(struct hostapd_iface *iface)
     290             : {
     291             :         struct wpa_scan_results *scan_res;
     292             :         int oper40;
     293             :         int res;
     294             : 
     295             :         /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
     296             :          * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
     297             : 
     298          55 :         iface->scan_cb = NULL;
     299             : 
     300          55 :         scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
     301          55 :         if (scan_res == NULL) {
     302           0 :                 hostapd_setup_interface_complete(iface, 1);
     303          55 :                 return;
     304             :         }
     305             : 
     306          55 :         if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
     307          32 :                 oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
     308             :         else
     309          23 :                 oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
     310          55 :         wpa_scan_results_free(scan_res);
     311             : 
     312          55 :         iface->secondary_ch = iface->conf->secondary_channel;
     313          55 :         if (!oper40) {
     314          15 :                 wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
     315             :                            "channel pri=%d sec=%d based on overlapping BSSes",
     316           5 :                            iface->conf->channel,
     317           5 :                            iface->conf->channel +
     318           5 :                            iface->conf->secondary_channel * 4);
     319           5 :                 iface->conf->secondary_channel = 0;
     320           5 :                 if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
     321             :                         /*
     322             :                          * TODO: Could consider scheduling another scan to check
     323             :                          * if channel width can be changed if no coex reports
     324             :                          * are received from associating stations.
     325             :                          */
     326             :                 }
     327             :         }
     328             : 
     329          55 :         res = ieee80211n_allowed_ht40_channel_pair(iface);
     330          55 :         if (!res) {
     331           1 :                 iface->conf->secondary_channel = 0;
     332           1 :                 wpa_printf(MSG_INFO, "Fallback to 20 MHz");
     333             :         }
     334             : 
     335          55 :         hostapd_setup_interface_complete(iface, !res);
     336             : }
     337             : 
     338             : 
     339          26 : static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
     340             :                                          struct wpa_driver_scan_params *params)
     341             : {
     342             :         /* Scan only the affected frequency range */
     343             :         int pri_freq, sec_freq;
     344             :         int affected_start, affected_end;
     345             :         int i, pos;
     346             :         struct hostapd_hw_modes *mode;
     347             : 
     348          26 :         if (iface->current_mode == NULL)
     349           0 :                 return;
     350             : 
     351          26 :         pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
     352          26 :         if (iface->conf->secondary_channel > 0)
     353          13 :                 sec_freq = pri_freq + 20;
     354             :         else
     355          13 :                 sec_freq = pri_freq - 20;
     356             :         /*
     357             :          * Note: Need to find the PRI channel also in cases where the affected
     358             :          * channel is the SEC channel of a 40 MHz BSS, so need to include the
     359             :          * scanning coverage here to be 40 MHz from the center frequency.
     360             :          */
     361          26 :         affected_start = (pri_freq + sec_freq) / 2 - 40;
     362          26 :         affected_end = (pri_freq + sec_freq) / 2 + 40;
     363          26 :         wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
     364             :                    affected_start, affected_end);
     365             : 
     366          26 :         mode = iface->current_mode;
     367          26 :         params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
     368          26 :         if (params->freqs == NULL)
     369           0 :                 return;
     370          26 :         pos = 0;
     371             : 
     372         390 :         for (i = 0; i < mode->num_channels; i++) {
     373         364 :                 struct hostapd_channel_data *chan = &mode->channels[i];
     374         364 :                 if (chan->flag & HOSTAPD_CHAN_DISABLED)
     375          78 :                         continue;
     376         572 :                 if (chan->freq < affected_start ||
     377         286 :                     chan->freq > affected_end)
     378           0 :                         continue;
     379         286 :                 params->freqs[pos++] = chan->freq;
     380             :         }
     381             : }
     382             : 
     383             : 
     384          32 : static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
     385             :                                         struct wpa_driver_scan_params *params)
     386             : {
     387             :         /* Scan only the affected frequency range */
     388             :         int pri_freq;
     389             :         int affected_start, affected_end;
     390             :         int i, pos;
     391             :         struct hostapd_hw_modes *mode;
     392             : 
     393          32 :         if (iface->current_mode == NULL)
     394           0 :                 return;
     395             : 
     396          32 :         pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
     397          32 :         if (iface->conf->secondary_channel > 0) {
     398          24 :                 affected_start = pri_freq - 10;
     399          24 :                 affected_end = pri_freq + 30;
     400             :         } else {
     401           8 :                 affected_start = pri_freq - 30;
     402           8 :                 affected_end = pri_freq + 10;
     403             :         }
     404          32 :         wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
     405             :                    affected_start, affected_end);
     406             : 
     407          32 :         mode = iface->current_mode;
     408          32 :         params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
     409          32 :         if (params->freqs == NULL)
     410           0 :                 return;
     411          32 :         pos = 0;
     412             : 
     413         800 :         for (i = 0; i < mode->num_channels; i++) {
     414         768 :                 struct hostapd_channel_data *chan = &mode->channels[i];
     415         768 :                 if (chan->flag & HOSTAPD_CHAN_DISABLED)
     416         471 :                         continue;
     417         553 :                 if (chan->freq < affected_start ||
     418         256 :                     chan->freq > affected_end)
     419         233 :                         continue;
     420          64 :                 params->freqs[pos++] = chan->freq;
     421             :         }
     422             : }
     423             : 
     424             : 
     425           0 : static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
     426             : {
     427             : #define HT2040_COEX_SCAN_RETRY 15
     428           0 :         struct hostapd_iface *iface = eloop_data;
     429             :         struct wpa_driver_scan_params params;
     430             :         int ret;
     431             : 
     432           0 :         os_memset(&params, 0, sizeof(params));
     433           0 :         if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
     434           0 :                 ieee80211n_scan_channels_2g4(iface, &params);
     435             :         else
     436           0 :                 ieee80211n_scan_channels_5g(iface, &params);
     437             : 
     438           0 :         ret = hostapd_driver_scan(iface->bss[0], &params);
     439           0 :         iface->num_ht40_scan_tries++;
     440           0 :         os_free(params.freqs);
     441             : 
     442           0 :         if (ret == -EBUSY &&
     443           0 :             iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
     444           0 :                 wpa_printf(MSG_ERROR,
     445             :                            "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
     446             :                            ret, strerror(-ret), iface->num_ht40_scan_tries);
     447           0 :                 eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
     448           0 :                 return;
     449             :         }
     450             : 
     451           0 :         if (ret == 0) {
     452           0 :                 iface->scan_cb = ieee80211n_check_scan;
     453           0 :                 return;
     454             :         }
     455             : 
     456           0 :         wpa_printf(MSG_DEBUG,
     457             :                    "Failed to request a scan in device, bringing up in HT20 mode");
     458           0 :         iface->conf->secondary_channel = 0;
     459           0 :         iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
     460           0 :         hostapd_setup_interface_complete(iface, 0);
     461             : }
     462             : 
     463             : 
     464        4307 : void hostapd_stop_setup_timers(struct hostapd_iface *iface)
     465             : {
     466        4307 :         eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
     467        4307 : }
     468             : 
     469             : 
     470        1962 : static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
     471             : {
     472             :         struct wpa_driver_scan_params params;
     473             :         int ret;
     474             : 
     475        1962 :         if (!iface->conf->secondary_channel)
     476        1904 :                 return 0; /* HT40 not used */
     477             : 
     478          58 :         hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
     479          58 :         wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
     480             :                    "40 MHz channel");
     481          58 :         os_memset(&params, 0, sizeof(params));
     482          58 :         if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
     483          26 :                 ieee80211n_scan_channels_2g4(iface, &params);
     484             :         else
     485          32 :                 ieee80211n_scan_channels_5g(iface, &params);
     486             : 
     487          58 :         ret = hostapd_driver_scan(iface->bss[0], &params);
     488          58 :         os_free(params.freqs);
     489             : 
     490          58 :         if (ret == -EBUSY) {
     491           0 :                 wpa_printf(MSG_ERROR,
     492             :                            "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
     493             :                            ret, strerror(-ret));
     494           0 :                 iface->num_ht40_scan_tries = 1;
     495           0 :                 eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
     496           0 :                 eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
     497           0 :                 return 1;
     498             :         }
     499             : 
     500          58 :         if (ret < 0) {
     501           0 :                 wpa_printf(MSG_ERROR,
     502             :                            "Failed to request a scan of neighboring BSSes ret=%d (%s)",
     503             :                            ret, strerror(-ret));
     504           0 :                 return -1;
     505             :         }
     506             : 
     507          58 :         iface->scan_cb = ieee80211n_check_scan;
     508          58 :         return 1;
     509             : }
     510             : 
     511             : 
     512        1964 : static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
     513             : {
     514        1964 :         u16 hw = iface->current_mode->ht_capab;
     515        1964 :         u16 conf = iface->conf->ht_capab;
     516             : 
     517        1965 :         if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
     518           1 :             !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
     519           1 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     520             :                            "HT capability [LDPC]");
     521           1 :                 return 0;
     522             :         }
     523             : 
     524             :         /*
     525             :          * Driver ACS chosen channel may not be HT40 due to internal driver
     526             :          * restrictions.
     527             :          */
     528        2019 :         if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
     529          56 :             !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
     530           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     531             :                            "HT capability [HT40*]");
     532           0 :                 return 0;
     533             :         }
     534             : 
     535        1963 :         switch (conf & HT_CAP_INFO_SMPS_MASK) {
     536             :         case HT_CAP_INFO_SMPS_STATIC:
     537           1 :                 if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
     538           0 :                         wpa_printf(MSG_ERROR,
     539             :                                    "Driver does not support configured HT capability [SMPS-STATIC]");
     540           0 :                         return 0;
     541             :                 }
     542           1 :                 break;
     543             :         case HT_CAP_INFO_SMPS_DYNAMIC:
     544           1 :                 if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
     545           0 :                         wpa_printf(MSG_ERROR,
     546             :                                    "Driver does not support configured HT capability [SMPS-DYNAMIC]");
     547           0 :                         return 0;
     548             :                 }
     549           1 :                 break;
     550             :         case HT_CAP_INFO_SMPS_DISABLED:
     551             :         default:
     552        1961 :                 break;
     553             :         }
     554             : 
     555        2301 :         if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
     556         338 :             !(hw & HT_CAP_INFO_GREEN_FIELD)) {
     557           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     558             :                            "HT capability [GF]");
     559           0 :                 return 0;
     560             :         }
     561             : 
     562        2301 :         if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
     563         338 :             !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
     564           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     565             :                            "HT capability [SHORT-GI-20]");
     566           0 :                 return 0;
     567             :         }
     568             : 
     569        2303 :         if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
     570         340 :             !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
     571           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     572             :                            "HT capability [SHORT-GI-40]");
     573           0 :                 return 0;
     574             :         }
     575             : 
     576        1963 :         if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
     577           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     578             :                            "HT capability [TX-STBC]");
     579           0 :                 return 0;
     580             :         }
     581             : 
     582        3926 :         if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
     583        1963 :             (hw & HT_CAP_INFO_RX_STBC_MASK)) {
     584           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     585             :                            "HT capability [RX-STBC*]");
     586           0 :                 return 0;
     587             :         }
     588             : 
     589        1963 :         if ((conf & HT_CAP_INFO_DELAYED_BA) &&
     590           0 :             !(hw & HT_CAP_INFO_DELAYED_BA)) {
     591           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     592             :                            "HT capability [DELAYED-BA]");
     593           0 :                 return 0;
     594             :         }
     595             : 
     596        1963 :         if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
     597           0 :             !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
     598           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     599             :                            "HT capability [MAX-AMSDU-7935]");
     600           0 :                 return 0;
     601             :         }
     602             : 
     603        1963 :         if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
     604           0 :             !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
     605           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     606             :                            "HT capability [DSSS_CCK-40]");
     607           0 :                 return 0;
     608             :         }
     609             : 
     610        1963 :         if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
     611           0 :             !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
     612           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     613             :                            "HT capability [LSIG-TXOP-PROT]");
     614           0 :                 return 0;
     615             :         }
     616             : 
     617        1963 :         return 1;
     618             : }
     619             : 
     620             : 
     621             : #ifdef CONFIG_IEEE80211AC
     622             : 
     623       25984 : static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
     624             : {
     625       25984 :         u32 req_cap = conf & cap;
     626             : 
     627             :         /*
     628             :          * Make sure we support all requested capabilities.
     629             :          * NOTE: We assume that 'cap' represents a capability mask,
     630             :          * not a discrete value.
     631             :          */
     632       25984 :         if ((hw & req_cap) != req_cap) {
     633           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
     634             :                            name);
     635           0 :                 return 0;
     636             :         }
     637       25984 :         return 1;
     638             : }
     639             : 
     640             : 
     641        8121 : static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
     642             :                                      unsigned int shift,
     643             :                                      const char *name)
     644             : {
     645        8121 :         u32 hw_max = hw & mask;
     646        8121 :         u32 conf_val = conf & mask;
     647             : 
     648        8121 :         if (conf_val > hw_max) {
     649           1 :                 wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
     650             :                            name, conf_val >> shift, hw_max >> shift);
     651           1 :                 return 0;
     652             :         }
     653        8120 :         return 1;
     654             : }
     655             : 
     656             : 
     657        1625 : static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
     658             : {
     659        1625 :         struct hostapd_hw_modes *mode = iface->current_mode;
     660        1625 :         u32 hw = mode->vht_capab;
     661        1625 :         u32 conf = iface->conf->vht_capab;
     662             : 
     663        1625 :         wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
     664             :                    hw, conf);
     665             : 
     666        3053 :         if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
     667        1429 :             iface->conf->bss[0]->vendor_vht &&
     668           2 :             mode->vht_capab == 0 && iface->hw_features) {
     669             :                 int i;
     670             : 
     671           2 :                 for (i = 0; i < iface->num_hw_features; i++) {
     672           2 :                         if (iface->hw_features[i].mode ==
     673             :                             HOSTAPD_MODE_IEEE80211A) {
     674           1 :                                 mode = &iface->hw_features[i];
     675           1 :                                 hw = mode->vht_capab;
     676           1 :                                 wpa_printf(MSG_DEBUG,
     677             :                                            "update hw vht capab based on 5 GHz band: 0x%x",
     678             :                                            hw);
     679           1 :                                 break;
     680             :                         }
     681             :                 }
     682             :         }
     683             : 
     684             : #define VHT_CAP_CHECK(cap) \
     685             :         do { \
     686             :                 if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
     687             :                         return 0; \
     688             :         } while (0)
     689             : 
     690             : #define VHT_CAP_CHECK_MAX(cap) \
     691             :         do { \
     692             :                 if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
     693             :                                                #cap)) \
     694             :                         return 0; \
     695             :         } while (0)
     696             : 
     697        1625 :         VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
     698        1624 :         VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
     699        1624 :         VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
     700        1624 :         VHT_CAP_CHECK(VHT_CAP_RXLDPC);
     701        1624 :         VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
     702        1624 :         VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
     703        1624 :         VHT_CAP_CHECK(VHT_CAP_TXSTBC);
     704        1624 :         VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
     705        1624 :         VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
     706        1624 :         VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
     707        1624 :         VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
     708        1624 :         VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
     709        1624 :         VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
     710        1624 :         VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
     711        1624 :         VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
     712        1624 :         VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
     713        1624 :         VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
     714        1624 :         VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
     715        1624 :         VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
     716        1624 :         VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
     717        1624 :         VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
     718             : 
     719             : #undef VHT_CAP_CHECK
     720             : #undef VHT_CAP_CHECK_MAX
     721             : 
     722        1624 :         return 1;
     723             : }
     724             : #endif /* CONFIG_IEEE80211AC */
     725             : 
     726             : #endif /* CONFIG_IEEE80211N */
     727             : 
     728             : 
     729        2007 : int hostapd_check_ht_capab(struct hostapd_iface *iface)
     730             : {
     731             : #ifdef CONFIG_IEEE80211N
     732             :         int ret;
     733        2007 :         if (!iface->conf->ieee80211n)
     734          43 :                 return 0;
     735             : 
     736        3922 :         if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B &&
     737        2162 :             iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G &&
     738         204 :             (iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) {
     739           0 :                 wpa_printf(MSG_DEBUG,
     740             :                            "Disable HT capability [DSSS_CCK-40] on 5 GHz band");
     741           0 :                 iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ;
     742             :         }
     743             : 
     744        1964 :         if (!ieee80211n_supported_ht_capab(iface))
     745           1 :                 return -1;
     746             : #ifdef CONFIG_IEEE80211AC
     747        1625 :         if (!ieee80211ac_supported_vht_capab(iface))
     748           1 :                 return -1;
     749             : #endif /* CONFIG_IEEE80211AC */
     750        1962 :         ret = ieee80211n_check_40mhz(iface);
     751        1962 :         if (ret)
     752          58 :                 return ret;
     753        1904 :         if (!ieee80211n_allowed_ht40_channel_pair(iface))
     754           0 :                 return -1;
     755             : #endif /* CONFIG_IEEE80211N */
     756             : 
     757        1904 :         return 0;
     758             : }
     759             : 
     760             : 
     761        2069 : static int hostapd_is_usable_chan(struct hostapd_iface *iface,
     762             :                                   int channel, int primary)
     763             : {
     764             :         int i;
     765             :         struct hostapd_channel_data *chan;
     766             : 
     767        2069 :         if (!iface->current_mode)
     768           0 :                 return 0;
     769             : 
     770        3674 :         for (i = 0; i < iface->current_mode->num_channels; i++) {
     771        3672 :                 chan = &iface->current_mode->channels[i];
     772        3672 :                 if (chan->chan != channel)
     773        1605 :                         continue;
     774             : 
     775        2067 :                 if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
     776        2067 :                         return 1;
     777             : 
     778           0 :                 wpa_printf(MSG_DEBUG,
     779             :                            "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
     780             :                            primary ? "" : "Configured HT40 secondary ",
     781           0 :                            i, chan->chan, chan->flag,
     782           0 :                            chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
     783           0 :                            chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
     784             :         }
     785             : 
     786           2 :         return 0;
     787             : }
     788             : 
     789             : 
     790        2009 : static int hostapd_is_usable_chans(struct hostapd_iface *iface)
     791             : {
     792        2009 :         if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
     793           2 :                 return 0;
     794             : 
     795        2007 :         if (!iface->conf->secondary_channel)
     796        1947 :                 return 1;
     797             : 
     798         120 :         return hostapd_is_usable_chan(iface, iface->conf->channel +
     799          60 :                                       iface->conf->secondary_channel * 4, 0);
     800             : }
     801             : 
     802             : 
     803             : static enum hostapd_chan_status
     804        2020 : hostapd_check_chans(struct hostapd_iface *iface)
     805             : {
     806        2020 :         if (iface->conf->channel) {
     807        2009 :                 if (hostapd_is_usable_chans(iface))
     808        2007 :                         return HOSTAPD_CHAN_VALID;
     809             :                 else
     810           2 :                         return HOSTAPD_CHAN_INVALID;
     811             :         }
     812             : 
     813             :         /*
     814             :          * The user set channel=0 or channel=acs_survey
     815             :          * which is used to trigger ACS.
     816             :          */
     817             : 
     818          11 :         switch (acs_init(iface)) {
     819             :         case HOSTAPD_CHAN_ACS:
     820          11 :                 return HOSTAPD_CHAN_ACS;
     821             :         case HOSTAPD_CHAN_VALID:
     822             :         case HOSTAPD_CHAN_INVALID:
     823             :         default:
     824           0 :                 return HOSTAPD_CHAN_INVALID;
     825             :         }
     826             : }
     827             : 
     828             : 
     829           2 : static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
     830             : {
     831           2 :         if (!iface->current_mode) {
     832           0 :                 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
     833             :                                HOSTAPD_LEVEL_WARNING,
     834             :                                "Hardware does not support configured mode");
     835           2 :                 return;
     836             :         }
     837           4 :         hostapd_logger(iface->bss[0], NULL,
     838             :                        HOSTAPD_MODULE_IEEE80211,
     839             :                        HOSTAPD_LEVEL_WARNING,
     840             :                        "Configured channel (%d) not found from the "
     841             :                        "channel list of current mode (%d) %s",
     842           2 :                        iface->conf->channel,
     843           2 :                        iface->current_mode->mode,
     844           2 :                        hostapd_hw_mode_txt(iface->current_mode->mode));
     845           2 :         hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
     846             :                        HOSTAPD_LEVEL_WARNING,
     847             :                        "Hardware does not support configured channel");
     848             : }
     849             : 
     850             : 
     851           9 : int hostapd_acs_completed(struct hostapd_iface *iface, int err)
     852             : {
     853           9 :         int ret = -1;
     854             : 
     855           9 :         if (err)
     856           0 :                 goto out;
     857             : 
     858           9 :         switch (hostapd_check_chans(iface)) {
     859             :         case HOSTAPD_CHAN_VALID:
     860          27 :                 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
     861             :                         ACS_EVENT_COMPLETED "freq=%d channel=%d",
     862           9 :                         hostapd_hw_get_freq(iface->bss[0],
     863           9 :                                             iface->conf->channel),
     864           9 :                         iface->conf->channel);
     865           9 :                 break;
     866             :         case HOSTAPD_CHAN_ACS:
     867           0 :                 wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
     868           0 :                 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
     869           0 :                 hostapd_notify_bad_chans(iface);
     870           0 :                 goto out;
     871             :         case HOSTAPD_CHAN_INVALID:
     872             :         default:
     873           0 :                 wpa_printf(MSG_ERROR, "ACS picked unusable channels");
     874           0 :                 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
     875           0 :                 hostapd_notify_bad_chans(iface);
     876           0 :                 goto out;
     877             :         }
     878             : 
     879           9 :         ret = hostapd_check_ht_capab(iface);
     880           9 :         if (ret < 0)
     881           0 :                 goto out;
     882           9 :         if (ret == 1) {
     883           3 :                 wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
     884           3 :                 return 0;
     885             :         }
     886             : 
     887           6 :         ret = 0;
     888             : out:
     889           6 :         return hostapd_setup_interface_complete(iface, ret);
     890             : }
     891             : 
     892             : 
     893             : /**
     894             :  * hostapd_select_hw_mode - Select the hardware mode
     895             :  * @iface: Pointer to interface data.
     896             :  * Returns: 0 on success, < 0 on failure
     897             :  *
     898             :  * Sets up the hardware mode, channel, rates, and passive scanning
     899             :  * based on the configuration.
     900             :  */
     901        2011 : int hostapd_select_hw_mode(struct hostapd_iface *iface)
     902             : {
     903             :         int i;
     904             : 
     905        2011 :         if (iface->num_hw_features < 1)
     906           0 :                 return -1;
     907             : 
     908        2227 :         if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
     909        2227 :              iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
     910        2007 :             iface->conf->channel == 14) {
     911           2 :                 wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
     912           2 :                 iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
     913           2 :                 iface->conf->ieee80211n = 0;
     914           2 :                 iface->conf->ieee80211ac = 0;
     915             :         }
     916             : 
     917        2011 :         iface->current_mode = NULL;
     918        2235 :         for (i = 0; i < iface->num_hw_features; i++) {
     919        2235 :                 struct hostapd_hw_modes *mode = &iface->hw_features[i];
     920        2235 :                 if (mode->mode == iface->conf->hw_mode) {
     921        2011 :                         iface->current_mode = mode;
     922        2011 :                         break;
     923             :                 }
     924             :         }
     925             : 
     926        2011 :         if (iface->current_mode == NULL) {
     927           0 :                 if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
     928           0 :                     !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
     929             :                 {
     930           0 :                         wpa_printf(MSG_ERROR,
     931             :                                    "Hardware does not support configured mode");
     932           0 :                         hostapd_logger(iface->bss[0], NULL,
     933             :                                        HOSTAPD_MODULE_IEEE80211,
     934             :                                        HOSTAPD_LEVEL_WARNING,
     935             :                                        "Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)",
     936           0 :                                        (int) iface->conf->hw_mode);
     937           0 :                         return -2;
     938             :                 }
     939             :         }
     940             : 
     941        2011 :         switch (hostapd_check_chans(iface)) {
     942             :         case HOSTAPD_CHAN_VALID:
     943        1998 :                 return 0;
     944             :         case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
     945          11 :                 return 1;
     946             :         case HOSTAPD_CHAN_INVALID:
     947             :         default:
     948           2 :                 hostapd_notify_bad_chans(iface);
     949           2 :                 return -3;
     950             :         }
     951             : }
     952             : 
     953             : 
     954        2015 : const char * hostapd_hw_mode_txt(int mode)
     955             : {
     956        2015 :         switch (mode) {
     957             :         case HOSTAPD_MODE_IEEE80211A:
     958         218 :                 return "IEEE 802.11a";
     959             :         case HOSTAPD_MODE_IEEE80211B:
     960           8 :                 return "IEEE 802.11b";
     961             :         case HOSTAPD_MODE_IEEE80211G:
     962        1789 :                 return "IEEE 802.11g";
     963             :         case HOSTAPD_MODE_IEEE80211AD:
     964           0 :                 return "IEEE 802.11ad";
     965             :         default:
     966           0 :                 return "UNKNOWN";
     967             :         }
     968             : }
     969             : 
     970             : 
     971        2087 : int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
     972             : {
     973        2087 :         return hw_get_freq(hapd->iface->current_mode, chan);
     974             : }
     975             : 
     976             : 
     977          64 : int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
     978             : {
     979          64 :         return hw_get_chan(hapd->iface->current_mode, freq);
     980             : }

Generated by: LCOV version 1.10