]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/common/hw_features_common.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / common / hw_features_common.c
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
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
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
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
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
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
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
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
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
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
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 sec_channel_offset,
365                             int vht_oper_chwidth, int center_segment0,
366                             int center_segment1, u32 vht_caps)
367 {
368         os_memset(data, 0, sizeof(*data));
369         data->mode = mode;
370         data->freq = freq;
371         data->channel = channel;
372         data->ht_enabled = ht_enabled;
373         data->vht_enabled = vht_enabled;
374         data->sec_channel_offset = sec_channel_offset;
375         data->center_freq1 = freq + sec_channel_offset * 10;
376         data->center_freq2 = 0;
377         data->bandwidth = sec_channel_offset ? 40 : 20;
378
379         if (data->vht_enabled) switch (vht_oper_chwidth) {
380         case VHT_CHANWIDTH_USE_HT:
381                 if (center_segment1 ||
382                     (center_segment0 != 0 &&
383                      5000 + center_segment0 * 5 != data->center_freq1 &&
384                      2407 + center_segment0 * 5 != data->center_freq1))
385                         return -1;
386                 break;
387         case VHT_CHANWIDTH_80P80MHZ:
388                 if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
389                         wpa_printf(MSG_ERROR,
390                                    "80+80 channel width is not supported!");
391                         return -1;
392                 }
393                 if (center_segment1 == center_segment0 + 4 ||
394                     center_segment1 == center_segment0 - 4)
395                         return -1;
396                 data->center_freq2 = 5000 + center_segment1 * 5;
397                 /* fall through */
398         case VHT_CHANWIDTH_80MHZ:
399                 data->bandwidth = 80;
400                 if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
401                      center_segment1) ||
402                     (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
403                      !center_segment1) ||
404                     !sec_channel_offset)
405                         return -1;
406                 if (!center_segment0) {
407                         if (channel <= 48)
408                                 center_segment0 = 42;
409                         else if (channel <= 64)
410                                 center_segment0 = 58;
411                         else if (channel <= 112)
412                                 center_segment0 = 106;
413                         else if (channel <= 128)
414                                 center_segment0 = 122;
415                         else if (channel <= 144)
416                                 center_segment0 = 138;
417                         else if (channel <= 161)
418                                 center_segment0 = 155;
419                         data->center_freq1 = 5000 + center_segment0 * 5;
420                 } else {
421                         /*
422                          * Note: HT/VHT config and params are coupled. Check if
423                          * HT40 channel band is in VHT80 Pri channel band
424                          * configuration.
425                          */
426                         if (center_segment0 == channel + 6 ||
427                             center_segment0 == channel + 2 ||
428                             center_segment0 == channel - 2 ||
429                             center_segment0 == channel - 6)
430                                 data->center_freq1 = 5000 + center_segment0 * 5;
431                         else
432                                 return -1;
433                 }
434                 break;
435         case VHT_CHANWIDTH_160MHZ:
436                 data->bandwidth = 160;
437                 if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
438                                   VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
439                         wpa_printf(MSG_ERROR,
440                                    "160MHZ channel width is not supported!");
441                         return -1;
442                 }
443                 if (center_segment1)
444                         return -1;
445                 if (!sec_channel_offset)
446                         return -1;
447                 /*
448                  * Note: HT/VHT config and params are coupled. Check if
449                  * HT40 channel band is in VHT160 channel band configuration.
450                  */
451                 if (center_segment0 == channel + 14 ||
452                     center_segment0 == channel + 10 ||
453                     center_segment0 == channel + 6 ||
454                     center_segment0 == channel + 2 ||
455                     center_segment0 == channel - 2 ||
456                     center_segment0 == channel - 6 ||
457                     center_segment0 == channel - 10 ||
458                     center_segment0 == channel - 14)
459                         data->center_freq1 = 5000 + center_segment0 * 5;
460                 else
461                         return -1;
462                 break;
463         }
464
465         return 0;
466 }
467
468
469 void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
470                       int disabled)
471 {
472         /* Masking these out disables HT40 */
473         le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
474                                 HT_CAP_INFO_SHORT_GI40MHZ);
475
476         if (disabled)
477                 htcaps->ht_capabilities_info &= ~msk;
478         else
479                 htcaps->ht_capabilities_info |= msk;
480 }
481
482
483 #ifdef CONFIG_IEEE80211AC
484
485 static int _ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap,
486                                   const char *name)
487 {
488         u32 req_cap = conf & cap;
489
490         /*
491          * Make sure we support all requested capabilities.
492          * NOTE: We assume that 'cap' represents a capability mask,
493          * not a discrete value.
494          */
495         if ((hw & req_cap) != req_cap) {
496                 wpa_printf(MSG_ERROR,
497                            "Driver does not support configured VHT capability [%s]",
498                            name);
499                 return 0;
500         }
501         return 1;
502 }
503
504
505 static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
506                                      unsigned int shift,
507                                      const char *name)
508 {
509         u32 hw_max = hw & mask;
510         u32 conf_val = conf & mask;
511
512         if (conf_val > hw_max) {
513                 wpa_printf(MSG_ERROR,
514                            "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
515                            name, conf_val >> shift, hw_max >> shift);
516                 return 0;
517         }
518         return 1;
519 }
520
521
522 int ieee80211ac_cap_check(u32 hw, u32 conf)
523 {
524 #define VHT_CAP_CHECK(cap) \
525         do { \
526                 if (!_ieee80211ac_cap_check(hw, conf, cap, #cap)) \
527                         return 0; \
528         } while (0)
529
530 #define VHT_CAP_CHECK_MAX(cap) \
531         do { \
532                 if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
533                                                #cap)) \
534                         return 0; \
535         } while (0)
536
537         VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
538         VHT_CAP_CHECK_MAX(VHT_CAP_SUPP_CHAN_WIDTH_MASK);
539         VHT_CAP_CHECK(VHT_CAP_RXLDPC);
540         VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
541         VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
542         VHT_CAP_CHECK(VHT_CAP_TXSTBC);
543         VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
544         VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
545         VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
546         VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
547         VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
548         VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
549         VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
550         VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
551         VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
552         VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
553         VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
554         VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
555         VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
556         VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
557
558 #undef VHT_CAP_CHECK
559 #undef VHT_CAP_CHECK_MAX
560
561         return 1;
562 }
563
564 #endif /* CONFIG_IEEE80211AC */
565
566
567 u32 num_chan_to_bw(int num_chans)
568 {
569         switch (num_chans) {
570         case 2:
571         case 4:
572         case 8:
573                 return num_chans * 20;
574         default:
575                 return 20;
576         }
577 }
578
579
580 /* check if BW is applicable for channel */
581 int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
582                     int ht40_plus, int pri)
583 {
584         u32 bw_mask;
585
586         switch (bw) {
587         case 20:
588                 bw_mask = HOSTAPD_CHAN_WIDTH_20;
589                 break;
590         case 40:
591                 /* HT 40 MHz support declared only for primary channel,
592                  * just skip 40 MHz secondary checking */
593                 if (pri && ht40_plus)
594                         bw_mask = HOSTAPD_CHAN_WIDTH_40P;
595                 else if (pri && !ht40_plus)
596                         bw_mask = HOSTAPD_CHAN_WIDTH_40M;
597                 else
598                         bw_mask = 0;
599                 break;
600         case 80:
601                 bw_mask = HOSTAPD_CHAN_WIDTH_80;
602                 break;
603         case 160:
604                 bw_mask = HOSTAPD_CHAN_WIDTH_160;
605                 break;
606         default:
607                 bw_mask = 0;
608                 break;
609         }
610
611         return (chan->allowed_bw & bw_mask) == bw_mask;
612 }
613
614
615 /* check if channel is allowed to be used as primary */
616 int chan_pri_allowed(const struct hostapd_channel_data *chan)
617 {
618         return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
619                 (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
620 }