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 1422976643 Lines: 374 461 81.1 %
Date: 2015-02-03 Functions: 28 28 100.0 %

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

Generated by: LCOV version 1.10