1 /* 2 * IEEE 802.11 Common routines 3 * Copyright (c) 2002-2013, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "defs.h" 13 #include "ieee802_11_defs.h" 14 #include "ieee802_11_common.h" 15 16 17 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 18 struct ieee802_11_elems *elems, 19 int show_errors) 20 { 21 unsigned int oui; 22 23 /* first 3 bytes in vendor specific information element are the IEEE 24 * OUI of the vendor. The following byte is used a vendor specific 25 * sub-type. */ 26 if (elen < 4) { 27 if (show_errors) { 28 wpa_printf(MSG_MSGDUMP, "short vendor specific " 29 "information element ignored (len=%lu)", 30 (unsigned long) elen); 31 } 32 return -1; 33 } 34 35 oui = WPA_GET_BE24(pos); 36 switch (oui) { 37 case OUI_MICROSOFT: 38 /* Microsoft/Wi-Fi information elements are further typed and 39 * subtyped */ 40 switch (pos[3]) { 41 case 1: 42 /* Microsoft OUI (00:50:F2) with OUI Type 1: 43 * real WPA information element */ 44 elems->wpa_ie = pos; 45 elems->wpa_ie_len = elen; 46 break; 47 case WMM_OUI_TYPE: 48 /* WMM information element */ 49 if (elen < 5) { 50 wpa_printf(MSG_MSGDUMP, "short WMM " 51 "information element ignored " 52 "(len=%lu)", 53 (unsigned long) elen); 54 return -1; 55 } 56 switch (pos[4]) { 57 case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 58 case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 59 /* 60 * Share same pointer since only one of these 61 * is used and they start with same data. 62 * Length field can be used to distinguish the 63 * IEs. 64 */ 65 elems->wmm = pos; 66 elems->wmm_len = elen; 67 break; 68 case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 69 elems->wmm_tspec = pos; 70 elems->wmm_tspec_len = elen; 71 break; 72 default: 73 wpa_printf(MSG_EXCESSIVE, "unknown WMM " 74 "information element ignored " 75 "(subtype=%d len=%lu)", 76 pos[4], (unsigned long) elen); 77 return -1; 78 } 79 break; 80 case 4: 81 /* Wi-Fi Protected Setup (WPS) IE */ 82 elems->wps_ie = pos; 83 elems->wps_ie_len = elen; 84 break; 85 default: 86 wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 87 "information element ignored " 88 "(type=%d len=%lu)", 89 pos[3], (unsigned long) elen); 90 return -1; 91 } 92 break; 93 94 case OUI_WFA: 95 switch (pos[3]) { 96 case P2P_OUI_TYPE: 97 /* Wi-Fi Alliance - P2P IE */ 98 elems->p2p = pos; 99 elems->p2p_len = elen; 100 break; 101 case WFD_OUI_TYPE: 102 /* Wi-Fi Alliance - WFD IE */ 103 elems->wfd = pos; 104 elems->wfd_len = elen; 105 break; 106 case HS20_INDICATION_OUI_TYPE: 107 /* Hotspot 2.0 */ 108 elems->hs20 = pos; 109 elems->hs20_len = elen; 110 break; 111 case HS20_OSEN_OUI_TYPE: 112 /* Hotspot 2.0 OSEN */ 113 elems->osen = pos; 114 elems->osen_len = elen; 115 break; 116 default: 117 wpa_printf(MSG_MSGDUMP, "Unknown WFA " 118 "information element ignored " 119 "(type=%d len=%lu)", 120 pos[3], (unsigned long) elen); 121 return -1; 122 } 123 break; 124 125 case OUI_BROADCOM: 126 switch (pos[3]) { 127 case VENDOR_HT_CAPAB_OUI_TYPE: 128 elems->vendor_ht_cap = pos; 129 elems->vendor_ht_cap_len = elen; 130 break; 131 default: 132 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 133 "information element ignored " 134 "(type=%d len=%lu)", 135 pos[3], (unsigned long) elen); 136 return -1; 137 } 138 break; 139 140 default: 141 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 142 "information element ignored (vendor OUI " 143 "%02x:%02x:%02x len=%lu)", 144 pos[0], pos[1], pos[2], (unsigned long) elen); 145 return -1; 146 } 147 148 return 0; 149 } 150 151 152 /** 153 * ieee802_11_parse_elems - Parse information elements in management frames 154 * @start: Pointer to the start of IEs 155 * @len: Length of IE buffer in octets 156 * @elems: Data structure for parsed elements 157 * @show_errors: Whether to show parsing errors in debug log 158 * Returns: Parsing result 159 */ 160 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 161 struct ieee802_11_elems *elems, 162 int show_errors) 163 { 164 size_t left = len; 165 const u8 *pos = start; 166 int unknown = 0; 167 168 os_memset(elems, 0, sizeof(*elems)); 169 170 while (left >= 2) { 171 u8 id, elen; 172 173 id = *pos++; 174 elen = *pos++; 175 left -= 2; 176 177 if (elen > left) { 178 if (show_errors) { 179 wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 180 "parse failed (id=%d elen=%d " 181 "left=%lu)", 182 id, elen, (unsigned long) left); 183 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 184 } 185 return ParseFailed; 186 } 187 188 switch (id) { 189 case WLAN_EID_SSID: 190 elems->ssid = pos; 191 elems->ssid_len = elen; 192 break; 193 case WLAN_EID_SUPP_RATES: 194 elems->supp_rates = pos; 195 elems->supp_rates_len = elen; 196 break; 197 case WLAN_EID_DS_PARAMS: 198 elems->ds_params = pos; 199 elems->ds_params_len = elen; 200 break; 201 case WLAN_EID_CF_PARAMS: 202 case WLAN_EID_TIM: 203 break; 204 case WLAN_EID_CHALLENGE: 205 elems->challenge = pos; 206 elems->challenge_len = elen; 207 break; 208 case WLAN_EID_ERP_INFO: 209 elems->erp_info = pos; 210 elems->erp_info_len = elen; 211 break; 212 case WLAN_EID_EXT_SUPP_RATES: 213 elems->ext_supp_rates = pos; 214 elems->ext_supp_rates_len = elen; 215 break; 216 case WLAN_EID_VENDOR_SPECIFIC: 217 if (ieee802_11_parse_vendor_specific(pos, elen, 218 elems, 219 show_errors)) 220 unknown++; 221 break; 222 case WLAN_EID_RSN: 223 elems->rsn_ie = pos; 224 elems->rsn_ie_len = elen; 225 break; 226 case WLAN_EID_PWR_CAPABILITY: 227 break; 228 case WLAN_EID_SUPPORTED_CHANNELS: 229 elems->supp_channels = pos; 230 elems->supp_channels_len = elen; 231 break; 232 case WLAN_EID_MOBILITY_DOMAIN: 233 elems->mdie = pos; 234 elems->mdie_len = elen; 235 break; 236 case WLAN_EID_FAST_BSS_TRANSITION: 237 elems->ftie = pos; 238 elems->ftie_len = elen; 239 break; 240 case WLAN_EID_TIMEOUT_INTERVAL: 241 elems->timeout_int = pos; 242 elems->timeout_int_len = elen; 243 break; 244 case WLAN_EID_HT_CAP: 245 elems->ht_capabilities = pos; 246 elems->ht_capabilities_len = elen; 247 break; 248 case WLAN_EID_HT_OPERATION: 249 elems->ht_operation = pos; 250 elems->ht_operation_len = elen; 251 break; 252 case WLAN_EID_VHT_CAP: 253 elems->vht_capabilities = pos; 254 elems->vht_capabilities_len = elen; 255 break; 256 case WLAN_EID_VHT_OPERATION: 257 elems->vht_operation = pos; 258 elems->vht_operation_len = elen; 259 break; 260 case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: 261 if (elen != 1) 262 break; 263 elems->vht_opmode_notif = pos; 264 break; 265 case WLAN_EID_LINK_ID: 266 if (elen < 18) 267 break; 268 elems->link_id = pos; 269 break; 270 case WLAN_EID_INTERWORKING: 271 elems->interworking = pos; 272 elems->interworking_len = elen; 273 break; 274 case WLAN_EID_QOS_MAP_SET: 275 if (elen < 16) 276 break; 277 elems->qos_map_set = pos; 278 elems->qos_map_set_len = elen; 279 break; 280 case WLAN_EID_EXT_CAPAB: 281 elems->ext_capab = pos; 282 elems->ext_capab_len = elen; 283 break; 284 case WLAN_EID_BSS_MAX_IDLE_PERIOD: 285 if (elen < 3) 286 break; 287 elems->bss_max_idle_period = pos; 288 break; 289 case WLAN_EID_SSID_LIST: 290 elems->ssid_list = pos; 291 elems->ssid_list_len = elen; 292 break; 293 default: 294 unknown++; 295 if (!show_errors) 296 break; 297 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 298 "ignored unknown element (id=%d elen=%d)", 299 id, elen); 300 break; 301 } 302 303 left -= elen; 304 pos += elen; 305 } 306 307 if (left) 308 return ParseFailed; 309 310 return unknown ? ParseUnknown : ParseOK; 311 } 312 313 314 int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 315 { 316 int count = 0; 317 const u8 *pos, *end; 318 319 if (ies == NULL) 320 return 0; 321 322 pos = ies; 323 end = ies + ies_len; 324 325 while (pos + 2 <= end) { 326 if (pos + 2 + pos[1] > end) 327 break; 328 count++; 329 pos += 2 + pos[1]; 330 } 331 332 return count; 333 } 334 335 336 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 337 u32 oui_type) 338 { 339 struct wpabuf *buf; 340 const u8 *end, *pos, *ie; 341 342 pos = ies; 343 end = ies + ies_len; 344 ie = NULL; 345 346 while (pos + 1 < end) { 347 if (pos + 2 + pos[1] > end) 348 return NULL; 349 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 350 WPA_GET_BE32(&pos[2]) == oui_type) { 351 ie = pos; 352 break; 353 } 354 pos += 2 + pos[1]; 355 } 356 357 if (ie == NULL) 358 return NULL; /* No specified vendor IE found */ 359 360 buf = wpabuf_alloc(ies_len); 361 if (buf == NULL) 362 return NULL; 363 364 /* 365 * There may be multiple vendor IEs in the message, so need to 366 * concatenate their data fields. 367 */ 368 while (pos + 1 < end) { 369 if (pos + 2 + pos[1] > end) 370 break; 371 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 372 WPA_GET_BE32(&pos[2]) == oui_type) 373 wpabuf_put_data(buf, pos + 6, pos[1] - 4); 374 pos += 2 + pos[1]; 375 } 376 377 return buf; 378 } 379 380 381 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 382 { 383 u16 fc, type, stype; 384 385 /* 386 * PS-Poll frames are 16 bytes. All other frames are 387 * 24 bytes or longer. 388 */ 389 if (len < 16) 390 return NULL; 391 392 fc = le_to_host16(hdr->frame_control); 393 type = WLAN_FC_GET_TYPE(fc); 394 stype = WLAN_FC_GET_STYPE(fc); 395 396 switch (type) { 397 case WLAN_FC_TYPE_DATA: 398 if (len < 24) 399 return NULL; 400 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 401 case WLAN_FC_FROMDS | WLAN_FC_TODS: 402 case WLAN_FC_TODS: 403 return hdr->addr1; 404 case WLAN_FC_FROMDS: 405 return hdr->addr2; 406 default: 407 return NULL; 408 } 409 case WLAN_FC_TYPE_CTRL: 410 if (stype != WLAN_FC_STYPE_PSPOLL) 411 return NULL; 412 return hdr->addr1; 413 case WLAN_FC_TYPE_MGMT: 414 return hdr->addr3; 415 default: 416 return NULL; 417 } 418 } 419 420 421 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 422 const char *name, const char *val) 423 { 424 int num, v; 425 const char *pos; 426 struct hostapd_wmm_ac_params *ac; 427 428 /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 429 pos = name + 7; 430 if (os_strncmp(pos, "be_", 3) == 0) { 431 num = 0; 432 pos += 3; 433 } else if (os_strncmp(pos, "bk_", 3) == 0) { 434 num = 1; 435 pos += 3; 436 } else if (os_strncmp(pos, "vi_", 3) == 0) { 437 num = 2; 438 pos += 3; 439 } else if (os_strncmp(pos, "vo_", 3) == 0) { 440 num = 3; 441 pos += 3; 442 } else { 443 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 444 return -1; 445 } 446 447 ac = &wmm_ac_params[num]; 448 449 if (os_strcmp(pos, "aifs") == 0) { 450 v = atoi(val); 451 if (v < 1 || v > 255) { 452 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 453 return -1; 454 } 455 ac->aifs = v; 456 } else if (os_strcmp(pos, "cwmin") == 0) { 457 v = atoi(val); 458 if (v < 0 || v > 12) { 459 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 460 return -1; 461 } 462 ac->cwmin = v; 463 } else if (os_strcmp(pos, "cwmax") == 0) { 464 v = atoi(val); 465 if (v < 0 || v > 12) { 466 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 467 return -1; 468 } 469 ac->cwmax = v; 470 } else if (os_strcmp(pos, "txop_limit") == 0) { 471 v = atoi(val); 472 if (v < 0 || v > 0xffff) { 473 wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 474 return -1; 475 } 476 ac->txop_limit = v; 477 } else if (os_strcmp(pos, "acm") == 0) { 478 v = atoi(val); 479 if (v < 0 || v > 1) { 480 wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 481 return -1; 482 } 483 ac->admission_control_mandatory = v; 484 } else { 485 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 486 return -1; 487 } 488 489 return 0; 490 } 491 492 493 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) 494 { 495 enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES; 496 497 if (freq >= 2412 && freq <= 2472) { 498 mode = HOSTAPD_MODE_IEEE80211G; 499 *channel = (freq - 2407) / 5; 500 } else if (freq == 2484) { 501 mode = HOSTAPD_MODE_IEEE80211B; 502 *channel = 14; 503 } else if (freq >= 4900 && freq < 5000) { 504 mode = HOSTAPD_MODE_IEEE80211A; 505 *channel = (freq - 4000) / 5; 506 } else if (freq >= 5000 && freq < 5900) { 507 mode = HOSTAPD_MODE_IEEE80211A; 508 *channel = (freq - 5000) / 5; 509 } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { 510 mode = HOSTAPD_MODE_IEEE80211AD; 511 *channel = (freq - 56160) / 2160; 512 } 513 514 return mode; 515 } 516 517 518 static int is_11b(u8 rate) 519 { 520 return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; 521 } 522 523 524 int supp_rates_11b_only(struct ieee802_11_elems *elems) 525 { 526 int num_11b = 0, num_others = 0; 527 int i; 528 529 if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) 530 return 0; 531 532 for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { 533 if (is_11b(elems->supp_rates[i])) 534 num_11b++; 535 else 536 num_others++; 537 } 538 539 for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; 540 i++) { 541 if (is_11b(elems->ext_supp_rates[i])) 542 num_11b++; 543 else 544 num_others++; 545 } 546 547 return num_11b > 0 && num_others == 0; 548 } 549 550 551 const char * fc2str(u16 fc) 552 { 553 u16 stype = WLAN_FC_GET_STYPE(fc); 554 #define C2S(x) case x: return #x; 555 556 switch (WLAN_FC_GET_TYPE(fc)) { 557 case WLAN_FC_TYPE_MGMT: 558 switch (stype) { 559 C2S(WLAN_FC_STYPE_ASSOC_REQ) 560 C2S(WLAN_FC_STYPE_ASSOC_RESP) 561 C2S(WLAN_FC_STYPE_REASSOC_REQ) 562 C2S(WLAN_FC_STYPE_REASSOC_RESP) 563 C2S(WLAN_FC_STYPE_PROBE_REQ) 564 C2S(WLAN_FC_STYPE_PROBE_RESP) 565 C2S(WLAN_FC_STYPE_BEACON) 566 C2S(WLAN_FC_STYPE_ATIM) 567 C2S(WLAN_FC_STYPE_DISASSOC) 568 C2S(WLAN_FC_STYPE_AUTH) 569 C2S(WLAN_FC_STYPE_DEAUTH) 570 C2S(WLAN_FC_STYPE_ACTION) 571 } 572 break; 573 case WLAN_FC_TYPE_CTRL: 574 switch (stype) { 575 C2S(WLAN_FC_STYPE_PSPOLL) 576 C2S(WLAN_FC_STYPE_RTS) 577 C2S(WLAN_FC_STYPE_CTS) 578 C2S(WLAN_FC_STYPE_ACK) 579 C2S(WLAN_FC_STYPE_CFEND) 580 C2S(WLAN_FC_STYPE_CFENDACK) 581 } 582 break; 583 case WLAN_FC_TYPE_DATA: 584 switch (stype) { 585 C2S(WLAN_FC_STYPE_DATA) 586 C2S(WLAN_FC_STYPE_DATA_CFACK) 587 C2S(WLAN_FC_STYPE_DATA_CFPOLL) 588 C2S(WLAN_FC_STYPE_DATA_CFACKPOLL) 589 C2S(WLAN_FC_STYPE_NULLFUNC) 590 C2S(WLAN_FC_STYPE_CFACK) 591 C2S(WLAN_FC_STYPE_CFPOLL) 592 C2S(WLAN_FC_STYPE_CFACKPOLL) 593 C2S(WLAN_FC_STYPE_QOS_DATA) 594 C2S(WLAN_FC_STYPE_QOS_DATA_CFACK) 595 C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL) 596 C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL) 597 C2S(WLAN_FC_STYPE_QOS_NULL) 598 C2S(WLAN_FC_STYPE_QOS_CFPOLL) 599 C2S(WLAN_FC_STYPE_QOS_CFACKPOLL) 600 } 601 break; 602 } 603 return "WLAN_FC_TYPE_UNKNOWN"; 604 #undef C2S 605 } 606