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 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 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 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 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 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 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 */ 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 */ 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