ieee802_11_common.c revision 051af73b8f8014eff33330aead0f36944b3403e6
1/* 2 * IEEE 802.11 Common routines 3 * Copyright (c) 2002-2013, Jouni Malinen <j@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 17static 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 default: 112 wpa_printf(MSG_MSGDUMP, "Unknown WFA " 113 "information element ignored " 114 "(type=%d len=%lu)\n", 115 pos[3], (unsigned long) elen); 116 return -1; 117 } 118 break; 119 120 case OUI_BROADCOM: 121 switch (pos[3]) { 122 case VENDOR_HT_CAPAB_OUI_TYPE: 123 elems->vendor_ht_cap = pos; 124 elems->vendor_ht_cap_len = elen; 125 break; 126 default: 127 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 128 "information element ignored " 129 "(type=%d len=%lu)", 130 pos[3], (unsigned long) elen); 131 return -1; 132 } 133 break; 134 135 default: 136 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 137 "information element ignored (vendor OUI " 138 "%02x:%02x:%02x len=%lu)", 139 pos[0], pos[1], pos[2], (unsigned long) elen); 140 return -1; 141 } 142 143 return 0; 144} 145 146 147/** 148 * ieee802_11_parse_elems - Parse information elements in management frames 149 * @start: Pointer to the start of IEs 150 * @len: Length of IE buffer in octets 151 * @elems: Data structure for parsed elements 152 * @show_errors: Whether to show parsing errors in debug log 153 * Returns: Parsing result 154 */ 155ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 156 struct ieee802_11_elems *elems, 157 int show_errors) 158{ 159 size_t left = len; 160 const u8 *pos = start; 161 int unknown = 0; 162 163 os_memset(elems, 0, sizeof(*elems)); 164 165 while (left >= 2) { 166 u8 id, elen; 167 168 id = *pos++; 169 elen = *pos++; 170 left -= 2; 171 172 if (elen > left) { 173 if (show_errors) { 174 wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 175 "parse failed (id=%d elen=%d " 176 "left=%lu)", 177 id, elen, (unsigned long) left); 178 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 179 } 180 return ParseFailed; 181 } 182 183 switch (id) { 184 case WLAN_EID_SSID: 185 elems->ssid = pos; 186 elems->ssid_len = elen; 187 break; 188 case WLAN_EID_SUPP_RATES: 189 elems->supp_rates = pos; 190 elems->supp_rates_len = elen; 191 break; 192 case WLAN_EID_FH_PARAMS: 193 elems->fh_params = pos; 194 elems->fh_params_len = elen; 195 break; 196 case WLAN_EID_DS_PARAMS: 197 elems->ds_params = pos; 198 elems->ds_params_len = elen; 199 break; 200 case WLAN_EID_CF_PARAMS: 201 elems->cf_params = pos; 202 elems->cf_params_len = elen; 203 break; 204 case WLAN_EID_TIM: 205 elems->tim = pos; 206 elems->tim_len = elen; 207 break; 208 case WLAN_EID_IBSS_PARAMS: 209 elems->ibss_params = pos; 210 elems->ibss_params_len = elen; 211 break; 212 case WLAN_EID_CHALLENGE: 213 elems->challenge = pos; 214 elems->challenge_len = elen; 215 break; 216 case WLAN_EID_ERP_INFO: 217 elems->erp_info = pos; 218 elems->erp_info_len = elen; 219 break; 220 case WLAN_EID_EXT_SUPP_RATES: 221 elems->ext_supp_rates = pos; 222 elems->ext_supp_rates_len = elen; 223 break; 224 case WLAN_EID_VENDOR_SPECIFIC: 225 if (ieee802_11_parse_vendor_specific(pos, elen, 226 elems, 227 show_errors)) 228 unknown++; 229 break; 230 case WLAN_EID_RSN: 231 elems->rsn_ie = pos; 232 elems->rsn_ie_len = elen; 233 break; 234 case WLAN_EID_PWR_CAPABILITY: 235 elems->power_cap = pos; 236 elems->power_cap_len = elen; 237 break; 238 case WLAN_EID_SUPPORTED_CHANNELS: 239 elems->supp_channels = pos; 240 elems->supp_channels_len = elen; 241 break; 242 case WLAN_EID_MOBILITY_DOMAIN: 243 elems->mdie = pos; 244 elems->mdie_len = elen; 245 break; 246 case WLAN_EID_FAST_BSS_TRANSITION: 247 elems->ftie = pos; 248 elems->ftie_len = elen; 249 break; 250 case WLAN_EID_TIMEOUT_INTERVAL: 251 elems->timeout_int = pos; 252 elems->timeout_int_len = elen; 253 break; 254 case WLAN_EID_HT_CAP: 255 elems->ht_capabilities = pos; 256 elems->ht_capabilities_len = elen; 257 break; 258 case WLAN_EID_HT_OPERATION: 259 elems->ht_operation = pos; 260 elems->ht_operation_len = elen; 261 break; 262 case WLAN_EID_VHT_CAP: 263 elems->vht_capabilities = pos; 264 elems->vht_capabilities_len = elen; 265 break; 266 case WLAN_EID_VHT_OPERATION: 267 elems->vht_operation = pos; 268 elems->vht_operation_len = elen; 269 break; 270 case WLAN_EID_LINK_ID: 271 if (elen < 18) 272 break; 273 elems->link_id = pos; 274 break; 275 case WLAN_EID_INTERWORKING: 276 elems->interworking = pos; 277 elems->interworking_len = elen; 278 break; 279 case WLAN_EID_QOS_MAP_SET: 280 if (elen < 16) 281 break; 282 elems->qos_map_set = pos; 283 elems->qos_map_set_len = elen; 284 break; 285 case WLAN_EID_EXT_CAPAB: 286 elems->ext_capab = pos; 287 elems->ext_capab_len = elen; 288 break; 289 case WLAN_EID_BSS_MAX_IDLE_PERIOD: 290 if (elen < 3) 291 break; 292 elems->bss_max_idle_period = pos; 293 break; 294 case WLAN_EID_SSID_LIST: 295 elems->ssid_list = pos; 296 elems->ssid_list_len = elen; 297 break; 298 default: 299 unknown++; 300 if (!show_errors) 301 break; 302 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 303 "ignored unknown element (id=%d elen=%d)", 304 id, elen); 305 break; 306 } 307 308 left -= elen; 309 pos += elen; 310 } 311 312 if (left) 313 return ParseFailed; 314 315 return unknown ? ParseUnknown : ParseOK; 316} 317 318 319int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 320{ 321 int count = 0; 322 const u8 *pos, *end; 323 324 if (ies == NULL) 325 return 0; 326 327 pos = ies; 328 end = ies + ies_len; 329 330 while (pos + 2 <= end) { 331 if (pos + 2 + pos[1] > end) 332 break; 333 count++; 334 pos += 2 + pos[1]; 335 } 336 337 return count; 338} 339 340 341struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 342 u32 oui_type) 343{ 344 struct wpabuf *buf; 345 const u8 *end, *pos, *ie; 346 347 pos = ies; 348 end = ies + ies_len; 349 ie = NULL; 350 351 while (pos + 1 < end) { 352 if (pos + 2 + pos[1] > end) 353 return NULL; 354 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 355 WPA_GET_BE32(&pos[2]) == oui_type) { 356 ie = pos; 357 break; 358 } 359 pos += 2 + pos[1]; 360 } 361 362 if (ie == NULL) 363 return NULL; /* No specified vendor IE found */ 364 365 buf = wpabuf_alloc(ies_len); 366 if (buf == NULL) 367 return NULL; 368 369 /* 370 * There may be multiple vendor IEs in the message, so need to 371 * concatenate their data fields. 372 */ 373 while (pos + 1 < end) { 374 if (pos + 2 + pos[1] > end) 375 break; 376 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 377 WPA_GET_BE32(&pos[2]) == oui_type) 378 wpabuf_put_data(buf, pos + 6, pos[1] - 4); 379 pos += 2 + pos[1]; 380 } 381 382 return buf; 383} 384 385 386const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 387{ 388 u16 fc, type, stype; 389 390 /* 391 * PS-Poll frames are 16 bytes. All other frames are 392 * 24 bytes or longer. 393 */ 394 if (len < 16) 395 return NULL; 396 397 fc = le_to_host16(hdr->frame_control); 398 type = WLAN_FC_GET_TYPE(fc); 399 stype = WLAN_FC_GET_STYPE(fc); 400 401 switch (type) { 402 case WLAN_FC_TYPE_DATA: 403 if (len < 24) 404 return NULL; 405 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 406 case WLAN_FC_FROMDS | WLAN_FC_TODS: 407 case WLAN_FC_TODS: 408 return hdr->addr1; 409 case WLAN_FC_FROMDS: 410 return hdr->addr2; 411 default: 412 return NULL; 413 } 414 case WLAN_FC_TYPE_CTRL: 415 if (stype != WLAN_FC_STYPE_PSPOLL) 416 return NULL; 417 return hdr->addr1; 418 case WLAN_FC_TYPE_MGMT: 419 return hdr->addr3; 420 default: 421 return NULL; 422 } 423} 424 425 426int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 427 const char *name, const char *val) 428{ 429 int num, v; 430 const char *pos; 431 struct hostapd_wmm_ac_params *ac; 432 433 /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 434 pos = name + 7; 435 if (os_strncmp(pos, "be_", 3) == 0) { 436 num = 0; 437 pos += 3; 438 } else if (os_strncmp(pos, "bk_", 3) == 0) { 439 num = 1; 440 pos += 3; 441 } else if (os_strncmp(pos, "vi_", 3) == 0) { 442 num = 2; 443 pos += 3; 444 } else if (os_strncmp(pos, "vo_", 3) == 0) { 445 num = 3; 446 pos += 3; 447 } else { 448 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 449 return -1; 450 } 451 452 ac = &wmm_ac_params[num]; 453 454 if (os_strcmp(pos, "aifs") == 0) { 455 v = atoi(val); 456 if (v < 1 || v > 255) { 457 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 458 return -1; 459 } 460 ac->aifs = v; 461 } else if (os_strcmp(pos, "cwmin") == 0) { 462 v = atoi(val); 463 if (v < 0 || v > 12) { 464 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 465 return -1; 466 } 467 ac->cwmin = v; 468 } else if (os_strcmp(pos, "cwmax") == 0) { 469 v = atoi(val); 470 if (v < 0 || v > 12) { 471 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 472 return -1; 473 } 474 ac->cwmax = v; 475 } else if (os_strcmp(pos, "txop_limit") == 0) { 476 v = atoi(val); 477 if (v < 0 || v > 0xffff) { 478 wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 479 return -1; 480 } 481 ac->txop_limit = v; 482 } else if (os_strcmp(pos, "acm") == 0) { 483 v = atoi(val); 484 if (v < 0 || v > 1) { 485 wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 486 return -1; 487 } 488 ac->admission_control_mandatory = v; 489 } else { 490 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 491 return -1; 492 } 493 494 return 0; 495} 496 497 498enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) 499{ 500 enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES; 501 502 if (freq >= 2412 && freq <= 2472) { 503 mode = HOSTAPD_MODE_IEEE80211G; 504 *channel = (freq - 2407) / 5; 505 } else if (freq == 2484) { 506 mode = HOSTAPD_MODE_IEEE80211B; 507 *channel = 14; 508 } else if (freq >= 4900 && freq < 5000) { 509 mode = HOSTAPD_MODE_IEEE80211A; 510 *channel = (freq - 4000) / 5; 511 } else if (freq >= 5000 && freq < 5900) { 512 mode = HOSTAPD_MODE_IEEE80211A; 513 *channel = (freq - 5000) / 5; 514 } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { 515 mode = HOSTAPD_MODE_IEEE80211AD; 516 *channel = (freq - 56160) / 2160; 517 } 518 519 return mode; 520} 521 522 523static int is_11b(u8 rate) 524{ 525 return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; 526} 527 528 529int supp_rates_11b_only(struct ieee802_11_elems *elems) 530{ 531 int num_11b = 0, num_others = 0; 532 int i; 533 534 if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) 535 return 0; 536 537 for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { 538 if (is_11b(elems->supp_rates[i])) 539 num_11b++; 540 else 541 num_others++; 542 } 543 544 for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; 545 i++) { 546 if (is_11b(elems->ext_supp_rates[i])) 547 num_11b++; 548 else 549 num_others++; 550 } 551 552 return num_11b > 0 && num_others == 0; 553} 554