139beb93cSSam Leffler /* 239beb93cSSam Leffler * IEEE 802.11 Common routines 3*e28a4053SRui Paulo * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "common.h" 1839beb93cSSam Leffler #include "ieee802_11_defs.h" 1939beb93cSSam Leffler #include "ieee802_11_common.h" 2039beb93cSSam Leffler 2139beb93cSSam Leffler 22*e28a4053SRui Paulo static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 2339beb93cSSam Leffler struct ieee802_11_elems *elems, 2439beb93cSSam Leffler int show_errors) 2539beb93cSSam Leffler { 2639beb93cSSam Leffler unsigned int oui; 2739beb93cSSam Leffler 2839beb93cSSam Leffler /* first 3 bytes in vendor specific information element are the IEEE 2939beb93cSSam Leffler * OUI of the vendor. The following byte is used a vendor specific 3039beb93cSSam Leffler * sub-type. */ 3139beb93cSSam Leffler if (elen < 4) { 3239beb93cSSam Leffler if (show_errors) { 3339beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "short vendor specific " 3439beb93cSSam Leffler "information element ignored (len=%lu)", 3539beb93cSSam Leffler (unsigned long) elen); 3639beb93cSSam Leffler } 3739beb93cSSam Leffler return -1; 3839beb93cSSam Leffler } 3939beb93cSSam Leffler 4039beb93cSSam Leffler oui = WPA_GET_BE24(pos); 4139beb93cSSam Leffler switch (oui) { 4239beb93cSSam Leffler case OUI_MICROSOFT: 4339beb93cSSam Leffler /* Microsoft/Wi-Fi information elements are further typed and 4439beb93cSSam Leffler * subtyped */ 4539beb93cSSam Leffler switch (pos[3]) { 4639beb93cSSam Leffler case 1: 4739beb93cSSam Leffler /* Microsoft OUI (00:50:F2) with OUI Type 1: 4839beb93cSSam Leffler * real WPA information element */ 4939beb93cSSam Leffler elems->wpa_ie = pos; 5039beb93cSSam Leffler elems->wpa_ie_len = elen; 5139beb93cSSam Leffler break; 523157ba21SRui Paulo case WMM_OUI_TYPE: 533157ba21SRui Paulo /* WMM information element */ 5439beb93cSSam Leffler if (elen < 5) { 553157ba21SRui Paulo wpa_printf(MSG_MSGDUMP, "short WMM " 5639beb93cSSam Leffler "information element ignored " 5739beb93cSSam Leffler "(len=%lu)", 5839beb93cSSam Leffler (unsigned long) elen); 5939beb93cSSam Leffler return -1; 6039beb93cSSam Leffler } 6139beb93cSSam Leffler switch (pos[4]) { 623157ba21SRui Paulo case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 633157ba21SRui Paulo case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 643157ba21SRui Paulo /* 653157ba21SRui Paulo * Share same pointer since only one of these 663157ba21SRui Paulo * is used and they start with same data. 673157ba21SRui Paulo * Length field can be used to distinguish the 683157ba21SRui Paulo * IEs. 693157ba21SRui Paulo */ 703157ba21SRui Paulo elems->wmm = pos; 713157ba21SRui Paulo elems->wmm_len = elen; 7239beb93cSSam Leffler break; 733157ba21SRui Paulo case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 743157ba21SRui Paulo elems->wmm_tspec = pos; 753157ba21SRui Paulo elems->wmm_tspec_len = elen; 7639beb93cSSam Leffler break; 7739beb93cSSam Leffler default: 783157ba21SRui Paulo wpa_printf(MSG_MSGDUMP, "unknown WMM " 7939beb93cSSam Leffler "information element ignored " 8039beb93cSSam Leffler "(subtype=%d len=%lu)", 8139beb93cSSam Leffler pos[4], (unsigned long) elen); 8239beb93cSSam Leffler return -1; 8339beb93cSSam Leffler } 8439beb93cSSam Leffler break; 8539beb93cSSam Leffler case 4: 8639beb93cSSam Leffler /* Wi-Fi Protected Setup (WPS) IE */ 8739beb93cSSam Leffler elems->wps_ie = pos; 8839beb93cSSam Leffler elems->wps_ie_len = elen; 8939beb93cSSam Leffler break; 9039beb93cSSam Leffler default: 9139beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "Unknown Microsoft " 9239beb93cSSam Leffler "information element ignored " 9339beb93cSSam Leffler "(type=%d len=%lu)\n", 9439beb93cSSam Leffler pos[3], (unsigned long) elen); 9539beb93cSSam Leffler return -1; 9639beb93cSSam Leffler } 9739beb93cSSam Leffler break; 9839beb93cSSam Leffler 9939beb93cSSam Leffler case OUI_BROADCOM: 10039beb93cSSam Leffler switch (pos[3]) { 10139beb93cSSam Leffler case VENDOR_HT_CAPAB_OUI_TYPE: 10239beb93cSSam Leffler elems->vendor_ht_cap = pos; 10339beb93cSSam Leffler elems->vendor_ht_cap_len = elen; 10439beb93cSSam Leffler break; 10539beb93cSSam Leffler default: 10639beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "Unknown Broadcom " 10739beb93cSSam Leffler "information element ignored " 10839beb93cSSam Leffler "(type=%d len=%lu)\n", 10939beb93cSSam Leffler pos[3], (unsigned long) elen); 11039beb93cSSam Leffler return -1; 11139beb93cSSam Leffler } 11239beb93cSSam Leffler break; 11339beb93cSSam Leffler 11439beb93cSSam Leffler default: 11539beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "unknown vendor specific information " 11639beb93cSSam Leffler "element ignored (vendor OUI %02x:%02x:%02x " 11739beb93cSSam Leffler "len=%lu)", 11839beb93cSSam Leffler pos[0], pos[1], pos[2], (unsigned long) elen); 11939beb93cSSam Leffler return -1; 12039beb93cSSam Leffler } 12139beb93cSSam Leffler 12239beb93cSSam Leffler return 0; 12339beb93cSSam Leffler } 12439beb93cSSam Leffler 12539beb93cSSam Leffler 12639beb93cSSam Leffler /** 12739beb93cSSam Leffler * ieee802_11_parse_elems - Parse information elements in management frames 12839beb93cSSam Leffler * @start: Pointer to the start of IEs 12939beb93cSSam Leffler * @len: Length of IE buffer in octets 13039beb93cSSam Leffler * @elems: Data structure for parsed elements 13139beb93cSSam Leffler * @show_errors: Whether to show parsing errors in debug log 13239beb93cSSam Leffler * Returns: Parsing result 13339beb93cSSam Leffler */ 134*e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 13539beb93cSSam Leffler struct ieee802_11_elems *elems, 13639beb93cSSam Leffler int show_errors) 13739beb93cSSam Leffler { 13839beb93cSSam Leffler size_t left = len; 139*e28a4053SRui Paulo const u8 *pos = start; 14039beb93cSSam Leffler int unknown = 0; 14139beb93cSSam Leffler 14239beb93cSSam Leffler os_memset(elems, 0, sizeof(*elems)); 14339beb93cSSam Leffler 14439beb93cSSam Leffler while (left >= 2) { 14539beb93cSSam Leffler u8 id, elen; 14639beb93cSSam Leffler 14739beb93cSSam Leffler id = *pos++; 14839beb93cSSam Leffler elen = *pos++; 14939beb93cSSam Leffler left -= 2; 15039beb93cSSam Leffler 15139beb93cSSam Leffler if (elen > left) { 15239beb93cSSam Leffler if (show_errors) { 15339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 15439beb93cSSam Leffler "parse failed (id=%d elen=%d " 15539beb93cSSam Leffler "left=%lu)", 15639beb93cSSam Leffler id, elen, (unsigned long) left); 15739beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 15839beb93cSSam Leffler } 15939beb93cSSam Leffler return ParseFailed; 16039beb93cSSam Leffler } 16139beb93cSSam Leffler 16239beb93cSSam Leffler switch (id) { 16339beb93cSSam Leffler case WLAN_EID_SSID: 16439beb93cSSam Leffler elems->ssid = pos; 16539beb93cSSam Leffler elems->ssid_len = elen; 16639beb93cSSam Leffler break; 16739beb93cSSam Leffler case WLAN_EID_SUPP_RATES: 16839beb93cSSam Leffler elems->supp_rates = pos; 16939beb93cSSam Leffler elems->supp_rates_len = elen; 17039beb93cSSam Leffler break; 17139beb93cSSam Leffler case WLAN_EID_FH_PARAMS: 17239beb93cSSam Leffler elems->fh_params = pos; 17339beb93cSSam Leffler elems->fh_params_len = elen; 17439beb93cSSam Leffler break; 17539beb93cSSam Leffler case WLAN_EID_DS_PARAMS: 17639beb93cSSam Leffler elems->ds_params = pos; 17739beb93cSSam Leffler elems->ds_params_len = elen; 17839beb93cSSam Leffler break; 17939beb93cSSam Leffler case WLAN_EID_CF_PARAMS: 18039beb93cSSam Leffler elems->cf_params = pos; 18139beb93cSSam Leffler elems->cf_params_len = elen; 18239beb93cSSam Leffler break; 18339beb93cSSam Leffler case WLAN_EID_TIM: 18439beb93cSSam Leffler elems->tim = pos; 18539beb93cSSam Leffler elems->tim_len = elen; 18639beb93cSSam Leffler break; 18739beb93cSSam Leffler case WLAN_EID_IBSS_PARAMS: 18839beb93cSSam Leffler elems->ibss_params = pos; 18939beb93cSSam Leffler elems->ibss_params_len = elen; 19039beb93cSSam Leffler break; 19139beb93cSSam Leffler case WLAN_EID_CHALLENGE: 19239beb93cSSam Leffler elems->challenge = pos; 19339beb93cSSam Leffler elems->challenge_len = elen; 19439beb93cSSam Leffler break; 19539beb93cSSam Leffler case WLAN_EID_ERP_INFO: 19639beb93cSSam Leffler elems->erp_info = pos; 19739beb93cSSam Leffler elems->erp_info_len = elen; 19839beb93cSSam Leffler break; 19939beb93cSSam Leffler case WLAN_EID_EXT_SUPP_RATES: 20039beb93cSSam Leffler elems->ext_supp_rates = pos; 20139beb93cSSam Leffler elems->ext_supp_rates_len = elen; 20239beb93cSSam Leffler break; 20339beb93cSSam Leffler case WLAN_EID_VENDOR_SPECIFIC: 20439beb93cSSam Leffler if (ieee802_11_parse_vendor_specific(pos, elen, 20539beb93cSSam Leffler elems, 20639beb93cSSam Leffler show_errors)) 20739beb93cSSam Leffler unknown++; 20839beb93cSSam Leffler break; 20939beb93cSSam Leffler case WLAN_EID_RSN: 21039beb93cSSam Leffler elems->rsn_ie = pos; 21139beb93cSSam Leffler elems->rsn_ie_len = elen; 21239beb93cSSam Leffler break; 21339beb93cSSam Leffler case WLAN_EID_PWR_CAPABILITY: 21439beb93cSSam Leffler elems->power_cap = pos; 21539beb93cSSam Leffler elems->power_cap_len = elen; 21639beb93cSSam Leffler break; 21739beb93cSSam Leffler case WLAN_EID_SUPPORTED_CHANNELS: 21839beb93cSSam Leffler elems->supp_channels = pos; 21939beb93cSSam Leffler elems->supp_channels_len = elen; 22039beb93cSSam Leffler break; 22139beb93cSSam Leffler case WLAN_EID_MOBILITY_DOMAIN: 22239beb93cSSam Leffler elems->mdie = pos; 22339beb93cSSam Leffler elems->mdie_len = elen; 22439beb93cSSam Leffler break; 22539beb93cSSam Leffler case WLAN_EID_FAST_BSS_TRANSITION: 22639beb93cSSam Leffler elems->ftie = pos; 22739beb93cSSam Leffler elems->ftie_len = elen; 22839beb93cSSam Leffler break; 22939beb93cSSam Leffler case WLAN_EID_TIMEOUT_INTERVAL: 23039beb93cSSam Leffler elems->timeout_int = pos; 23139beb93cSSam Leffler elems->timeout_int_len = elen; 23239beb93cSSam Leffler break; 23339beb93cSSam Leffler case WLAN_EID_HT_CAP: 23439beb93cSSam Leffler elems->ht_capabilities = pos; 23539beb93cSSam Leffler elems->ht_capabilities_len = elen; 23639beb93cSSam Leffler break; 23739beb93cSSam Leffler case WLAN_EID_HT_OPERATION: 23839beb93cSSam Leffler elems->ht_operation = pos; 23939beb93cSSam Leffler elems->ht_operation_len = elen; 24039beb93cSSam Leffler break; 24139beb93cSSam Leffler default: 24239beb93cSSam Leffler unknown++; 24339beb93cSSam Leffler if (!show_errors) 24439beb93cSSam Leffler break; 24539beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 24639beb93cSSam Leffler "ignored unknown element (id=%d elen=%d)", 24739beb93cSSam Leffler id, elen); 24839beb93cSSam Leffler break; 24939beb93cSSam Leffler } 25039beb93cSSam Leffler 25139beb93cSSam Leffler left -= elen; 25239beb93cSSam Leffler pos += elen; 25339beb93cSSam Leffler } 25439beb93cSSam Leffler 25539beb93cSSam Leffler if (left) 25639beb93cSSam Leffler return ParseFailed; 25739beb93cSSam Leffler 25839beb93cSSam Leffler return unknown ? ParseUnknown : ParseOK; 25939beb93cSSam Leffler } 260*e28a4053SRui Paulo 261*e28a4053SRui Paulo 262*e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 263*e28a4053SRui Paulo { 264*e28a4053SRui Paulo int count = 0; 265*e28a4053SRui Paulo const u8 *pos, *end; 266*e28a4053SRui Paulo 267*e28a4053SRui Paulo if (ies == NULL) 268*e28a4053SRui Paulo return 0; 269*e28a4053SRui Paulo 270*e28a4053SRui Paulo pos = ies; 271*e28a4053SRui Paulo end = ies + ies_len; 272*e28a4053SRui Paulo 273*e28a4053SRui Paulo while (pos + 2 <= end) { 274*e28a4053SRui Paulo if (pos + 2 + pos[1] > end) 275*e28a4053SRui Paulo break; 276*e28a4053SRui Paulo count++; 277*e28a4053SRui Paulo pos += 2 + pos[1]; 278*e28a4053SRui Paulo } 279*e28a4053SRui Paulo 280*e28a4053SRui Paulo return count; 281*e28a4053SRui Paulo } 282*e28a4053SRui Paulo 283*e28a4053SRui Paulo 284*e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 285*e28a4053SRui Paulo u32 oui_type) 286*e28a4053SRui Paulo { 287*e28a4053SRui Paulo struct wpabuf *buf; 288*e28a4053SRui Paulo const u8 *end, *pos, *ie; 289*e28a4053SRui Paulo 290*e28a4053SRui Paulo pos = ies; 291*e28a4053SRui Paulo end = ies + ies_len; 292*e28a4053SRui Paulo ie = NULL; 293*e28a4053SRui Paulo 294*e28a4053SRui Paulo while (pos + 1 < end) { 295*e28a4053SRui Paulo if (pos + 2 + pos[1] > end) 296*e28a4053SRui Paulo return NULL; 297*e28a4053SRui Paulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 298*e28a4053SRui Paulo WPA_GET_BE32(&pos[2]) == oui_type) { 299*e28a4053SRui Paulo ie = pos; 300*e28a4053SRui Paulo break; 301*e28a4053SRui Paulo } 302*e28a4053SRui Paulo pos += 2 + pos[1]; 303*e28a4053SRui Paulo } 304*e28a4053SRui Paulo 305*e28a4053SRui Paulo if (ie == NULL) 306*e28a4053SRui Paulo return NULL; /* No specified vendor IE found */ 307*e28a4053SRui Paulo 308*e28a4053SRui Paulo buf = wpabuf_alloc(ies_len); 309*e28a4053SRui Paulo if (buf == NULL) 310*e28a4053SRui Paulo return NULL; 311*e28a4053SRui Paulo 312*e28a4053SRui Paulo /* 313*e28a4053SRui Paulo * There may be multiple vendor IEs in the message, so need to 314*e28a4053SRui Paulo * concatenate their data fields. 315*e28a4053SRui Paulo */ 316*e28a4053SRui Paulo while (pos + 1 < end) { 317*e28a4053SRui Paulo if (pos + 2 + pos[1] > end) 318*e28a4053SRui Paulo break; 319*e28a4053SRui Paulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 320*e28a4053SRui Paulo WPA_GET_BE32(&pos[2]) == oui_type) 321*e28a4053SRui Paulo wpabuf_put_data(buf, pos + 6, pos[1] - 4); 322*e28a4053SRui Paulo pos += 2 + pos[1]; 323*e28a4053SRui Paulo } 324*e28a4053SRui Paulo 325*e28a4053SRui Paulo return buf; 326*e28a4053SRui Paulo } 327