139beb93cSSam Leffler /* 239beb93cSSam Leffler * IEEE 802.11 Common routines 34bc52338SCy Schubert * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 125b9c547cSRui Paulo #include "defs.h" 13325151a3SRui Paulo #include "wpa_common.h" 1485732ac8SCy Schubert #include "drivers/driver.h" 15325151a3SRui Paulo #include "qca-vendor.h" 1639beb93cSSam Leffler #include "ieee802_11_defs.h" 1739beb93cSSam Leffler #include "ieee802_11_common.h" 1839beb93cSSam Leffler 1939beb93cSSam Leffler 20e28a4053SRui Paulo static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 2139beb93cSSam Leffler struct ieee802_11_elems *elems, 2239beb93cSSam Leffler int show_errors) 2339beb93cSSam Leffler { 2439beb93cSSam Leffler unsigned int oui; 2539beb93cSSam Leffler 2639beb93cSSam Leffler /* first 3 bytes in vendor specific information element are the IEEE 2739beb93cSSam Leffler * OUI of the vendor. The following byte is used a vendor specific 2839beb93cSSam Leffler * sub-type. */ 2939beb93cSSam Leffler if (elen < 4) { 3039beb93cSSam Leffler if (show_errors) { 3139beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "short vendor specific " 3239beb93cSSam Leffler "information element ignored (len=%lu)", 3339beb93cSSam Leffler (unsigned long) elen); 3439beb93cSSam Leffler } 3539beb93cSSam Leffler return -1; 3639beb93cSSam Leffler } 3739beb93cSSam Leffler 3839beb93cSSam Leffler oui = WPA_GET_BE24(pos); 3939beb93cSSam Leffler switch (oui) { 4039beb93cSSam Leffler case OUI_MICROSOFT: 4139beb93cSSam Leffler /* Microsoft/Wi-Fi information elements are further typed and 4239beb93cSSam Leffler * subtyped */ 4339beb93cSSam Leffler switch (pos[3]) { 4439beb93cSSam Leffler case 1: 4539beb93cSSam Leffler /* Microsoft OUI (00:50:F2) with OUI Type 1: 4639beb93cSSam Leffler * real WPA information element */ 4739beb93cSSam Leffler elems->wpa_ie = pos; 4839beb93cSSam Leffler elems->wpa_ie_len = elen; 4939beb93cSSam Leffler break; 503157ba21SRui Paulo case WMM_OUI_TYPE: 513157ba21SRui Paulo /* WMM information element */ 5239beb93cSSam Leffler if (elen < 5) { 533157ba21SRui Paulo wpa_printf(MSG_MSGDUMP, "short WMM " 5439beb93cSSam Leffler "information element ignored " 5539beb93cSSam Leffler "(len=%lu)", 5639beb93cSSam Leffler (unsigned long) elen); 5739beb93cSSam Leffler return -1; 5839beb93cSSam Leffler } 5939beb93cSSam Leffler switch (pos[4]) { 603157ba21SRui Paulo case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 613157ba21SRui Paulo case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 623157ba21SRui Paulo /* 633157ba21SRui Paulo * Share same pointer since only one of these 643157ba21SRui Paulo * is used and they start with same data. 653157ba21SRui Paulo * Length field can be used to distinguish the 663157ba21SRui Paulo * IEs. 673157ba21SRui Paulo */ 683157ba21SRui Paulo elems->wmm = pos; 693157ba21SRui Paulo elems->wmm_len = elen; 7039beb93cSSam Leffler break; 713157ba21SRui Paulo case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 723157ba21SRui Paulo elems->wmm_tspec = pos; 733157ba21SRui Paulo elems->wmm_tspec_len = elen; 7439beb93cSSam Leffler break; 7539beb93cSSam Leffler default: 76f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown WMM " 7739beb93cSSam Leffler "information element ignored " 7839beb93cSSam Leffler "(subtype=%d len=%lu)", 7939beb93cSSam Leffler pos[4], (unsigned long) elen); 8039beb93cSSam Leffler return -1; 8139beb93cSSam Leffler } 8239beb93cSSam Leffler break; 8339beb93cSSam Leffler case 4: 8439beb93cSSam Leffler /* Wi-Fi Protected Setup (WPS) IE */ 8539beb93cSSam Leffler elems->wps_ie = pos; 8639beb93cSSam Leffler elems->wps_ie_len = elen; 8739beb93cSSam Leffler break; 8839beb93cSSam Leffler default: 89f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 90f05cddf9SRui Paulo "information element ignored " 91f05cddf9SRui Paulo "(type=%d len=%lu)", 92f05cddf9SRui Paulo pos[3], (unsigned long) elen); 93f05cddf9SRui Paulo return -1; 94f05cddf9SRui Paulo } 95f05cddf9SRui Paulo break; 96f05cddf9SRui Paulo 97f05cddf9SRui Paulo case OUI_WFA: 98f05cddf9SRui Paulo switch (pos[3]) { 99f05cddf9SRui Paulo case P2P_OUI_TYPE: 100f05cddf9SRui Paulo /* Wi-Fi Alliance - P2P IE */ 101f05cddf9SRui Paulo elems->p2p = pos; 102f05cddf9SRui Paulo elems->p2p_len = elen; 103f05cddf9SRui Paulo break; 104f05cddf9SRui Paulo case WFD_OUI_TYPE: 105f05cddf9SRui Paulo /* Wi-Fi Alliance - WFD IE */ 106f05cddf9SRui Paulo elems->wfd = pos; 107f05cddf9SRui Paulo elems->wfd_len = elen; 108f05cddf9SRui Paulo break; 109f05cddf9SRui Paulo case HS20_INDICATION_OUI_TYPE: 110f05cddf9SRui Paulo /* Hotspot 2.0 */ 111f05cddf9SRui Paulo elems->hs20 = pos; 112f05cddf9SRui Paulo elems->hs20_len = elen; 113f05cddf9SRui Paulo break; 1145b9c547cSRui Paulo case HS20_OSEN_OUI_TYPE: 1155b9c547cSRui Paulo /* Hotspot 2.0 OSEN */ 1165b9c547cSRui Paulo elems->osen = pos; 1175b9c547cSRui Paulo elems->osen_len = elen; 1185b9c547cSRui Paulo break; 119780fb4a2SCy Schubert case MBO_OUI_TYPE: 120780fb4a2SCy Schubert /* MBO-OCE */ 121780fb4a2SCy Schubert elems->mbo = pos; 122780fb4a2SCy Schubert elems->mbo_len = elen; 123780fb4a2SCy Schubert break; 12485732ac8SCy Schubert case HS20_ROAMING_CONS_SEL_OUI_TYPE: 12585732ac8SCy Schubert /* Hotspot 2.0 Roaming Consortium Selection */ 12685732ac8SCy Schubert elems->roaming_cons_sel = pos; 12785732ac8SCy Schubert elems->roaming_cons_sel_len = elen; 12885732ac8SCy Schubert break; 1294bc52338SCy Schubert case MULTI_AP_OUI_TYPE: 1304bc52338SCy Schubert elems->multi_ap = pos; 1314bc52338SCy Schubert elems->multi_ap_len = elen; 1324bc52338SCy Schubert break; 133f05cddf9SRui Paulo default: 134f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Unknown WFA " 13539beb93cSSam Leffler "information element ignored " 1365b9c547cSRui Paulo "(type=%d len=%lu)", 13739beb93cSSam Leffler pos[3], (unsigned long) elen); 13839beb93cSSam Leffler return -1; 13939beb93cSSam Leffler } 14039beb93cSSam Leffler break; 14139beb93cSSam Leffler 14239beb93cSSam Leffler case OUI_BROADCOM: 14339beb93cSSam Leffler switch (pos[3]) { 14439beb93cSSam Leffler case VENDOR_HT_CAPAB_OUI_TYPE: 14539beb93cSSam Leffler elems->vendor_ht_cap = pos; 14639beb93cSSam Leffler elems->vendor_ht_cap_len = elen; 14739beb93cSSam Leffler break; 1485b9c547cSRui Paulo case VENDOR_VHT_TYPE: 1495b9c547cSRui Paulo if (elen > 4 && 1505b9c547cSRui Paulo (pos[4] == VENDOR_VHT_SUBTYPE || 1515b9c547cSRui Paulo pos[4] == VENDOR_VHT_SUBTYPE2)) { 1525b9c547cSRui Paulo elems->vendor_vht = pos; 1535b9c547cSRui Paulo elems->vendor_vht_len = elen; 1545b9c547cSRui Paulo } else 1555b9c547cSRui Paulo return -1; 1565b9c547cSRui Paulo break; 15739beb93cSSam Leffler default: 158f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 15939beb93cSSam Leffler "information element ignored " 160f05cddf9SRui Paulo "(type=%d len=%lu)", 16139beb93cSSam Leffler pos[3], (unsigned long) elen); 16239beb93cSSam Leffler return -1; 16339beb93cSSam Leffler } 16439beb93cSSam Leffler break; 16539beb93cSSam Leffler 166325151a3SRui Paulo case OUI_QCA: 167325151a3SRui Paulo switch (pos[3]) { 168325151a3SRui Paulo case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: 169325151a3SRui Paulo elems->pref_freq_list = pos; 170325151a3SRui Paulo elems->pref_freq_list_len = elen; 171325151a3SRui Paulo break; 172325151a3SRui Paulo default: 173325151a3SRui Paulo wpa_printf(MSG_EXCESSIVE, 174325151a3SRui Paulo "Unknown QCA information element ignored (type=%d len=%lu)", 175325151a3SRui Paulo pos[3], (unsigned long) elen); 176325151a3SRui Paulo return -1; 177325151a3SRui Paulo } 178325151a3SRui Paulo break; 179325151a3SRui Paulo 18039beb93cSSam Leffler default: 181f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 182f05cddf9SRui Paulo "information element ignored (vendor OUI " 183f05cddf9SRui Paulo "%02x:%02x:%02x len=%lu)", 18439beb93cSSam Leffler pos[0], pos[1], pos[2], (unsigned long) elen); 18539beb93cSSam Leffler return -1; 18639beb93cSSam Leffler } 18739beb93cSSam Leffler 18839beb93cSSam Leffler return 0; 18939beb93cSSam Leffler } 19039beb93cSSam Leffler 19139beb93cSSam Leffler 19285732ac8SCy Schubert static int ieee802_11_parse_extension(const u8 *pos, size_t elen, 19385732ac8SCy Schubert struct ieee802_11_elems *elems, 19485732ac8SCy Schubert int show_errors) 19585732ac8SCy Schubert { 19685732ac8SCy Schubert u8 ext_id; 19785732ac8SCy Schubert 19885732ac8SCy Schubert if (elen < 1) { 19985732ac8SCy Schubert if (show_errors) { 20085732ac8SCy Schubert wpa_printf(MSG_MSGDUMP, 20185732ac8SCy Schubert "short information element (Ext)"); 20285732ac8SCy Schubert } 20385732ac8SCy Schubert return -1; 20485732ac8SCy Schubert } 20585732ac8SCy Schubert 20685732ac8SCy Schubert ext_id = *pos++; 20785732ac8SCy Schubert elen--; 20885732ac8SCy Schubert 20985732ac8SCy Schubert switch (ext_id) { 21085732ac8SCy Schubert case WLAN_EID_EXT_ASSOC_DELAY_INFO: 21185732ac8SCy Schubert if (elen != 1) 21285732ac8SCy Schubert break; 21385732ac8SCy Schubert elems->assoc_delay_info = pos; 21485732ac8SCy Schubert break; 21585732ac8SCy Schubert case WLAN_EID_EXT_FILS_REQ_PARAMS: 21685732ac8SCy Schubert if (elen < 3) 21785732ac8SCy Schubert break; 21885732ac8SCy Schubert elems->fils_req_params = pos; 21985732ac8SCy Schubert elems->fils_req_params_len = elen; 22085732ac8SCy Schubert break; 22185732ac8SCy Schubert case WLAN_EID_EXT_FILS_KEY_CONFIRM: 22285732ac8SCy Schubert elems->fils_key_confirm = pos; 22385732ac8SCy Schubert elems->fils_key_confirm_len = elen; 22485732ac8SCy Schubert break; 22585732ac8SCy Schubert case WLAN_EID_EXT_FILS_SESSION: 22685732ac8SCy Schubert if (elen != FILS_SESSION_LEN) 22785732ac8SCy Schubert break; 22885732ac8SCy Schubert elems->fils_session = pos; 22985732ac8SCy Schubert break; 23085732ac8SCy Schubert case WLAN_EID_EXT_FILS_HLP_CONTAINER: 23185732ac8SCy Schubert if (elen < 2 * ETH_ALEN) 23285732ac8SCy Schubert break; 23385732ac8SCy Schubert elems->fils_hlp = pos; 23485732ac8SCy Schubert elems->fils_hlp_len = elen; 23585732ac8SCy Schubert break; 23685732ac8SCy Schubert case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN: 23785732ac8SCy Schubert if (elen < 1) 23885732ac8SCy Schubert break; 23985732ac8SCy Schubert elems->fils_ip_addr_assign = pos; 24085732ac8SCy Schubert elems->fils_ip_addr_assign_len = elen; 24185732ac8SCy Schubert break; 24285732ac8SCy Schubert case WLAN_EID_EXT_KEY_DELIVERY: 24385732ac8SCy Schubert if (elen < WPA_KEY_RSC_LEN) 24485732ac8SCy Schubert break; 24585732ac8SCy Schubert elems->key_delivery = pos; 24685732ac8SCy Schubert elems->key_delivery_len = elen; 24785732ac8SCy Schubert break; 24885732ac8SCy Schubert case WLAN_EID_EXT_FILS_WRAPPED_DATA: 24985732ac8SCy Schubert elems->fils_wrapped_data = pos; 25085732ac8SCy Schubert elems->fils_wrapped_data_len = elen; 25185732ac8SCy Schubert break; 25285732ac8SCy Schubert case WLAN_EID_EXT_FILS_PUBLIC_KEY: 25385732ac8SCy Schubert if (elen < 1) 25485732ac8SCy Schubert break; 25585732ac8SCy Schubert elems->fils_pk = pos; 25685732ac8SCy Schubert elems->fils_pk_len = elen; 25785732ac8SCy Schubert break; 25885732ac8SCy Schubert case WLAN_EID_EXT_FILS_NONCE: 25985732ac8SCy Schubert if (elen != FILS_NONCE_LEN) 26085732ac8SCy Schubert break; 26185732ac8SCy Schubert elems->fils_nonce = pos; 26285732ac8SCy Schubert break; 26385732ac8SCy Schubert case WLAN_EID_EXT_OWE_DH_PARAM: 26485732ac8SCy Schubert if (elen < 2) 26585732ac8SCy Schubert break; 26685732ac8SCy Schubert elems->owe_dh = pos; 26785732ac8SCy Schubert elems->owe_dh_len = elen; 26885732ac8SCy Schubert break; 26985732ac8SCy Schubert case WLAN_EID_EXT_PASSWORD_IDENTIFIER: 27085732ac8SCy Schubert elems->password_id = pos; 27185732ac8SCy Schubert elems->password_id_len = elen; 27285732ac8SCy Schubert break; 2734bc52338SCy Schubert case WLAN_EID_EXT_HE_CAPABILITIES: 2744bc52338SCy Schubert elems->he_capabilities = pos; 2754bc52338SCy Schubert elems->he_capabilities_len = elen; 2764bc52338SCy Schubert break; 277*206b73d0SCy Schubert case WLAN_EID_EXT_HE_OPERATION: 278*206b73d0SCy Schubert elems->he_operation = pos; 279*206b73d0SCy Schubert elems->he_operation_len = elen; 280*206b73d0SCy Schubert break; 2814bc52338SCy Schubert case WLAN_EID_EXT_OCV_OCI: 2824bc52338SCy Schubert elems->oci = pos; 2834bc52338SCy Schubert elems->oci_len = elen; 2844bc52338SCy Schubert break; 28585732ac8SCy Schubert default: 28685732ac8SCy Schubert if (show_errors) { 28785732ac8SCy Schubert wpa_printf(MSG_MSGDUMP, 28885732ac8SCy Schubert "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)", 28985732ac8SCy Schubert ext_id, (unsigned int) elen); 29085732ac8SCy Schubert } 29185732ac8SCy Schubert return -1; 29285732ac8SCy Schubert } 29385732ac8SCy Schubert 29485732ac8SCy Schubert return 0; 29585732ac8SCy Schubert } 29685732ac8SCy Schubert 29785732ac8SCy Schubert 29839beb93cSSam Leffler /** 29939beb93cSSam Leffler * ieee802_11_parse_elems - Parse information elements in management frames 30039beb93cSSam Leffler * @start: Pointer to the start of IEs 30139beb93cSSam Leffler * @len: Length of IE buffer in octets 30239beb93cSSam Leffler * @elems: Data structure for parsed elements 30339beb93cSSam Leffler * @show_errors: Whether to show parsing errors in debug log 30439beb93cSSam Leffler * Returns: Parsing result 30539beb93cSSam Leffler */ 306e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 30739beb93cSSam Leffler struct ieee802_11_elems *elems, 30839beb93cSSam Leffler int show_errors) 30939beb93cSSam Leffler { 3104bc52338SCy Schubert const struct element *elem; 31139beb93cSSam Leffler int unknown = 0; 31239beb93cSSam Leffler 31339beb93cSSam Leffler os_memset(elems, 0, sizeof(*elems)); 31439beb93cSSam Leffler 3154bc52338SCy Schubert if (!start) 3164bc52338SCy Schubert return ParseOK; 31739beb93cSSam Leffler 3184bc52338SCy Schubert for_each_element(elem, start, len) { 3194bc52338SCy Schubert u8 id = elem->id, elen = elem->datalen; 3204bc52338SCy Schubert const u8 *pos = elem->data; 32139beb93cSSam Leffler 32239beb93cSSam Leffler switch (id) { 32339beb93cSSam Leffler case WLAN_EID_SSID: 324325151a3SRui Paulo if (elen > SSID_MAX_LEN) { 325325151a3SRui Paulo wpa_printf(MSG_DEBUG, 326325151a3SRui Paulo "Ignored too long SSID element (elen=%u)", 327325151a3SRui Paulo elen); 328325151a3SRui Paulo break; 329325151a3SRui Paulo } 33039beb93cSSam Leffler elems->ssid = pos; 33139beb93cSSam Leffler elems->ssid_len = elen; 33239beb93cSSam Leffler break; 33339beb93cSSam Leffler case WLAN_EID_SUPP_RATES: 33439beb93cSSam Leffler elems->supp_rates = pos; 33539beb93cSSam Leffler elems->supp_rates_len = elen; 33639beb93cSSam Leffler break; 33739beb93cSSam Leffler case WLAN_EID_DS_PARAMS: 338325151a3SRui Paulo if (elen < 1) 339325151a3SRui Paulo break; 34039beb93cSSam Leffler elems->ds_params = pos; 34139beb93cSSam Leffler break; 34239beb93cSSam Leffler case WLAN_EID_CF_PARAMS: 34339beb93cSSam Leffler case WLAN_EID_TIM: 34439beb93cSSam Leffler break; 34539beb93cSSam Leffler case WLAN_EID_CHALLENGE: 34639beb93cSSam Leffler elems->challenge = pos; 34739beb93cSSam Leffler elems->challenge_len = elen; 34839beb93cSSam Leffler break; 34939beb93cSSam Leffler case WLAN_EID_ERP_INFO: 350325151a3SRui Paulo if (elen < 1) 351325151a3SRui Paulo break; 35239beb93cSSam Leffler elems->erp_info = pos; 35339beb93cSSam Leffler break; 35439beb93cSSam Leffler case WLAN_EID_EXT_SUPP_RATES: 35539beb93cSSam Leffler elems->ext_supp_rates = pos; 35639beb93cSSam Leffler elems->ext_supp_rates_len = elen; 35739beb93cSSam Leffler break; 35839beb93cSSam Leffler case WLAN_EID_VENDOR_SPECIFIC: 35939beb93cSSam Leffler if (ieee802_11_parse_vendor_specific(pos, elen, 36039beb93cSSam Leffler elems, 36139beb93cSSam Leffler show_errors)) 36239beb93cSSam Leffler unknown++; 36339beb93cSSam Leffler break; 36439beb93cSSam Leffler case WLAN_EID_RSN: 36539beb93cSSam Leffler elems->rsn_ie = pos; 36639beb93cSSam Leffler elems->rsn_ie_len = elen; 36739beb93cSSam Leffler break; 36839beb93cSSam Leffler case WLAN_EID_PWR_CAPABILITY: 36985732ac8SCy Schubert if (elen < 2) 37085732ac8SCy Schubert break; 37185732ac8SCy Schubert elems->power_capab = pos; 37285732ac8SCy Schubert elems->power_capab_len = elen; 37339beb93cSSam Leffler break; 37439beb93cSSam Leffler case WLAN_EID_SUPPORTED_CHANNELS: 37539beb93cSSam Leffler elems->supp_channels = pos; 37639beb93cSSam Leffler elems->supp_channels_len = elen; 37739beb93cSSam Leffler break; 37839beb93cSSam Leffler case WLAN_EID_MOBILITY_DOMAIN: 379325151a3SRui Paulo if (elen < sizeof(struct rsn_mdie)) 380325151a3SRui Paulo break; 38139beb93cSSam Leffler elems->mdie = pos; 38239beb93cSSam Leffler elems->mdie_len = elen; 38339beb93cSSam Leffler break; 38439beb93cSSam Leffler case WLAN_EID_FAST_BSS_TRANSITION: 385325151a3SRui Paulo if (elen < sizeof(struct rsn_ftie)) 386325151a3SRui Paulo break; 38739beb93cSSam Leffler elems->ftie = pos; 38839beb93cSSam Leffler elems->ftie_len = elen; 38939beb93cSSam Leffler break; 39039beb93cSSam Leffler case WLAN_EID_TIMEOUT_INTERVAL: 391325151a3SRui Paulo if (elen != 5) 392325151a3SRui Paulo break; 39339beb93cSSam Leffler elems->timeout_int = pos; 39439beb93cSSam Leffler break; 39539beb93cSSam Leffler case WLAN_EID_HT_CAP: 396325151a3SRui Paulo if (elen < sizeof(struct ieee80211_ht_capabilities)) 397325151a3SRui Paulo break; 39839beb93cSSam Leffler elems->ht_capabilities = pos; 39939beb93cSSam Leffler break; 40039beb93cSSam Leffler case WLAN_EID_HT_OPERATION: 401325151a3SRui Paulo if (elen < sizeof(struct ieee80211_ht_operation)) 402325151a3SRui Paulo break; 40339beb93cSSam Leffler elems->ht_operation = pos; 40439beb93cSSam Leffler break; 4055b9c547cSRui Paulo case WLAN_EID_MESH_CONFIG: 4065b9c547cSRui Paulo elems->mesh_config = pos; 4075b9c547cSRui Paulo elems->mesh_config_len = elen; 4085b9c547cSRui Paulo break; 4095b9c547cSRui Paulo case WLAN_EID_MESH_ID: 4105b9c547cSRui Paulo elems->mesh_id = pos; 4115b9c547cSRui Paulo elems->mesh_id_len = elen; 4125b9c547cSRui Paulo break; 4135b9c547cSRui Paulo case WLAN_EID_PEER_MGMT: 4145b9c547cSRui Paulo elems->peer_mgmt = pos; 4155b9c547cSRui Paulo elems->peer_mgmt_len = elen; 4165b9c547cSRui Paulo break; 417f05cddf9SRui Paulo case WLAN_EID_VHT_CAP: 418325151a3SRui Paulo if (elen < sizeof(struct ieee80211_vht_capabilities)) 419325151a3SRui Paulo break; 420f05cddf9SRui Paulo elems->vht_capabilities = pos; 421f05cddf9SRui Paulo break; 422f05cddf9SRui Paulo case WLAN_EID_VHT_OPERATION: 423325151a3SRui Paulo if (elen < sizeof(struct ieee80211_vht_operation)) 424325151a3SRui Paulo break; 425f05cddf9SRui Paulo elems->vht_operation = pos; 426f05cddf9SRui Paulo break; 4275b9c547cSRui Paulo case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: 4285b9c547cSRui Paulo if (elen != 1) 4295b9c547cSRui Paulo break; 4305b9c547cSRui Paulo elems->vht_opmode_notif = pos; 4315b9c547cSRui Paulo break; 432f05cddf9SRui Paulo case WLAN_EID_LINK_ID: 433f05cddf9SRui Paulo if (elen < 18) 434f05cddf9SRui Paulo break; 435f05cddf9SRui Paulo elems->link_id = pos; 436f05cddf9SRui Paulo break; 437f05cddf9SRui Paulo case WLAN_EID_INTERWORKING: 438f05cddf9SRui Paulo elems->interworking = pos; 439f05cddf9SRui Paulo elems->interworking_len = elen; 440f05cddf9SRui Paulo break; 4415b9c547cSRui Paulo case WLAN_EID_QOS_MAP_SET: 4425b9c547cSRui Paulo if (elen < 16) 4435b9c547cSRui Paulo break; 4445b9c547cSRui Paulo elems->qos_map_set = pos; 4455b9c547cSRui Paulo elems->qos_map_set_len = elen; 4465b9c547cSRui Paulo break; 447f05cddf9SRui Paulo case WLAN_EID_EXT_CAPAB: 448f05cddf9SRui Paulo elems->ext_capab = pos; 449f05cddf9SRui Paulo elems->ext_capab_len = elen; 450f05cddf9SRui Paulo break; 451f05cddf9SRui Paulo case WLAN_EID_BSS_MAX_IDLE_PERIOD: 452f05cddf9SRui Paulo if (elen < 3) 453f05cddf9SRui Paulo break; 454f05cddf9SRui Paulo elems->bss_max_idle_period = pos; 455f05cddf9SRui Paulo break; 456f05cddf9SRui Paulo case WLAN_EID_SSID_LIST: 457f05cddf9SRui Paulo elems->ssid_list = pos; 458f05cddf9SRui Paulo elems->ssid_list_len = elen; 459f05cddf9SRui Paulo break; 4605b9c547cSRui Paulo case WLAN_EID_AMPE: 4615b9c547cSRui Paulo elems->ampe = pos; 4625b9c547cSRui Paulo elems->ampe_len = elen; 4635b9c547cSRui Paulo break; 4645b9c547cSRui Paulo case WLAN_EID_MIC: 4655b9c547cSRui Paulo elems->mic = pos; 4665b9c547cSRui Paulo elems->mic_len = elen; 4675b9c547cSRui Paulo /* after mic everything is encrypted, so stop. */ 4684bc52338SCy Schubert goto done; 469325151a3SRui Paulo case WLAN_EID_MULTI_BAND: 470325151a3SRui Paulo if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) { 471325151a3SRui Paulo wpa_printf(MSG_MSGDUMP, 472325151a3SRui Paulo "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)", 473325151a3SRui Paulo id, elen); 474325151a3SRui Paulo break; 475325151a3SRui Paulo } 476325151a3SRui Paulo 477325151a3SRui Paulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos; 478325151a3SRui Paulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen; 479325151a3SRui Paulo elems->mb_ies.nof_ies++; 480325151a3SRui Paulo break; 481780fb4a2SCy Schubert case WLAN_EID_SUPPORTED_OPERATING_CLASSES: 482780fb4a2SCy Schubert elems->supp_op_classes = pos; 483780fb4a2SCy Schubert elems->supp_op_classes_len = elen; 484780fb4a2SCy Schubert break; 485780fb4a2SCy Schubert case WLAN_EID_RRM_ENABLED_CAPABILITIES: 486780fb4a2SCy Schubert elems->rrm_enabled = pos; 487780fb4a2SCy Schubert elems->rrm_enabled_len = elen; 488780fb4a2SCy Schubert break; 48985732ac8SCy Schubert case WLAN_EID_CAG_NUMBER: 49085732ac8SCy Schubert elems->cag_number = pos; 49185732ac8SCy Schubert elems->cag_number_len = elen; 49285732ac8SCy Schubert break; 49385732ac8SCy Schubert case WLAN_EID_AP_CSN: 49485732ac8SCy Schubert if (elen < 1) 49585732ac8SCy Schubert break; 49685732ac8SCy Schubert elems->ap_csn = pos; 49785732ac8SCy Schubert break; 49885732ac8SCy Schubert case WLAN_EID_FILS_INDICATION: 49985732ac8SCy Schubert if (elen < 2) 50085732ac8SCy Schubert break; 50185732ac8SCy Schubert elems->fils_indic = pos; 50285732ac8SCy Schubert elems->fils_indic_len = elen; 50385732ac8SCy Schubert break; 50485732ac8SCy Schubert case WLAN_EID_DILS: 50585732ac8SCy Schubert if (elen < 2) 50685732ac8SCy Schubert break; 50785732ac8SCy Schubert elems->dils = pos; 50885732ac8SCy Schubert elems->dils_len = elen; 50985732ac8SCy Schubert break; 51085732ac8SCy Schubert case WLAN_EID_FRAGMENT: 51185732ac8SCy Schubert /* TODO */ 51285732ac8SCy Schubert break; 51385732ac8SCy Schubert case WLAN_EID_EXTENSION: 51485732ac8SCy Schubert if (ieee802_11_parse_extension(pos, elen, elems, 51585732ac8SCy Schubert show_errors)) 51685732ac8SCy Schubert unknown++; 51785732ac8SCy Schubert break; 51839beb93cSSam Leffler default: 51939beb93cSSam Leffler unknown++; 52039beb93cSSam Leffler if (!show_errors) 52139beb93cSSam Leffler break; 52239beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 52339beb93cSSam Leffler "ignored unknown element (id=%d elen=%d)", 52439beb93cSSam Leffler id, elen); 52539beb93cSSam Leffler break; 52639beb93cSSam Leffler } 52739beb93cSSam Leffler } 52839beb93cSSam Leffler 5294bc52338SCy Schubert if (!for_each_element_completed(elem, start, len)) { 5304bc52338SCy Schubert if (show_errors) { 5314bc52338SCy Schubert wpa_printf(MSG_DEBUG, 5324bc52338SCy Schubert "IEEE 802.11 element parse failed @%d", 5334bc52338SCy Schubert (int) (start + len - (const u8 *) elem)); 5344bc52338SCy Schubert wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 5354bc52338SCy Schubert } 53639beb93cSSam Leffler return ParseFailed; 5374bc52338SCy Schubert } 53839beb93cSSam Leffler 5394bc52338SCy Schubert done: 54039beb93cSSam Leffler return unknown ? ParseUnknown : ParseOK; 54139beb93cSSam Leffler } 542e28a4053SRui Paulo 543e28a4053SRui Paulo 544e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 545e28a4053SRui Paulo { 5464bc52338SCy Schubert const struct element *elem; 547e28a4053SRui Paulo int count = 0; 548e28a4053SRui Paulo 549e28a4053SRui Paulo if (ies == NULL) 550e28a4053SRui Paulo return 0; 551e28a4053SRui Paulo 5524bc52338SCy Schubert for_each_element(elem, ies, ies_len) 553e28a4053SRui Paulo count++; 554e28a4053SRui Paulo 555e28a4053SRui Paulo return count; 556e28a4053SRui Paulo } 557e28a4053SRui Paulo 558e28a4053SRui Paulo 559e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 560e28a4053SRui Paulo u32 oui_type) 561e28a4053SRui Paulo { 562e28a4053SRui Paulo struct wpabuf *buf; 5634bc52338SCy Schubert const struct element *elem, *found = NULL; 564e28a4053SRui Paulo 5654bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { 5664bc52338SCy Schubert if (elem->datalen >= 4 && 5674bc52338SCy Schubert WPA_GET_BE32(elem->data) == oui_type) { 5684bc52338SCy Schubert found = elem; 569e28a4053SRui Paulo break; 570e28a4053SRui Paulo } 571e28a4053SRui Paulo } 572e28a4053SRui Paulo 5734bc52338SCy Schubert if (!found) 574e28a4053SRui Paulo return NULL; /* No specified vendor IE found */ 575e28a4053SRui Paulo 576e28a4053SRui Paulo buf = wpabuf_alloc(ies_len); 577e28a4053SRui Paulo if (buf == NULL) 578e28a4053SRui Paulo return NULL; 579e28a4053SRui Paulo 580e28a4053SRui Paulo /* 581e28a4053SRui Paulo * There may be multiple vendor IEs in the message, so need to 582e28a4053SRui Paulo * concatenate their data fields. 583e28a4053SRui Paulo */ 5844bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { 5854bc52338SCy Schubert if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type) 5864bc52338SCy Schubert wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4); 587e28a4053SRui Paulo } 588e28a4053SRui Paulo 589e28a4053SRui Paulo return buf; 590e28a4053SRui Paulo } 591f05cddf9SRui Paulo 592f05cddf9SRui Paulo 593f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 594f05cddf9SRui Paulo { 595f05cddf9SRui Paulo u16 fc, type, stype; 596f05cddf9SRui Paulo 597f05cddf9SRui Paulo /* 598f05cddf9SRui Paulo * PS-Poll frames are 16 bytes. All other frames are 599f05cddf9SRui Paulo * 24 bytes or longer. 600f05cddf9SRui Paulo */ 601f05cddf9SRui Paulo if (len < 16) 602f05cddf9SRui Paulo return NULL; 603f05cddf9SRui Paulo 604f05cddf9SRui Paulo fc = le_to_host16(hdr->frame_control); 605f05cddf9SRui Paulo type = WLAN_FC_GET_TYPE(fc); 606f05cddf9SRui Paulo stype = WLAN_FC_GET_STYPE(fc); 607f05cddf9SRui Paulo 608f05cddf9SRui Paulo switch (type) { 609f05cddf9SRui Paulo case WLAN_FC_TYPE_DATA: 610f05cddf9SRui Paulo if (len < 24) 611f05cddf9SRui Paulo return NULL; 612f05cddf9SRui Paulo switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 613f05cddf9SRui Paulo case WLAN_FC_FROMDS | WLAN_FC_TODS: 614f05cddf9SRui Paulo case WLAN_FC_TODS: 615f05cddf9SRui Paulo return hdr->addr1; 616f05cddf9SRui Paulo case WLAN_FC_FROMDS: 617f05cddf9SRui Paulo return hdr->addr2; 618f05cddf9SRui Paulo default: 619f05cddf9SRui Paulo return NULL; 620f05cddf9SRui Paulo } 621f05cddf9SRui Paulo case WLAN_FC_TYPE_CTRL: 622f05cddf9SRui Paulo if (stype != WLAN_FC_STYPE_PSPOLL) 623f05cddf9SRui Paulo return NULL; 624f05cddf9SRui Paulo return hdr->addr1; 625f05cddf9SRui Paulo case WLAN_FC_TYPE_MGMT: 626f05cddf9SRui Paulo return hdr->addr3; 627f05cddf9SRui Paulo default: 628f05cddf9SRui Paulo return NULL; 629f05cddf9SRui Paulo } 630f05cddf9SRui Paulo } 631f05cddf9SRui Paulo 632f05cddf9SRui Paulo 633f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 634f05cddf9SRui Paulo const char *name, const char *val) 635f05cddf9SRui Paulo { 636f05cddf9SRui Paulo int num, v; 637f05cddf9SRui Paulo const char *pos; 638f05cddf9SRui Paulo struct hostapd_wmm_ac_params *ac; 639f05cddf9SRui Paulo 640f05cddf9SRui Paulo /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 641f05cddf9SRui Paulo pos = name + 7; 642f05cddf9SRui Paulo if (os_strncmp(pos, "be_", 3) == 0) { 643f05cddf9SRui Paulo num = 0; 644f05cddf9SRui Paulo pos += 3; 645f05cddf9SRui Paulo } else if (os_strncmp(pos, "bk_", 3) == 0) { 646f05cddf9SRui Paulo num = 1; 647f05cddf9SRui Paulo pos += 3; 648f05cddf9SRui Paulo } else if (os_strncmp(pos, "vi_", 3) == 0) { 649f05cddf9SRui Paulo num = 2; 650f05cddf9SRui Paulo pos += 3; 651f05cddf9SRui Paulo } else if (os_strncmp(pos, "vo_", 3) == 0) { 652f05cddf9SRui Paulo num = 3; 653f05cddf9SRui Paulo pos += 3; 654f05cddf9SRui Paulo } else { 655f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 656f05cddf9SRui Paulo return -1; 657f05cddf9SRui Paulo } 658f05cddf9SRui Paulo 659f05cddf9SRui Paulo ac = &wmm_ac_params[num]; 660f05cddf9SRui Paulo 661f05cddf9SRui Paulo if (os_strcmp(pos, "aifs") == 0) { 662f05cddf9SRui Paulo v = atoi(val); 663f05cddf9SRui Paulo if (v < 1 || v > 255) { 664f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 665f05cddf9SRui Paulo return -1; 666f05cddf9SRui Paulo } 667f05cddf9SRui Paulo ac->aifs = v; 668f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmin") == 0) { 669f05cddf9SRui Paulo v = atoi(val); 670325151a3SRui Paulo if (v < 0 || v > 15) { 671f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 672f05cddf9SRui Paulo return -1; 673f05cddf9SRui Paulo } 674f05cddf9SRui Paulo ac->cwmin = v; 675f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmax") == 0) { 676f05cddf9SRui Paulo v = atoi(val); 677325151a3SRui Paulo if (v < 0 || v > 15) { 678f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 679f05cddf9SRui Paulo return -1; 680f05cddf9SRui Paulo } 681f05cddf9SRui Paulo ac->cwmax = v; 682f05cddf9SRui Paulo } else if (os_strcmp(pos, "txop_limit") == 0) { 683f05cddf9SRui Paulo v = atoi(val); 684f05cddf9SRui Paulo if (v < 0 || v > 0xffff) { 685f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 686f05cddf9SRui Paulo return -1; 687f05cddf9SRui Paulo } 688f05cddf9SRui Paulo ac->txop_limit = v; 689f05cddf9SRui Paulo } else if (os_strcmp(pos, "acm") == 0) { 690f05cddf9SRui Paulo v = atoi(val); 691f05cddf9SRui Paulo if (v < 0 || v > 1) { 692f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 693f05cddf9SRui Paulo return -1; 694f05cddf9SRui Paulo } 695f05cddf9SRui Paulo ac->admission_control_mandatory = v; 696f05cddf9SRui Paulo } else { 697f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 698f05cddf9SRui Paulo return -1; 699f05cddf9SRui Paulo } 700f05cddf9SRui Paulo 701f05cddf9SRui Paulo return 0; 702f05cddf9SRui Paulo } 7035b9c547cSRui Paulo 7045b9c547cSRui Paulo 7055b9c547cSRui Paulo enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) 7065b9c547cSRui Paulo { 707325151a3SRui Paulo u8 op_class; 708325151a3SRui Paulo 709*206b73d0SCy Schubert return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT, 710780fb4a2SCy Schubert &op_class, channel); 711325151a3SRui Paulo } 712325151a3SRui Paulo 713325151a3SRui Paulo 714325151a3SRui Paulo /** 715325151a3SRui Paulo * ieee80211_freq_to_channel_ext - Convert frequency into channel info 716325151a3SRui Paulo * for HT40 and VHT. DFS channels are not covered. 717325151a3SRui Paulo * @freq: Frequency (MHz) to convert 718325151a3SRui Paulo * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below 719*206b73d0SCy Schubert * @vht: VHT channel width (CHANWIDTH_*) 720325151a3SRui Paulo * @op_class: Buffer for returning operating class 721325151a3SRui Paulo * @channel: Buffer for returning channel number 722325151a3SRui Paulo * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure 723325151a3SRui Paulo */ 724325151a3SRui Paulo enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, 725325151a3SRui Paulo int sec_channel, int vht, 726325151a3SRui Paulo u8 *op_class, u8 *channel) 727325151a3SRui Paulo { 728780fb4a2SCy Schubert u8 vht_opclass; 729780fb4a2SCy Schubert 730325151a3SRui Paulo /* TODO: more operating classes */ 731325151a3SRui Paulo 732325151a3SRui Paulo if (sec_channel > 1 || sec_channel < -1) 733325151a3SRui Paulo return NUM_HOSTAPD_MODES; 7345b9c547cSRui Paulo 7355b9c547cSRui Paulo if (freq >= 2412 && freq <= 2472) { 736325151a3SRui Paulo if ((freq - 2407) % 5) 737325151a3SRui Paulo return NUM_HOSTAPD_MODES; 738325151a3SRui Paulo 739325151a3SRui Paulo if (vht) 740325151a3SRui Paulo return NUM_HOSTAPD_MODES; 741325151a3SRui Paulo 742325151a3SRui Paulo /* 2.407 GHz, channels 1..13 */ 743325151a3SRui Paulo if (sec_channel == 1) 744325151a3SRui Paulo *op_class = 83; 745325151a3SRui Paulo else if (sec_channel == -1) 746325151a3SRui Paulo *op_class = 84; 747325151a3SRui Paulo else 748325151a3SRui Paulo *op_class = 81; 749325151a3SRui Paulo 7505b9c547cSRui Paulo *channel = (freq - 2407) / 5; 751325151a3SRui Paulo 752325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211G; 753325151a3SRui Paulo } 754325151a3SRui Paulo 755325151a3SRui Paulo if (freq == 2484) { 756325151a3SRui Paulo if (sec_channel || vht) 757325151a3SRui Paulo return NUM_HOSTAPD_MODES; 758325151a3SRui Paulo 759325151a3SRui Paulo *op_class = 82; /* channel 14 */ 7605b9c547cSRui Paulo *channel = 14; 761325151a3SRui Paulo 762325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211B; 763325151a3SRui Paulo } 764325151a3SRui Paulo 765325151a3SRui Paulo if (freq >= 4900 && freq < 5000) { 766325151a3SRui Paulo if ((freq - 4000) % 5) 767325151a3SRui Paulo return NUM_HOSTAPD_MODES; 7685b9c547cSRui Paulo *channel = (freq - 4000) / 5; 769325151a3SRui Paulo *op_class = 0; /* TODO */ 770325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 771325151a3SRui Paulo } 772325151a3SRui Paulo 773780fb4a2SCy Schubert switch (vht) { 774*206b73d0SCy Schubert case CHANWIDTH_80MHZ: 775780fb4a2SCy Schubert vht_opclass = 128; 776780fb4a2SCy Schubert break; 777*206b73d0SCy Schubert case CHANWIDTH_160MHZ: 778780fb4a2SCy Schubert vht_opclass = 129; 779780fb4a2SCy Schubert break; 780*206b73d0SCy Schubert case CHANWIDTH_80P80MHZ: 781780fb4a2SCy Schubert vht_opclass = 130; 782780fb4a2SCy Schubert break; 783780fb4a2SCy Schubert default: 784780fb4a2SCy Schubert vht_opclass = 0; 785780fb4a2SCy Schubert break; 786780fb4a2SCy Schubert } 787780fb4a2SCy Schubert 788325151a3SRui Paulo /* 5 GHz, channels 36..48 */ 789325151a3SRui Paulo if (freq >= 5180 && freq <= 5240) { 790325151a3SRui Paulo if ((freq - 5000) % 5) 791325151a3SRui Paulo return NUM_HOSTAPD_MODES; 792325151a3SRui Paulo 793780fb4a2SCy Schubert if (vht_opclass) 794780fb4a2SCy Schubert *op_class = vht_opclass; 795780fb4a2SCy Schubert else if (sec_channel == 1) 796325151a3SRui Paulo *op_class = 116; 797325151a3SRui Paulo else if (sec_channel == -1) 798325151a3SRui Paulo *op_class = 117; 799325151a3SRui Paulo else 800325151a3SRui Paulo *op_class = 115; 801325151a3SRui Paulo 8025b9c547cSRui Paulo *channel = (freq - 5000) / 5; 803325151a3SRui Paulo 804325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 805325151a3SRui Paulo } 806325151a3SRui Paulo 80785732ac8SCy Schubert /* 5 GHz, channels 52..64 */ 80885732ac8SCy Schubert if (freq >= 5260 && freq <= 5320) { 80985732ac8SCy Schubert if ((freq - 5000) % 5) 81085732ac8SCy Schubert return NUM_HOSTAPD_MODES; 81185732ac8SCy Schubert 81285732ac8SCy Schubert if (vht_opclass) 81385732ac8SCy Schubert *op_class = vht_opclass; 81485732ac8SCy Schubert else if (sec_channel == 1) 81585732ac8SCy Schubert *op_class = 119; 81685732ac8SCy Schubert else if (sec_channel == -1) 81785732ac8SCy Schubert *op_class = 120; 81885732ac8SCy Schubert else 81985732ac8SCy Schubert *op_class = 118; 82085732ac8SCy Schubert 82185732ac8SCy Schubert *channel = (freq - 5000) / 5; 82285732ac8SCy Schubert 82385732ac8SCy Schubert return HOSTAPD_MODE_IEEE80211A; 82485732ac8SCy Schubert } 82585732ac8SCy Schubert 826325151a3SRui Paulo /* 5 GHz, channels 149..169 */ 827325151a3SRui Paulo if (freq >= 5745 && freq <= 5845) { 828325151a3SRui Paulo if ((freq - 5000) % 5) 829325151a3SRui Paulo return NUM_HOSTAPD_MODES; 830325151a3SRui Paulo 831780fb4a2SCy Schubert if (vht_opclass) 832780fb4a2SCy Schubert *op_class = vht_opclass; 833780fb4a2SCy Schubert else if (sec_channel == 1) 834780fb4a2SCy Schubert *op_class = 126; 835780fb4a2SCy Schubert else if (sec_channel == -1) 836780fb4a2SCy Schubert *op_class = 127; 837780fb4a2SCy Schubert else if (freq <= 5805) 838780fb4a2SCy Schubert *op_class = 124; 839780fb4a2SCy Schubert else 840325151a3SRui Paulo *op_class = 125; 841325151a3SRui Paulo 842325151a3SRui Paulo *channel = (freq - 5000) / 5; 843325151a3SRui Paulo 844325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 845325151a3SRui Paulo } 846325151a3SRui Paulo 847780fb4a2SCy Schubert /* 5 GHz, channels 100..140 */ 848780fb4a2SCy Schubert if (freq >= 5000 && freq <= 5700) { 849780fb4a2SCy Schubert if ((freq - 5000) % 5) 850780fb4a2SCy Schubert return NUM_HOSTAPD_MODES; 851780fb4a2SCy Schubert 852780fb4a2SCy Schubert if (vht_opclass) 853780fb4a2SCy Schubert *op_class = vht_opclass; 854780fb4a2SCy Schubert else if (sec_channel == 1) 855780fb4a2SCy Schubert *op_class = 122; 856780fb4a2SCy Schubert else if (sec_channel == -1) 857780fb4a2SCy Schubert *op_class = 123; 858780fb4a2SCy Schubert else 859780fb4a2SCy Schubert *op_class = 121; 860780fb4a2SCy Schubert 861780fb4a2SCy Schubert *channel = (freq - 5000) / 5; 862780fb4a2SCy Schubert 863780fb4a2SCy Schubert return HOSTAPD_MODE_IEEE80211A; 864780fb4a2SCy Schubert } 865780fb4a2SCy Schubert 866325151a3SRui Paulo if (freq >= 5000 && freq < 5900) { 867325151a3SRui Paulo if ((freq - 5000) % 5) 868325151a3SRui Paulo return NUM_HOSTAPD_MODES; 869325151a3SRui Paulo *channel = (freq - 5000) / 5; 870325151a3SRui Paulo *op_class = 0; /* TODO */ 871325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 872325151a3SRui Paulo } 873325151a3SRui Paulo 874325151a3SRui Paulo /* 56.16 GHz, channel 1..4 */ 875325151a3SRui Paulo if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { 876325151a3SRui Paulo if (sec_channel || vht) 877325151a3SRui Paulo return NUM_HOSTAPD_MODES; 878325151a3SRui Paulo 8795b9c547cSRui Paulo *channel = (freq - 56160) / 2160; 880325151a3SRui Paulo *op_class = 180; 881325151a3SRui Paulo 882325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211AD; 8835b9c547cSRui Paulo } 8845b9c547cSRui Paulo 885325151a3SRui Paulo return NUM_HOSTAPD_MODES; 8865b9c547cSRui Paulo } 8875b9c547cSRui Paulo 8885b9c547cSRui Paulo 8894bc52338SCy Schubert int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, 8904bc52338SCy Schubert int sec_channel, u8 *op_class, u8 *channel) 8914bc52338SCy Schubert { 8924bc52338SCy Schubert int vht = CHAN_WIDTH_UNKNOWN; 8934bc52338SCy Schubert 8944bc52338SCy Schubert switch (chanwidth) { 8954bc52338SCy Schubert case CHAN_WIDTH_UNKNOWN: 8964bc52338SCy Schubert case CHAN_WIDTH_20_NOHT: 8974bc52338SCy Schubert case CHAN_WIDTH_20: 8984bc52338SCy Schubert case CHAN_WIDTH_40: 899*206b73d0SCy Schubert vht = CHANWIDTH_USE_HT; 9004bc52338SCy Schubert break; 9014bc52338SCy Schubert case CHAN_WIDTH_80: 902*206b73d0SCy Schubert vht = CHANWIDTH_80MHZ; 9034bc52338SCy Schubert break; 9044bc52338SCy Schubert case CHAN_WIDTH_80P80: 905*206b73d0SCy Schubert vht = CHANWIDTH_80P80MHZ; 9064bc52338SCy Schubert break; 9074bc52338SCy Schubert case CHAN_WIDTH_160: 908*206b73d0SCy Schubert vht = CHANWIDTH_160MHZ; 9094bc52338SCy Schubert break; 9104bc52338SCy Schubert } 9114bc52338SCy Schubert 9124bc52338SCy Schubert if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class, 9134bc52338SCy Schubert channel) == NUM_HOSTAPD_MODES) { 9144bc52338SCy Schubert wpa_printf(MSG_WARNING, 9154bc52338SCy Schubert "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)", 9164bc52338SCy Schubert freq, chanwidth, sec_channel); 9174bc52338SCy Schubert return -1; 9184bc52338SCy Schubert } 9194bc52338SCy Schubert 9204bc52338SCy Schubert return 0; 9214bc52338SCy Schubert } 9224bc52338SCy Schubert 9234bc52338SCy Schubert 924325151a3SRui Paulo static const char *const us_op_class_cc[] = { 9255b9c547cSRui Paulo "US", "CA", NULL 9265b9c547cSRui Paulo }; 9275b9c547cSRui Paulo 928325151a3SRui Paulo static const char *const eu_op_class_cc[] = { 9295b9c547cSRui Paulo "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", 9305b9c547cSRui Paulo "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT", 9315b9c547cSRui Paulo "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", 9325b9c547cSRui Paulo "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL 9335b9c547cSRui Paulo }; 9345b9c547cSRui Paulo 935325151a3SRui Paulo static const char *const jp_op_class_cc[] = { 9365b9c547cSRui Paulo "JP", NULL 9375b9c547cSRui Paulo }; 9385b9c547cSRui Paulo 939325151a3SRui Paulo static const char *const cn_op_class_cc[] = { 940325151a3SRui Paulo "CN", NULL 9415b9c547cSRui Paulo }; 9425b9c547cSRui Paulo 9435b9c547cSRui Paulo 944325151a3SRui Paulo static int country_match(const char *const cc[], const char *const country) 9455b9c547cSRui Paulo { 9465b9c547cSRui Paulo int i; 9475b9c547cSRui Paulo 9485b9c547cSRui Paulo if (country == NULL) 9495b9c547cSRui Paulo return 0; 9505b9c547cSRui Paulo for (i = 0; cc[i]; i++) { 9515b9c547cSRui Paulo if (cc[i][0] == country[0] && cc[i][1] == country[1]) 9525b9c547cSRui Paulo return 1; 9535b9c547cSRui Paulo } 9545b9c547cSRui Paulo 9555b9c547cSRui Paulo return 0; 9565b9c547cSRui Paulo } 9575b9c547cSRui Paulo 9585b9c547cSRui Paulo 9595b9c547cSRui Paulo static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan) 9605b9c547cSRui Paulo { 9615b9c547cSRui Paulo switch (op_class) { 9625b9c547cSRui Paulo case 12: /* channels 1..11 */ 9635b9c547cSRui Paulo case 32: /* channels 1..7; 40 MHz */ 9645b9c547cSRui Paulo case 33: /* channels 5..11; 40 MHz */ 9655b9c547cSRui Paulo if (chan < 1 || chan > 11) 9665b9c547cSRui Paulo return -1; 9675b9c547cSRui Paulo return 2407 + 5 * chan; 9685b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 9695b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 9705b9c547cSRui Paulo case 22: /* channels 36,44; 40 MHz */ 9715b9c547cSRui Paulo case 23: /* channels 52,60; 40 MHz */ 9725b9c547cSRui Paulo case 27: /* channels 40,48; 40 MHz */ 9735b9c547cSRui Paulo case 28: /* channels 56,64; 40 MHz */ 9745b9c547cSRui Paulo if (chan < 36 || chan > 64) 9755b9c547cSRui Paulo return -1; 9765b9c547cSRui Paulo return 5000 + 5 * chan; 9775b9c547cSRui Paulo case 4: /* channels 100-144 */ 9785b9c547cSRui Paulo case 24: /* channels 100-140; 40 MHz */ 9795b9c547cSRui Paulo if (chan < 100 || chan > 144) 9805b9c547cSRui Paulo return -1; 9815b9c547cSRui Paulo return 5000 + 5 * chan; 9825b9c547cSRui Paulo case 3: /* channels 149,153,157,161 */ 9835b9c547cSRui Paulo case 25: /* channels 149,157; 40 MHz */ 9845b9c547cSRui Paulo case 26: /* channels 149,157; 40 MHz */ 9855b9c547cSRui Paulo case 30: /* channels 153,161; 40 MHz */ 9865b9c547cSRui Paulo case 31: /* channels 153,161; 40 MHz */ 9875b9c547cSRui Paulo if (chan < 149 || chan > 161) 9885b9c547cSRui Paulo return -1; 9895b9c547cSRui Paulo return 5000 + 5 * chan; 990325151a3SRui Paulo case 5: /* channels 149,153,157,161,165 */ 991325151a3SRui Paulo if (chan < 149 || chan > 165) 992325151a3SRui Paulo return -1; 993325151a3SRui Paulo return 5000 + 5 * chan; 9945b9c547cSRui Paulo case 34: /* 60 GHz band, channels 1..3 */ 9955b9c547cSRui Paulo if (chan < 1 || chan > 3) 9965b9c547cSRui Paulo return -1; 9975b9c547cSRui Paulo return 56160 + 2160 * chan; 9985b9c547cSRui Paulo } 9995b9c547cSRui Paulo return -1; 10005b9c547cSRui Paulo } 10015b9c547cSRui Paulo 10025b9c547cSRui Paulo 10035b9c547cSRui Paulo static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan) 10045b9c547cSRui Paulo { 10055b9c547cSRui Paulo switch (op_class) { 10065b9c547cSRui Paulo case 4: /* channels 1..13 */ 10075b9c547cSRui Paulo case 11: /* channels 1..9; 40 MHz */ 10085b9c547cSRui Paulo case 12: /* channels 5..13; 40 MHz */ 10095b9c547cSRui Paulo if (chan < 1 || chan > 13) 10105b9c547cSRui Paulo return -1; 10115b9c547cSRui Paulo return 2407 + 5 * chan; 10125b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 10135b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 10145b9c547cSRui Paulo case 5: /* channels 36,44; 40 MHz */ 10155b9c547cSRui Paulo case 6: /* channels 52,60; 40 MHz */ 10165b9c547cSRui Paulo case 8: /* channels 40,48; 40 MHz */ 10175b9c547cSRui Paulo case 9: /* channels 56,64; 40 MHz */ 10185b9c547cSRui Paulo if (chan < 36 || chan > 64) 10195b9c547cSRui Paulo return -1; 10205b9c547cSRui Paulo return 5000 + 5 * chan; 10215b9c547cSRui Paulo case 3: /* channels 100-140 */ 10225b9c547cSRui Paulo case 7: /* channels 100-132; 40 MHz */ 10235b9c547cSRui Paulo case 10: /* channels 104-136; 40 MHz */ 10245b9c547cSRui Paulo case 16: /* channels 100-140 */ 10255b9c547cSRui Paulo if (chan < 100 || chan > 140) 10265b9c547cSRui Paulo return -1; 10275b9c547cSRui Paulo return 5000 + 5 * chan; 10285b9c547cSRui Paulo case 17: /* channels 149,153,157,161,165,169 */ 10295b9c547cSRui Paulo if (chan < 149 || chan > 169) 10305b9c547cSRui Paulo return -1; 10315b9c547cSRui Paulo return 5000 + 5 * chan; 10325b9c547cSRui Paulo case 18: /* 60 GHz band, channels 1..4 */ 10335b9c547cSRui Paulo if (chan < 1 || chan > 4) 10345b9c547cSRui Paulo return -1; 10355b9c547cSRui Paulo return 56160 + 2160 * chan; 10365b9c547cSRui Paulo } 10375b9c547cSRui Paulo return -1; 10385b9c547cSRui Paulo } 10395b9c547cSRui Paulo 10405b9c547cSRui Paulo 10415b9c547cSRui Paulo static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) 10425b9c547cSRui Paulo { 10435b9c547cSRui Paulo switch (op_class) { 10445b9c547cSRui Paulo case 30: /* channels 1..13 */ 10455b9c547cSRui Paulo case 56: /* channels 1..9; 40 MHz */ 10465b9c547cSRui Paulo case 57: /* channels 5..13; 40 MHz */ 10475b9c547cSRui Paulo if (chan < 1 || chan > 13) 10485b9c547cSRui Paulo return -1; 10495b9c547cSRui Paulo return 2407 + 5 * chan; 10505b9c547cSRui Paulo case 31: /* channel 14 */ 10515b9c547cSRui Paulo if (chan != 14) 10525b9c547cSRui Paulo return -1; 10535b9c547cSRui Paulo return 2414 + 5 * chan; 10545b9c547cSRui Paulo case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */ 10555b9c547cSRui Paulo case 32: /* channels 52,56,60,64 */ 10565b9c547cSRui Paulo case 33: /* channels 52,56,60,64 */ 10575b9c547cSRui Paulo case 36: /* channels 36,44; 40 MHz */ 10585b9c547cSRui Paulo case 37: /* channels 52,60; 40 MHz */ 10595b9c547cSRui Paulo case 38: /* channels 52,60; 40 MHz */ 10605b9c547cSRui Paulo case 41: /* channels 40,48; 40 MHz */ 10615b9c547cSRui Paulo case 42: /* channels 56,64; 40 MHz */ 10625b9c547cSRui Paulo case 43: /* channels 56,64; 40 MHz */ 10635b9c547cSRui Paulo if (chan < 34 || chan > 64) 10645b9c547cSRui Paulo return -1; 10655b9c547cSRui Paulo return 5000 + 5 * chan; 10665b9c547cSRui Paulo case 34: /* channels 100-140 */ 10675b9c547cSRui Paulo case 35: /* channels 100-140 */ 10685b9c547cSRui Paulo case 39: /* channels 100-132; 40 MHz */ 10695b9c547cSRui Paulo case 40: /* channels 100-132; 40 MHz */ 10705b9c547cSRui Paulo case 44: /* channels 104-136; 40 MHz */ 10715b9c547cSRui Paulo case 45: /* channels 104-136; 40 MHz */ 10725b9c547cSRui Paulo case 58: /* channels 100-140 */ 10735b9c547cSRui Paulo if (chan < 100 || chan > 140) 10745b9c547cSRui Paulo return -1; 10755b9c547cSRui Paulo return 5000 + 5 * chan; 10765b9c547cSRui Paulo case 59: /* 60 GHz band, channels 1..4 */ 10775b9c547cSRui Paulo if (chan < 1 || chan > 3) 10785b9c547cSRui Paulo return -1; 10795b9c547cSRui Paulo return 56160 + 2160 * chan; 10805b9c547cSRui Paulo } 10815b9c547cSRui Paulo return -1; 10825b9c547cSRui Paulo } 10835b9c547cSRui Paulo 10845b9c547cSRui Paulo 10855b9c547cSRui Paulo static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan) 10865b9c547cSRui Paulo { 10875b9c547cSRui Paulo switch (op_class) { 10885b9c547cSRui Paulo case 7: /* channels 1..13 */ 10895b9c547cSRui Paulo case 8: /* channels 1..9; 40 MHz */ 10905b9c547cSRui Paulo case 9: /* channels 5..13; 40 MHz */ 10915b9c547cSRui Paulo if (chan < 1 || chan > 13) 10925b9c547cSRui Paulo return -1; 10935b9c547cSRui Paulo return 2407 + 5 * chan; 10945b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 10955b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 10965b9c547cSRui Paulo case 4: /* channels 36,44; 40 MHz */ 10975b9c547cSRui Paulo case 5: /* channels 52,60; 40 MHz */ 10985b9c547cSRui Paulo if (chan < 36 || chan > 64) 10995b9c547cSRui Paulo return -1; 11005b9c547cSRui Paulo return 5000 + 5 * chan; 11015b9c547cSRui Paulo case 3: /* channels 149,153,157,161,165 */ 11025b9c547cSRui Paulo case 6: /* channels 149,157; 40 MHz */ 11035b9c547cSRui Paulo if (chan < 149 || chan > 165) 11045b9c547cSRui Paulo return -1; 11055b9c547cSRui Paulo return 5000 + 5 * chan; 11065b9c547cSRui Paulo } 11075b9c547cSRui Paulo return -1; 11085b9c547cSRui Paulo } 11095b9c547cSRui Paulo 11105b9c547cSRui Paulo 11115b9c547cSRui Paulo static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) 11125b9c547cSRui Paulo { 11135b9c547cSRui Paulo /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ 11145b9c547cSRui Paulo switch (op_class) { 11155b9c547cSRui Paulo case 81: 11165b9c547cSRui Paulo /* channels 1..13 */ 11175b9c547cSRui Paulo if (chan < 1 || chan > 13) 11185b9c547cSRui Paulo return -1; 11195b9c547cSRui Paulo return 2407 + 5 * chan; 11205b9c547cSRui Paulo case 82: 11215b9c547cSRui Paulo /* channel 14 */ 11225b9c547cSRui Paulo if (chan != 14) 11235b9c547cSRui Paulo return -1; 11245b9c547cSRui Paulo return 2414 + 5 * chan; 11255b9c547cSRui Paulo case 83: /* channels 1..9; 40 MHz */ 11265b9c547cSRui Paulo case 84: /* channels 5..13; 40 MHz */ 11275b9c547cSRui Paulo if (chan < 1 || chan > 13) 11285b9c547cSRui Paulo return -1; 11295b9c547cSRui Paulo return 2407 + 5 * chan; 11305b9c547cSRui Paulo case 115: /* channels 36,40,44,48; indoor only */ 11315b9c547cSRui Paulo case 116: /* channels 36,44; 40 MHz; indoor only */ 11325b9c547cSRui Paulo case 117: /* channels 40,48; 40 MHz; indoor only */ 11335b9c547cSRui Paulo case 118: /* channels 52,56,60,64; dfs */ 11345b9c547cSRui Paulo case 119: /* channels 52,60; 40 MHz; dfs */ 11355b9c547cSRui Paulo case 120: /* channels 56,64; 40 MHz; dfs */ 11365b9c547cSRui Paulo if (chan < 36 || chan > 64) 11375b9c547cSRui Paulo return -1; 11385b9c547cSRui Paulo return 5000 + 5 * chan; 11395b9c547cSRui Paulo case 121: /* channels 100-140 */ 11405b9c547cSRui Paulo case 122: /* channels 100-142; 40 MHz */ 11415b9c547cSRui Paulo case 123: /* channels 104-136; 40 MHz */ 11425b9c547cSRui Paulo if (chan < 100 || chan > 140) 11435b9c547cSRui Paulo return -1; 11445b9c547cSRui Paulo return 5000 + 5 * chan; 11455b9c547cSRui Paulo case 124: /* channels 149,153,157,161 */ 11465b9c547cSRui Paulo case 126: /* channels 149,157; 40 MHz */ 11475b9c547cSRui Paulo case 127: /* channels 153,161; 40 MHz */ 11485b9c547cSRui Paulo if (chan < 149 || chan > 161) 11495b9c547cSRui Paulo return -1; 11505b9c547cSRui Paulo return 5000 + 5 * chan; 1151325151a3SRui Paulo case 125: /* channels 149,153,157,161,165,169 */ 1152325151a3SRui Paulo if (chan < 149 || chan > 169) 1153325151a3SRui Paulo return -1; 1154325151a3SRui Paulo return 5000 + 5 * chan; 11555b9c547cSRui Paulo case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ 11565b9c547cSRui Paulo case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ 11575b9c547cSRui Paulo if (chan < 36 || chan > 161) 11585b9c547cSRui Paulo return -1; 11595b9c547cSRui Paulo return 5000 + 5 * chan; 11605b9c547cSRui Paulo case 129: /* center freqs 50, 114; 160 MHz */ 116185732ac8SCy Schubert if (chan < 36 || chan > 128) 11625b9c547cSRui Paulo return -1; 11635b9c547cSRui Paulo return 5000 + 5 * chan; 11645b9c547cSRui Paulo case 180: /* 60 GHz band, channels 1..4 */ 11655b9c547cSRui Paulo if (chan < 1 || chan > 4) 11665b9c547cSRui Paulo return -1; 11675b9c547cSRui Paulo return 56160 + 2160 * chan; 11685b9c547cSRui Paulo } 11695b9c547cSRui Paulo return -1; 11705b9c547cSRui Paulo } 11715b9c547cSRui Paulo 11725b9c547cSRui Paulo /** 11735b9c547cSRui Paulo * ieee80211_chan_to_freq - Convert channel info to frequency 11745b9c547cSRui Paulo * @country: Country code, if known; otherwise, global operating class is used 11755b9c547cSRui Paulo * @op_class: Operating class 11765b9c547cSRui Paulo * @chan: Channel number 11775b9c547cSRui Paulo * Returns: Frequency in MHz or -1 if the specified channel is unknown 11785b9c547cSRui Paulo */ 11795b9c547cSRui Paulo int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan) 11805b9c547cSRui Paulo { 11815b9c547cSRui Paulo int freq; 11825b9c547cSRui Paulo 11835b9c547cSRui Paulo if (country_match(us_op_class_cc, country)) { 11845b9c547cSRui Paulo freq = ieee80211_chan_to_freq_us(op_class, chan); 11855b9c547cSRui Paulo if (freq > 0) 11865b9c547cSRui Paulo return freq; 11875b9c547cSRui Paulo } 11885b9c547cSRui Paulo 11895b9c547cSRui Paulo if (country_match(eu_op_class_cc, country)) { 11905b9c547cSRui Paulo freq = ieee80211_chan_to_freq_eu(op_class, chan); 11915b9c547cSRui Paulo if (freq > 0) 11925b9c547cSRui Paulo return freq; 11935b9c547cSRui Paulo } 11945b9c547cSRui Paulo 11955b9c547cSRui Paulo if (country_match(jp_op_class_cc, country)) { 11965b9c547cSRui Paulo freq = ieee80211_chan_to_freq_jp(op_class, chan); 11975b9c547cSRui Paulo if (freq > 0) 11985b9c547cSRui Paulo return freq; 11995b9c547cSRui Paulo } 12005b9c547cSRui Paulo 12015b9c547cSRui Paulo if (country_match(cn_op_class_cc, country)) { 12025b9c547cSRui Paulo freq = ieee80211_chan_to_freq_cn(op_class, chan); 12035b9c547cSRui Paulo if (freq > 0) 12045b9c547cSRui Paulo return freq; 12055b9c547cSRui Paulo } 12065b9c547cSRui Paulo 12075b9c547cSRui Paulo return ieee80211_chan_to_freq_global(op_class, chan); 12085b9c547cSRui Paulo } 12095b9c547cSRui Paulo 12105b9c547cSRui Paulo 121185732ac8SCy Schubert int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, 121285732ac8SCy Schubert u16 num_modes) 12135b9c547cSRui Paulo { 121485732ac8SCy Schubert int i, j; 121585732ac8SCy Schubert 121685732ac8SCy Schubert if (!modes || !num_modes) 121785732ac8SCy Schubert return (freq >= 5260 && freq <= 5320) || 121885732ac8SCy Schubert (freq >= 5500 && freq <= 5700); 121985732ac8SCy Schubert 122085732ac8SCy Schubert for (i = 0; i < num_modes; i++) { 122185732ac8SCy Schubert for (j = 0; j < modes[i].num_channels; j++) { 122285732ac8SCy Schubert if (modes[i].channels[j].freq == freq && 122385732ac8SCy Schubert (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR)) 122485732ac8SCy Schubert return 1; 122585732ac8SCy Schubert } 122685732ac8SCy Schubert } 122785732ac8SCy Schubert 122885732ac8SCy Schubert return 0; 12295b9c547cSRui Paulo } 12305b9c547cSRui Paulo 12315b9c547cSRui Paulo 12325b9c547cSRui Paulo static int is_11b(u8 rate) 12335b9c547cSRui Paulo { 12345b9c547cSRui Paulo return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; 12355b9c547cSRui Paulo } 12365b9c547cSRui Paulo 12375b9c547cSRui Paulo 12385b9c547cSRui Paulo int supp_rates_11b_only(struct ieee802_11_elems *elems) 12395b9c547cSRui Paulo { 12405b9c547cSRui Paulo int num_11b = 0, num_others = 0; 12415b9c547cSRui Paulo int i; 12425b9c547cSRui Paulo 12435b9c547cSRui Paulo if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) 12445b9c547cSRui Paulo return 0; 12455b9c547cSRui Paulo 12465b9c547cSRui Paulo for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { 12475b9c547cSRui Paulo if (is_11b(elems->supp_rates[i])) 12485b9c547cSRui Paulo num_11b++; 12495b9c547cSRui Paulo else 12505b9c547cSRui Paulo num_others++; 12515b9c547cSRui Paulo } 12525b9c547cSRui Paulo 12535b9c547cSRui Paulo for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; 12545b9c547cSRui Paulo i++) { 12555b9c547cSRui Paulo if (is_11b(elems->ext_supp_rates[i])) 12565b9c547cSRui Paulo num_11b++; 12575b9c547cSRui Paulo else 12585b9c547cSRui Paulo num_others++; 12595b9c547cSRui Paulo } 12605b9c547cSRui Paulo 12615b9c547cSRui Paulo return num_11b > 0 && num_others == 0; 12625b9c547cSRui Paulo } 12635b9c547cSRui Paulo 12645b9c547cSRui Paulo 12655b9c547cSRui Paulo const char * fc2str(u16 fc) 12665b9c547cSRui Paulo { 12675b9c547cSRui Paulo u16 stype = WLAN_FC_GET_STYPE(fc); 12685b9c547cSRui Paulo #define C2S(x) case x: return #x; 12695b9c547cSRui Paulo 12705b9c547cSRui Paulo switch (WLAN_FC_GET_TYPE(fc)) { 12715b9c547cSRui Paulo case WLAN_FC_TYPE_MGMT: 12725b9c547cSRui Paulo switch (stype) { 12735b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ASSOC_REQ) 12745b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ASSOC_RESP) 12755b9c547cSRui Paulo C2S(WLAN_FC_STYPE_REASSOC_REQ) 12765b9c547cSRui Paulo C2S(WLAN_FC_STYPE_REASSOC_RESP) 12775b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PROBE_REQ) 12785b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PROBE_RESP) 12795b9c547cSRui Paulo C2S(WLAN_FC_STYPE_BEACON) 12805b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ATIM) 12815b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DISASSOC) 12825b9c547cSRui Paulo C2S(WLAN_FC_STYPE_AUTH) 12835b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DEAUTH) 12845b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ACTION) 12855b9c547cSRui Paulo } 12865b9c547cSRui Paulo break; 12875b9c547cSRui Paulo case WLAN_FC_TYPE_CTRL: 12885b9c547cSRui Paulo switch (stype) { 12895b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PSPOLL) 12905b9c547cSRui Paulo C2S(WLAN_FC_STYPE_RTS) 12915b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CTS) 12925b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ACK) 12935b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFEND) 12945b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFENDACK) 12955b9c547cSRui Paulo } 12965b9c547cSRui Paulo break; 12975b9c547cSRui Paulo case WLAN_FC_TYPE_DATA: 12985b9c547cSRui Paulo switch (stype) { 12995b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA) 13005b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFACK) 13015b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFPOLL) 13025b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFACKPOLL) 13035b9c547cSRui Paulo C2S(WLAN_FC_STYPE_NULLFUNC) 13045b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFACK) 13055b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFPOLL) 13065b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFACKPOLL) 13075b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA) 13085b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACK) 13095b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL) 13105b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL) 13115b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_NULL) 13125b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_CFPOLL) 13135b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_CFACKPOLL) 13145b9c547cSRui Paulo } 13155b9c547cSRui Paulo break; 13165b9c547cSRui Paulo } 13175b9c547cSRui Paulo return "WLAN_FC_TYPE_UNKNOWN"; 13185b9c547cSRui Paulo #undef C2S 13195b9c547cSRui Paulo } 1320325151a3SRui Paulo 1321325151a3SRui Paulo 1322*206b73d0SCy Schubert const char * reason2str(u16 reason) 1323*206b73d0SCy Schubert { 1324*206b73d0SCy Schubert #define R2S(r) case WLAN_REASON_ ## r: return #r; 1325*206b73d0SCy Schubert switch (reason) { 1326*206b73d0SCy Schubert R2S(UNSPECIFIED) 1327*206b73d0SCy Schubert R2S(PREV_AUTH_NOT_VALID) 1328*206b73d0SCy Schubert R2S(DEAUTH_LEAVING) 1329*206b73d0SCy Schubert R2S(DISASSOC_DUE_TO_INACTIVITY) 1330*206b73d0SCy Schubert R2S(DISASSOC_AP_BUSY) 1331*206b73d0SCy Schubert R2S(CLASS2_FRAME_FROM_NONAUTH_STA) 1332*206b73d0SCy Schubert R2S(CLASS3_FRAME_FROM_NONASSOC_STA) 1333*206b73d0SCy Schubert R2S(DISASSOC_STA_HAS_LEFT) 1334*206b73d0SCy Schubert R2S(STA_REQ_ASSOC_WITHOUT_AUTH) 1335*206b73d0SCy Schubert R2S(PWR_CAPABILITY_NOT_VALID) 1336*206b73d0SCy Schubert R2S(SUPPORTED_CHANNEL_NOT_VALID) 1337*206b73d0SCy Schubert R2S(BSS_TRANSITION_DISASSOC) 1338*206b73d0SCy Schubert R2S(INVALID_IE) 1339*206b73d0SCy Schubert R2S(MICHAEL_MIC_FAILURE) 1340*206b73d0SCy Schubert R2S(4WAY_HANDSHAKE_TIMEOUT) 1341*206b73d0SCy Schubert R2S(GROUP_KEY_UPDATE_TIMEOUT) 1342*206b73d0SCy Schubert R2S(IE_IN_4WAY_DIFFERS) 1343*206b73d0SCy Schubert R2S(GROUP_CIPHER_NOT_VALID) 1344*206b73d0SCy Schubert R2S(PAIRWISE_CIPHER_NOT_VALID) 1345*206b73d0SCy Schubert R2S(AKMP_NOT_VALID) 1346*206b73d0SCy Schubert R2S(UNSUPPORTED_RSN_IE_VERSION) 1347*206b73d0SCy Schubert R2S(INVALID_RSN_IE_CAPAB) 1348*206b73d0SCy Schubert R2S(IEEE_802_1X_AUTH_FAILED) 1349*206b73d0SCy Schubert R2S(CIPHER_SUITE_REJECTED) 1350*206b73d0SCy Schubert R2S(TDLS_TEARDOWN_UNREACHABLE) 1351*206b73d0SCy Schubert R2S(TDLS_TEARDOWN_UNSPECIFIED) 1352*206b73d0SCy Schubert R2S(SSP_REQUESTED_DISASSOC) 1353*206b73d0SCy Schubert R2S(NO_SSP_ROAMING_AGREEMENT) 1354*206b73d0SCy Schubert R2S(BAD_CIPHER_OR_AKM) 1355*206b73d0SCy Schubert R2S(NOT_AUTHORIZED_THIS_LOCATION) 1356*206b73d0SCy Schubert R2S(SERVICE_CHANGE_PRECLUDES_TS) 1357*206b73d0SCy Schubert R2S(UNSPECIFIED_QOS_REASON) 1358*206b73d0SCy Schubert R2S(NOT_ENOUGH_BANDWIDTH) 1359*206b73d0SCy Schubert R2S(DISASSOC_LOW_ACK) 1360*206b73d0SCy Schubert R2S(EXCEEDED_TXOP) 1361*206b73d0SCy Schubert R2S(STA_LEAVING) 1362*206b73d0SCy Schubert R2S(END_TS_BA_DLS) 1363*206b73d0SCy Schubert R2S(UNKNOWN_TS_BA) 1364*206b73d0SCy Schubert R2S(TIMEOUT) 1365*206b73d0SCy Schubert R2S(PEERKEY_MISMATCH) 1366*206b73d0SCy Schubert R2S(AUTHORIZED_ACCESS_LIMIT_REACHED) 1367*206b73d0SCy Schubert R2S(EXTERNAL_SERVICE_REQUIREMENTS) 1368*206b73d0SCy Schubert R2S(INVALID_FT_ACTION_FRAME_COUNT) 1369*206b73d0SCy Schubert R2S(INVALID_PMKID) 1370*206b73d0SCy Schubert R2S(INVALID_MDE) 1371*206b73d0SCy Schubert R2S(INVALID_FTE) 1372*206b73d0SCy Schubert R2S(MESH_PEERING_CANCELLED) 1373*206b73d0SCy Schubert R2S(MESH_MAX_PEERS) 1374*206b73d0SCy Schubert R2S(MESH_CONFIG_POLICY_VIOLATION) 1375*206b73d0SCy Schubert R2S(MESH_CLOSE_RCVD) 1376*206b73d0SCy Schubert R2S(MESH_MAX_RETRIES) 1377*206b73d0SCy Schubert R2S(MESH_CONFIRM_TIMEOUT) 1378*206b73d0SCy Schubert R2S(MESH_INVALID_GTK) 1379*206b73d0SCy Schubert R2S(MESH_INCONSISTENT_PARAMS) 1380*206b73d0SCy Schubert R2S(MESH_INVALID_SECURITY_CAP) 1381*206b73d0SCy Schubert R2S(MESH_PATH_ERROR_NO_PROXY_INFO) 1382*206b73d0SCy Schubert R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO) 1383*206b73d0SCy Schubert R2S(MESH_PATH_ERROR_DEST_UNREACHABLE) 1384*206b73d0SCy Schubert R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS) 1385*206b73d0SCy Schubert R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ) 1386*206b73d0SCy Schubert R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED) 1387*206b73d0SCy Schubert } 1388*206b73d0SCy Schubert return "UNKNOWN"; 1389*206b73d0SCy Schubert #undef R2S 1390*206b73d0SCy Schubert } 1391*206b73d0SCy Schubert 1392*206b73d0SCy Schubert 1393*206b73d0SCy Schubert const char * status2str(u16 status) 1394*206b73d0SCy Schubert { 1395*206b73d0SCy Schubert #define S2S(s) case WLAN_STATUS_ ## s: return #s; 1396*206b73d0SCy Schubert switch (status) { 1397*206b73d0SCy Schubert S2S(SUCCESS) 1398*206b73d0SCy Schubert S2S(UNSPECIFIED_FAILURE) 1399*206b73d0SCy Schubert S2S(TDLS_WAKEUP_ALTERNATE) 1400*206b73d0SCy Schubert S2S(TDLS_WAKEUP_REJECT) 1401*206b73d0SCy Schubert S2S(SECURITY_DISABLED) 1402*206b73d0SCy Schubert S2S(UNACCEPTABLE_LIFETIME) 1403*206b73d0SCy Schubert S2S(NOT_IN_SAME_BSS) 1404*206b73d0SCy Schubert S2S(CAPS_UNSUPPORTED) 1405*206b73d0SCy Schubert S2S(REASSOC_NO_ASSOC) 1406*206b73d0SCy Schubert S2S(ASSOC_DENIED_UNSPEC) 1407*206b73d0SCy Schubert S2S(NOT_SUPPORTED_AUTH_ALG) 1408*206b73d0SCy Schubert S2S(UNKNOWN_AUTH_TRANSACTION) 1409*206b73d0SCy Schubert S2S(CHALLENGE_FAIL) 1410*206b73d0SCy Schubert S2S(AUTH_TIMEOUT) 1411*206b73d0SCy Schubert S2S(AP_UNABLE_TO_HANDLE_NEW_STA) 1412*206b73d0SCy Schubert S2S(ASSOC_DENIED_RATES) 1413*206b73d0SCy Schubert S2S(ASSOC_DENIED_NOSHORT) 1414*206b73d0SCy Schubert S2S(SPEC_MGMT_REQUIRED) 1415*206b73d0SCy Schubert S2S(PWR_CAPABILITY_NOT_VALID) 1416*206b73d0SCy Schubert S2S(SUPPORTED_CHANNEL_NOT_VALID) 1417*206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME) 1418*206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_HT) 1419*206b73d0SCy Schubert S2S(R0KH_UNREACHABLE) 1420*206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_PCO) 1421*206b73d0SCy Schubert S2S(ASSOC_REJECTED_TEMPORARILY) 1422*206b73d0SCy Schubert S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION) 1423*206b73d0SCy Schubert S2S(UNSPECIFIED_QOS_FAILURE) 1424*206b73d0SCy Schubert S2S(DENIED_INSUFFICIENT_BANDWIDTH) 1425*206b73d0SCy Schubert S2S(DENIED_POOR_CHANNEL_CONDITIONS) 1426*206b73d0SCy Schubert S2S(DENIED_QOS_NOT_SUPPORTED) 1427*206b73d0SCy Schubert S2S(REQUEST_DECLINED) 1428*206b73d0SCy Schubert S2S(INVALID_PARAMETERS) 1429*206b73d0SCy Schubert S2S(REJECTED_WITH_SUGGESTED_CHANGES) 1430*206b73d0SCy Schubert S2S(INVALID_IE) 1431*206b73d0SCy Schubert S2S(GROUP_CIPHER_NOT_VALID) 1432*206b73d0SCy Schubert S2S(PAIRWISE_CIPHER_NOT_VALID) 1433*206b73d0SCy Schubert S2S(AKMP_NOT_VALID) 1434*206b73d0SCy Schubert S2S(UNSUPPORTED_RSN_IE_VERSION) 1435*206b73d0SCy Schubert S2S(INVALID_RSN_IE_CAPAB) 1436*206b73d0SCy Schubert S2S(CIPHER_REJECTED_PER_POLICY) 1437*206b73d0SCy Schubert S2S(TS_NOT_CREATED) 1438*206b73d0SCy Schubert S2S(DIRECT_LINK_NOT_ALLOWED) 1439*206b73d0SCy Schubert S2S(DEST_STA_NOT_PRESENT) 1440*206b73d0SCy Schubert S2S(DEST_STA_NOT_QOS_STA) 1441*206b73d0SCy Schubert S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE) 1442*206b73d0SCy Schubert S2S(INVALID_FT_ACTION_FRAME_COUNT) 1443*206b73d0SCy Schubert S2S(INVALID_PMKID) 1444*206b73d0SCy Schubert S2S(INVALID_MDIE) 1445*206b73d0SCy Schubert S2S(INVALID_FTIE) 1446*206b73d0SCy Schubert S2S(REQUESTED_TCLAS_NOT_SUPPORTED) 1447*206b73d0SCy Schubert S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES) 1448*206b73d0SCy Schubert S2S(TRY_ANOTHER_BSS) 1449*206b73d0SCy Schubert S2S(GAS_ADV_PROTO_NOT_SUPPORTED) 1450*206b73d0SCy Schubert S2S(NO_OUTSTANDING_GAS_REQ) 1451*206b73d0SCy Schubert S2S(GAS_RESP_NOT_RECEIVED) 1452*206b73d0SCy Schubert S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP) 1453*206b73d0SCy Schubert S2S(GAS_RESP_LARGER_THAN_LIMIT) 1454*206b73d0SCy Schubert S2S(REQ_REFUSED_HOME) 1455*206b73d0SCy Schubert S2S(ADV_SRV_UNREACHABLE) 1456*206b73d0SCy Schubert S2S(REQ_REFUSED_SSPN) 1457*206b73d0SCy Schubert S2S(REQ_REFUSED_UNAUTH_ACCESS) 1458*206b73d0SCy Schubert S2S(INVALID_RSNIE) 1459*206b73d0SCy Schubert S2S(U_APSD_COEX_NOT_SUPPORTED) 1460*206b73d0SCy Schubert S2S(U_APSD_COEX_MODE_NOT_SUPPORTED) 1461*206b73d0SCy Schubert S2S(BAD_INTERVAL_WITH_U_APSD_COEX) 1462*206b73d0SCy Schubert S2S(ANTI_CLOGGING_TOKEN_REQ) 1463*206b73d0SCy Schubert S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED) 1464*206b73d0SCy Schubert S2S(CANNOT_FIND_ALT_TBTT) 1465*206b73d0SCy Schubert S2S(TRANSMISSION_FAILURE) 1466*206b73d0SCy Schubert S2S(REQ_TCLAS_NOT_SUPPORTED) 1467*206b73d0SCy Schubert S2S(TCLAS_RESOURCES_EXCHAUSTED) 1468*206b73d0SCy Schubert S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION) 1469*206b73d0SCy Schubert S2S(REJECT_WITH_SCHEDULE) 1470*206b73d0SCy Schubert S2S(REJECT_NO_WAKEUP_SPECIFIED) 1471*206b73d0SCy Schubert S2S(SUCCESS_POWER_SAVE_MODE) 1472*206b73d0SCy Schubert S2S(PENDING_ADMITTING_FST_SESSION) 1473*206b73d0SCy Schubert S2S(PERFORMING_FST_NOW) 1474*206b73d0SCy Schubert S2S(PENDING_GAP_IN_BA_WINDOW) 1475*206b73d0SCy Schubert S2S(REJECT_U_PID_SETTING) 1476*206b73d0SCy Schubert S2S(REFUSED_EXTERNAL_REASON) 1477*206b73d0SCy Schubert S2S(REFUSED_AP_OUT_OF_MEMORY) 1478*206b73d0SCy Schubert S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED) 1479*206b73d0SCy Schubert S2S(QUERY_RESP_OUTSTANDING) 1480*206b73d0SCy Schubert S2S(REJECT_DSE_BAND) 1481*206b73d0SCy Schubert S2S(TCLAS_PROCESSING_TERMINATED) 1482*206b73d0SCy Schubert S2S(TS_SCHEDULE_CONFLICT) 1483*206b73d0SCy Schubert S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL) 1484*206b73d0SCy Schubert S2S(MCCAOP_RESERVATION_CONFLICT) 1485*206b73d0SCy Schubert S2S(MAF_LIMIT_EXCEEDED) 1486*206b73d0SCy Schubert S2S(MCCA_TRACK_LIMIT_EXCEEDED) 1487*206b73d0SCy Schubert S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT) 1488*206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_VHT) 1489*206b73d0SCy Schubert S2S(ENABLEMENT_DENIED) 1490*206b73d0SCy Schubert S2S(RESTRICTION_FROM_AUTHORIZED_GDB) 1491*206b73d0SCy Schubert S2S(AUTHORIZATION_DEENABLED) 1492*206b73d0SCy Schubert S2S(FILS_AUTHENTICATION_FAILURE) 1493*206b73d0SCy Schubert S2S(UNKNOWN_AUTHENTICATION_SERVER) 1494*206b73d0SCy Schubert S2S(UNKNOWN_PASSWORD_IDENTIFIER) 1495*206b73d0SCy Schubert } 1496*206b73d0SCy Schubert return "UNKNOWN"; 1497*206b73d0SCy Schubert #undef S2S 1498*206b73d0SCy Schubert } 1499*206b73d0SCy Schubert 1500*206b73d0SCy Schubert 1501325151a3SRui Paulo int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, 1502325151a3SRui Paulo size_t ies_len) 1503325151a3SRui Paulo { 15044bc52338SCy Schubert const struct element *elem; 15054bc52338SCy Schubert 1506325151a3SRui Paulo os_memset(info, 0, sizeof(*info)); 1507325151a3SRui Paulo 15084bc52338SCy Schubert if (!ies_buf) 15094bc52338SCy Schubert return 0; 1510325151a3SRui Paulo 15114bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) { 15124bc52338SCy Schubert if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED) 15134bc52338SCy Schubert return 0; 1514325151a3SRui Paulo 15154bc52338SCy Schubert wpa_printf(MSG_DEBUG, "MB IE of %u bytes found", 15164bc52338SCy Schubert elem->datalen + 2); 15174bc52338SCy Schubert info->ies[info->nof_ies].ie = elem->data; 15184bc52338SCy Schubert info->ies[info->nof_ies].ie_len = elem->datalen; 1519325151a3SRui Paulo info->nof_ies++; 1520325151a3SRui Paulo } 1521325151a3SRui Paulo 15224bc52338SCy Schubert if (!for_each_element_completed(elem, ies_buf, ies_len)) { 15234bc52338SCy Schubert wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len); 15244bc52338SCy Schubert return -1; 1525325151a3SRui Paulo } 1526325151a3SRui Paulo 1527325151a3SRui Paulo return 0; 1528325151a3SRui Paulo } 1529325151a3SRui Paulo 1530325151a3SRui Paulo 1531325151a3SRui Paulo struct wpabuf * mb_ies_by_info(struct mb_ies_info *info) 1532325151a3SRui Paulo { 1533325151a3SRui Paulo struct wpabuf *mb_ies = NULL; 1534325151a3SRui Paulo 1535325151a3SRui Paulo WPA_ASSERT(info != NULL); 1536325151a3SRui Paulo 1537325151a3SRui Paulo if (info->nof_ies) { 1538325151a3SRui Paulo u8 i; 1539325151a3SRui Paulo size_t mb_ies_size = 0; 1540325151a3SRui Paulo 1541325151a3SRui Paulo for (i = 0; i < info->nof_ies; i++) 1542325151a3SRui Paulo mb_ies_size += 2 + info->ies[i].ie_len; 1543325151a3SRui Paulo 1544325151a3SRui Paulo mb_ies = wpabuf_alloc(mb_ies_size); 1545325151a3SRui Paulo if (mb_ies) { 1546325151a3SRui Paulo for (i = 0; i < info->nof_ies; i++) { 1547325151a3SRui Paulo wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND); 1548325151a3SRui Paulo wpabuf_put_u8(mb_ies, info->ies[i].ie_len); 1549325151a3SRui Paulo wpabuf_put_data(mb_ies, 1550325151a3SRui Paulo info->ies[i].ie, 1551325151a3SRui Paulo info->ies[i].ie_len); 1552325151a3SRui Paulo } 1553325151a3SRui Paulo } 1554325151a3SRui Paulo } 1555325151a3SRui Paulo 1556325151a3SRui Paulo return mb_ies; 1557325151a3SRui Paulo } 1558780fb4a2SCy Schubert 1559780fb4a2SCy Schubert 1560780fb4a2SCy Schubert const struct oper_class_map global_op_class[] = { 1561780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP }, 1562780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP }, 1563780fb4a2SCy Schubert 1564780fb4a2SCy Schubert /* Do not enable HT40 on 2.4 GHz for P2P use for now */ 1565780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP }, 1566780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP }, 1567780fb4a2SCy Schubert 1568780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, 1569780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, 1570780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, 1571780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, 1572780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, 1573780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, 1574780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, 1575780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP }, 1576780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP }, 1577780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, 1578780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP }, 1579780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP }, 1580780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP }, 1581780fb4a2SCy Schubert 1582780fb4a2SCy Schubert /* 1583780fb4a2SCy Schubert * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center 1584780fb4a2SCy Schubert * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of 1585780fb4a2SCy Schubert * 80 MHz, but currently use the following definition for simplicity 1586780fb4a2SCy Schubert * (these center frequencies are not actual channels, which makes 1587780fb4a2SCy Schubert * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take 1588780fb4a2SCy Schubert * care of removing invalid channels. 1589780fb4a2SCy Schubert */ 1590780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP }, 1591780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP }, 1592780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP }, 1593780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP }, 1594780fb4a2SCy Schubert { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } 1595780fb4a2SCy Schubert }; 1596780fb4a2SCy Schubert 1597780fb4a2SCy Schubert 1598780fb4a2SCy Schubert static enum phy_type ieee80211_phy_type_by_freq(int freq) 1599780fb4a2SCy Schubert { 1600780fb4a2SCy Schubert enum hostapd_hw_mode hw_mode; 1601780fb4a2SCy Schubert u8 channel; 1602780fb4a2SCy Schubert 1603780fb4a2SCy Schubert hw_mode = ieee80211_freq_to_chan(freq, &channel); 1604780fb4a2SCy Schubert 1605780fb4a2SCy Schubert switch (hw_mode) { 1606780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211A: 1607780fb4a2SCy Schubert return PHY_TYPE_OFDM; 1608780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211B: 1609780fb4a2SCy Schubert return PHY_TYPE_HRDSSS; 1610780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211G: 1611780fb4a2SCy Schubert return PHY_TYPE_ERP; 1612780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211AD: 1613780fb4a2SCy Schubert return PHY_TYPE_DMG; 1614780fb4a2SCy Schubert default: 1615780fb4a2SCy Schubert return PHY_TYPE_UNSPECIFIED; 1616780fb4a2SCy Schubert }; 1617780fb4a2SCy Schubert } 1618780fb4a2SCy Schubert 1619780fb4a2SCy Schubert 1620780fb4a2SCy Schubert /* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */ 1621780fb4a2SCy Schubert enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht) 1622780fb4a2SCy Schubert { 1623780fb4a2SCy Schubert if (vht) 1624780fb4a2SCy Schubert return PHY_TYPE_VHT; 1625780fb4a2SCy Schubert if (ht) 1626780fb4a2SCy Schubert return PHY_TYPE_HT; 1627780fb4a2SCy Schubert 1628780fb4a2SCy Schubert return ieee80211_phy_type_by_freq(freq); 1629780fb4a2SCy Schubert } 1630780fb4a2SCy Schubert 1631780fb4a2SCy Schubert 1632780fb4a2SCy Schubert size_t global_op_class_size = ARRAY_SIZE(global_op_class); 1633780fb4a2SCy Schubert 1634780fb4a2SCy Schubert 1635780fb4a2SCy Schubert /** 1636780fb4a2SCy Schubert * get_ie - Fetch a specified information element from IEs buffer 1637780fb4a2SCy Schubert * @ies: Information elements buffer 1638780fb4a2SCy Schubert * @len: Information elements buffer length 1639780fb4a2SCy Schubert * @eid: Information element identifier (WLAN_EID_*) 1640780fb4a2SCy Schubert * Returns: Pointer to the information element (id field) or %NULL if not found 1641780fb4a2SCy Schubert * 1642780fb4a2SCy Schubert * This function returns the first matching information element in the IEs 1643780fb4a2SCy Schubert * buffer or %NULL in case the element is not found. 1644780fb4a2SCy Schubert */ 1645780fb4a2SCy Schubert const u8 * get_ie(const u8 *ies, size_t len, u8 eid) 1646780fb4a2SCy Schubert { 16474bc52338SCy Schubert const struct element *elem; 1648780fb4a2SCy Schubert 1649780fb4a2SCy Schubert if (!ies) 1650780fb4a2SCy Schubert return NULL; 1651780fb4a2SCy Schubert 16524bc52338SCy Schubert for_each_element_id(elem, eid, ies, len) 16534bc52338SCy Schubert return &elem->id; 1654780fb4a2SCy Schubert 1655780fb4a2SCy Schubert return NULL; 1656780fb4a2SCy Schubert } 1657780fb4a2SCy Schubert 1658780fb4a2SCy Schubert 165985732ac8SCy Schubert /** 166085732ac8SCy Schubert * get_ie_ext - Fetch a specified extended information element from IEs buffer 166185732ac8SCy Schubert * @ies: Information elements buffer 166285732ac8SCy Schubert * @len: Information elements buffer length 166385732ac8SCy Schubert * @ext: Information element extension identifier (WLAN_EID_EXT_*) 166485732ac8SCy Schubert * Returns: Pointer to the information element (id field) or %NULL if not found 166585732ac8SCy Schubert * 166685732ac8SCy Schubert * This function returns the first matching information element in the IEs 166785732ac8SCy Schubert * buffer or %NULL in case the element is not found. 166885732ac8SCy Schubert */ 166985732ac8SCy Schubert const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext) 167085732ac8SCy Schubert { 16714bc52338SCy Schubert const struct element *elem; 167285732ac8SCy Schubert 167385732ac8SCy Schubert if (!ies) 167485732ac8SCy Schubert return NULL; 167585732ac8SCy Schubert 16764bc52338SCy Schubert for_each_element_extid(elem, ext, ies, len) 16774bc52338SCy Schubert return &elem->id; 167885732ac8SCy Schubert 16794bc52338SCy Schubert return NULL; 16804bc52338SCy Schubert } 168185732ac8SCy Schubert 168285732ac8SCy Schubert 16834bc52338SCy Schubert const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) 16844bc52338SCy Schubert { 16854bc52338SCy Schubert const struct element *elem; 16864bc52338SCy Schubert 16874bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) { 16884bc52338SCy Schubert if (elem->datalen >= 4 && 16894bc52338SCy Schubert vendor_type == WPA_GET_BE32(elem->data)) 16904bc52338SCy Schubert return &elem->id; 169185732ac8SCy Schubert } 169285732ac8SCy Schubert 169385732ac8SCy Schubert return NULL; 169485732ac8SCy Schubert } 169585732ac8SCy Schubert 169685732ac8SCy Schubert 1697780fb4a2SCy Schubert size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) 1698780fb4a2SCy Schubert { 1699780fb4a2SCy Schubert /* 1700780fb4a2SCy Schubert * MBO IE requires 6 bytes without the attributes: EID (1), length (1), 1701780fb4a2SCy Schubert * OUI (3), OUI type (1). 1702780fb4a2SCy Schubert */ 1703780fb4a2SCy Schubert if (len < 6 + attr_len) { 1704780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1705780fb4a2SCy Schubert "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu", 1706780fb4a2SCy Schubert len, attr_len); 1707780fb4a2SCy Schubert return 0; 1708780fb4a2SCy Schubert } 1709780fb4a2SCy Schubert 1710780fb4a2SCy Schubert *buf++ = WLAN_EID_VENDOR_SPECIFIC; 1711780fb4a2SCy Schubert *buf++ = attr_len + 4; 1712780fb4a2SCy Schubert WPA_PUT_BE24(buf, OUI_WFA); 1713780fb4a2SCy Schubert buf += 3; 1714780fb4a2SCy Schubert *buf++ = MBO_OUI_TYPE; 1715780fb4a2SCy Schubert os_memcpy(buf, attr, attr_len); 1716780fb4a2SCy Schubert 1717780fb4a2SCy Schubert return 6 + attr_len; 1718780fb4a2SCy Schubert } 171985732ac8SCy Schubert 172085732ac8SCy Schubert 17214bc52338SCy Schubert size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value) 17224bc52338SCy Schubert { 17234bc52338SCy Schubert u8 *pos = buf; 17244bc52338SCy Schubert 17254bc52338SCy Schubert if (len < 9) 17264bc52338SCy Schubert return 0; 17274bc52338SCy Schubert 17284bc52338SCy Schubert *pos++ = WLAN_EID_VENDOR_SPECIFIC; 17294bc52338SCy Schubert *pos++ = 7; /* len */ 17304bc52338SCy Schubert WPA_PUT_BE24(pos, OUI_WFA); 17314bc52338SCy Schubert pos += 3; 17324bc52338SCy Schubert *pos++ = MULTI_AP_OUI_TYPE; 17334bc52338SCy Schubert *pos++ = MULTI_AP_SUB_ELEM_TYPE; 17344bc52338SCy Schubert *pos++ = 1; /* len */ 17354bc52338SCy Schubert *pos++ = value; 17364bc52338SCy Schubert 17374bc52338SCy Schubert return pos - buf; 17384bc52338SCy Schubert } 17394bc52338SCy Schubert 17404bc52338SCy Schubert 174185732ac8SCy Schubert static const struct country_op_class us_op_class[] = { 174285732ac8SCy Schubert { 1, 115 }, 174385732ac8SCy Schubert { 2, 118 }, 174485732ac8SCy Schubert { 3, 124 }, 174585732ac8SCy Schubert { 4, 121 }, 174685732ac8SCy Schubert { 5, 125 }, 174785732ac8SCy Schubert { 12, 81 }, 174885732ac8SCy Schubert { 22, 116 }, 174985732ac8SCy Schubert { 23, 119 }, 175085732ac8SCy Schubert { 24, 122 }, 175185732ac8SCy Schubert { 25, 126 }, 175285732ac8SCy Schubert { 26, 126 }, 175385732ac8SCy Schubert { 27, 117 }, 175485732ac8SCy Schubert { 28, 120 }, 175585732ac8SCy Schubert { 29, 123 }, 175685732ac8SCy Schubert { 30, 127 }, 175785732ac8SCy Schubert { 31, 127 }, 175885732ac8SCy Schubert { 32, 83 }, 175985732ac8SCy Schubert { 33, 84 }, 176085732ac8SCy Schubert { 34, 180 }, 176185732ac8SCy Schubert }; 176285732ac8SCy Schubert 176385732ac8SCy Schubert static const struct country_op_class eu_op_class[] = { 176485732ac8SCy Schubert { 1, 115 }, 176585732ac8SCy Schubert { 2, 118 }, 176685732ac8SCy Schubert { 3, 121 }, 176785732ac8SCy Schubert { 4, 81 }, 176885732ac8SCy Schubert { 5, 116 }, 176985732ac8SCy Schubert { 6, 119 }, 177085732ac8SCy Schubert { 7, 122 }, 177185732ac8SCy Schubert { 8, 117 }, 177285732ac8SCy Schubert { 9, 120 }, 177385732ac8SCy Schubert { 10, 123 }, 177485732ac8SCy Schubert { 11, 83 }, 177585732ac8SCy Schubert { 12, 84 }, 177685732ac8SCy Schubert { 17, 125 }, 177785732ac8SCy Schubert { 18, 180 }, 177885732ac8SCy Schubert }; 177985732ac8SCy Schubert 178085732ac8SCy Schubert static const struct country_op_class jp_op_class[] = { 178185732ac8SCy Schubert { 1, 115 }, 178285732ac8SCy Schubert { 30, 81 }, 178385732ac8SCy Schubert { 31, 82 }, 178485732ac8SCy Schubert { 32, 118 }, 178585732ac8SCy Schubert { 33, 118 }, 178685732ac8SCy Schubert { 34, 121 }, 178785732ac8SCy Schubert { 35, 121 }, 178885732ac8SCy Schubert { 36, 116 }, 178985732ac8SCy Schubert { 37, 119 }, 179085732ac8SCy Schubert { 38, 119 }, 179185732ac8SCy Schubert { 39, 122 }, 179285732ac8SCy Schubert { 40, 122 }, 179385732ac8SCy Schubert { 41, 117 }, 179485732ac8SCy Schubert { 42, 120 }, 179585732ac8SCy Schubert { 43, 120 }, 179685732ac8SCy Schubert { 44, 123 }, 179785732ac8SCy Schubert { 45, 123 }, 179885732ac8SCy Schubert { 56, 83 }, 179985732ac8SCy Schubert { 57, 84 }, 180085732ac8SCy Schubert { 58, 121 }, 180185732ac8SCy Schubert { 59, 180 }, 180285732ac8SCy Schubert }; 180385732ac8SCy Schubert 180485732ac8SCy Schubert static const struct country_op_class cn_op_class[] = { 180585732ac8SCy Schubert { 1, 115 }, 180685732ac8SCy Schubert { 2, 118 }, 180785732ac8SCy Schubert { 3, 125 }, 180885732ac8SCy Schubert { 4, 116 }, 180985732ac8SCy Schubert { 5, 119 }, 181085732ac8SCy Schubert { 6, 126 }, 181185732ac8SCy Schubert { 7, 81 }, 181285732ac8SCy Schubert { 8, 83 }, 181385732ac8SCy Schubert { 9, 84 }, 181485732ac8SCy Schubert }; 181585732ac8SCy Schubert 181685732ac8SCy Schubert static u8 181785732ac8SCy Schubert global_op_class_from_country_array(u8 op_class, size_t array_size, 181885732ac8SCy Schubert const struct country_op_class *country_array) 181985732ac8SCy Schubert { 182085732ac8SCy Schubert size_t i; 182185732ac8SCy Schubert 182285732ac8SCy Schubert for (i = 0; i < array_size; i++) { 182385732ac8SCy Schubert if (country_array[i].country_op_class == op_class) 182485732ac8SCy Schubert return country_array[i].global_op_class; 182585732ac8SCy Schubert } 182685732ac8SCy Schubert 182785732ac8SCy Schubert return 0; 182885732ac8SCy Schubert } 182985732ac8SCy Schubert 183085732ac8SCy Schubert 183185732ac8SCy Schubert u8 country_to_global_op_class(const char *country, u8 op_class) 183285732ac8SCy Schubert { 183385732ac8SCy Schubert const struct country_op_class *country_array; 183485732ac8SCy Schubert size_t size; 183585732ac8SCy Schubert u8 g_op_class; 183685732ac8SCy Schubert 183785732ac8SCy Schubert if (country_match(us_op_class_cc, country)) { 183885732ac8SCy Schubert country_array = us_op_class; 183985732ac8SCy Schubert size = ARRAY_SIZE(us_op_class); 184085732ac8SCy Schubert } else if (country_match(eu_op_class_cc, country)) { 184185732ac8SCy Schubert country_array = eu_op_class; 184285732ac8SCy Schubert size = ARRAY_SIZE(eu_op_class); 184385732ac8SCy Schubert } else if (country_match(jp_op_class_cc, country)) { 184485732ac8SCy Schubert country_array = jp_op_class; 184585732ac8SCy Schubert size = ARRAY_SIZE(jp_op_class); 184685732ac8SCy Schubert } else if (country_match(cn_op_class_cc, country)) { 184785732ac8SCy Schubert country_array = cn_op_class; 184885732ac8SCy Schubert size = ARRAY_SIZE(cn_op_class); 184985732ac8SCy Schubert } else { 185085732ac8SCy Schubert /* 185185732ac8SCy Schubert * Countries that do not match any of the above countries use 185285732ac8SCy Schubert * global operating classes 185385732ac8SCy Schubert */ 185485732ac8SCy Schubert return op_class; 185585732ac8SCy Schubert } 185685732ac8SCy Schubert 185785732ac8SCy Schubert g_op_class = global_op_class_from_country_array(op_class, size, 185885732ac8SCy Schubert country_array); 185985732ac8SCy Schubert 186085732ac8SCy Schubert /* 186185732ac8SCy Schubert * If the given operating class did not match any of the country's 186285732ac8SCy Schubert * operating classes, assume that global operating class is used. 186385732ac8SCy Schubert */ 186485732ac8SCy Schubert return g_op_class ? g_op_class : op_class; 186585732ac8SCy Schubert } 186685732ac8SCy Schubert 186785732ac8SCy Schubert 186885732ac8SCy Schubert const struct oper_class_map * get_oper_class(const char *country, u8 op_class) 186985732ac8SCy Schubert { 187085732ac8SCy Schubert const struct oper_class_map *op; 187185732ac8SCy Schubert 187285732ac8SCy Schubert if (country) 187385732ac8SCy Schubert op_class = country_to_global_op_class(country, op_class); 187485732ac8SCy Schubert 187585732ac8SCy Schubert op = &global_op_class[0]; 187685732ac8SCy Schubert while (op->op_class && op->op_class != op_class) 187785732ac8SCy Schubert op++; 187885732ac8SCy Schubert 187985732ac8SCy Schubert if (!op->op_class) 188085732ac8SCy Schubert return NULL; 188185732ac8SCy Schubert 188285732ac8SCy Schubert return op; 188385732ac8SCy Schubert } 188485732ac8SCy Schubert 188585732ac8SCy Schubert 18864bc52338SCy Schubert int oper_class_bw_to_int(const struct oper_class_map *map) 18874bc52338SCy Schubert { 18884bc52338SCy Schubert switch (map->bw) { 18894bc52338SCy Schubert case BW20: 18904bc52338SCy Schubert return 20; 18914bc52338SCy Schubert case BW40PLUS: 18924bc52338SCy Schubert case BW40MINUS: 18934bc52338SCy Schubert return 40; 18944bc52338SCy Schubert case BW80: 18954bc52338SCy Schubert return 80; 18964bc52338SCy Schubert case BW80P80: 18974bc52338SCy Schubert case BW160: 18984bc52338SCy Schubert return 160; 18994bc52338SCy Schubert case BW2160: 19004bc52338SCy Schubert return 2160; 19014bc52338SCy Schubert default: 19024bc52338SCy Schubert return 0; 19034bc52338SCy Schubert } 19044bc52338SCy Schubert } 19054bc52338SCy Schubert 19064bc52338SCy Schubert 190785732ac8SCy Schubert int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, 190885732ac8SCy Schubert size_t nei_rep_len) 190985732ac8SCy Schubert { 191085732ac8SCy Schubert u8 *nei_pos = nei_rep; 191185732ac8SCy Schubert const char *end; 191285732ac8SCy Schubert 191385732ac8SCy Schubert /* 191485732ac8SCy Schubert * BSS Transition Candidate List Entries - Neighbor Report elements 191585732ac8SCy Schubert * neighbor=<BSSID>,<BSSID Information>,<Operating Class>, 191685732ac8SCy Schubert * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>] 191785732ac8SCy Schubert */ 191885732ac8SCy Schubert while (pos) { 191985732ac8SCy Schubert u8 *nei_start; 192085732ac8SCy Schubert long int val; 192185732ac8SCy Schubert char *endptr, *tmp; 192285732ac8SCy Schubert 192385732ac8SCy Schubert pos = os_strstr(pos, " neighbor="); 192485732ac8SCy Schubert if (!pos) 192585732ac8SCy Schubert break; 192685732ac8SCy Schubert if (nei_pos + 15 > nei_rep + nei_rep_len) { 192785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 192885732ac8SCy Schubert "Not enough room for additional neighbor"); 192985732ac8SCy Schubert return -1; 193085732ac8SCy Schubert } 193185732ac8SCy Schubert pos += 10; 193285732ac8SCy Schubert 193385732ac8SCy Schubert nei_start = nei_pos; 193485732ac8SCy Schubert *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT; 193585732ac8SCy Schubert nei_pos++; /* length to be filled in */ 193685732ac8SCy Schubert 193785732ac8SCy Schubert if (hwaddr_aton(pos, nei_pos)) { 193885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Invalid BSSID"); 193985732ac8SCy Schubert return -1; 194085732ac8SCy Schubert } 194185732ac8SCy Schubert nei_pos += ETH_ALEN; 194285732ac8SCy Schubert pos += 17; 194385732ac8SCy Schubert if (*pos != ',') { 194485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing BSSID Information"); 194585732ac8SCy Schubert return -1; 194685732ac8SCy Schubert } 194785732ac8SCy Schubert pos++; 194885732ac8SCy Schubert 194985732ac8SCy Schubert val = strtol(pos, &endptr, 0); 195085732ac8SCy Schubert WPA_PUT_LE32(nei_pos, val); 195185732ac8SCy Schubert nei_pos += 4; 195285732ac8SCy Schubert if (*endptr != ',') { 195385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing Operating Class"); 195485732ac8SCy Schubert return -1; 195585732ac8SCy Schubert } 195685732ac8SCy Schubert pos = endptr + 1; 195785732ac8SCy Schubert 195885732ac8SCy Schubert *nei_pos++ = atoi(pos); /* Operating Class */ 195985732ac8SCy Schubert pos = os_strchr(pos, ','); 196085732ac8SCy Schubert if (pos == NULL) { 196185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing Channel Number"); 196285732ac8SCy Schubert return -1; 196385732ac8SCy Schubert } 196485732ac8SCy Schubert pos++; 196585732ac8SCy Schubert 196685732ac8SCy Schubert *nei_pos++ = atoi(pos); /* Channel Number */ 196785732ac8SCy Schubert pos = os_strchr(pos, ','); 196885732ac8SCy Schubert if (pos == NULL) { 196985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing PHY Type"); 197085732ac8SCy Schubert return -1; 197185732ac8SCy Schubert } 197285732ac8SCy Schubert pos++; 197385732ac8SCy Schubert 197485732ac8SCy Schubert *nei_pos++ = atoi(pos); /* PHY Type */ 197585732ac8SCy Schubert end = os_strchr(pos, ' '); 197685732ac8SCy Schubert tmp = os_strchr(pos, ','); 197785732ac8SCy Schubert if (tmp && (!end || tmp < end)) { 197885732ac8SCy Schubert /* Optional Subelements (hexdump) */ 197985732ac8SCy Schubert size_t len; 198085732ac8SCy Schubert 198185732ac8SCy Schubert pos = tmp + 1; 198285732ac8SCy Schubert end = os_strchr(pos, ' '); 198385732ac8SCy Schubert if (end) 198485732ac8SCy Schubert len = end - pos; 198585732ac8SCy Schubert else 198685732ac8SCy Schubert len = os_strlen(pos); 198785732ac8SCy Schubert if (nei_pos + len / 2 > nei_rep + nei_rep_len) { 198885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 198985732ac8SCy Schubert "Not enough room for neighbor subelements"); 199085732ac8SCy Schubert return -1; 199185732ac8SCy Schubert } 199285732ac8SCy Schubert if (len & 0x01 || 199385732ac8SCy Schubert hexstr2bin(pos, nei_pos, len / 2) < 0) { 199485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 199585732ac8SCy Schubert "Invalid neighbor subelement info"); 199685732ac8SCy Schubert return -1; 199785732ac8SCy Schubert } 199885732ac8SCy Schubert nei_pos += len / 2; 199985732ac8SCy Schubert pos = end; 200085732ac8SCy Schubert } 200185732ac8SCy Schubert 200285732ac8SCy Schubert nei_start[1] = nei_pos - nei_start - 2; 200385732ac8SCy Schubert } 200485732ac8SCy Schubert 200585732ac8SCy Schubert return nei_pos - nei_rep; 200685732ac8SCy Schubert } 20074bc52338SCy Schubert 20084bc52338SCy Schubert 20094bc52338SCy Schubert int ieee802_11_ext_capab(const u8 *ie, unsigned int capab) 20104bc52338SCy Schubert { 20114bc52338SCy Schubert if (!ie || ie[1] <= capab / 8) 20124bc52338SCy Schubert return 0; 20134bc52338SCy Schubert return !!(ie[2 + capab / 8] & BIT(capab % 8)); 20144bc52338SCy Schubert } 2015