xref: /dragonfly/contrib/wpa_supplicant/src/common/hw_features_common.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * Common hostapd/wpa_supplicant HW features
3  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4  * Copyright (c) 2015, Qualcomm Atheros, Inc.
5  *
6  * This software may be distributed under the terms of the BSD license.
7  * See README for more details.
8  */
9 
10 #include "includes.h"
11 
12 #include "common.h"
13 #include "defs.h"
14 #include "ieee802_11_defs.h"
15 #include "ieee802_11_common.h"
16 #include "hw_features_common.h"
17 
18 
hw_get_channel_chan(struct hostapd_hw_modes * mode,int chan,int * freq)19 struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
20                                                               int chan, int *freq)
21 {
22           int i;
23 
24           if (freq)
25                     *freq = 0;
26 
27           if (!mode)
28                     return NULL;
29 
30           for (i = 0; i < mode->num_channels; i++) {
31                     struct hostapd_channel_data *ch = &mode->channels[i];
32                     if (ch->chan == chan) {
33                               if (freq)
34                                         *freq = ch->freq;
35                               return ch;
36                     }
37           }
38 
39           return NULL;
40 }
41 
42 
hw_get_channel_freq(struct hostapd_hw_modes * mode,int freq,int * chan)43 struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
44                                                               int freq, int *chan)
45 {
46           int i;
47 
48           if (chan)
49                     *chan = 0;
50 
51           if (!mode)
52                     return NULL;
53 
54           for (i = 0; i < mode->num_channels; i++) {
55                     struct hostapd_channel_data *ch = &mode->channels[i];
56                     if (ch->freq == freq) {
57                               if (chan)
58                                         *chan = ch->chan;
59                               return ch;
60                     }
61           }
62 
63           return NULL;
64 }
65 
66 
hw_get_freq(struct hostapd_hw_modes * mode,int chan)67 int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
68 {
69           int freq;
70 
71           hw_get_channel_chan(mode, chan, &freq);
72 
73           return freq;
74 }
75 
76 
hw_get_chan(struct hostapd_hw_modes * mode,int freq)77 int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
78 {
79           int chan;
80 
81           hw_get_channel_freq(mode, freq, &chan);
82 
83           return chan;
84 }
85 
86 
allowed_ht40_channel_pair(struct hostapd_hw_modes * mode,int pri_chan,int sec_chan)87 int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
88                                     int sec_chan)
89 {
90           int ok, first;
91           int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
92                                 149, 157, 165, 184, 192 };
93           size_t k;
94           struct hostapd_channel_data *p_chan, *s_chan;
95           const int ht40_plus = pri_chan < sec_chan;
96 
97           p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
98           if (!p_chan)
99                     return 0;
100 
101           if (pri_chan == sec_chan || !sec_chan) {
102                     if (chan_pri_allowed(p_chan))
103                               return 1; /* HT40 not used */
104 
105                     wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
106                                  pri_chan);
107                     return 0;
108           }
109 
110           s_chan = hw_get_channel_chan(mode, sec_chan, NULL);
111           if (!s_chan)
112                     return 0;
113 
114           wpa_printf(MSG_DEBUG,
115                        "HT40: control channel: %d  secondary channel: %d",
116                        pri_chan, sec_chan);
117 
118           /* Verify that HT40 secondary channel is an allowed 20 MHz
119            * channel */
120           if ((s_chan->flag & HOSTAPD_CHAN_DISABLED) ||
121               (ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
122               (!ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
123                     wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
124                                  sec_chan);
125                     return 0;
126           }
127 
128           /*
129            * Verify that HT40 primary,secondary channel pair is allowed per
130            * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
131            * 2.4 GHz rules allow all cases where the secondary channel fits into
132            * the list of allowed channels (already checked above).
133            */
134           if (mode->mode != HOSTAPD_MODE_IEEE80211A)
135                     return 1;
136 
137           first = pri_chan < sec_chan ? pri_chan : sec_chan;
138 
139           ok = 0;
140           for (k = 0; k < ARRAY_SIZE(allowed); k++) {
141                     if (first == allowed[k]) {
142                               ok = 1;
143                               break;
144                     }
145           }
146           if (!ok) {
147                     wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
148                                  pri_chan, sec_chan);
149                     return 0;
150           }
151 
152           return 1;
153 }
154 
155 
get_pri_sec_chan(struct wpa_scan_res * bss,int * pri_chan,int * sec_chan)156 void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
157 {
158           struct ieee80211_ht_operation *oper;
159           struct ieee802_11_elems elems;
160 
161           *pri_chan = *sec_chan = 0;
162 
163           ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
164           if (elems.ht_operation) {
165                     oper = (struct ieee80211_ht_operation *) elems.ht_operation;
166                     *pri_chan = oper->primary_chan;
167                     if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
168                               int sec = oper->ht_param &
169                                         HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
170                               if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
171                                         *sec_chan = *pri_chan + 4;
172                               else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
173                                         *sec_chan = *pri_chan - 4;
174                     }
175           }
176 }
177 
178 
check_40mhz_5g(struct hostapd_hw_modes * mode,struct wpa_scan_results * scan_res,int pri_chan,int sec_chan)179 int check_40mhz_5g(struct hostapd_hw_modes *mode,
180                        struct wpa_scan_results *scan_res, int pri_chan,
181                        int sec_chan)
182 {
183           int pri_freq, sec_freq, pri_bss, sec_bss;
184           int bss_pri_chan, bss_sec_chan;
185           size_t i;
186           int match;
187 
188           if (!mode || !scan_res || !pri_chan || !sec_chan ||
189               pri_chan == sec_chan)
190                     return 0;
191 
192           pri_freq = hw_get_freq(mode, pri_chan);
193           sec_freq = hw_get_freq(mode, sec_chan);
194 
195           /*
196            * Switch PRI/SEC channels if Beacons were detected on selected SEC
197            * channel, but not on selected PRI channel.
198            */
199           pri_bss = sec_bss = 0;
200           for (i = 0; i < scan_res->num; i++) {
201                     struct wpa_scan_res *bss = scan_res->res[i];
202                     if (bss->freq == pri_freq)
203                               pri_bss++;
204                     else if (bss->freq == sec_freq)
205                               sec_bss++;
206           }
207           if (sec_bss && !pri_bss) {
208                     wpa_printf(MSG_INFO,
209                                  "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes");
210                     return 2;
211           }
212 
213           /*
214            * Match PRI/SEC channel with any existing HT40 BSS on the same
215            * channels that we are about to use (if already mixed order in
216            * existing BSSes, use own preference).
217            */
218           match = 0;
219           for (i = 0; i < scan_res->num; i++) {
220                     struct wpa_scan_res *bss = scan_res->res[i];
221                     get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
222                     if (pri_chan == bss_pri_chan &&
223                         sec_chan == bss_sec_chan) {
224                               match = 1;
225                               break;
226                     }
227           }
228           if (!match) {
229                     for (i = 0; i < scan_res->num; i++) {
230                               struct wpa_scan_res *bss = scan_res->res[i];
231                               get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
232                               if (pri_chan == bss_sec_chan &&
233                                   sec_chan == bss_pri_chan) {
234                                         wpa_printf(MSG_INFO, "Switch own primary and "
235                                                      "secondary channel due to BSS "
236                                                      "overlap with " MACSTR,
237                                                      MAC2STR(bss->bssid));
238                                         return 2;
239                               }
240                     }
241           }
242 
243           return 1;
244 }
245 
246 
check_20mhz_bss(struct wpa_scan_res * bss,int pri_freq,int start,int end)247 static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start,
248                                  int end)
249 {
250           struct ieee802_11_elems elems;
251           struct ieee80211_ht_operation *oper;
252 
253           if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
254                     return 0;
255 
256           ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
257           if (!elems.ht_capabilities) {
258                     wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
259                                  MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
260                     return 1;
261           }
262 
263           if (elems.ht_operation) {
264                     oper = (struct ieee80211_ht_operation *) elems.ht_operation;
265                     if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
266                               return 0;
267 
268                     wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
269                                  MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
270                     return 1;
271           }
272           return 0;
273 }
274 
275 
check_40mhz_2g4(struct hostapd_hw_modes * mode,struct wpa_scan_results * scan_res,int pri_chan,int sec_chan)276 int check_40mhz_2g4(struct hostapd_hw_modes *mode,
277                         struct wpa_scan_results *scan_res, int pri_chan,
278                         int sec_chan)
279 {
280           int pri_freq, sec_freq;
281           int affected_start, affected_end;
282           size_t i;
283 
284           if (!mode || !scan_res || !pri_chan || !sec_chan ||
285               pri_chan == sec_chan)
286                     return 0;
287 
288           pri_freq = hw_get_freq(mode, pri_chan);
289           sec_freq = hw_get_freq(mode, sec_chan);
290 
291           affected_start = (pri_freq + sec_freq) / 2 - 25;
292           affected_end = (pri_freq + sec_freq) / 2 + 25;
293           wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
294                        affected_start, affected_end);
295           for (i = 0; i < scan_res->num; i++) {
296                     struct wpa_scan_res *bss = scan_res->res[i];
297                     int pri = bss->freq;
298                     int sec = pri;
299                     struct ieee802_11_elems elems;
300 
301                     /* Check for overlapping 20 MHz BSS */
302                     if (check_20mhz_bss(bss, pri_freq, affected_start,
303                                             affected_end)) {
304                               wpa_printf(MSG_DEBUG,
305                                            "Overlapping 20 MHz BSS is found");
306                               return 0;
307                     }
308 
309                     get_pri_sec_chan(bss, &pri_chan, &sec_chan);
310 
311                     if (sec_chan) {
312                               if (sec_chan < pri_chan)
313                                         sec = pri - 20;
314                               else
315                                         sec = pri + 20;
316                     }
317 
318                     if ((pri < affected_start || pri > affected_end) &&
319                         (sec < affected_start || sec > affected_end))
320                               continue; /* not within affected channel range */
321 
322                     wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
323                                  " freq=%d pri=%d sec=%d",
324                                  MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
325 
326                     if (sec_chan) {
327                               if (pri_freq != pri || sec_freq != sec) {
328                                         wpa_printf(MSG_DEBUG,
329                                                      "40 MHz pri/sec mismatch with BSS "
330                                                      MACSTR
331                                                      " <%d,%d> (chan=%d%c) vs. <%d,%d>",
332                                                      MAC2STR(bss->bssid),
333                                                      pri, sec, pri_chan,
334                                                      sec > pri ? '+' : '-',
335                                                      pri_freq, sec_freq);
336                                         return 0;
337                               }
338                     }
339 
340                     ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
341                                                0);
342                     if (elems.ht_capabilities) {
343                               struct ieee80211_ht_capabilities *ht_cap =
344                                         (struct ieee80211_ht_capabilities *)
345                                         elems.ht_capabilities;
346 
347                               if (le_to_host16(ht_cap->ht_capabilities_info) &
348                                   HT_CAP_INFO_40MHZ_INTOLERANT) {
349                                         wpa_printf(MSG_DEBUG,
350                                                      "40 MHz Intolerant is set on channel %d in BSS "
351                                                      MACSTR, pri, MAC2STR(bss->bssid));
352                                         return 0;
353                               }
354                     }
355           }
356 
357           return 1;
358 }
359 
360 
hostapd_set_freq_params(struct hostapd_freq_params * data,enum hostapd_hw_mode mode,int freq,int channel,int ht_enabled,int vht_enabled,int he_enabled,int sec_channel_offset,int oper_chwidth,int center_segment0,int center_segment1,u32 vht_caps,struct he_capabilities * he_cap)361 int hostapd_set_freq_params(struct hostapd_freq_params *data,
362                                   enum hostapd_hw_mode mode,
363                                   int freq, int channel, int ht_enabled,
364                                   int vht_enabled, int he_enabled,
365                                   int sec_channel_offset,
366                                   int oper_chwidth, int center_segment0,
367                                   int center_segment1, u32 vht_caps,
368                                   struct he_capabilities *he_cap)
369 {
370           if (!he_cap)
371                     he_enabled = 0;
372           os_memset(data, 0, sizeof(*data));
373           data->mode = mode;
374           data->freq = freq;
375           data->channel = channel;
376           data->ht_enabled = ht_enabled;
377           data->vht_enabled = vht_enabled;
378           data->he_enabled = he_enabled;
379           data->sec_channel_offset = sec_channel_offset;
380           data->center_freq1 = freq + sec_channel_offset * 10;
381           data->center_freq2 = 0;
382           data->bandwidth = sec_channel_offset ? 40 : 20;
383 
384           if (data->vht_enabled) switch (oper_chwidth) {
385           case CHANWIDTH_USE_HT:
386                     if (center_segment1 ||
387                         (center_segment0 != 0 &&
388                          5000 + center_segment0 * 5 != data->center_freq1 &&
389                          2407 + center_segment0 * 5 != data->center_freq1))
390                               return -1;
391                     break;
392           case CHANWIDTH_80P80MHZ:
393                     if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
394                               wpa_printf(MSG_ERROR,
395                                            "80+80 channel width is not supported!");
396                               return -1;
397                     }
398                     if (center_segment1 == center_segment0 + 4 ||
399                         center_segment1 == center_segment0 - 4)
400                               return -1;
401                     data->center_freq2 = 5000 + center_segment1 * 5;
402                     /* fall through */
403           case CHANWIDTH_80MHZ:
404                     data->bandwidth = 80;
405                     if ((oper_chwidth == CHANWIDTH_80MHZ &&
406                          center_segment1) ||
407                         (oper_chwidth == CHANWIDTH_80P80MHZ &&
408                          !center_segment1) ||
409                         !sec_channel_offset)
410                               return -1;
411                     if (!center_segment0) {
412                               if (channel <= 48)
413                                         center_segment0 = 42;
414                               else if (channel <= 64)
415                                         center_segment0 = 58;
416                               else if (channel <= 112)
417                                         center_segment0 = 106;
418                               else if (channel <= 128)
419                                         center_segment0 = 122;
420                               else if (channel <= 144)
421                                         center_segment0 = 138;
422                               else if (channel <= 161)
423                                         center_segment0 = 155;
424                               data->center_freq1 = 5000 + center_segment0 * 5;
425                     } else {
426                               /*
427                                * Note: HT/VHT config and params are coupled. Check if
428                                * HT40 channel band is in VHT80 Pri channel band
429                                * configuration.
430                                */
431                               if (center_segment0 == channel + 6 ||
432                                   center_segment0 == channel + 2 ||
433                                   center_segment0 == channel - 2 ||
434                                   center_segment0 == channel - 6)
435                                         data->center_freq1 = 5000 + center_segment0 * 5;
436                               else
437                                         return -1;
438                     }
439                     break;
440           case CHANWIDTH_160MHZ:
441                     data->bandwidth = 160;
442                     if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
443                                           VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
444                               wpa_printf(MSG_ERROR,
445                                            "160MHZ channel width is not supported!");
446                               return -1;
447                     }
448                     if (center_segment1)
449                               return -1;
450                     if (!sec_channel_offset)
451                               return -1;
452                     /*
453                      * Note: HT/VHT config and params are coupled. Check if
454                      * HT40 channel band is in VHT160 channel band configuration.
455                      */
456                     if (center_segment0 == channel + 14 ||
457                         center_segment0 == channel + 10 ||
458                         center_segment0 == channel + 6 ||
459                         center_segment0 == channel + 2 ||
460                         center_segment0 == channel - 2 ||
461                         center_segment0 == channel - 6 ||
462                         center_segment0 == channel - 10 ||
463                         center_segment0 == channel - 14)
464                               data->center_freq1 = 5000 + center_segment0 * 5;
465                     else
466                               return -1;
467                     break;
468           }
469 
470           return 0;
471 }
472 
473 
set_disable_ht40(struct ieee80211_ht_capabilities * htcaps,int disabled)474 void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
475                           int disabled)
476 {
477           /* Masking these out disables HT40 */
478           le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
479                                         HT_CAP_INFO_SHORT_GI40MHZ);
480 
481           if (disabled)
482                     htcaps->ht_capabilities_info &= ~msk;
483           else
484                     htcaps->ht_capabilities_info |= msk;
485 }
486 
487 
488 #ifdef CONFIG_IEEE80211AC
489 
_ieee80211ac_cap_check(u32 hw,u32 conf,u32 cap,const char * name)490 static int _ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap,
491                                           const char *name)
492 {
493           u32 req_cap = conf & cap;
494 
495           /*
496            * Make sure we support all requested capabilities.
497            * NOTE: We assume that 'cap' represents a capability mask,
498            * not a discrete value.
499            */
500           if ((hw & req_cap) != req_cap) {
501                     wpa_printf(MSG_ERROR,
502                                  "Driver does not support configured VHT capability [%s]",
503                                  name);
504                     return 0;
505           }
506           return 1;
507 }
508 
509 
ieee80211ac_cap_check_max(u32 hw,u32 conf,u32 mask,unsigned int shift,const char * name)510 static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
511                                              unsigned int shift,
512                                              const char *name)
513 {
514           u32 hw_max = hw & mask;
515           u32 conf_val = conf & mask;
516 
517           if (conf_val > hw_max) {
518                     wpa_printf(MSG_ERROR,
519                                  "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
520                                  name, conf_val >> shift, hw_max >> shift);
521                     return 0;
522           }
523           return 1;
524 }
525 
526 
ieee80211ac_cap_check(u32 hw,u32 conf)527 int ieee80211ac_cap_check(u32 hw, u32 conf)
528 {
529 #define VHT_CAP_CHECK(cap) \
530           do { \
531                     if (!_ieee80211ac_cap_check(hw, conf, cap, #cap)) \
532                               return 0; \
533           } while (0)
534 
535 #define VHT_CAP_CHECK_MAX(cap) \
536           do { \
537                     if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
538                                                          #cap)) \
539                               return 0; \
540           } while (0)
541 
542           VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
543           VHT_CAP_CHECK_MAX(VHT_CAP_SUPP_CHAN_WIDTH_MASK);
544           VHT_CAP_CHECK(VHT_CAP_RXLDPC);
545           VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
546           VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
547           VHT_CAP_CHECK(VHT_CAP_TXSTBC);
548           VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
549           VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
550           VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
551           VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
552           VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
553           VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
554           VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
555           VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
556           VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
557           VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
558           VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
559           VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
560           VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
561           VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
562 
563 #undef VHT_CAP_CHECK
564 #undef VHT_CAP_CHECK_MAX
565 
566           return 1;
567 }
568 
569 #endif /* CONFIG_IEEE80211AC */
570 
571 
num_chan_to_bw(int num_chans)572 u32 num_chan_to_bw(int num_chans)
573 {
574           switch (num_chans) {
575           case 2:
576           case 4:
577           case 8:
578                     return num_chans * 20;
579           default:
580                     return 20;
581           }
582 }
583 
584 
585 /* check if BW is applicable for channel */
chan_bw_allowed(const struct hostapd_channel_data * chan,u32 bw,int ht40_plus,int pri)586 int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
587                         int ht40_plus, int pri)
588 {
589           u32 bw_mask;
590 
591           switch (bw) {
592           case 20:
593                     bw_mask = HOSTAPD_CHAN_WIDTH_20;
594                     break;
595           case 40:
596                     /* HT 40 MHz support declared only for primary channel,
597                      * just skip 40 MHz secondary checking */
598                     if (pri && ht40_plus)
599                               bw_mask = HOSTAPD_CHAN_WIDTH_40P;
600                     else if (pri && !ht40_plus)
601                               bw_mask = HOSTAPD_CHAN_WIDTH_40M;
602                     else
603                               bw_mask = 0;
604                     break;
605           case 80:
606                     bw_mask = HOSTAPD_CHAN_WIDTH_80;
607                     break;
608           case 160:
609                     bw_mask = HOSTAPD_CHAN_WIDTH_160;
610                     break;
611           default:
612                     bw_mask = 0;
613                     break;
614           }
615 
616           return (chan->allowed_bw & bw_mask) == bw_mask;
617 }
618 
619 
620 /* check if channel is allowed to be used as primary */
chan_pri_allowed(const struct hostapd_channel_data * chan)621 int chan_pri_allowed(const struct hostapd_channel_data *chan)
622 {
623           return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
624                     (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
625 }
626