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 1401264779 Lines: 462 586 78.8 %
Date: 2014-05-28 Functions: 29 30 96.7 %

          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 "hostapd.h"
      19             : #include "ap_config.h"
      20             : #include "ap_drv_ops.h"
      21             : #include "acs.h"
      22             : #include "ieee802_11.h"
      23             : #include "beacon.h"
      24             : #include "hw_features.h"
      25             : 
      26             : 
      27        1367 : void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
      28             :                               size_t num_hw_features)
      29             : {
      30             :         size_t i;
      31             : 
      32        1367 :         if (hw_features == NULL)
      33        2058 :                 return;
      34             : 
      35        2704 :         for (i = 0; i < num_hw_features; i++) {
      36        2028 :                 os_free(hw_features[i].channels);
      37        2028 :                 os_free(hw_features[i].rates);
      38             :         }
      39             : 
      40         676 :         os_free(hw_features);
      41             : }
      42             : 
      43             : 
      44             : #ifndef CONFIG_NO_STDOUT_DEBUG
      45          15 : static char * dfs_info(struct hostapd_channel_data *chan)
      46             : {
      47             :         static char info[256];
      48             :         char *state;
      49             : 
      50          15 :         switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
      51             :         case HOSTAPD_CHAN_DFS_UNKNOWN:
      52           0 :                 state = "unknown";
      53           0 :                 break;
      54             :         case HOSTAPD_CHAN_DFS_USABLE:
      55          15 :                 state = "usable";
      56          15 :                 break;
      57             :         case HOSTAPD_CHAN_DFS_UNAVAILABLE:
      58           0 :                 state = "unavailable";
      59           0 :                 break;
      60             :         case HOSTAPD_CHAN_DFS_AVAILABLE:
      61           0 :                 state = "available";
      62           0 :                 break;
      63             :         default:
      64           0 :                 return "";
      65             :         }
      66          15 :         os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
      67          15 :         info[sizeof(info) - 1] = '\0';
      68             : 
      69          15 :         return info;
      70             : }
      71             : #endif /* CONFIG_NO_STDOUT_DEBUG */
      72             : 
      73             : 
      74         678 : int hostapd_get_hw_features(struct hostapd_iface *iface)
      75             : {
      76         678 :         struct hostapd_data *hapd = iface->bss[0];
      77         678 :         int ret = 0, i, j;
      78             :         u16 num_modes, flags;
      79             :         struct hostapd_hw_modes *modes;
      80             : 
      81         678 :         if (hostapd_drv_none(hapd))
      82           2 :                 return -1;
      83         676 :         modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
      84         676 :         if (modes == NULL) {
      85           0 :                 hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
      86             :                                HOSTAPD_LEVEL_DEBUG,
      87             :                                "Fetching hardware channel/rate support not "
      88             :                                "supported.");
      89           0 :                 return -1;
      90             :         }
      91             : 
      92         676 :         iface->hw_flags = flags;
      93             : 
      94         676 :         hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
      95         676 :         iface->hw_features = modes;
      96         676 :         iface->num_hw_features = num_modes;
      97             : 
      98        2704 :         for (i = 0; i < num_modes; i++) {
      99        2028 :                 struct hostapd_hw_modes *feature = &modes[i];
     100        2031 :                 int dfs_enabled = hapd->iconf->ieee80211h &&
     101           3 :                         (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
     102             : 
     103             :                 /* set flag for channels we can use in current regulatory
     104             :                  * domain */
     105       37180 :                 for (j = 0; j < feature->num_channels; j++) {
     106       35152 :                         int dfs = 0;
     107             : 
     108             :                         /*
     109             :                          * Disable all channels that are marked not to allow
     110             :                          * IBSS operation or active scanning.
     111             :                          * Use radar channels only if the driver supports DFS.
     112             :                          */
     113       35152 :                         if ((feature->channels[j].flag &
     114       10136 :                              HOSTAPD_CHAN_RADAR) && dfs_enabled) {
     115          15 :                                 dfs = 1;
     116       35137 :                         } else if (((feature->channels[j].flag &
     117       10121 :                                      HOSTAPD_CHAN_RADAR) &&
     118       10121 :                                     !(iface->drv_flags &
     119       25016 :                                       WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
     120       25016 :                                    (feature->channels[j].flag &
     121             :                                     (HOSTAPD_CHAN_NO_IBSS |
     122             :                                      HOSTAPD_CHAN_PASSIVE_SCAN))) {
     123       18672 :                                 feature->channels[j].flag |=
     124             :                                         HOSTAPD_CHAN_DISABLED;
     125             :                         }
     126             : 
     127       35152 :                         if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
     128       18672 :                                 continue;
     129             : 
     130       82415 :                         wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
     131             :                                    "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
     132       16480 :                                    feature->mode,
     133       16480 :                                    feature->channels[j].chan,
     134       16480 :                                    feature->channels[j].freq,
     135       16480 :                                    feature->channels[j].max_tx_power,
     136          15 :                                    dfs ? dfs_info(&feature->channels[j]) : "");
     137             :                 }
     138             :         }
     139             : 
     140         676 :         return ret;
     141             : }
     142             : 
     143             : 
     144         663 : int hostapd_prepare_rates(struct hostapd_iface *iface,
     145             :                           struct hostapd_hw_modes *mode)
     146             : {
     147         663 :         int i, num_basic_rates = 0;
     148         663 :         int basic_rates_a[] = { 60, 120, 240, -1 };
     149         663 :         int basic_rates_b[] = { 10, 20, -1 };
     150         663 :         int basic_rates_g[] = { 10, 20, 55, 110, -1 };
     151             :         int *basic_rates;
     152             : 
     153         663 :         if (iface->conf->basic_rates)
     154         116 :                 basic_rates = iface->conf->basic_rates;
     155         547 :         else switch (mode->mode) {
     156             :         case HOSTAPD_MODE_IEEE80211A:
     157          19 :                 basic_rates = basic_rates_a;
     158          19 :                 break;
     159             :         case HOSTAPD_MODE_IEEE80211B:
     160           3 :                 basic_rates = basic_rates_b;
     161           3 :                 break;
     162             :         case HOSTAPD_MODE_IEEE80211G:
     163         525 :                 basic_rates = basic_rates_g;
     164         525 :                 break;
     165             :         case HOSTAPD_MODE_IEEE80211AD:
     166           0 :                 return 0; /* No basic rates for 11ad */
     167             :         default:
     168           0 :                 return -1;
     169             :         }
     170             : 
     171         663 :         i = 0;
     172        3846 :         while (basic_rates[i] >= 0)
     173        2520 :                 i++;
     174         663 :         if (i)
     175         663 :                 i++; /* -1 termination */
     176         663 :         os_free(iface->basic_rates);
     177         663 :         iface->basic_rates = os_malloc(i * sizeof(int));
     178         663 :         if (iface->basic_rates)
     179         663 :                 os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
     180             : 
     181         663 :         os_free(iface->current_rates);
     182         663 :         iface->num_rates = 0;
     183             : 
     184         663 :         iface->current_rates =
     185         663 :                 os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
     186         663 :         if (!iface->current_rates) {
     187           0 :                 wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
     188             :                            "table.");
     189           0 :                 return -1;
     190             :         }
     191             : 
     192        8519 :         for (i = 0; i < mode->num_rates; i++) {
     193             :                 struct hostapd_rate_data *rate;
     194             : 
     195        9256 :                 if (iface->conf->supported_rates &&
     196        1400 :                     !hostapd_rate_found(iface->conf->supported_rates,
     197        1400 :                                         mode->rates[i]))
     198         468 :                         continue;
     199             : 
     200        7388 :                 rate = &iface->current_rates[iface->num_rates];
     201        7388 :                 rate->rate = mode->rates[i];
     202        7388 :                 if (hostapd_rate_found(basic_rates, rate->rate)) {
     203        2516 :                         rate->flags |= HOSTAPD_RATE_BASIC;
     204        2516 :                         num_basic_rates++;
     205             :                 }
     206        7388 :                 wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
     207             :                            iface->num_rates, rate->rate, rate->flags);
     208        7388 :                 iface->num_rates++;
     209             :         }
     210             : 
     211         664 :         if ((iface->num_rates == 0 || num_basic_rates == 0) &&
     212           2 :             (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
     213           0 :                 wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
     214             :                            "rate sets (%d,%d).",
     215             :                            iface->num_rates, num_basic_rates);
     216           0 :                 return -1;
     217             :         }
     218             : 
     219         663 :         return 0;
     220             : }
     221             : 
     222             : 
     223             : #ifdef CONFIG_IEEE80211N
     224         659 : static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
     225             : {
     226             :         int sec_chan, ok, j, first;
     227         659 :         int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
     228             :                           184, 192 };
     229             :         size_t k;
     230             : 
     231         659 :         if (!iface->conf->secondary_channel)
     232         637 :                 return 1; /* HT40 not used */
     233             : 
     234          22 :         sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
     235          22 :         wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
     236             :                    "secondary channel: %d",
     237          22 :                    iface->conf->channel, sec_chan);
     238             : 
     239             :         /* Verify that HT40 secondary channel is an allowed 20 MHz
     240             :          * channel */
     241          22 :         ok = 0;
     242          61 :         for (j = 0; j < iface->current_mode->num_channels; j++) {
     243          61 :                 struct hostapd_channel_data *chan =
     244          61 :                         &iface->current_mode->channels[j];
     245         122 :                 if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
     246          61 :                     chan->chan == sec_chan) {
     247          22 :                         ok = 1;
     248          22 :                         break;
     249             :                 }
     250             :         }
     251          22 :         if (!ok) {
     252           0 :                 wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
     253             :                            sec_chan);
     254           0 :                 return 0;
     255             :         }
     256             : 
     257             :         /*
     258             :          * Verify that HT40 primary,secondary channel pair is allowed per
     259             :          * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
     260             :          * 2.4 GHz rules allow all cases where the secondary channel fits into
     261             :          * the list of allowed channels (already checked above).
     262             :          */
     263          22 :         if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
     264          13 :                 return 1;
     265             : 
     266           9 :         if (iface->conf->secondary_channel > 0)
     267           9 :                 first = iface->conf->channel;
     268             :         else
     269           0 :                 first = sec_chan;
     270             : 
     271           9 :         ok = 0;
     272           9 :         for (k = 0; k < ARRAY_SIZE(allowed); k++) {
     273           9 :                 if (first == allowed[k]) {
     274           9 :                         ok = 1;
     275           9 :                         break;
     276             :                 }
     277             :         }
     278           9 :         if (!ok) {
     279           0 :                 wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
     280           0 :                            iface->conf->channel,
     281           0 :                            iface->conf->secondary_channel);
     282           0 :                 return 0;
     283             :         }
     284             : 
     285           9 :         return 1;
     286             : }
     287             : 
     288             : 
     289           2 : static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
     290             : {
     291           2 :         if (iface->conf->secondary_channel > 0) {
     292           0 :                 iface->conf->channel += 4;
     293           0 :                 iface->conf->secondary_channel = -1;
     294             :         } else {
     295           2 :                 iface->conf->channel -= 4;
     296           2 :                 iface->conf->secondary_channel = 1;
     297             :         }
     298           2 : }
     299             : 
     300             : 
     301           6 : static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
     302             :                                         int *pri_chan, int *sec_chan)
     303             : {
     304             :         struct ieee80211_ht_operation *oper;
     305             :         struct ieee802_11_elems elems;
     306             : 
     307           6 :         *pri_chan = *sec_chan = 0;
     308             : 
     309           6 :         ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
     310          12 :         if (elems.ht_operation &&
     311           6 :             elems.ht_operation_len >= sizeof(*oper)) {
     312           6 :                 oper = (struct ieee80211_ht_operation *) elems.ht_operation;
     313           6 :                 *pri_chan = oper->primary_chan;
     314           6 :                 if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
     315           5 :                         int sec = oper->ht_param &
     316             :                                 HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
     317           5 :                         if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
     318           4 :                                 *sec_chan = *pri_chan + 4;
     319           1 :                         else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
     320           1 :                                 *sec_chan = *pri_chan - 4;
     321             :                 }
     322             :         }
     323           6 : }
     324             : 
     325             : 
     326           9 : static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
     327             :                                      struct wpa_scan_results *scan_res)
     328             : {
     329             :         int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
     330             :         int bss_pri_chan, bss_sec_chan;
     331             :         size_t i;
     332             :         int match;
     333             : 
     334           9 :         pri_chan = iface->conf->channel;
     335           9 :         sec_chan = pri_chan + iface->conf->secondary_channel * 4;
     336           9 :         pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
     337           9 :         if (iface->conf->secondary_channel > 0)
     338           7 :                 sec_freq = pri_freq + 20;
     339             :         else
     340           2 :                 sec_freq = pri_freq - 20;
     341             : 
     342             :         /*
     343             :          * Switch PRI/SEC channels if Beacons were detected on selected SEC
     344             :          * channel, but not on selected PRI channel.
     345             :          */
     346           9 :         pri_bss = sec_bss = 0;
     347          13 :         for (i = 0; i < scan_res->num; i++) {
     348           4 :                 struct wpa_scan_res *bss = scan_res->res[i];
     349           4 :                 if (bss->freq == pri_freq)
     350           2 :                         pri_bss++;
     351           2 :                 else if (bss->freq == sec_freq)
     352           2 :                         sec_bss++;
     353             :         }
     354           9 :         if (sec_bss && !pri_bss) {
     355           1 :                 wpa_printf(MSG_INFO, "Switch own primary and secondary "
     356             :                            "channel to get secondary channel with no Beacons "
     357             :                            "from other BSSes");
     358           1 :                 ieee80211n_switch_pri_sec(iface);
     359           1 :                 return 1;
     360             :         }
     361             : 
     362             :         /*
     363             :          * Match PRI/SEC channel with any existing HT40 BSS on the same
     364             :          * channels that we are about to use (if already mixed order in
     365             :          * existing BSSes, use own preference).
     366             :          */
     367           8 :         match = 0;
     368          10 :         for (i = 0; i < scan_res->num; i++) {
     369           3 :                 struct wpa_scan_res *bss = scan_res->res[i];
     370           3 :                 ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
     371           5 :                 if (pri_chan == bss_pri_chan &&
     372           2 :                     sec_chan == bss_sec_chan) {
     373           1 :                         match = 1;
     374           1 :                         break;
     375             :                 }
     376             :         }
     377           8 :         if (!match) {
     378           7 :                 for (i = 0; i < scan_res->num; i++) {
     379           1 :                         struct wpa_scan_res *bss = scan_res->res[i];
     380           1 :                         ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
     381             :                                                     &bss_sec_chan);
     382           2 :                         if (pri_chan == bss_sec_chan &&
     383           1 :                             sec_chan == bss_pri_chan) {
     384           6 :                                 wpa_printf(MSG_INFO, "Switch own primary and "
     385             :                                            "secondary channel due to BSS "
     386             :                                            "overlap with " MACSTR,
     387           6 :                                            MAC2STR(bss->bssid));
     388           1 :                                 ieee80211n_switch_pri_sec(iface);
     389           1 :                                 break;
     390             :                         }
     391             :                 }
     392             :         }
     393             : 
     394           8 :         return 1;
     395             : }
     396             : 
     397             : 
     398           3 : static int ieee80211n_check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq,
     399             :                                       int start, int end)
     400             : {
     401             :         struct ieee802_11_elems elems;
     402             :         struct ieee80211_ht_operation *oper;
     403             : 
     404           3 :         if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
     405           1 :                 return 0;
     406             : 
     407           2 :         ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
     408           2 :         if (!elems.ht_capabilities) {
     409           7 :                 wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
     410           6 :                            MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
     411           1 :                 return 1;
     412             :         }
     413             : 
     414           2 :         if (elems.ht_operation &&
     415           1 :             elems.ht_operation_len >= sizeof(*oper)) {
     416           1 :                 oper = (struct ieee80211_ht_operation *) elems.ht_operation;
     417           1 :                 if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
     418           1 :                         return 0;
     419             : 
     420           0 :                 wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
     421           0 :                            MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
     422           0 :                 return 1;
     423             :         }
     424           0 :         return 0;
     425             : }
     426             : 
     427             : 
     428          15 : static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
     429             :                                       struct wpa_scan_results *scan_res)
     430             : {
     431             :         int pri_freq, sec_freq;
     432             :         int affected_start, affected_end;
     433             :         size_t i;
     434             : 
     435          15 :         pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
     436          15 :         if (iface->conf->secondary_channel > 0)
     437           5 :                 sec_freq = pri_freq + 20;
     438             :         else
     439          10 :                 sec_freq = pri_freq - 20;
     440          15 :         affected_start = (pri_freq + sec_freq) / 2 - 25;
     441          15 :         affected_end = (pri_freq + sec_freq) / 2 + 25;
     442          15 :         wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
     443             :                    affected_start, affected_end);
     444          16 :         for (i = 0; i < scan_res->num; i++) {
     445           3 :                 struct wpa_scan_res *bss = scan_res->res[i];
     446           3 :                 int pri = bss->freq;
     447           3 :                 int sec = pri;
     448             :                 int sec_chan, pri_chan;
     449             :                 struct ieee802_11_elems elems;
     450             : 
     451             :                 /* Check for overlapping 20 MHz BSS */
     452           3 :                 if (ieee80211n_check_20mhz_bss(bss, pri_freq, affected_start,
     453             :                                                affected_end)) {
     454           1 :                         wpa_printf(MSG_DEBUG,
     455             :                                    "Overlapping 20 MHz BSS is found");
     456           3 :                         return 0;
     457             :                 }
     458             : 
     459           2 :                 ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
     460             : 
     461           2 :                 if (sec_chan) {
     462           2 :                         if (sec_chan < pri_chan)
     463           1 :                                 sec = pri - 20;
     464             :                         else
     465           1 :                                 sec = pri + 20;
     466             :                 }
     467             : 
     468           2 :                 if ((pri < affected_start || pri > affected_end) &&
     469           0 :                     (sec < affected_start || sec > affected_end))
     470           0 :                         continue; /* not within affected channel range */
     471             : 
     472          14 :                 wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
     473             :                            " freq=%d pri=%d sec=%d",
     474          12 :                            MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
     475             : 
     476           2 :                 if (sec_chan) {
     477           2 :                         if (pri_freq != pri || sec_freq != sec) {
     478           7 :                                 wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
     479             :                                            "mismatch with BSS " MACSTR
     480             :                                            " <%d,%d> (chan=%d%c) vs. <%d,%d>",
     481           6 :                                            MAC2STR(bss->bssid),
     482             :                                            pri, sec, pri_chan,
     483             :                                            sec > pri ? '+' : '-',
     484             :                                            pri_freq, sec_freq);
     485           1 :                                 return 0;
     486             :                         }
     487             :                 }
     488             : 
     489           1 :                 ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
     490             :                                        0);
     491           2 :                 if (elems.ht_capabilities &&
     492           1 :                     elems.ht_capabilities_len >=
     493             :                     sizeof(struct ieee80211_ht_capabilities)) {
     494           1 :                         struct ieee80211_ht_capabilities *ht_cap =
     495             :                                 (struct ieee80211_ht_capabilities *)
     496             :                                 elems.ht_capabilities;
     497             : 
     498           1 :                         if (le_to_host16(ht_cap->ht_capabilities_info) &
     499             :                             HT_CAP_INFO_40MHZ_INTOLERANT) {
     500           0 :                                 wpa_printf(MSG_DEBUG,
     501             :                                            "40 MHz Intolerant is set on channel %d in BSS "
     502           0 :                                            MACSTR, pri, MAC2STR(bss->bssid));
     503           0 :                                 return 0;
     504             :                         }
     505             :                 }
     506             :         }
     507             : 
     508          13 :         return 1;
     509             : }
     510             : 
     511             : 
     512          24 : static void ieee80211n_check_scan(struct hostapd_iface *iface)
     513             : {
     514             :         struct wpa_scan_results *scan_res;
     515             :         int oper40;
     516             :         int res;
     517             : 
     518             :         /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
     519             :          * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
     520             : 
     521          24 :         iface->scan_cb = NULL;
     522             : 
     523          24 :         scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
     524          24 :         if (scan_res == NULL) {
     525           0 :                 hostapd_setup_interface_complete(iface, 1);
     526          24 :                 return;
     527             :         }
     528             : 
     529          24 :         if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
     530           9 :                 oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
     531             :         else
     532          15 :                 oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
     533          24 :         wpa_scan_results_free(scan_res);
     534             : 
     535          24 :         iface->secondary_ch = iface->conf->secondary_channel;
     536          24 :         if (!oper40) {
     537           6 :                 wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
     538             :                            "channel pri=%d sec=%d based on overlapping BSSes",
     539           2 :                            iface->conf->channel,
     540           2 :                            iface->conf->channel +
     541           2 :                            iface->conf->secondary_channel * 4);
     542           2 :                 iface->conf->secondary_channel = 0;
     543           2 :                 if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
     544             :                         /*
     545             :                          * TODO: Could consider scheduling another scan to check
     546             :                          * if channel width can be changed if no coex reports
     547             :                          * are received from associating stations.
     548             :                          */
     549             :                 }
     550             :         }
     551             : 
     552          24 :         res = ieee80211n_allowed_ht40_channel_pair(iface);
     553          24 :         if (!res) {
     554           0 :                 iface->conf->secondary_channel = 0;
     555           0 :                 wpa_printf(MSG_INFO, "Fallback to 20 MHz");
     556             :         }
     557             : 
     558          24 :         hostapd_setup_interface_complete(iface, !res);
     559             : }
     560             : 
     561             : 
     562          18 : static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
     563             :                                          struct wpa_driver_scan_params *params)
     564             : {
     565             :         /* Scan only the affected frequency range */
     566             :         int pri_freq, sec_freq;
     567             :         int affected_start, affected_end;
     568             :         int i, pos;
     569             :         struct hostapd_hw_modes *mode;
     570             : 
     571          18 :         if (iface->current_mode == NULL)
     572           0 :                 return;
     573             : 
     574          18 :         pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
     575          18 :         if (iface->conf->secondary_channel > 0)
     576           8 :                 sec_freq = pri_freq + 20;
     577             :         else
     578          10 :                 sec_freq = pri_freq - 20;
     579          18 :         affected_start = (pri_freq + sec_freq) / 2 - 25;
     580          18 :         affected_end = (pri_freq + sec_freq) / 2 + 25;
     581          18 :         wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
     582             :                    affected_start, affected_end);
     583             : 
     584          18 :         mode = iface->current_mode;
     585          18 :         params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
     586          18 :         if (params->freqs == NULL)
     587           0 :                 return;
     588          18 :         pos = 0;
     589             : 
     590         270 :         for (i = 0; i < mode->num_channels; i++) {
     591         252 :                 struct hostapd_channel_data *chan = &mode->channels[i];
     592         252 :                 if (chan->flag & HOSTAPD_CHAN_DISABLED)
     593          36 :                         continue;
     594         430 :                 if (chan->freq < affected_start ||
     595         214 :                     chan->freq > affected_end)
     596          65 :                         continue;
     597         151 :                 params->freqs[pos++] = chan->freq;
     598             :         }
     599             : }
     600             : 
     601             : 
     602           9 : static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
     603             :                                         struct wpa_driver_scan_params *params)
     604             : {
     605             :         /* Scan only the affected frequency range */
     606             :         int pri_freq;
     607             :         int affected_start, affected_end;
     608             :         int i, pos;
     609             :         struct hostapd_hw_modes *mode;
     610             : 
     611           9 :         if (iface->current_mode == NULL)
     612           0 :                 return;
     613             : 
     614           9 :         pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
     615           9 :         if (iface->conf->secondary_channel > 0) {
     616           7 :                 affected_start = pri_freq - 10;
     617           7 :                 affected_end = pri_freq + 30;
     618             :         } else {
     619           2 :                 affected_start = pri_freq - 30;
     620           2 :                 affected_end = pri_freq + 10;
     621             :         }
     622           9 :         wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
     623             :                    affected_start, affected_end);
     624             : 
     625           9 :         mode = iface->current_mode;
     626           9 :         params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
     627           9 :         if (params->freqs == NULL)
     628           0 :                 return;
     629           9 :         pos = 0;
     630             : 
     631         225 :         for (i = 0; i < mode->num_channels; i++) {
     632         216 :                 struct hostapd_channel_data *chan = &mode->channels[i];
     633         216 :                 if (chan->flag & HOSTAPD_CHAN_DISABLED)
     634         150 :                         continue;
     635         132 :                 if (chan->freq < affected_start ||
     636          66 :                     chan->freq > affected_end)
     637          48 :                         continue;
     638          18 :                 params->freqs[pos++] = chan->freq;
     639             :         }
     640             : }
     641             : 
     642             : 
     643           0 : static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
     644             : {
     645             : #define HT2040_COEX_SCAN_RETRY 15
     646           0 :         struct hostapd_iface *iface = eloop_data;
     647             :         struct wpa_driver_scan_params params;
     648             :         int ret;
     649             : 
     650           0 :         os_memset(&params, 0, sizeof(params));
     651           0 :         if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
     652           0 :                 ieee80211n_scan_channels_2g4(iface, &params);
     653             :         else
     654           0 :                 ieee80211n_scan_channels_5g(iface, &params);
     655             : 
     656           0 :         ret = hostapd_driver_scan(iface->bss[0], &params);
     657           0 :         iface->num_ht40_scan_tries++;
     658           0 :         os_free(params.freqs);
     659             : 
     660           0 :         if (ret == -EBUSY &&
     661           0 :             iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
     662           0 :                 wpa_printf(MSG_ERROR,
     663             :                            "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
     664             :                            ret, strerror(-ret), iface->num_ht40_scan_tries);
     665           0 :                 eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
     666           0 :                 return;
     667             :         }
     668             : 
     669           0 :         if (ret == 0) {
     670           0 :                 iface->scan_cb = ieee80211n_check_scan;
     671           0 :                 return;
     672             :         }
     673             : 
     674           0 :         wpa_printf(MSG_DEBUG,
     675             :                    "Failed to request a scan in device, bringing up in HT20 mode");
     676           0 :         iface->conf->secondary_channel = 0;
     677           0 :         iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
     678           0 :         hostapd_setup_interface_complete(iface, 0);
     679             : }
     680             : 
     681             : 
     682         680 : void hostapd_stop_setup_timers(struct hostapd_iface *iface)
     683             : {
     684         680 :         eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
     685         680 : }
     686             : 
     687             : 
     688         662 : static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
     689             : {
     690             :         struct wpa_driver_scan_params params;
     691             :         int ret;
     692             : 
     693         662 :         if (!iface->conf->secondary_channel)
     694         635 :                 return 0; /* HT40 not used */
     695             : 
     696          27 :         hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
     697          27 :         wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
     698             :                    "40 MHz channel");
     699          27 :         os_memset(&params, 0, sizeof(params));
     700          27 :         if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
     701          18 :                 ieee80211n_scan_channels_2g4(iface, &params);
     702             :         else
     703           9 :                 ieee80211n_scan_channels_5g(iface, &params);
     704             : 
     705          27 :         ret = hostapd_driver_scan(iface->bss[0], &params);
     706          27 :         os_free(params.freqs);
     707             : 
     708          27 :         if (ret == -EBUSY) {
     709           0 :                 wpa_printf(MSG_ERROR,
     710             :                            "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
     711             :                            ret, strerror(-ret));
     712           0 :                 iface->num_ht40_scan_tries = 1;
     713           0 :                 eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
     714           0 :                 eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
     715           0 :                 return 1;
     716             :         }
     717             : 
     718          27 :         if (ret < 0) {
     719           0 :                 wpa_printf(MSG_ERROR,
     720             :                            "Failed to request a scan of neighboring BSSes ret=%d (%s)",
     721             :                            ret, strerror(-ret));
     722           0 :                 return -1;
     723             :         }
     724             : 
     725          27 :         iface->scan_cb = ieee80211n_check_scan;
     726          27 :         return 1;
     727             : }
     728             : 
     729             : 
     730         664 : static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
     731             : {
     732         664 :         u16 hw = iface->current_mode->ht_capab;
     733         664 :         u16 conf = iface->conf->ht_capab;
     734             : 
     735         665 :         if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
     736           1 :             !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
     737           1 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     738             :                            "HT capability [LDPC]");
     739           1 :                 return 0;
     740             :         }
     741             : 
     742         691 :         if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
     743          28 :             !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
     744           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     745             :                            "HT capability [HT40*]");
     746           0 :                 return 0;
     747             :         }
     748             : 
     749        1326 :         if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
     750         663 :             (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
     751           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     752             :                            "HT capability [SMPS-*]");
     753           0 :                 return 0;
     754             :         }
     755             : 
     756         789 :         if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
     757         126 :             !(hw & HT_CAP_INFO_GREEN_FIELD)) {
     758           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     759             :                            "HT capability [GF]");
     760           0 :                 return 0;
     761             :         }
     762             : 
     763         663 :         if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
     764           0 :             !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
     765           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     766             :                            "HT capability [SHORT-GI-20]");
     767           0 :                 return 0;
     768             :         }
     769             : 
     770         791 :         if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
     771         128 :             !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
     772           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     773             :                            "HT capability [SHORT-GI-40]");
     774           0 :                 return 0;
     775             :         }
     776             : 
     777         663 :         if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
     778           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     779             :                            "HT capability [TX-STBC]");
     780           0 :                 return 0;
     781             :         }
     782             : 
     783        1326 :         if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
     784         663 :             (hw & HT_CAP_INFO_RX_STBC_MASK)) {
     785           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     786             :                            "HT capability [RX-STBC*]");
     787           0 :                 return 0;
     788             :         }
     789             : 
     790         663 :         if ((conf & HT_CAP_INFO_DELAYED_BA) &&
     791           0 :             !(hw & HT_CAP_INFO_DELAYED_BA)) {
     792           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     793             :                            "HT capability [DELAYED-BA]");
     794           0 :                 return 0;
     795             :         }
     796             : 
     797         663 :         if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
     798           0 :             !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
     799           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     800             :                            "HT capability [MAX-AMSDU-7935]");
     801           0 :                 return 0;
     802             :         }
     803             : 
     804         663 :         if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
     805           0 :             !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
     806           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     807             :                            "HT capability [DSSS_CCK-40]");
     808           0 :                 return 0;
     809             :         }
     810             : 
     811         663 :         if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
     812           0 :             !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
     813           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured "
     814             :                            "HT capability [LSIG-TXOP-PROT]");
     815           0 :                 return 0;
     816             :         }
     817             : 
     818         663 :         return 1;
     819             : }
     820             : 
     821             : 
     822             : #ifdef CONFIG_IEEE80211AC
     823             : 
     824        8576 : static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
     825             : {
     826        8576 :         u32 req_cap = conf & cap;
     827             : 
     828             :         /*
     829             :          * Make sure we support all requested capabilities.
     830             :          * NOTE: We assume that 'cap' represents a capability mask,
     831             :          * not a discrete value.
     832             :          */
     833        8576 :         if ((hw & req_cap) != req_cap) {
     834           0 :                 wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
     835             :                            name);
     836           0 :                 return 0;
     837             :         }
     838        8576 :         return 1;
     839             : }
     840             : 
     841             : 
     842        2681 : static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
     843             :                                      const char *name)
     844             : {
     845        2681 :         u32 hw_max = hw & cap;
     846        2681 :         u32 conf_val = conf & cap;
     847             : 
     848        2681 :         if (conf_val > hw_max) {
     849           1 :                 int offset = find_first_bit(cap);
     850           1 :                 wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
     851             :                            name, conf_val >> offset, hw_max >> offset);
     852           1 :                 return 0;
     853             :         }
     854        2680 :         return 1;
     855             : }
     856             : 
     857             : 
     858         537 : static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
     859             : {
     860         537 :         u32 hw = iface->current_mode->vht_capab;
     861         537 :         u32 conf = iface->conf->vht_capab;
     862             : 
     863         537 :         wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
     864             :                    hw, conf);
     865             : 
     866             : #define VHT_CAP_CHECK(cap) \
     867             :         do { \
     868             :                 if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
     869             :                         return 0; \
     870             :         } while (0)
     871             : 
     872             : #define VHT_CAP_CHECK_MAX(cap) \
     873             :         do { \
     874             :                 if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
     875             :                         return 0; \
     876             :         } while (0)
     877             : 
     878         537 :         VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
     879         536 :         VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
     880         536 :         VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
     881         536 :         VHT_CAP_CHECK(VHT_CAP_RXLDPC);
     882         536 :         VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
     883         536 :         VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
     884         536 :         VHT_CAP_CHECK(VHT_CAP_TXSTBC);
     885         536 :         VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
     886         536 :         VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
     887         536 :         VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
     888         536 :         VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
     889         536 :         VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
     890         536 :         VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
     891         536 :         VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
     892         536 :         VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
     893         536 :         VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
     894         536 :         VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
     895         536 :         VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
     896         536 :         VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
     897         536 :         VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
     898         536 :         VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
     899             : 
     900             : #undef VHT_CAP_CHECK
     901             : #undef VHT_CAP_CHECK_MAX
     902             : 
     903         536 :         return 1;
     904             : }
     905             : #endif /* CONFIG_IEEE80211AC */
     906             : 
     907             : #endif /* CONFIG_IEEE80211N */
     908             : 
     909             : 
     910         669 : int hostapd_check_ht_capab(struct hostapd_iface *iface)
     911             : {
     912             : #ifdef CONFIG_IEEE80211N
     913             :         int ret;
     914         669 :         if (!iface->conf->ieee80211n)
     915           5 :                 return 0;
     916         664 :         if (!ieee80211n_supported_ht_capab(iface))
     917           1 :                 return -1;
     918             : #ifdef CONFIG_IEEE80211AC
     919         537 :         if (!ieee80211ac_supported_vht_capab(iface))
     920           1 :                 return -1;
     921             : #endif /* CONFIG_IEEE80211AC */
     922         662 :         ret = ieee80211n_check_40mhz(iface);
     923         662 :         if (ret)
     924          27 :                 return ret;
     925         635 :         if (!ieee80211n_allowed_ht40_channel_pair(iface))
     926           0 :                 return -1;
     927             : #endif /* CONFIG_IEEE80211N */
     928             : 
     929         635 :         return 0;
     930             : }
     931             : 
     932             : 
     933         700 : static int hostapd_is_usable_chan(struct hostapd_iface *iface,
     934             :                                   int channel, int primary)
     935             : {
     936             :         int i;
     937             :         struct hostapd_channel_data *chan;
     938             : 
     939        1604 :         for (i = 0; i < iface->current_mode->num_channels; i++) {
     940        1602 :                 chan = &iface->current_mode->channels[i];
     941        1602 :                 if (chan->chan != channel)
     942         904 :                         continue;
     943             : 
     944         698 :                 if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
     945         698 :                         return 1;
     946             : 
     947           0 :                 wpa_printf(MSG_DEBUG,
     948             :                            "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s",
     949             :                            primary ? "" : "Configured HT40 secondary ",
     950           0 :                            i, chan->chan, chan->flag,
     951           0 :                            chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "",
     952           0 :                            chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ?
     953             :                            " PASSIVE-SCAN" : "",
     954           0 :                            chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
     955             :         }
     956             : 
     957           2 :         return 0;
     958             : }
     959             : 
     960             : 
     961         671 : static int hostapd_is_usable_chans(struct hostapd_iface *iface)
     962             : {
     963         671 :         if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
     964           2 :                 return 0;
     965             : 
     966         669 :         if (!iface->conf->secondary_channel)
     967         640 :                 return 1;
     968             : 
     969          58 :         return hostapd_is_usable_chan(iface, iface->conf->channel +
     970          29 :                                       iface->conf->secondary_channel * 4, 0);
     971             : }
     972             : 
     973             : 
     974             : static enum hostapd_chan_status
     975         680 : hostapd_check_chans(struct hostapd_iface *iface)
     976             : {
     977         680 :         if (iface->conf->channel) {
     978         671 :                 if (hostapd_is_usable_chans(iface))
     979         669 :                         return HOSTAPD_CHAN_VALID;
     980             :                 else
     981           2 :                         return HOSTAPD_CHAN_INVALID;
     982             :         }
     983             : 
     984             :         /*
     985             :          * The user set channel=0 or channel=acs_survey
     986             :          * which is used to trigger ACS.
     987             :          */
     988             : 
     989           9 :         switch (acs_init(iface)) {
     990             :         case HOSTAPD_CHAN_ACS:
     991           9 :                 return HOSTAPD_CHAN_ACS;
     992             :         case HOSTAPD_CHAN_VALID:
     993             :         case HOSTAPD_CHAN_INVALID:
     994             :         default:
     995           0 :                 return HOSTAPD_CHAN_INVALID;
     996             :         }
     997             : }
     998             : 
     999             : 
    1000           2 : static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
    1001             : {
    1002           4 :         hostapd_logger(iface->bss[0], NULL,
    1003             :                        HOSTAPD_MODULE_IEEE80211,
    1004             :                        HOSTAPD_LEVEL_WARNING,
    1005             :                        "Configured channel (%d) not found from the "
    1006             :                        "channel list of current mode (%d) %s",
    1007           2 :                        iface->conf->channel,
    1008           2 :                        iface->current_mode->mode,
    1009           2 :                        hostapd_hw_mode_txt(iface->current_mode->mode));
    1010           2 :         hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
    1011             :                        HOSTAPD_LEVEL_WARNING,
    1012             :                        "Hardware does not support configured channel");
    1013           2 : }
    1014             : 
    1015             : 
    1016           7 : int hostapd_acs_completed(struct hostapd_iface *iface, int err)
    1017             : {
    1018           7 :         int ret = -1;
    1019             : 
    1020           7 :         if (err)
    1021           3 :                 goto out;
    1022             : 
    1023           4 :         switch (hostapd_check_chans(iface)) {
    1024             :         case HOSTAPD_CHAN_VALID:
    1025          12 :                 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
    1026             :                         ACS_EVENT_COMPLETED "freq=%d channel=%d",
    1027           4 :                         hostapd_hw_get_freq(iface->bss[0],
    1028           4 :                                             iface->conf->channel),
    1029           4 :                         iface->conf->channel);
    1030           4 :                 break;
    1031             :         case HOSTAPD_CHAN_ACS:
    1032           0 :                 wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
    1033           0 :                 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
    1034           0 :                 hostapd_notify_bad_chans(iface);
    1035           0 :                 goto out;
    1036             :         case HOSTAPD_CHAN_INVALID:
    1037             :         default:
    1038           0 :                 wpa_printf(MSG_ERROR, "ACS picked unusable channels");
    1039           0 :                 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
    1040           0 :                 hostapd_notify_bad_chans(iface);
    1041           0 :                 goto out;
    1042             :         }
    1043             : 
    1044           4 :         ret = hostapd_check_ht_capab(iface);
    1045           4 :         if (ret < 0)
    1046           0 :                 goto out;
    1047           4 :         if (ret == 1) {
    1048           1 :                 wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
    1049           1 :                 return 0;
    1050             :         }
    1051             : 
    1052           3 :         ret = 0;
    1053             : out:
    1054           6 :         return hostapd_setup_interface_complete(iface, ret);
    1055             : }
    1056             : 
    1057             : 
    1058             : /**
    1059             :  * hostapd_select_hw_mode - Select the hardware mode
    1060             :  * @iface: Pointer to interface data.
    1061             :  * Returns: 0 on success, < 0 on failure
    1062             :  *
    1063             :  * Sets up the hardware mode, channel, rates, and passive scanning
    1064             :  * based on the configuration.
    1065             :  */
    1066         676 : int hostapd_select_hw_mode(struct hostapd_iface *iface)
    1067             : {
    1068             :         int i;
    1069             : 
    1070         676 :         if (iface->num_hw_features < 1)
    1071           0 :                 return -1;
    1072             : 
    1073         703 :         if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
    1074         703 :              iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
    1075         675 :             iface->conf->channel == 14) {
    1076           2 :                 wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
    1077           2 :                 iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
    1078           2 :                 iface->conf->ieee80211n = 0;
    1079           2 :                 iface->conf->ieee80211ac = 0;
    1080             :         }
    1081             : 
    1082         676 :         iface->current_mode = NULL;
    1083         706 :         for (i = 0; i < iface->num_hw_features; i++) {
    1084         706 :                 struct hostapd_hw_modes *mode = &iface->hw_features[i];
    1085         706 :                 if (mode->mode == iface->conf->hw_mode) {
    1086         676 :                         iface->current_mode = mode;
    1087         676 :                         break;
    1088             :                 }
    1089             :         }
    1090             : 
    1091         676 :         if (iface->current_mode == NULL) {
    1092           0 :                 wpa_printf(MSG_ERROR, "Hardware does not support configured "
    1093             :                            "mode");
    1094           0 :                 hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
    1095             :                                HOSTAPD_LEVEL_WARNING,
    1096             :                                "Hardware does not support configured mode "
    1097             :                                "(%d) (hw_mode in hostapd.conf)",
    1098           0 :                                (int) iface->conf->hw_mode);
    1099           0 :                 return -2;
    1100             :         }
    1101             : 
    1102         676 :         switch (hostapd_check_chans(iface)) {
    1103             :         case HOSTAPD_CHAN_VALID:
    1104         665 :                 return 0;
    1105             :         case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
    1106           9 :                 return 1;
    1107             :         case HOSTAPD_CHAN_INVALID:
    1108             :         default:
    1109           2 :                 hostapd_notify_bad_chans(iface);
    1110           2 :                 return -3;
    1111             :         }
    1112             : }
    1113             : 
    1114             : 
    1115         666 : const char * hostapd_hw_mode_txt(int mode)
    1116             : {
    1117         666 :         switch (mode) {
    1118             :         case HOSTAPD_MODE_IEEE80211A:
    1119          20 :                 return "IEEE 802.11a";
    1120             :         case HOSTAPD_MODE_IEEE80211B:
    1121           3 :                 return "IEEE 802.11b";
    1122             :         case HOSTAPD_MODE_IEEE80211G:
    1123         643 :                 return "IEEE 802.11g";
    1124             :         case HOSTAPD_MODE_IEEE80211AD:
    1125           0 :                 return "IEEE 802.11ad";
    1126             :         default:
    1127           0 :                 return "UNKNOWN";
    1128             :         }
    1129             : }
    1130             : 
    1131             : 
    1132         721 : int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
    1133             : {
    1134             :         int i;
    1135             : 
    1136         721 :         if (!hapd->iface->current_mode)
    1137           0 :                 return 0;
    1138             : 
    1139        1655 :         for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
    1140        1655 :                 struct hostapd_channel_data *ch =
    1141        1655 :                         &hapd->iface->current_mode->channels[i];
    1142        1655 :                 if (ch->chan == chan)
    1143         721 :                         return ch->freq;
    1144             :         }
    1145             : 
    1146           0 :         return 0;
    1147             : }
    1148             : 
    1149             : 
    1150           2 : int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
    1151             : {
    1152             :         int i;
    1153             : 
    1154           2 :         if (!hapd->iface->current_mode)
    1155           0 :                 return 0;
    1156             : 
    1157           8 :         for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
    1158           8 :                 struct hostapd_channel_data *ch =
    1159           8 :                         &hapd->iface->current_mode->channels[i];
    1160           8 :                 if (ch->freq == freq)
    1161           2 :                         return ch->chan;
    1162             :         }
    1163             : 
    1164           0 :         return 0;
    1165             : }

Generated by: LCOV version 1.10