139beb93cSSam Leffler /* 239beb93cSSam Leffler * IEEE 802.11 Common routines 3*f05cddf9SRui Paulo * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "ieee802_11_defs.h" 1339beb93cSSam Leffler #include "ieee802_11_common.h" 1439beb93cSSam Leffler 1539beb93cSSam Leffler 16e28a4053SRui Paulo static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 1739beb93cSSam Leffler struct ieee802_11_elems *elems, 1839beb93cSSam Leffler int show_errors) 1939beb93cSSam Leffler { 2039beb93cSSam Leffler unsigned int oui; 2139beb93cSSam Leffler 2239beb93cSSam Leffler /* first 3 bytes in vendor specific information element are the IEEE 2339beb93cSSam Leffler * OUI of the vendor. The following byte is used a vendor specific 2439beb93cSSam Leffler * sub-type. */ 2539beb93cSSam Leffler if (elen < 4) { 2639beb93cSSam Leffler if (show_errors) { 2739beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "short vendor specific " 2839beb93cSSam Leffler "information element ignored (len=%lu)", 2939beb93cSSam Leffler (unsigned long) elen); 3039beb93cSSam Leffler } 3139beb93cSSam Leffler return -1; 3239beb93cSSam Leffler } 3339beb93cSSam Leffler 3439beb93cSSam Leffler oui = WPA_GET_BE24(pos); 3539beb93cSSam Leffler switch (oui) { 3639beb93cSSam Leffler case OUI_MICROSOFT: 3739beb93cSSam Leffler /* Microsoft/Wi-Fi information elements are further typed and 3839beb93cSSam Leffler * subtyped */ 3939beb93cSSam Leffler switch (pos[3]) { 4039beb93cSSam Leffler case 1: 4139beb93cSSam Leffler /* Microsoft OUI (00:50:F2) with OUI Type 1: 4239beb93cSSam Leffler * real WPA information element */ 4339beb93cSSam Leffler elems->wpa_ie = pos; 4439beb93cSSam Leffler elems->wpa_ie_len = elen; 4539beb93cSSam Leffler break; 463157ba21SRui Paulo case WMM_OUI_TYPE: 473157ba21SRui Paulo /* WMM information element */ 4839beb93cSSam Leffler if (elen < 5) { 493157ba21SRui Paulo wpa_printf(MSG_MSGDUMP, "short WMM " 5039beb93cSSam Leffler "information element ignored " 5139beb93cSSam Leffler "(len=%lu)", 5239beb93cSSam Leffler (unsigned long) elen); 5339beb93cSSam Leffler return -1; 5439beb93cSSam Leffler } 5539beb93cSSam Leffler switch (pos[4]) { 563157ba21SRui Paulo case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 573157ba21SRui Paulo case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 583157ba21SRui Paulo /* 593157ba21SRui Paulo * Share same pointer since only one of these 603157ba21SRui Paulo * is used and they start with same data. 613157ba21SRui Paulo * Length field can be used to distinguish the 623157ba21SRui Paulo * IEs. 633157ba21SRui Paulo */ 643157ba21SRui Paulo elems->wmm = pos; 653157ba21SRui Paulo elems->wmm_len = elen; 6639beb93cSSam Leffler break; 673157ba21SRui Paulo case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 683157ba21SRui Paulo elems->wmm_tspec = pos; 693157ba21SRui Paulo elems->wmm_tspec_len = elen; 7039beb93cSSam Leffler break; 7139beb93cSSam Leffler default: 72*f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown WMM " 7339beb93cSSam Leffler "information element ignored " 7439beb93cSSam Leffler "(subtype=%d len=%lu)", 7539beb93cSSam Leffler pos[4], (unsigned long) elen); 7639beb93cSSam Leffler return -1; 7739beb93cSSam Leffler } 7839beb93cSSam Leffler break; 7939beb93cSSam Leffler case 4: 8039beb93cSSam Leffler /* Wi-Fi Protected Setup (WPS) IE */ 8139beb93cSSam Leffler elems->wps_ie = pos; 8239beb93cSSam Leffler elems->wps_ie_len = elen; 8339beb93cSSam Leffler break; 8439beb93cSSam Leffler default: 85*f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 86*f05cddf9SRui Paulo "information element ignored " 87*f05cddf9SRui Paulo "(type=%d len=%lu)", 88*f05cddf9SRui Paulo pos[3], (unsigned long) elen); 89*f05cddf9SRui Paulo return -1; 90*f05cddf9SRui Paulo } 91*f05cddf9SRui Paulo break; 92*f05cddf9SRui Paulo 93*f05cddf9SRui Paulo case OUI_WFA: 94*f05cddf9SRui Paulo switch (pos[3]) { 95*f05cddf9SRui Paulo case P2P_OUI_TYPE: 96*f05cddf9SRui Paulo /* Wi-Fi Alliance - P2P IE */ 97*f05cddf9SRui Paulo elems->p2p = pos; 98*f05cddf9SRui Paulo elems->p2p_len = elen; 99*f05cddf9SRui Paulo break; 100*f05cddf9SRui Paulo case WFD_OUI_TYPE: 101*f05cddf9SRui Paulo /* Wi-Fi Alliance - WFD IE */ 102*f05cddf9SRui Paulo elems->wfd = pos; 103*f05cddf9SRui Paulo elems->wfd_len = elen; 104*f05cddf9SRui Paulo break; 105*f05cddf9SRui Paulo case HS20_INDICATION_OUI_TYPE: 106*f05cddf9SRui Paulo /* Hotspot 2.0 */ 107*f05cddf9SRui Paulo elems->hs20 = pos; 108*f05cddf9SRui Paulo elems->hs20_len = elen; 109*f05cddf9SRui Paulo break; 110*f05cddf9SRui Paulo default: 111*f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Unknown WFA " 11239beb93cSSam Leffler "information element ignored " 11339beb93cSSam Leffler "(type=%d len=%lu)\n", 11439beb93cSSam Leffler pos[3], (unsigned long) elen); 11539beb93cSSam Leffler return -1; 11639beb93cSSam Leffler } 11739beb93cSSam Leffler break; 11839beb93cSSam Leffler 11939beb93cSSam Leffler case OUI_BROADCOM: 12039beb93cSSam Leffler switch (pos[3]) { 12139beb93cSSam Leffler case VENDOR_HT_CAPAB_OUI_TYPE: 12239beb93cSSam Leffler elems->vendor_ht_cap = pos; 12339beb93cSSam Leffler elems->vendor_ht_cap_len = elen; 12439beb93cSSam Leffler break; 12539beb93cSSam Leffler default: 126*f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 12739beb93cSSam Leffler "information element ignored " 128*f05cddf9SRui Paulo "(type=%d len=%lu)", 12939beb93cSSam Leffler pos[3], (unsigned long) elen); 13039beb93cSSam Leffler return -1; 13139beb93cSSam Leffler } 13239beb93cSSam Leffler break; 13339beb93cSSam Leffler 13439beb93cSSam Leffler default: 135*f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 136*f05cddf9SRui Paulo "information element ignored (vendor OUI " 137*f05cddf9SRui Paulo "%02x:%02x:%02x len=%lu)", 13839beb93cSSam Leffler pos[0], pos[1], pos[2], (unsigned long) elen); 13939beb93cSSam Leffler return -1; 14039beb93cSSam Leffler } 14139beb93cSSam Leffler 14239beb93cSSam Leffler return 0; 14339beb93cSSam Leffler } 14439beb93cSSam Leffler 14539beb93cSSam Leffler 14639beb93cSSam Leffler /** 14739beb93cSSam Leffler * ieee802_11_parse_elems - Parse information elements in management frames 14839beb93cSSam Leffler * @start: Pointer to the start of IEs 14939beb93cSSam Leffler * @len: Length of IE buffer in octets 15039beb93cSSam Leffler * @elems: Data structure for parsed elements 15139beb93cSSam Leffler * @show_errors: Whether to show parsing errors in debug log 15239beb93cSSam Leffler * Returns: Parsing result 15339beb93cSSam Leffler */ 154e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 15539beb93cSSam Leffler struct ieee802_11_elems *elems, 15639beb93cSSam Leffler int show_errors) 15739beb93cSSam Leffler { 15839beb93cSSam Leffler size_t left = len; 159e28a4053SRui Paulo const u8 *pos = start; 16039beb93cSSam Leffler int unknown = 0; 16139beb93cSSam Leffler 16239beb93cSSam Leffler os_memset(elems, 0, sizeof(*elems)); 16339beb93cSSam Leffler 16439beb93cSSam Leffler while (left >= 2) { 16539beb93cSSam Leffler u8 id, elen; 16639beb93cSSam Leffler 16739beb93cSSam Leffler id = *pos++; 16839beb93cSSam Leffler elen = *pos++; 16939beb93cSSam Leffler left -= 2; 17039beb93cSSam Leffler 17139beb93cSSam Leffler if (elen > left) { 17239beb93cSSam Leffler if (show_errors) { 17339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 17439beb93cSSam Leffler "parse failed (id=%d elen=%d " 17539beb93cSSam Leffler "left=%lu)", 17639beb93cSSam Leffler id, elen, (unsigned long) left); 17739beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 17839beb93cSSam Leffler } 17939beb93cSSam Leffler return ParseFailed; 18039beb93cSSam Leffler } 18139beb93cSSam Leffler 18239beb93cSSam Leffler switch (id) { 18339beb93cSSam Leffler case WLAN_EID_SSID: 18439beb93cSSam Leffler elems->ssid = pos; 18539beb93cSSam Leffler elems->ssid_len = elen; 18639beb93cSSam Leffler break; 18739beb93cSSam Leffler case WLAN_EID_SUPP_RATES: 18839beb93cSSam Leffler elems->supp_rates = pos; 18939beb93cSSam Leffler elems->supp_rates_len = elen; 19039beb93cSSam Leffler break; 19139beb93cSSam Leffler case WLAN_EID_FH_PARAMS: 19239beb93cSSam Leffler elems->fh_params = pos; 19339beb93cSSam Leffler elems->fh_params_len = elen; 19439beb93cSSam Leffler break; 19539beb93cSSam Leffler case WLAN_EID_DS_PARAMS: 19639beb93cSSam Leffler elems->ds_params = pos; 19739beb93cSSam Leffler elems->ds_params_len = elen; 19839beb93cSSam Leffler break; 19939beb93cSSam Leffler case WLAN_EID_CF_PARAMS: 20039beb93cSSam Leffler elems->cf_params = pos; 20139beb93cSSam Leffler elems->cf_params_len = elen; 20239beb93cSSam Leffler break; 20339beb93cSSam Leffler case WLAN_EID_TIM: 20439beb93cSSam Leffler elems->tim = pos; 20539beb93cSSam Leffler elems->tim_len = elen; 20639beb93cSSam Leffler break; 20739beb93cSSam Leffler case WLAN_EID_IBSS_PARAMS: 20839beb93cSSam Leffler elems->ibss_params = pos; 20939beb93cSSam Leffler elems->ibss_params_len = elen; 21039beb93cSSam Leffler break; 21139beb93cSSam Leffler case WLAN_EID_CHALLENGE: 21239beb93cSSam Leffler elems->challenge = pos; 21339beb93cSSam Leffler elems->challenge_len = elen; 21439beb93cSSam Leffler break; 21539beb93cSSam Leffler case WLAN_EID_ERP_INFO: 21639beb93cSSam Leffler elems->erp_info = pos; 21739beb93cSSam Leffler elems->erp_info_len = elen; 21839beb93cSSam Leffler break; 21939beb93cSSam Leffler case WLAN_EID_EXT_SUPP_RATES: 22039beb93cSSam Leffler elems->ext_supp_rates = pos; 22139beb93cSSam Leffler elems->ext_supp_rates_len = elen; 22239beb93cSSam Leffler break; 22339beb93cSSam Leffler case WLAN_EID_VENDOR_SPECIFIC: 22439beb93cSSam Leffler if (ieee802_11_parse_vendor_specific(pos, elen, 22539beb93cSSam Leffler elems, 22639beb93cSSam Leffler show_errors)) 22739beb93cSSam Leffler unknown++; 22839beb93cSSam Leffler break; 22939beb93cSSam Leffler case WLAN_EID_RSN: 23039beb93cSSam Leffler elems->rsn_ie = pos; 23139beb93cSSam Leffler elems->rsn_ie_len = elen; 23239beb93cSSam Leffler break; 23339beb93cSSam Leffler case WLAN_EID_PWR_CAPABILITY: 23439beb93cSSam Leffler elems->power_cap = pos; 23539beb93cSSam Leffler elems->power_cap_len = elen; 23639beb93cSSam Leffler break; 23739beb93cSSam Leffler case WLAN_EID_SUPPORTED_CHANNELS: 23839beb93cSSam Leffler elems->supp_channels = pos; 23939beb93cSSam Leffler elems->supp_channels_len = elen; 24039beb93cSSam Leffler break; 24139beb93cSSam Leffler case WLAN_EID_MOBILITY_DOMAIN: 24239beb93cSSam Leffler elems->mdie = pos; 24339beb93cSSam Leffler elems->mdie_len = elen; 24439beb93cSSam Leffler break; 24539beb93cSSam Leffler case WLAN_EID_FAST_BSS_TRANSITION: 24639beb93cSSam Leffler elems->ftie = pos; 24739beb93cSSam Leffler elems->ftie_len = elen; 24839beb93cSSam Leffler break; 24939beb93cSSam Leffler case WLAN_EID_TIMEOUT_INTERVAL: 25039beb93cSSam Leffler elems->timeout_int = pos; 25139beb93cSSam Leffler elems->timeout_int_len = elen; 25239beb93cSSam Leffler break; 25339beb93cSSam Leffler case WLAN_EID_HT_CAP: 25439beb93cSSam Leffler elems->ht_capabilities = pos; 25539beb93cSSam Leffler elems->ht_capabilities_len = elen; 25639beb93cSSam Leffler break; 25739beb93cSSam Leffler case WLAN_EID_HT_OPERATION: 25839beb93cSSam Leffler elems->ht_operation = pos; 25939beb93cSSam Leffler elems->ht_operation_len = elen; 26039beb93cSSam Leffler break; 261*f05cddf9SRui Paulo case WLAN_EID_VHT_CAP: 262*f05cddf9SRui Paulo elems->vht_capabilities = pos; 263*f05cddf9SRui Paulo elems->vht_capabilities_len = elen; 264*f05cddf9SRui Paulo break; 265*f05cddf9SRui Paulo case WLAN_EID_VHT_OPERATION: 266*f05cddf9SRui Paulo elems->vht_operation = pos; 267*f05cddf9SRui Paulo elems->vht_operation_len = elen; 268*f05cddf9SRui Paulo break; 269*f05cddf9SRui Paulo case WLAN_EID_LINK_ID: 270*f05cddf9SRui Paulo if (elen < 18) 271*f05cddf9SRui Paulo break; 272*f05cddf9SRui Paulo elems->link_id = pos; 273*f05cddf9SRui Paulo break; 274*f05cddf9SRui Paulo case WLAN_EID_INTERWORKING: 275*f05cddf9SRui Paulo elems->interworking = pos; 276*f05cddf9SRui Paulo elems->interworking_len = elen; 277*f05cddf9SRui Paulo break; 278*f05cddf9SRui Paulo case WLAN_EID_EXT_CAPAB: 279*f05cddf9SRui Paulo elems->ext_capab = pos; 280*f05cddf9SRui Paulo elems->ext_capab_len = elen; 281*f05cddf9SRui Paulo break; 282*f05cddf9SRui Paulo case WLAN_EID_BSS_MAX_IDLE_PERIOD: 283*f05cddf9SRui Paulo if (elen < 3) 284*f05cddf9SRui Paulo break; 285*f05cddf9SRui Paulo elems->bss_max_idle_period = pos; 286*f05cddf9SRui Paulo break; 287*f05cddf9SRui Paulo case WLAN_EID_SSID_LIST: 288*f05cddf9SRui Paulo elems->ssid_list = pos; 289*f05cddf9SRui Paulo elems->ssid_list_len = elen; 290*f05cddf9SRui Paulo break; 29139beb93cSSam Leffler default: 29239beb93cSSam Leffler unknown++; 29339beb93cSSam Leffler if (!show_errors) 29439beb93cSSam Leffler break; 29539beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 29639beb93cSSam Leffler "ignored unknown element (id=%d elen=%d)", 29739beb93cSSam Leffler id, elen); 29839beb93cSSam Leffler break; 29939beb93cSSam Leffler } 30039beb93cSSam Leffler 30139beb93cSSam Leffler left -= elen; 30239beb93cSSam Leffler pos += elen; 30339beb93cSSam Leffler } 30439beb93cSSam Leffler 30539beb93cSSam Leffler if (left) 30639beb93cSSam Leffler return ParseFailed; 30739beb93cSSam Leffler 30839beb93cSSam Leffler return unknown ? ParseUnknown : ParseOK; 30939beb93cSSam Leffler } 310e28a4053SRui Paulo 311e28a4053SRui Paulo 312e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 313e28a4053SRui Paulo { 314e28a4053SRui Paulo int count = 0; 315e28a4053SRui Paulo const u8 *pos, *end; 316e28a4053SRui Paulo 317e28a4053SRui Paulo if (ies == NULL) 318e28a4053SRui Paulo return 0; 319e28a4053SRui Paulo 320e28a4053SRui Paulo pos = ies; 321e28a4053SRui Paulo end = ies + ies_len; 322e28a4053SRui Paulo 323e28a4053SRui Paulo while (pos + 2 <= end) { 324e28a4053SRui Paulo if (pos + 2 + pos[1] > end) 325e28a4053SRui Paulo break; 326e28a4053SRui Paulo count++; 327e28a4053SRui Paulo pos += 2 + pos[1]; 328e28a4053SRui Paulo } 329e28a4053SRui Paulo 330e28a4053SRui Paulo return count; 331e28a4053SRui Paulo } 332e28a4053SRui Paulo 333e28a4053SRui Paulo 334e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 335e28a4053SRui Paulo u32 oui_type) 336e28a4053SRui Paulo { 337e28a4053SRui Paulo struct wpabuf *buf; 338e28a4053SRui Paulo const u8 *end, *pos, *ie; 339e28a4053SRui Paulo 340e28a4053SRui Paulo pos = ies; 341e28a4053SRui Paulo end = ies + ies_len; 342e28a4053SRui Paulo ie = NULL; 343e28a4053SRui Paulo 344e28a4053SRui Paulo while (pos + 1 < end) { 345e28a4053SRui Paulo if (pos + 2 + pos[1] > end) 346e28a4053SRui Paulo return NULL; 347e28a4053SRui Paulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 348e28a4053SRui Paulo WPA_GET_BE32(&pos[2]) == oui_type) { 349e28a4053SRui Paulo ie = pos; 350e28a4053SRui Paulo break; 351e28a4053SRui Paulo } 352e28a4053SRui Paulo pos += 2 + pos[1]; 353e28a4053SRui Paulo } 354e28a4053SRui Paulo 355e28a4053SRui Paulo if (ie == NULL) 356e28a4053SRui Paulo return NULL; /* No specified vendor IE found */ 357e28a4053SRui Paulo 358e28a4053SRui Paulo buf = wpabuf_alloc(ies_len); 359e28a4053SRui Paulo if (buf == NULL) 360e28a4053SRui Paulo return NULL; 361e28a4053SRui Paulo 362e28a4053SRui Paulo /* 363e28a4053SRui Paulo * There may be multiple vendor IEs in the message, so need to 364e28a4053SRui Paulo * concatenate their data fields. 365e28a4053SRui Paulo */ 366e28a4053SRui Paulo while (pos + 1 < end) { 367e28a4053SRui Paulo if (pos + 2 + pos[1] > end) 368e28a4053SRui Paulo break; 369e28a4053SRui Paulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 370e28a4053SRui Paulo WPA_GET_BE32(&pos[2]) == oui_type) 371e28a4053SRui Paulo wpabuf_put_data(buf, pos + 6, pos[1] - 4); 372e28a4053SRui Paulo pos += 2 + pos[1]; 373e28a4053SRui Paulo } 374e28a4053SRui Paulo 375e28a4053SRui Paulo return buf; 376e28a4053SRui Paulo } 377*f05cddf9SRui Paulo 378*f05cddf9SRui Paulo 379*f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 380*f05cddf9SRui Paulo { 381*f05cddf9SRui Paulo u16 fc, type, stype; 382*f05cddf9SRui Paulo 383*f05cddf9SRui Paulo /* 384*f05cddf9SRui Paulo * PS-Poll frames are 16 bytes. All other frames are 385*f05cddf9SRui Paulo * 24 bytes or longer. 386*f05cddf9SRui Paulo */ 387*f05cddf9SRui Paulo if (len < 16) 388*f05cddf9SRui Paulo return NULL; 389*f05cddf9SRui Paulo 390*f05cddf9SRui Paulo fc = le_to_host16(hdr->frame_control); 391*f05cddf9SRui Paulo type = WLAN_FC_GET_TYPE(fc); 392*f05cddf9SRui Paulo stype = WLAN_FC_GET_STYPE(fc); 393*f05cddf9SRui Paulo 394*f05cddf9SRui Paulo switch (type) { 395*f05cddf9SRui Paulo case WLAN_FC_TYPE_DATA: 396*f05cddf9SRui Paulo if (len < 24) 397*f05cddf9SRui Paulo return NULL; 398*f05cddf9SRui Paulo switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 399*f05cddf9SRui Paulo case WLAN_FC_FROMDS | WLAN_FC_TODS: 400*f05cddf9SRui Paulo case WLAN_FC_TODS: 401*f05cddf9SRui Paulo return hdr->addr1; 402*f05cddf9SRui Paulo case WLAN_FC_FROMDS: 403*f05cddf9SRui Paulo return hdr->addr2; 404*f05cddf9SRui Paulo default: 405*f05cddf9SRui Paulo return NULL; 406*f05cddf9SRui Paulo } 407*f05cddf9SRui Paulo case WLAN_FC_TYPE_CTRL: 408*f05cddf9SRui Paulo if (stype != WLAN_FC_STYPE_PSPOLL) 409*f05cddf9SRui Paulo return NULL; 410*f05cddf9SRui Paulo return hdr->addr1; 411*f05cddf9SRui Paulo case WLAN_FC_TYPE_MGMT: 412*f05cddf9SRui Paulo return hdr->addr3; 413*f05cddf9SRui Paulo default: 414*f05cddf9SRui Paulo return NULL; 415*f05cddf9SRui Paulo } 416*f05cddf9SRui Paulo } 417*f05cddf9SRui Paulo 418*f05cddf9SRui Paulo 419*f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 420*f05cddf9SRui Paulo const char *name, const char *val) 421*f05cddf9SRui Paulo { 422*f05cddf9SRui Paulo int num, v; 423*f05cddf9SRui Paulo const char *pos; 424*f05cddf9SRui Paulo struct hostapd_wmm_ac_params *ac; 425*f05cddf9SRui Paulo 426*f05cddf9SRui Paulo /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 427*f05cddf9SRui Paulo pos = name + 7; 428*f05cddf9SRui Paulo if (os_strncmp(pos, "be_", 3) == 0) { 429*f05cddf9SRui Paulo num = 0; 430*f05cddf9SRui Paulo pos += 3; 431*f05cddf9SRui Paulo } else if (os_strncmp(pos, "bk_", 3) == 0) { 432*f05cddf9SRui Paulo num = 1; 433*f05cddf9SRui Paulo pos += 3; 434*f05cddf9SRui Paulo } else if (os_strncmp(pos, "vi_", 3) == 0) { 435*f05cddf9SRui Paulo num = 2; 436*f05cddf9SRui Paulo pos += 3; 437*f05cddf9SRui Paulo } else if (os_strncmp(pos, "vo_", 3) == 0) { 438*f05cddf9SRui Paulo num = 3; 439*f05cddf9SRui Paulo pos += 3; 440*f05cddf9SRui Paulo } else { 441*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 442*f05cddf9SRui Paulo return -1; 443*f05cddf9SRui Paulo } 444*f05cddf9SRui Paulo 445*f05cddf9SRui Paulo ac = &wmm_ac_params[num]; 446*f05cddf9SRui Paulo 447*f05cddf9SRui Paulo if (os_strcmp(pos, "aifs") == 0) { 448*f05cddf9SRui Paulo v = atoi(val); 449*f05cddf9SRui Paulo if (v < 1 || v > 255) { 450*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 451*f05cddf9SRui Paulo return -1; 452*f05cddf9SRui Paulo } 453*f05cddf9SRui Paulo ac->aifs = v; 454*f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmin") == 0) { 455*f05cddf9SRui Paulo v = atoi(val); 456*f05cddf9SRui Paulo if (v < 0 || v > 12) { 457*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 458*f05cddf9SRui Paulo return -1; 459*f05cddf9SRui Paulo } 460*f05cddf9SRui Paulo ac->cwmin = v; 461*f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmax") == 0) { 462*f05cddf9SRui Paulo v = atoi(val); 463*f05cddf9SRui Paulo if (v < 0 || v > 12) { 464*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 465*f05cddf9SRui Paulo return -1; 466*f05cddf9SRui Paulo } 467*f05cddf9SRui Paulo ac->cwmax = v; 468*f05cddf9SRui Paulo } else if (os_strcmp(pos, "txop_limit") == 0) { 469*f05cddf9SRui Paulo v = atoi(val); 470*f05cddf9SRui Paulo if (v < 0 || v > 0xffff) { 471*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 472*f05cddf9SRui Paulo return -1; 473*f05cddf9SRui Paulo } 474*f05cddf9SRui Paulo ac->txop_limit = v; 475*f05cddf9SRui Paulo } else if (os_strcmp(pos, "acm") == 0) { 476*f05cddf9SRui Paulo v = atoi(val); 477*f05cddf9SRui Paulo if (v < 0 || v > 1) { 478*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 479*f05cddf9SRui Paulo return -1; 480*f05cddf9SRui Paulo } 481*f05cddf9SRui Paulo ac->admission_control_mandatory = v; 482*f05cddf9SRui Paulo } else { 483*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 484*f05cddf9SRui Paulo return -1; 485*f05cddf9SRui Paulo } 486*f05cddf9SRui Paulo 487*f05cddf9SRui Paulo return 0; 488*f05cddf9SRui Paulo } 489