1/* 2 * IEEE 802.11 Common routines 3 * Copyright (c) 2002-2012, 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 "ieee802_11_defs.h" 13#include "ieee802_11_common.h" 14 15 16static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 17 struct ieee802_11_elems *elems, 18 int show_errors) 19{ 20 unsigned int oui; 21 22 /* first 3 bytes in vendor specific information element are the IEEE 23 * OUI of the vendor. The following byte is used a vendor specific 24 * sub-type. */ 25 if (elen < 4) { 26 if (show_errors) { 27 wpa_printf(MSG_MSGDUMP, "short vendor specific " 28 "information element ignored (len=%lu)", 29 (unsigned long) elen); 30 } 31 return -1; 32 } 33 34 oui = WPA_GET_BE24(pos); 35 switch (oui) { 36 case OUI_MICROSOFT: 37 /* Microsoft/Wi-Fi information elements are further typed and 38 * subtyped */ 39 switch (pos[3]) { 40 case 1: 41 /* Microsoft OUI (00:50:F2) with OUI Type 1: 42 * real WPA information element */ 43 elems->wpa_ie = pos; 44 elems->wpa_ie_len = elen; 45 break; 46 case WMM_OUI_TYPE: 47 /* WMM information element */ 48 if (elen < 5) { 49 wpa_printf(MSG_MSGDUMP, "short WMM " 50 "information element ignored " 51 "(len=%lu)", 52 (unsigned long) elen); 53 return -1; 54 } 55 switch (pos[4]) { 56 case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 57 case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 58 /* 59 * Share same pointer since only one of these 60 * is used and they start with same data. 61 * Length field can be used to distinguish the 62 * IEs. 63 */ 64 elems->wmm = pos; 65 elems->wmm_len = elen; 66 break; 67 case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 68 elems->wmm_tspec = pos; 69 elems->wmm_tspec_len = elen; 70 break; 71 default: 72 wpa_printf(MSG_EXCESSIVE, "unknown WMM " 73 "information element ignored " 74 "(subtype=%d len=%lu)", 75 pos[4], (unsigned long) elen); 76 return -1; 77 } 78 break; 79 case 4: 80 /* Wi-Fi Protected Setup (WPS) IE */ 81 elems->wps_ie = pos; 82 elems->wps_ie_len = elen; 83 break; 84 default: 85 wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 86 "information element ignored " 87 "(type=%d len=%lu)", 88 pos[3], (unsigned long) elen); 89 return -1; 90 } 91 break; 92 93 case OUI_WFA: 94 switch (pos[3]) { 95 case P2P_OUI_TYPE: 96 /* Wi-Fi Alliance - P2P IE */ 97 elems->p2p = pos; 98 elems->p2p_len = elen; 99 break; 100 case WFD_OUI_TYPE: 101 /* Wi-Fi Alliance - WFD IE */ 102 elems->wfd = pos; 103 elems->wfd_len = elen; 104 break; 105 case HS20_INDICATION_OUI_TYPE: 106 /* Hotspot 2.0 */ 107 elems->hs20 = pos; 108 elems->hs20_len = elen; 109 break; 110 default: 111 wpa_printf(MSG_MSGDUMP, "Unknown WFA " 112 "information element ignored " 113 "(type=%d len=%lu)\n", 114 pos[3], (unsigned long) elen); 115 return -1; 116 } 117 break; 118 119 case OUI_BROADCOM: 120 switch (pos[3]) { 121 case VENDOR_HT_CAPAB_OUI_TYPE: 122 elems->vendor_ht_cap = pos; 123 elems->vendor_ht_cap_len = elen; 124 break; 125 default: 126 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 127 "information element ignored " 128 "(type=%d len=%lu)", 129 pos[3], (unsigned long) elen); 130 return -1; 131 } 132 break; 133 134 default: 135 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 136 "information element ignored (vendor OUI " 137 "%02x:%02x:%02x len=%lu)", 138 pos[0], pos[1], pos[2], (unsigned long) elen); 139 return -1; 140 } 141 142 return 0; 143} 144 145 146/** 147 * ieee802_11_parse_elems - Parse information elements in management frames 148 * @start: Pointer to the start of IEs 149 * @len: Length of IE buffer in octets 150 * @elems: Data structure for parsed elements 151 * @show_errors: Whether to show parsing errors in debug log 152 * Returns: Parsing result 153 */ 154ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 155 struct ieee802_11_elems *elems, 156 int show_errors) 157{ 158 size_t left = len; 159 const u8 *pos = start; 160 int unknown = 0; 161 162 os_memset(elems, 0, sizeof(*elems)); 163 164 while (left >= 2) { 165 u8 id, elen; 166 167 id = *pos++; 168 elen = *pos++; 169 left -= 2; 170 171 if (elen > left) { 172 if (show_errors) { 173 wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 174 "parse failed (id=%d elen=%d " 175 "left=%lu)", 176 id, elen, (unsigned long) left); 177 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 178 } 179 return ParseFailed; 180 } 181 182 switch (id) { 183 case WLAN_EID_SSID: 184 elems->ssid = pos; 185 elems->ssid_len = elen; 186 break; 187 case WLAN_EID_SUPP_RATES: 188 elems->supp_rates = pos; 189 elems->supp_rates_len = elen; 190 break; 191 case WLAN_EID_FH_PARAMS: 192 elems->fh_params = pos; 193 elems->fh_params_len = elen; 194 break; 195 case WLAN_EID_DS_PARAMS: 196 elems->ds_params = pos; 197 elems->ds_params_len = elen; 198 break; 199 case WLAN_EID_CF_PARAMS: 200 elems->cf_params = pos; 201 elems->cf_params_len = elen; 202 break; 203 case WLAN_EID_TIM: 204 elems->tim = pos; 205 elems->tim_len = elen; 206 break; 207 case WLAN_EID_IBSS_PARAMS: 208 elems->ibss_params = pos; 209 elems->ibss_params_len = elen; 210 break; 211 case WLAN_EID_CHALLENGE: 212 elems->challenge = pos; 213 elems->challenge_len = elen; 214 break; 215 case WLAN_EID_ERP_INFO: 216 elems->erp_info = pos; 217 elems->erp_info_len = elen; 218 break; 219 case WLAN_EID_EXT_SUPP_RATES: 220 elems->ext_supp_rates = pos; 221 elems->ext_supp_rates_len = elen; 222 break; 223 case WLAN_EID_VENDOR_SPECIFIC: 224 if (ieee802_11_parse_vendor_specific(pos, elen, 225 elems, 226 show_errors)) 227 unknown++; 228 break; 229 case WLAN_EID_RSN: 230 elems->rsn_ie = pos; 231 elems->rsn_ie_len = elen; 232 break; 233 case WLAN_EID_PWR_CAPABILITY: 234 elems->power_cap = pos; 235 elems->power_cap_len = elen; 236 break; 237 case WLAN_EID_SUPPORTED_CHANNELS: 238 elems->supp_channels = pos; 239 elems->supp_channels_len = elen; 240 break; 241 case WLAN_EID_MOBILITY_DOMAIN: 242 elems->mdie = pos; 243 elems->mdie_len = elen; 244 break; 245 case WLAN_EID_FAST_BSS_TRANSITION: 246 elems->ftie = pos; 247 elems->ftie_len = elen; 248 break; 249 case WLAN_EID_TIMEOUT_INTERVAL: 250 elems->timeout_int = pos; 251 elems->timeout_int_len = elen; 252 break; 253 case WLAN_EID_HT_CAP: 254 elems->ht_capabilities = pos; 255 elems->ht_capabilities_len = elen; 256 break; 257 case WLAN_EID_HT_OPERATION: 258 elems->ht_operation = pos; 259 elems->ht_operation_len = elen; 260 break; 261 case WLAN_EID_VHT_CAP: 262 elems->vht_capabilities = pos; 263 elems->vht_capabilities_len = elen; 264 break; 265 case WLAN_EID_VHT_OPERATION: 266 elems->vht_operation = pos; 267 elems->vht_operation_len = elen; 268 break; 269 case WLAN_EID_LINK_ID: 270 if (elen < 18) 271 break; 272 elems->link_id = pos; 273 break; 274 case WLAN_EID_INTERWORKING: 275 elems->interworking = pos; 276 elems->interworking_len = elen; 277 break; 278 case WLAN_EID_EXT_CAPAB: 279 elems->ext_capab = pos; 280 elems->ext_capab_len = elen; 281 break; 282 case WLAN_EID_BSS_MAX_IDLE_PERIOD: 283 if (elen < 3) 284 break; 285 elems->bss_max_idle_period = pos; 286 break; 287 default: 288 unknown++; 289 if (!show_errors) 290 break; 291 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 292 "ignored unknown element (id=%d elen=%d)", 293 id, elen); 294 break; 295 } 296 297 left -= elen; 298 pos += elen; 299 } 300 301 if (left) 302 return ParseFailed; 303 304 return unknown ? ParseUnknown : ParseOK; 305} 306 307 308int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 309{ 310 int count = 0; 311 const u8 *pos, *end; 312 313 if (ies == NULL) 314 return 0; 315 316 pos = ies; 317 end = ies + ies_len; 318 319 while (pos + 2 <= end) { 320 if (pos + 2 + pos[1] > end) 321 break; 322 count++; 323 pos += 2 + pos[1]; 324 } 325 326 return count; 327} 328 329 330struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 331 u32 oui_type) 332{ 333 struct wpabuf *buf; 334 const u8 *end, *pos, *ie; 335 336 pos = ies; 337 end = ies + ies_len; 338 ie = NULL; 339 340 while (pos + 1 < end) { 341 if (pos + 2 + pos[1] > end) 342 return NULL; 343 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 344 WPA_GET_BE32(&pos[2]) == oui_type) { 345 ie = pos; 346 break; 347 } 348 pos += 2 + pos[1]; 349 } 350 351 if (ie == NULL) 352 return NULL; /* No specified vendor IE found */ 353 354 buf = wpabuf_alloc(ies_len); 355 if (buf == NULL) 356 return NULL; 357 358 /* 359 * There may be multiple vendor IEs in the message, so need to 360 * concatenate their data fields. 361 */ 362 while (pos + 1 < end) { 363 if (pos + 2 + pos[1] > end) 364 break; 365 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 366 WPA_GET_BE32(&pos[2]) == oui_type) 367 wpabuf_put_data(buf, pos + 6, pos[1] - 4); 368 pos += 2 + pos[1]; 369 } 370 371 return buf; 372} 373 374 375const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 376{ 377 u16 fc, type, stype; 378 379 /* 380 * PS-Poll frames are 16 bytes. All other frames are 381 * 24 bytes or longer. 382 */ 383 if (len < 16) 384 return NULL; 385 386 fc = le_to_host16(hdr->frame_control); 387 type = WLAN_FC_GET_TYPE(fc); 388 stype = WLAN_FC_GET_STYPE(fc); 389 390 switch (type) { 391 case WLAN_FC_TYPE_DATA: 392 if (len < 24) 393 return NULL; 394 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 395 case WLAN_FC_FROMDS | WLAN_FC_TODS: 396 case WLAN_FC_TODS: 397 return hdr->addr1; 398 case WLAN_FC_FROMDS: 399 return hdr->addr2; 400 default: 401 return NULL; 402 } 403 case WLAN_FC_TYPE_CTRL: 404 if (stype != WLAN_FC_STYPE_PSPOLL) 405 return NULL; 406 return hdr->addr1; 407 case WLAN_FC_TYPE_MGMT: 408 return hdr->addr3; 409 default: 410 return NULL; 411 } 412} 413 414 415int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 416 const char *name, const char *val) 417{ 418 int num, v; 419 const char *pos; 420 struct hostapd_wmm_ac_params *ac; 421 422 /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 423 pos = name + 7; 424 if (os_strncmp(pos, "be_", 3) == 0) { 425 num = 0; 426 pos += 3; 427 } else if (os_strncmp(pos, "bk_", 3) == 0) { 428 num = 1; 429 pos += 3; 430 } else if (os_strncmp(pos, "vi_", 3) == 0) { 431 num = 2; 432 pos += 3; 433 } else if (os_strncmp(pos, "vo_", 3) == 0) { 434 num = 3; 435 pos += 3; 436 } else { 437 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 438 return -1; 439 } 440 441 ac = &wmm_ac_params[num]; 442 443 if (os_strcmp(pos, "aifs") == 0) { 444 v = atoi(val); 445 if (v < 1 || v > 255) { 446 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 447 return -1; 448 } 449 ac->aifs = v; 450 } else if (os_strcmp(pos, "cwmin") == 0) { 451 v = atoi(val); 452 if (v < 0 || v > 12) { 453 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 454 return -1; 455 } 456 ac->cwmin = v; 457 } else if (os_strcmp(pos, "cwmax") == 0) { 458 v = atoi(val); 459 if (v < 0 || v > 12) { 460 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 461 return -1; 462 } 463 ac->cwmax = v; 464 } else if (os_strcmp(pos, "txop_limit") == 0) { 465 v = atoi(val); 466 if (v < 0 || v > 0xffff) { 467 wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 468 return -1; 469 } 470 ac->txop_limit = v; 471 } else if (os_strcmp(pos, "acm") == 0) { 472 v = atoi(val); 473 if (v < 0 || v > 1) { 474 wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 475 return -1; 476 } 477 ac->admission_control_mandatory = v; 478 } else { 479 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 480 return -1; 481 } 482 483 return 0; 484} 485