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; 133c1d255d3SCy Schubert case OWE_OUI_TYPE: 134c1d255d3SCy Schubert /* OWE Transition Mode element */ 135c1d255d3SCy Schubert break; 136c1d255d3SCy Schubert case DPP_CC_OUI_TYPE: 137c1d255d3SCy Schubert /* DPP Configurator Connectivity element */ 138c1d255d3SCy Schubert break; 139c1d255d3SCy Schubert case SAE_PK_OUI_TYPE: 140c1d255d3SCy Schubert elems->sae_pk = pos + 4; 141c1d255d3SCy Schubert elems->sae_pk_len = elen - 4; 142c1d255d3SCy Schubert break; 143f05cddf9SRui Paulo default: 144f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Unknown WFA " 14539beb93cSSam Leffler "information element ignored " 1465b9c547cSRui Paulo "(type=%d len=%lu)", 14739beb93cSSam Leffler pos[3], (unsigned long) elen); 14839beb93cSSam Leffler return -1; 14939beb93cSSam Leffler } 15039beb93cSSam Leffler break; 15139beb93cSSam Leffler 15239beb93cSSam Leffler case OUI_BROADCOM: 15339beb93cSSam Leffler switch (pos[3]) { 15439beb93cSSam Leffler case VENDOR_HT_CAPAB_OUI_TYPE: 15539beb93cSSam Leffler elems->vendor_ht_cap = pos; 15639beb93cSSam Leffler elems->vendor_ht_cap_len = elen; 15739beb93cSSam Leffler break; 1585b9c547cSRui Paulo case VENDOR_VHT_TYPE: 1595b9c547cSRui Paulo if (elen > 4 && 1605b9c547cSRui Paulo (pos[4] == VENDOR_VHT_SUBTYPE || 1615b9c547cSRui Paulo pos[4] == VENDOR_VHT_SUBTYPE2)) { 1625b9c547cSRui Paulo elems->vendor_vht = pos; 1635b9c547cSRui Paulo elems->vendor_vht_len = elen; 1645b9c547cSRui Paulo } else 1655b9c547cSRui Paulo return -1; 1665b9c547cSRui Paulo break; 16739beb93cSSam Leffler default: 168f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 16939beb93cSSam Leffler "information element ignored " 170f05cddf9SRui Paulo "(type=%d len=%lu)", 17139beb93cSSam Leffler pos[3], (unsigned long) elen); 17239beb93cSSam Leffler return -1; 17339beb93cSSam Leffler } 17439beb93cSSam Leffler break; 17539beb93cSSam Leffler 176325151a3SRui Paulo case OUI_QCA: 177325151a3SRui Paulo switch (pos[3]) { 178325151a3SRui Paulo case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: 179325151a3SRui Paulo elems->pref_freq_list = pos; 180325151a3SRui Paulo elems->pref_freq_list_len = elen; 181325151a3SRui Paulo break; 182325151a3SRui Paulo default: 183325151a3SRui Paulo wpa_printf(MSG_EXCESSIVE, 184325151a3SRui Paulo "Unknown QCA information element ignored (type=%d len=%lu)", 185325151a3SRui Paulo pos[3], (unsigned long) elen); 186325151a3SRui Paulo return -1; 187325151a3SRui Paulo } 188325151a3SRui Paulo break; 189325151a3SRui Paulo 19039beb93cSSam Leffler default: 191f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 192f05cddf9SRui Paulo "information element ignored (vendor OUI " 193f05cddf9SRui Paulo "%02x:%02x:%02x len=%lu)", 19439beb93cSSam Leffler pos[0], pos[1], pos[2], (unsigned long) elen); 19539beb93cSSam Leffler return -1; 19639beb93cSSam Leffler } 19739beb93cSSam Leffler 19839beb93cSSam Leffler return 0; 19939beb93cSSam Leffler } 20039beb93cSSam Leffler 20139beb93cSSam Leffler 20285732ac8SCy Schubert static int ieee802_11_parse_extension(const u8 *pos, size_t elen, 20385732ac8SCy Schubert struct ieee802_11_elems *elems, 20485732ac8SCy Schubert int show_errors) 20585732ac8SCy Schubert { 20685732ac8SCy Schubert u8 ext_id; 20785732ac8SCy Schubert 20885732ac8SCy Schubert if (elen < 1) { 20985732ac8SCy Schubert if (show_errors) { 21085732ac8SCy Schubert wpa_printf(MSG_MSGDUMP, 21185732ac8SCy Schubert "short information element (Ext)"); 21285732ac8SCy Schubert } 21385732ac8SCy Schubert return -1; 21485732ac8SCy Schubert } 21585732ac8SCy Schubert 21685732ac8SCy Schubert ext_id = *pos++; 21785732ac8SCy Schubert elen--; 21885732ac8SCy Schubert 219c1d255d3SCy Schubert elems->frag_ies.last_eid_ext = 0; 220c1d255d3SCy Schubert 22185732ac8SCy Schubert switch (ext_id) { 22285732ac8SCy Schubert case WLAN_EID_EXT_ASSOC_DELAY_INFO: 22385732ac8SCy Schubert if (elen != 1) 22485732ac8SCy Schubert break; 22585732ac8SCy Schubert elems->assoc_delay_info = pos; 22685732ac8SCy Schubert break; 22785732ac8SCy Schubert case WLAN_EID_EXT_FILS_REQ_PARAMS: 22885732ac8SCy Schubert if (elen < 3) 22985732ac8SCy Schubert break; 23085732ac8SCy Schubert elems->fils_req_params = pos; 23185732ac8SCy Schubert elems->fils_req_params_len = elen; 23285732ac8SCy Schubert break; 23385732ac8SCy Schubert case WLAN_EID_EXT_FILS_KEY_CONFIRM: 23485732ac8SCy Schubert elems->fils_key_confirm = pos; 23585732ac8SCy Schubert elems->fils_key_confirm_len = elen; 23685732ac8SCy Schubert break; 23785732ac8SCy Schubert case WLAN_EID_EXT_FILS_SESSION: 23885732ac8SCy Schubert if (elen != FILS_SESSION_LEN) 23985732ac8SCy Schubert break; 24085732ac8SCy Schubert elems->fils_session = pos; 24185732ac8SCy Schubert break; 24285732ac8SCy Schubert case WLAN_EID_EXT_FILS_HLP_CONTAINER: 24385732ac8SCy Schubert if (elen < 2 * ETH_ALEN) 24485732ac8SCy Schubert break; 24585732ac8SCy Schubert elems->fils_hlp = pos; 24685732ac8SCy Schubert elems->fils_hlp_len = elen; 24785732ac8SCy Schubert break; 24885732ac8SCy Schubert case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN: 24985732ac8SCy Schubert if (elen < 1) 25085732ac8SCy Schubert break; 25185732ac8SCy Schubert elems->fils_ip_addr_assign = pos; 25285732ac8SCy Schubert elems->fils_ip_addr_assign_len = elen; 25385732ac8SCy Schubert break; 25485732ac8SCy Schubert case WLAN_EID_EXT_KEY_DELIVERY: 25585732ac8SCy Schubert if (elen < WPA_KEY_RSC_LEN) 25685732ac8SCy Schubert break; 25785732ac8SCy Schubert elems->key_delivery = pos; 25885732ac8SCy Schubert elems->key_delivery_len = elen; 25985732ac8SCy Schubert break; 260c1d255d3SCy Schubert case WLAN_EID_EXT_WRAPPED_DATA: 261c1d255d3SCy Schubert elems->wrapped_data = pos; 262c1d255d3SCy Schubert elems->wrapped_data_len = elen; 26385732ac8SCy Schubert break; 26485732ac8SCy Schubert case WLAN_EID_EXT_FILS_PUBLIC_KEY: 26585732ac8SCy Schubert if (elen < 1) 26685732ac8SCy Schubert break; 26785732ac8SCy Schubert elems->fils_pk = pos; 26885732ac8SCy Schubert elems->fils_pk_len = elen; 26985732ac8SCy Schubert break; 27085732ac8SCy Schubert case WLAN_EID_EXT_FILS_NONCE: 27185732ac8SCy Schubert if (elen != FILS_NONCE_LEN) 27285732ac8SCy Schubert break; 27385732ac8SCy Schubert elems->fils_nonce = pos; 27485732ac8SCy Schubert break; 27585732ac8SCy Schubert case WLAN_EID_EXT_OWE_DH_PARAM: 27685732ac8SCy Schubert if (elen < 2) 27785732ac8SCy Schubert break; 27885732ac8SCy Schubert elems->owe_dh = pos; 27985732ac8SCy Schubert elems->owe_dh_len = elen; 28085732ac8SCy Schubert break; 28185732ac8SCy Schubert case WLAN_EID_EXT_PASSWORD_IDENTIFIER: 28285732ac8SCy Schubert elems->password_id = pos; 28385732ac8SCy Schubert elems->password_id_len = elen; 28485732ac8SCy Schubert break; 2854bc52338SCy Schubert case WLAN_EID_EXT_HE_CAPABILITIES: 2864bc52338SCy Schubert elems->he_capabilities = pos; 2874bc52338SCy Schubert elems->he_capabilities_len = elen; 2884bc52338SCy Schubert break; 289206b73d0SCy Schubert case WLAN_EID_EXT_HE_OPERATION: 290206b73d0SCy Schubert elems->he_operation = pos; 291206b73d0SCy Schubert elems->he_operation_len = elen; 292206b73d0SCy Schubert break; 2934bc52338SCy Schubert case WLAN_EID_EXT_OCV_OCI: 2944bc52338SCy Schubert elems->oci = pos; 2954bc52338SCy Schubert elems->oci_len = elen; 2964bc52338SCy Schubert break; 297c1d255d3SCy Schubert case WLAN_EID_EXT_SHORT_SSID_LIST: 298c1d255d3SCy Schubert elems->short_ssid_list = pos; 299c1d255d3SCy Schubert elems->short_ssid_list_len = elen; 300c1d255d3SCy Schubert break; 301c1d255d3SCy Schubert case WLAN_EID_EXT_HE_6GHZ_BAND_CAP: 302c1d255d3SCy Schubert if (elen < sizeof(struct ieee80211_he_6ghz_band_cap)) 303c1d255d3SCy Schubert break; 304c1d255d3SCy Schubert elems->he_6ghz_band_cap = pos; 305c1d255d3SCy Schubert break; 306c1d255d3SCy Schubert case WLAN_EID_EXT_PASN_PARAMS: 307c1d255d3SCy Schubert elems->pasn_params = pos; 308c1d255d3SCy Schubert elems->pasn_params_len = elen; 309c1d255d3SCy Schubert break; 31085732ac8SCy Schubert default: 31185732ac8SCy Schubert if (show_errors) { 31285732ac8SCy Schubert wpa_printf(MSG_MSGDUMP, 31385732ac8SCy Schubert "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)", 31485732ac8SCy Schubert ext_id, (unsigned int) elen); 31585732ac8SCy Schubert } 31685732ac8SCy Schubert return -1; 31785732ac8SCy Schubert } 31885732ac8SCy Schubert 319c1d255d3SCy Schubert if (elen == 254) 320c1d255d3SCy Schubert elems->frag_ies.last_eid_ext = ext_id; 321c1d255d3SCy Schubert 32285732ac8SCy Schubert return 0; 32385732ac8SCy Schubert } 32485732ac8SCy Schubert 32585732ac8SCy Schubert 326c1d255d3SCy Schubert static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies, 327c1d255d3SCy Schubert const u8 *pos, u8 elen) 328c1d255d3SCy Schubert { 329c1d255d3SCy Schubert if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) { 330c1d255d3SCy Schubert wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip"); 331c1d255d3SCy Schubert return; 332c1d255d3SCy Schubert } 333c1d255d3SCy Schubert 334c1d255d3SCy Schubert /* 335c1d255d3SCy Schubert * Note: while EID == 0 is a valid ID (SSID IE), it should not be 336c1d255d3SCy Schubert * fragmented. 337c1d255d3SCy Schubert */ 338c1d255d3SCy Schubert if (!frag_ies->last_eid) { 339c1d255d3SCy Schubert wpa_printf(MSG_MSGDUMP, 340c1d255d3SCy Schubert "Fragment without a valid last element - skip"); 341c1d255d3SCy Schubert return; 342c1d255d3SCy Schubert } 343c1d255d3SCy Schubert 344c1d255d3SCy Schubert frag_ies->frags[frag_ies->n_frags].ie = pos; 345c1d255d3SCy Schubert frag_ies->frags[frag_ies->n_frags].ie_len = elen; 346c1d255d3SCy Schubert frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid; 347c1d255d3SCy Schubert frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext; 348c1d255d3SCy Schubert frag_ies->n_frags++; 349c1d255d3SCy Schubert } 350c1d255d3SCy Schubert 351c1d255d3SCy Schubert 35239beb93cSSam Leffler /** 35339beb93cSSam Leffler * ieee802_11_parse_elems - Parse information elements in management frames 35439beb93cSSam Leffler * @start: Pointer to the start of IEs 35539beb93cSSam Leffler * @len: Length of IE buffer in octets 35639beb93cSSam Leffler * @elems: Data structure for parsed elements 35739beb93cSSam Leffler * @show_errors: Whether to show parsing errors in debug log 35839beb93cSSam Leffler * Returns: Parsing result 35939beb93cSSam Leffler */ 360e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 36139beb93cSSam Leffler struct ieee802_11_elems *elems, 36239beb93cSSam Leffler int show_errors) 36339beb93cSSam Leffler { 3644bc52338SCy Schubert const struct element *elem; 36539beb93cSSam Leffler int unknown = 0; 36639beb93cSSam Leffler 36739beb93cSSam Leffler os_memset(elems, 0, sizeof(*elems)); 36839beb93cSSam Leffler 3694bc52338SCy Schubert if (!start) 3704bc52338SCy Schubert return ParseOK; 37139beb93cSSam Leffler 3724bc52338SCy Schubert for_each_element(elem, start, len) { 3734bc52338SCy Schubert u8 id = elem->id, elen = elem->datalen; 3744bc52338SCy Schubert const u8 *pos = elem->data; 37539beb93cSSam Leffler 37639beb93cSSam Leffler switch (id) { 37739beb93cSSam Leffler case WLAN_EID_SSID: 378325151a3SRui Paulo if (elen > SSID_MAX_LEN) { 379325151a3SRui Paulo wpa_printf(MSG_DEBUG, 380325151a3SRui Paulo "Ignored too long SSID element (elen=%u)", 381325151a3SRui Paulo elen); 382325151a3SRui Paulo break; 383325151a3SRui Paulo } 384c1d255d3SCy Schubert if (elems->ssid) { 385c1d255d3SCy Schubert wpa_printf(MSG_MSGDUMP, 386c1d255d3SCy Schubert "Ignored duplicated SSID element"); 387c1d255d3SCy Schubert break; 388c1d255d3SCy Schubert } 38939beb93cSSam Leffler elems->ssid = pos; 39039beb93cSSam Leffler elems->ssid_len = elen; 39139beb93cSSam Leffler break; 39239beb93cSSam Leffler case WLAN_EID_SUPP_RATES: 39339beb93cSSam Leffler elems->supp_rates = pos; 39439beb93cSSam Leffler elems->supp_rates_len = elen; 39539beb93cSSam Leffler break; 39639beb93cSSam Leffler case WLAN_EID_DS_PARAMS: 397325151a3SRui Paulo if (elen < 1) 398325151a3SRui Paulo break; 39939beb93cSSam Leffler elems->ds_params = pos; 40039beb93cSSam Leffler break; 40139beb93cSSam Leffler case WLAN_EID_CF_PARAMS: 40239beb93cSSam Leffler case WLAN_EID_TIM: 40339beb93cSSam Leffler break; 40439beb93cSSam Leffler case WLAN_EID_CHALLENGE: 40539beb93cSSam Leffler elems->challenge = pos; 40639beb93cSSam Leffler elems->challenge_len = elen; 40739beb93cSSam Leffler break; 40839beb93cSSam Leffler case WLAN_EID_ERP_INFO: 409325151a3SRui Paulo if (elen < 1) 410325151a3SRui Paulo break; 41139beb93cSSam Leffler elems->erp_info = pos; 41239beb93cSSam Leffler break; 41339beb93cSSam Leffler case WLAN_EID_EXT_SUPP_RATES: 41439beb93cSSam Leffler elems->ext_supp_rates = pos; 41539beb93cSSam Leffler elems->ext_supp_rates_len = elen; 41639beb93cSSam Leffler break; 41739beb93cSSam Leffler case WLAN_EID_VENDOR_SPECIFIC: 41839beb93cSSam Leffler if (ieee802_11_parse_vendor_specific(pos, elen, 41939beb93cSSam Leffler elems, 42039beb93cSSam Leffler show_errors)) 42139beb93cSSam Leffler unknown++; 42239beb93cSSam Leffler break; 42339beb93cSSam Leffler case WLAN_EID_RSN: 42439beb93cSSam Leffler elems->rsn_ie = pos; 42539beb93cSSam Leffler elems->rsn_ie_len = elen; 42639beb93cSSam Leffler break; 427c1d255d3SCy Schubert case WLAN_EID_RSNX: 428c1d255d3SCy Schubert elems->rsnxe = pos; 429c1d255d3SCy Schubert elems->rsnxe_len = elen; 430c1d255d3SCy Schubert break; 43139beb93cSSam Leffler case WLAN_EID_PWR_CAPABILITY: 43285732ac8SCy Schubert if (elen < 2) 43385732ac8SCy Schubert break; 43485732ac8SCy Schubert elems->power_capab = pos; 43585732ac8SCy Schubert elems->power_capab_len = elen; 43639beb93cSSam Leffler break; 43739beb93cSSam Leffler case WLAN_EID_SUPPORTED_CHANNELS: 43839beb93cSSam Leffler elems->supp_channels = pos; 43939beb93cSSam Leffler elems->supp_channels_len = elen; 44039beb93cSSam Leffler break; 44139beb93cSSam Leffler case WLAN_EID_MOBILITY_DOMAIN: 442325151a3SRui Paulo if (elen < sizeof(struct rsn_mdie)) 443325151a3SRui Paulo break; 44439beb93cSSam Leffler elems->mdie = pos; 44539beb93cSSam Leffler elems->mdie_len = elen; 44639beb93cSSam Leffler break; 44739beb93cSSam Leffler case WLAN_EID_FAST_BSS_TRANSITION: 448325151a3SRui Paulo if (elen < sizeof(struct rsn_ftie)) 449325151a3SRui Paulo break; 45039beb93cSSam Leffler elems->ftie = pos; 45139beb93cSSam Leffler elems->ftie_len = elen; 45239beb93cSSam Leffler break; 45339beb93cSSam Leffler case WLAN_EID_TIMEOUT_INTERVAL: 454325151a3SRui Paulo if (elen != 5) 455325151a3SRui Paulo break; 45639beb93cSSam Leffler elems->timeout_int = pos; 45739beb93cSSam Leffler break; 45839beb93cSSam Leffler case WLAN_EID_HT_CAP: 459325151a3SRui Paulo if (elen < sizeof(struct ieee80211_ht_capabilities)) 460325151a3SRui Paulo break; 46139beb93cSSam Leffler elems->ht_capabilities = pos; 46239beb93cSSam Leffler break; 46339beb93cSSam Leffler case WLAN_EID_HT_OPERATION: 464325151a3SRui Paulo if (elen < sizeof(struct ieee80211_ht_operation)) 465325151a3SRui Paulo break; 46639beb93cSSam Leffler elems->ht_operation = pos; 46739beb93cSSam Leffler break; 4685b9c547cSRui Paulo case WLAN_EID_MESH_CONFIG: 4695b9c547cSRui Paulo elems->mesh_config = pos; 4705b9c547cSRui Paulo elems->mesh_config_len = elen; 4715b9c547cSRui Paulo break; 4725b9c547cSRui Paulo case WLAN_EID_MESH_ID: 4735b9c547cSRui Paulo elems->mesh_id = pos; 4745b9c547cSRui Paulo elems->mesh_id_len = elen; 4755b9c547cSRui Paulo break; 4765b9c547cSRui Paulo case WLAN_EID_PEER_MGMT: 4775b9c547cSRui Paulo elems->peer_mgmt = pos; 4785b9c547cSRui Paulo elems->peer_mgmt_len = elen; 4795b9c547cSRui Paulo break; 480f05cddf9SRui Paulo case WLAN_EID_VHT_CAP: 481325151a3SRui Paulo if (elen < sizeof(struct ieee80211_vht_capabilities)) 482325151a3SRui Paulo break; 483f05cddf9SRui Paulo elems->vht_capabilities = pos; 484f05cddf9SRui Paulo break; 485f05cddf9SRui Paulo case WLAN_EID_VHT_OPERATION: 486325151a3SRui Paulo if (elen < sizeof(struct ieee80211_vht_operation)) 487325151a3SRui Paulo break; 488f05cddf9SRui Paulo elems->vht_operation = pos; 489f05cddf9SRui Paulo break; 4905b9c547cSRui Paulo case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: 4915b9c547cSRui Paulo if (elen != 1) 4925b9c547cSRui Paulo break; 4935b9c547cSRui Paulo elems->vht_opmode_notif = pos; 4945b9c547cSRui Paulo break; 495f05cddf9SRui Paulo case WLAN_EID_LINK_ID: 496f05cddf9SRui Paulo if (elen < 18) 497f05cddf9SRui Paulo break; 498f05cddf9SRui Paulo elems->link_id = pos; 499f05cddf9SRui Paulo break; 500f05cddf9SRui Paulo case WLAN_EID_INTERWORKING: 501f05cddf9SRui Paulo elems->interworking = pos; 502f05cddf9SRui Paulo elems->interworking_len = elen; 503f05cddf9SRui Paulo break; 5045b9c547cSRui Paulo case WLAN_EID_QOS_MAP_SET: 5055b9c547cSRui Paulo if (elen < 16) 5065b9c547cSRui Paulo break; 5075b9c547cSRui Paulo elems->qos_map_set = pos; 5085b9c547cSRui Paulo elems->qos_map_set_len = elen; 5095b9c547cSRui Paulo break; 510f05cddf9SRui Paulo case WLAN_EID_EXT_CAPAB: 511f05cddf9SRui Paulo elems->ext_capab = pos; 512f05cddf9SRui Paulo elems->ext_capab_len = elen; 513f05cddf9SRui Paulo break; 514f05cddf9SRui Paulo case WLAN_EID_BSS_MAX_IDLE_PERIOD: 515f05cddf9SRui Paulo if (elen < 3) 516f05cddf9SRui Paulo break; 517f05cddf9SRui Paulo elems->bss_max_idle_period = pos; 518f05cddf9SRui Paulo break; 519f05cddf9SRui Paulo case WLAN_EID_SSID_LIST: 520f05cddf9SRui Paulo elems->ssid_list = pos; 521f05cddf9SRui Paulo elems->ssid_list_len = elen; 522f05cddf9SRui Paulo break; 5235b9c547cSRui Paulo case WLAN_EID_AMPE: 5245b9c547cSRui Paulo elems->ampe = pos; 5255b9c547cSRui Paulo elems->ampe_len = elen; 5265b9c547cSRui Paulo break; 5275b9c547cSRui Paulo case WLAN_EID_MIC: 5285b9c547cSRui Paulo elems->mic = pos; 5295b9c547cSRui Paulo elems->mic_len = elen; 5305b9c547cSRui Paulo /* after mic everything is encrypted, so stop. */ 5314bc52338SCy Schubert goto done; 532325151a3SRui Paulo case WLAN_EID_MULTI_BAND: 533325151a3SRui Paulo if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) { 534325151a3SRui Paulo wpa_printf(MSG_MSGDUMP, 535325151a3SRui Paulo "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)", 536325151a3SRui Paulo id, elen); 537325151a3SRui Paulo break; 538325151a3SRui Paulo } 539325151a3SRui Paulo 540325151a3SRui Paulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos; 541325151a3SRui Paulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen; 542325151a3SRui Paulo elems->mb_ies.nof_ies++; 543325151a3SRui Paulo break; 544780fb4a2SCy Schubert case WLAN_EID_SUPPORTED_OPERATING_CLASSES: 545780fb4a2SCy Schubert elems->supp_op_classes = pos; 546780fb4a2SCy Schubert elems->supp_op_classes_len = elen; 547780fb4a2SCy Schubert break; 548780fb4a2SCy Schubert case WLAN_EID_RRM_ENABLED_CAPABILITIES: 549780fb4a2SCy Schubert elems->rrm_enabled = pos; 550780fb4a2SCy Schubert elems->rrm_enabled_len = elen; 551780fb4a2SCy Schubert break; 55285732ac8SCy Schubert case WLAN_EID_CAG_NUMBER: 55385732ac8SCy Schubert elems->cag_number = pos; 55485732ac8SCy Schubert elems->cag_number_len = elen; 55585732ac8SCy Schubert break; 55685732ac8SCy Schubert case WLAN_EID_AP_CSN: 55785732ac8SCy Schubert if (elen < 1) 55885732ac8SCy Schubert break; 55985732ac8SCy Schubert elems->ap_csn = pos; 56085732ac8SCy Schubert break; 56185732ac8SCy Schubert case WLAN_EID_FILS_INDICATION: 56285732ac8SCy Schubert if (elen < 2) 56385732ac8SCy Schubert break; 56485732ac8SCy Schubert elems->fils_indic = pos; 56585732ac8SCy Schubert elems->fils_indic_len = elen; 56685732ac8SCy Schubert break; 56785732ac8SCy Schubert case WLAN_EID_DILS: 56885732ac8SCy Schubert if (elen < 2) 56985732ac8SCy Schubert break; 57085732ac8SCy Schubert elems->dils = pos; 57185732ac8SCy Schubert elems->dils_len = elen; 57285732ac8SCy Schubert break; 573c1d255d3SCy Schubert case WLAN_EID_S1G_CAPABILITIES: 574c1d255d3SCy Schubert if (elen < 15) 575c1d255d3SCy Schubert break; 576c1d255d3SCy Schubert elems->s1g_capab = pos; 577c1d255d3SCy Schubert break; 57885732ac8SCy Schubert case WLAN_EID_FRAGMENT: 579c1d255d3SCy Schubert ieee802_11_parse_fragment(&elems->frag_ies, pos, elen); 58085732ac8SCy Schubert break; 58185732ac8SCy Schubert case WLAN_EID_EXTENSION: 58285732ac8SCy Schubert if (ieee802_11_parse_extension(pos, elen, elems, 58385732ac8SCy Schubert show_errors)) 58485732ac8SCy Schubert unknown++; 58585732ac8SCy Schubert break; 58639beb93cSSam Leffler default: 58739beb93cSSam Leffler unknown++; 58839beb93cSSam Leffler if (!show_errors) 58939beb93cSSam Leffler break; 59039beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 59139beb93cSSam Leffler "ignored unknown element (id=%d elen=%d)", 59239beb93cSSam Leffler id, elen); 59339beb93cSSam Leffler break; 59439beb93cSSam Leffler } 595c1d255d3SCy Schubert 596c1d255d3SCy Schubert if (id != WLAN_EID_FRAGMENT && elen == 255) 597c1d255d3SCy Schubert elems->frag_ies.last_eid = id; 598c1d255d3SCy Schubert 599c1d255d3SCy Schubert if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext) 600c1d255d3SCy Schubert elems->frag_ies.last_eid = 0; 60139beb93cSSam Leffler } 60239beb93cSSam Leffler 6034bc52338SCy Schubert if (!for_each_element_completed(elem, start, len)) { 6044bc52338SCy Schubert if (show_errors) { 6054bc52338SCy Schubert wpa_printf(MSG_DEBUG, 6064bc52338SCy Schubert "IEEE 802.11 element parse failed @%d", 6074bc52338SCy Schubert (int) (start + len - (const u8 *) elem)); 6084bc52338SCy Schubert wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 6094bc52338SCy Schubert } 61039beb93cSSam Leffler return ParseFailed; 6114bc52338SCy Schubert } 61239beb93cSSam Leffler 6134bc52338SCy Schubert done: 61439beb93cSSam Leffler return unknown ? ParseUnknown : ParseOK; 61539beb93cSSam Leffler } 616e28a4053SRui Paulo 617e28a4053SRui Paulo 618e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 619e28a4053SRui Paulo { 6204bc52338SCy Schubert const struct element *elem; 621e28a4053SRui Paulo int count = 0; 622e28a4053SRui Paulo 623e28a4053SRui Paulo if (ies == NULL) 624e28a4053SRui Paulo return 0; 625e28a4053SRui Paulo 6264bc52338SCy Schubert for_each_element(elem, ies, ies_len) 627e28a4053SRui Paulo count++; 628e28a4053SRui Paulo 629e28a4053SRui Paulo return count; 630e28a4053SRui Paulo } 631e28a4053SRui Paulo 632e28a4053SRui Paulo 633e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 634e28a4053SRui Paulo u32 oui_type) 635e28a4053SRui Paulo { 636e28a4053SRui Paulo struct wpabuf *buf; 6374bc52338SCy Schubert const struct element *elem, *found = NULL; 638e28a4053SRui Paulo 6394bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { 6404bc52338SCy Schubert if (elem->datalen >= 4 && 6414bc52338SCy Schubert WPA_GET_BE32(elem->data) == oui_type) { 6424bc52338SCy Schubert found = elem; 643e28a4053SRui Paulo break; 644e28a4053SRui Paulo } 645e28a4053SRui Paulo } 646e28a4053SRui Paulo 6474bc52338SCy Schubert if (!found) 648e28a4053SRui Paulo return NULL; /* No specified vendor IE found */ 649e28a4053SRui Paulo 650e28a4053SRui Paulo buf = wpabuf_alloc(ies_len); 651e28a4053SRui Paulo if (buf == NULL) 652e28a4053SRui Paulo return NULL; 653e28a4053SRui Paulo 654e28a4053SRui Paulo /* 655e28a4053SRui Paulo * There may be multiple vendor IEs in the message, so need to 656e28a4053SRui Paulo * concatenate their data fields. 657e28a4053SRui Paulo */ 6584bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { 6594bc52338SCy Schubert if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type) 6604bc52338SCy Schubert wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4); 661e28a4053SRui Paulo } 662e28a4053SRui Paulo 663e28a4053SRui Paulo return buf; 664e28a4053SRui Paulo } 665f05cddf9SRui Paulo 666f05cddf9SRui Paulo 667f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 668f05cddf9SRui Paulo { 669f05cddf9SRui Paulo u16 fc, type, stype; 670f05cddf9SRui Paulo 671f05cddf9SRui Paulo /* 672f05cddf9SRui Paulo * PS-Poll frames are 16 bytes. All other frames are 673f05cddf9SRui Paulo * 24 bytes or longer. 674f05cddf9SRui Paulo */ 675f05cddf9SRui Paulo if (len < 16) 676f05cddf9SRui Paulo return NULL; 677f05cddf9SRui Paulo 678f05cddf9SRui Paulo fc = le_to_host16(hdr->frame_control); 679f05cddf9SRui Paulo type = WLAN_FC_GET_TYPE(fc); 680f05cddf9SRui Paulo stype = WLAN_FC_GET_STYPE(fc); 681f05cddf9SRui Paulo 682f05cddf9SRui Paulo switch (type) { 683f05cddf9SRui Paulo case WLAN_FC_TYPE_DATA: 684f05cddf9SRui Paulo if (len < 24) 685f05cddf9SRui Paulo return NULL; 686f05cddf9SRui Paulo switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 687f05cddf9SRui Paulo case WLAN_FC_FROMDS | WLAN_FC_TODS: 688f05cddf9SRui Paulo case WLAN_FC_TODS: 689f05cddf9SRui Paulo return hdr->addr1; 690f05cddf9SRui Paulo case WLAN_FC_FROMDS: 691f05cddf9SRui Paulo return hdr->addr2; 692f05cddf9SRui Paulo default: 693f05cddf9SRui Paulo return NULL; 694f05cddf9SRui Paulo } 695f05cddf9SRui Paulo case WLAN_FC_TYPE_CTRL: 696f05cddf9SRui Paulo if (stype != WLAN_FC_STYPE_PSPOLL) 697f05cddf9SRui Paulo return NULL; 698f05cddf9SRui Paulo return hdr->addr1; 699f05cddf9SRui Paulo case WLAN_FC_TYPE_MGMT: 700f05cddf9SRui Paulo return hdr->addr3; 701f05cddf9SRui Paulo default: 702f05cddf9SRui Paulo return NULL; 703f05cddf9SRui Paulo } 704f05cddf9SRui Paulo } 705f05cddf9SRui Paulo 706f05cddf9SRui Paulo 707f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 708f05cddf9SRui Paulo const char *name, const char *val) 709f05cddf9SRui Paulo { 710f05cddf9SRui Paulo int num, v; 711f05cddf9SRui Paulo const char *pos; 712f05cddf9SRui Paulo struct hostapd_wmm_ac_params *ac; 713f05cddf9SRui Paulo 714f05cddf9SRui Paulo /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 715f05cddf9SRui Paulo pos = name + 7; 716f05cddf9SRui Paulo if (os_strncmp(pos, "be_", 3) == 0) { 717f05cddf9SRui Paulo num = 0; 718f05cddf9SRui Paulo pos += 3; 719f05cddf9SRui Paulo } else if (os_strncmp(pos, "bk_", 3) == 0) { 720f05cddf9SRui Paulo num = 1; 721f05cddf9SRui Paulo pos += 3; 722f05cddf9SRui Paulo } else if (os_strncmp(pos, "vi_", 3) == 0) { 723f05cddf9SRui Paulo num = 2; 724f05cddf9SRui Paulo pos += 3; 725f05cddf9SRui Paulo } else if (os_strncmp(pos, "vo_", 3) == 0) { 726f05cddf9SRui Paulo num = 3; 727f05cddf9SRui Paulo pos += 3; 728f05cddf9SRui Paulo } else { 729f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 730f05cddf9SRui Paulo return -1; 731f05cddf9SRui Paulo } 732f05cddf9SRui Paulo 733f05cddf9SRui Paulo ac = &wmm_ac_params[num]; 734f05cddf9SRui Paulo 735f05cddf9SRui Paulo if (os_strcmp(pos, "aifs") == 0) { 736f05cddf9SRui Paulo v = atoi(val); 737f05cddf9SRui Paulo if (v < 1 || v > 255) { 738f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 739f05cddf9SRui Paulo return -1; 740f05cddf9SRui Paulo } 741f05cddf9SRui Paulo ac->aifs = v; 742f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmin") == 0) { 743f05cddf9SRui Paulo v = atoi(val); 744325151a3SRui Paulo if (v < 0 || v > 15) { 745f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 746f05cddf9SRui Paulo return -1; 747f05cddf9SRui Paulo } 748f05cddf9SRui Paulo ac->cwmin = v; 749f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmax") == 0) { 750f05cddf9SRui Paulo v = atoi(val); 751325151a3SRui Paulo if (v < 0 || v > 15) { 752f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 753f05cddf9SRui Paulo return -1; 754f05cddf9SRui Paulo } 755f05cddf9SRui Paulo ac->cwmax = v; 756f05cddf9SRui Paulo } else if (os_strcmp(pos, "txop_limit") == 0) { 757f05cddf9SRui Paulo v = atoi(val); 758f05cddf9SRui Paulo if (v < 0 || v > 0xffff) { 759f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 760f05cddf9SRui Paulo return -1; 761f05cddf9SRui Paulo } 762f05cddf9SRui Paulo ac->txop_limit = v; 763f05cddf9SRui Paulo } else if (os_strcmp(pos, "acm") == 0) { 764f05cddf9SRui Paulo v = atoi(val); 765f05cddf9SRui Paulo if (v < 0 || v > 1) { 766f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 767f05cddf9SRui Paulo return -1; 768f05cddf9SRui Paulo } 769f05cddf9SRui Paulo ac->admission_control_mandatory = v; 770f05cddf9SRui Paulo } else { 771f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 772f05cddf9SRui Paulo return -1; 773f05cddf9SRui Paulo } 774f05cddf9SRui Paulo 775f05cddf9SRui Paulo return 0; 776f05cddf9SRui Paulo } 7775b9c547cSRui Paulo 7785b9c547cSRui Paulo 779c1d255d3SCy Schubert /* convert floats with one decimal place to value*10 int, i.e., 780c1d255d3SCy Schubert * "1.5" will return 15 781c1d255d3SCy Schubert */ 782c1d255d3SCy Schubert static int hostapd_config_read_int10(const char *value) 783c1d255d3SCy Schubert { 784c1d255d3SCy Schubert int i, d; 785c1d255d3SCy Schubert char *pos; 786c1d255d3SCy Schubert 787c1d255d3SCy Schubert i = atoi(value); 788c1d255d3SCy Schubert pos = os_strchr(value, '.'); 789c1d255d3SCy Schubert d = 0; 790c1d255d3SCy Schubert if (pos) { 791c1d255d3SCy Schubert pos++; 792c1d255d3SCy Schubert if (*pos >= '0' && *pos <= '9') 793c1d255d3SCy Schubert d = *pos - '0'; 794c1d255d3SCy Schubert } 795c1d255d3SCy Schubert 796c1d255d3SCy Schubert return i * 10 + d; 797c1d255d3SCy Schubert } 798c1d255d3SCy Schubert 799c1d255d3SCy Schubert 800c1d255d3SCy Schubert static int valid_cw(int cw) 801c1d255d3SCy Schubert { 802c1d255d3SCy Schubert return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 || 803c1d255d3SCy Schubert cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 || 804c1d255d3SCy Schubert cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 || 805c1d255d3SCy Schubert cw == 32767); 806c1d255d3SCy Schubert } 807c1d255d3SCy Schubert 808c1d255d3SCy Schubert 809c1d255d3SCy Schubert int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[], 810c1d255d3SCy Schubert const char *name, const char *val) 811c1d255d3SCy Schubert { 812c1d255d3SCy Schubert int num; 813c1d255d3SCy Schubert const char *pos; 814c1d255d3SCy Schubert struct hostapd_tx_queue_params *queue; 815c1d255d3SCy Schubert 816c1d255d3SCy Schubert /* skip 'tx_queue_' prefix */ 817c1d255d3SCy Schubert pos = name + 9; 818c1d255d3SCy Schubert if (os_strncmp(pos, "data", 4) == 0 && 819c1d255d3SCy Schubert pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') { 820c1d255d3SCy Schubert num = pos[4] - '0'; 821c1d255d3SCy Schubert pos += 6; 822c1d255d3SCy Schubert } else if (os_strncmp(pos, "after_beacon_", 13) == 0 || 823c1d255d3SCy Schubert os_strncmp(pos, "beacon_", 7) == 0) { 824c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); 825c1d255d3SCy Schubert return 0; 826c1d255d3SCy Schubert } else { 827c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos); 828c1d255d3SCy Schubert return -1; 829c1d255d3SCy Schubert } 830c1d255d3SCy Schubert 831c1d255d3SCy Schubert if (num >= NUM_TX_QUEUES) { 832c1d255d3SCy Schubert /* for backwards compatibility, do not trigger failure */ 833c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); 834c1d255d3SCy Schubert return 0; 835c1d255d3SCy Schubert } 836c1d255d3SCy Schubert 837c1d255d3SCy Schubert queue = &tx_queue[num]; 838c1d255d3SCy Schubert 839c1d255d3SCy Schubert if (os_strcmp(pos, "aifs") == 0) { 840c1d255d3SCy Schubert queue->aifs = atoi(val); 841c1d255d3SCy Schubert if (queue->aifs < 0 || queue->aifs > 255) { 842c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Invalid AIFS value %d", 843c1d255d3SCy Schubert queue->aifs); 844c1d255d3SCy Schubert return -1; 845c1d255d3SCy Schubert } 846c1d255d3SCy Schubert } else if (os_strcmp(pos, "cwmin") == 0) { 847c1d255d3SCy Schubert queue->cwmin = atoi(val); 848c1d255d3SCy Schubert if (!valid_cw(queue->cwmin)) { 849c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Invalid cwMin value %d", 850c1d255d3SCy Schubert queue->cwmin); 851c1d255d3SCy Schubert return -1; 852c1d255d3SCy Schubert } 853c1d255d3SCy Schubert } else if (os_strcmp(pos, "cwmax") == 0) { 854c1d255d3SCy Schubert queue->cwmax = atoi(val); 855c1d255d3SCy Schubert if (!valid_cw(queue->cwmax)) { 856c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Invalid cwMax value %d", 857c1d255d3SCy Schubert queue->cwmax); 858c1d255d3SCy Schubert return -1; 859c1d255d3SCy Schubert } 860c1d255d3SCy Schubert } else if (os_strcmp(pos, "burst") == 0) { 861c1d255d3SCy Schubert queue->burst = hostapd_config_read_int10(val); 862c1d255d3SCy Schubert } else { 863c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos); 864c1d255d3SCy Schubert return -1; 865c1d255d3SCy Schubert } 866c1d255d3SCy Schubert 867c1d255d3SCy Schubert return 0; 868c1d255d3SCy Schubert } 869c1d255d3SCy Schubert 870c1d255d3SCy Schubert 8715b9c547cSRui Paulo enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) 8725b9c547cSRui Paulo { 873325151a3SRui Paulo u8 op_class; 874325151a3SRui Paulo 875206b73d0SCy Schubert return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT, 876780fb4a2SCy Schubert &op_class, channel); 877325151a3SRui Paulo } 878325151a3SRui Paulo 879325151a3SRui Paulo 880325151a3SRui Paulo /** 881325151a3SRui Paulo * ieee80211_freq_to_channel_ext - Convert frequency into channel info 882c1d255d3SCy Schubert * for HT40, VHT, and HE. DFS channels are not covered. 883325151a3SRui Paulo * @freq: Frequency (MHz) to convert 884325151a3SRui Paulo * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below 885c1d255d3SCy Schubert * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*) 886325151a3SRui Paulo * @op_class: Buffer for returning operating class 887325151a3SRui Paulo * @channel: Buffer for returning channel number 888325151a3SRui Paulo * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure 889325151a3SRui Paulo */ 890325151a3SRui Paulo enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, 891c1d255d3SCy Schubert int sec_channel, 892c1d255d3SCy Schubert int chanwidth, 893325151a3SRui Paulo u8 *op_class, u8 *channel) 894325151a3SRui Paulo { 895780fb4a2SCy Schubert u8 vht_opclass; 896780fb4a2SCy Schubert 897325151a3SRui Paulo /* TODO: more operating classes */ 898325151a3SRui Paulo 899325151a3SRui Paulo if (sec_channel > 1 || sec_channel < -1) 900325151a3SRui Paulo return NUM_HOSTAPD_MODES; 9015b9c547cSRui Paulo 9025b9c547cSRui Paulo if (freq >= 2412 && freq <= 2472) { 903325151a3SRui Paulo if ((freq - 2407) % 5) 904325151a3SRui Paulo return NUM_HOSTAPD_MODES; 905325151a3SRui Paulo 906c1d255d3SCy Schubert if (chanwidth) 907325151a3SRui Paulo return NUM_HOSTAPD_MODES; 908325151a3SRui Paulo 909325151a3SRui Paulo /* 2.407 GHz, channels 1..13 */ 910325151a3SRui Paulo if (sec_channel == 1) 911325151a3SRui Paulo *op_class = 83; 912325151a3SRui Paulo else if (sec_channel == -1) 913325151a3SRui Paulo *op_class = 84; 914325151a3SRui Paulo else 915325151a3SRui Paulo *op_class = 81; 916325151a3SRui Paulo 9175b9c547cSRui Paulo *channel = (freq - 2407) / 5; 918325151a3SRui Paulo 919325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211G; 920325151a3SRui Paulo } 921325151a3SRui Paulo 922325151a3SRui Paulo if (freq == 2484) { 923c1d255d3SCy Schubert if (sec_channel || chanwidth) 924325151a3SRui Paulo return NUM_HOSTAPD_MODES; 925325151a3SRui Paulo 926325151a3SRui Paulo *op_class = 82; /* channel 14 */ 9275b9c547cSRui Paulo *channel = 14; 928325151a3SRui Paulo 929325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211B; 930325151a3SRui Paulo } 931325151a3SRui Paulo 932325151a3SRui Paulo if (freq >= 4900 && freq < 5000) { 933325151a3SRui Paulo if ((freq - 4000) % 5) 934325151a3SRui Paulo return NUM_HOSTAPD_MODES; 9355b9c547cSRui Paulo *channel = (freq - 4000) / 5; 936325151a3SRui Paulo *op_class = 0; /* TODO */ 937325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 938325151a3SRui Paulo } 939325151a3SRui Paulo 940c1d255d3SCy Schubert switch (chanwidth) { 941206b73d0SCy Schubert case CHANWIDTH_80MHZ: 942780fb4a2SCy Schubert vht_opclass = 128; 943780fb4a2SCy Schubert break; 944206b73d0SCy Schubert case CHANWIDTH_160MHZ: 945780fb4a2SCy Schubert vht_opclass = 129; 946780fb4a2SCy Schubert break; 947206b73d0SCy Schubert case CHANWIDTH_80P80MHZ: 948780fb4a2SCy Schubert vht_opclass = 130; 949780fb4a2SCy Schubert break; 950780fb4a2SCy Schubert default: 951780fb4a2SCy Schubert vht_opclass = 0; 952780fb4a2SCy Schubert break; 953780fb4a2SCy Schubert } 954780fb4a2SCy Schubert 955325151a3SRui Paulo /* 5 GHz, channels 36..48 */ 956325151a3SRui Paulo if (freq >= 5180 && freq <= 5240) { 957325151a3SRui Paulo if ((freq - 5000) % 5) 958325151a3SRui Paulo return NUM_HOSTAPD_MODES; 959325151a3SRui Paulo 960780fb4a2SCy Schubert if (vht_opclass) 961780fb4a2SCy Schubert *op_class = vht_opclass; 962780fb4a2SCy Schubert else if (sec_channel == 1) 963325151a3SRui Paulo *op_class = 116; 964325151a3SRui Paulo else if (sec_channel == -1) 965325151a3SRui Paulo *op_class = 117; 966325151a3SRui Paulo else 967325151a3SRui Paulo *op_class = 115; 968325151a3SRui Paulo 9695b9c547cSRui Paulo *channel = (freq - 5000) / 5; 970325151a3SRui Paulo 971325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 972325151a3SRui Paulo } 973325151a3SRui Paulo 97485732ac8SCy Schubert /* 5 GHz, channels 52..64 */ 97585732ac8SCy Schubert if (freq >= 5260 && freq <= 5320) { 97685732ac8SCy Schubert if ((freq - 5000) % 5) 97785732ac8SCy Schubert return NUM_HOSTAPD_MODES; 97885732ac8SCy Schubert 97985732ac8SCy Schubert if (vht_opclass) 98085732ac8SCy Schubert *op_class = vht_opclass; 98185732ac8SCy Schubert else if (sec_channel == 1) 98285732ac8SCy Schubert *op_class = 119; 98385732ac8SCy Schubert else if (sec_channel == -1) 98485732ac8SCy Schubert *op_class = 120; 98585732ac8SCy Schubert else 98685732ac8SCy Schubert *op_class = 118; 98785732ac8SCy Schubert 98885732ac8SCy Schubert *channel = (freq - 5000) / 5; 98985732ac8SCy Schubert 99085732ac8SCy Schubert return HOSTAPD_MODE_IEEE80211A; 99185732ac8SCy Schubert } 99285732ac8SCy Schubert 993c1d255d3SCy Schubert /* 5 GHz, channels 149..177 */ 994c1d255d3SCy Schubert if (freq >= 5745 && freq <= 5885) { 995325151a3SRui Paulo if ((freq - 5000) % 5) 996325151a3SRui Paulo return NUM_HOSTAPD_MODES; 997325151a3SRui Paulo 998780fb4a2SCy Schubert if (vht_opclass) 999780fb4a2SCy Schubert *op_class = vht_opclass; 1000780fb4a2SCy Schubert else if (sec_channel == 1) 1001780fb4a2SCy Schubert *op_class = 126; 1002780fb4a2SCy Schubert else if (sec_channel == -1) 1003780fb4a2SCy Schubert *op_class = 127; 1004780fb4a2SCy Schubert else if (freq <= 5805) 1005780fb4a2SCy Schubert *op_class = 124; 1006780fb4a2SCy Schubert else 1007325151a3SRui Paulo *op_class = 125; 1008325151a3SRui Paulo 1009325151a3SRui Paulo *channel = (freq - 5000) / 5; 1010325151a3SRui Paulo 1011325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 1012325151a3SRui Paulo } 1013325151a3SRui Paulo 1014*4b72b91aSCy Schubert /* 5 GHz, channels 100..144 */ 1015*4b72b91aSCy Schubert if (freq >= 5500 && freq <= 5720) { 1016780fb4a2SCy Schubert if ((freq - 5000) % 5) 1017780fb4a2SCy Schubert return NUM_HOSTAPD_MODES; 1018780fb4a2SCy Schubert 1019780fb4a2SCy Schubert if (vht_opclass) 1020780fb4a2SCy Schubert *op_class = vht_opclass; 1021780fb4a2SCy Schubert else if (sec_channel == 1) 1022780fb4a2SCy Schubert *op_class = 122; 1023780fb4a2SCy Schubert else if (sec_channel == -1) 1024780fb4a2SCy Schubert *op_class = 123; 1025780fb4a2SCy Schubert else 1026780fb4a2SCy Schubert *op_class = 121; 1027780fb4a2SCy Schubert 1028780fb4a2SCy Schubert *channel = (freq - 5000) / 5; 1029780fb4a2SCy Schubert 1030780fb4a2SCy Schubert return HOSTAPD_MODE_IEEE80211A; 1031780fb4a2SCy Schubert } 1032780fb4a2SCy Schubert 1033325151a3SRui Paulo if (freq >= 5000 && freq < 5900) { 1034325151a3SRui Paulo if ((freq - 5000) % 5) 1035325151a3SRui Paulo return NUM_HOSTAPD_MODES; 1036325151a3SRui Paulo *channel = (freq - 5000) / 5; 1037325151a3SRui Paulo *op_class = 0; /* TODO */ 1038325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 1039325151a3SRui Paulo } 1040325151a3SRui Paulo 1041c1d255d3SCy Schubert if (freq > 5950 && freq <= 7115) { 1042c1d255d3SCy Schubert if ((freq - 5950) % 5) 1043325151a3SRui Paulo return NUM_HOSTAPD_MODES; 1044325151a3SRui Paulo 1045c1d255d3SCy Schubert switch (chanwidth) { 1046c1d255d3SCy Schubert case CHANWIDTH_80MHZ: 1047c1d255d3SCy Schubert *op_class = 133; 1048c1d255d3SCy Schubert break; 1049c1d255d3SCy Schubert case CHANWIDTH_160MHZ: 1050c1d255d3SCy Schubert *op_class = 134; 1051c1d255d3SCy Schubert break; 1052c1d255d3SCy Schubert case CHANWIDTH_80P80MHZ: 1053c1d255d3SCy Schubert *op_class = 135; 1054c1d255d3SCy Schubert break; 1055c1d255d3SCy Schubert default: 1056c1d255d3SCy Schubert if (sec_channel) 1057c1d255d3SCy Schubert *op_class = 132; 1058c1d255d3SCy Schubert else 1059c1d255d3SCy Schubert *op_class = 131; 1060c1d255d3SCy Schubert break; 1061c1d255d3SCy Schubert } 1062c1d255d3SCy Schubert 1063c1d255d3SCy Schubert *channel = (freq - 5950) / 5; 1064c1d255d3SCy Schubert return HOSTAPD_MODE_IEEE80211A; 1065c1d255d3SCy Schubert } 1066c1d255d3SCy Schubert 1067c1d255d3SCy Schubert if (freq == 5935) { 1068c1d255d3SCy Schubert *op_class = 136; 1069c1d255d3SCy Schubert *channel = (freq - 5925) / 5; 1070c1d255d3SCy Schubert return HOSTAPD_MODE_IEEE80211A; 1071c1d255d3SCy Schubert } 1072c1d255d3SCy Schubert 1073c1d255d3SCy Schubert /* 56.16 GHz, channel 1..6 */ 1074c1d255d3SCy Schubert if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) { 1075c1d255d3SCy Schubert if (sec_channel) 1076c1d255d3SCy Schubert return NUM_HOSTAPD_MODES; 1077c1d255d3SCy Schubert 1078c1d255d3SCy Schubert switch (chanwidth) { 1079c1d255d3SCy Schubert case CHANWIDTH_USE_HT: 1080c1d255d3SCy Schubert case CHANWIDTH_2160MHZ: 10815b9c547cSRui Paulo *channel = (freq - 56160) / 2160; 1082325151a3SRui Paulo *op_class = 180; 1083c1d255d3SCy Schubert break; 1084c1d255d3SCy Schubert case CHANWIDTH_4320MHZ: 1085c1d255d3SCy Schubert /* EDMG channels 9 - 13 */ 1086c1d255d3SCy Schubert if (freq > 56160 + 2160 * 5) 1087c1d255d3SCy Schubert return NUM_HOSTAPD_MODES; 1088c1d255d3SCy Schubert 1089c1d255d3SCy Schubert *channel = (freq - 56160) / 2160 + 8; 1090c1d255d3SCy Schubert *op_class = 181; 1091c1d255d3SCy Schubert break; 1092c1d255d3SCy Schubert case CHANWIDTH_6480MHZ: 1093c1d255d3SCy Schubert /* EDMG channels 17 - 20 */ 1094c1d255d3SCy Schubert if (freq > 56160 + 2160 * 4) 1095c1d255d3SCy Schubert return NUM_HOSTAPD_MODES; 1096c1d255d3SCy Schubert 1097c1d255d3SCy Schubert *channel = (freq - 56160) / 2160 + 16; 1098c1d255d3SCy Schubert *op_class = 182; 1099c1d255d3SCy Schubert break; 1100c1d255d3SCy Schubert case CHANWIDTH_8640MHZ: 1101c1d255d3SCy Schubert /* EDMG channels 25 - 27 */ 1102c1d255d3SCy Schubert if (freq > 56160 + 2160 * 3) 1103c1d255d3SCy Schubert return NUM_HOSTAPD_MODES; 1104c1d255d3SCy Schubert 1105c1d255d3SCy Schubert *channel = (freq - 56160) / 2160 + 24; 1106c1d255d3SCy Schubert *op_class = 183; 1107c1d255d3SCy Schubert break; 1108c1d255d3SCy Schubert default: 1109c1d255d3SCy Schubert return NUM_HOSTAPD_MODES; 1110c1d255d3SCy Schubert } 1111325151a3SRui Paulo 1112325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211AD; 11135b9c547cSRui Paulo } 11145b9c547cSRui Paulo 1115325151a3SRui Paulo return NUM_HOSTAPD_MODES; 11165b9c547cSRui Paulo } 11175b9c547cSRui Paulo 11185b9c547cSRui Paulo 11194bc52338SCy Schubert int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, 11204bc52338SCy Schubert int sec_channel, u8 *op_class, u8 *channel) 11214bc52338SCy Schubert { 1122c1d255d3SCy Schubert int cw = CHAN_WIDTH_UNKNOWN; 11234bc52338SCy Schubert 11244bc52338SCy Schubert switch (chanwidth) { 11254bc52338SCy Schubert case CHAN_WIDTH_UNKNOWN: 11264bc52338SCy Schubert case CHAN_WIDTH_20_NOHT: 11274bc52338SCy Schubert case CHAN_WIDTH_20: 11284bc52338SCy Schubert case CHAN_WIDTH_40: 1129c1d255d3SCy Schubert cw = CHANWIDTH_USE_HT; 11304bc52338SCy Schubert break; 11314bc52338SCy Schubert case CHAN_WIDTH_80: 1132c1d255d3SCy Schubert cw = CHANWIDTH_80MHZ; 11334bc52338SCy Schubert break; 11344bc52338SCy Schubert case CHAN_WIDTH_80P80: 1135c1d255d3SCy Schubert cw = CHANWIDTH_80P80MHZ; 11364bc52338SCy Schubert break; 11374bc52338SCy Schubert case CHAN_WIDTH_160: 1138c1d255d3SCy Schubert cw = CHANWIDTH_160MHZ; 1139c1d255d3SCy Schubert break; 1140c1d255d3SCy Schubert case CHAN_WIDTH_2160: 1141c1d255d3SCy Schubert cw = CHANWIDTH_2160MHZ; 1142c1d255d3SCy Schubert break; 1143c1d255d3SCy Schubert case CHAN_WIDTH_4320: 1144c1d255d3SCy Schubert cw = CHANWIDTH_4320MHZ; 1145c1d255d3SCy Schubert break; 1146c1d255d3SCy Schubert case CHAN_WIDTH_6480: 1147c1d255d3SCy Schubert cw = CHANWIDTH_6480MHZ; 1148c1d255d3SCy Schubert break; 1149c1d255d3SCy Schubert case CHAN_WIDTH_8640: 1150c1d255d3SCy Schubert cw = CHANWIDTH_8640MHZ; 11514bc52338SCy Schubert break; 11524bc52338SCy Schubert } 11534bc52338SCy Schubert 1154c1d255d3SCy Schubert if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class, 11554bc52338SCy Schubert channel) == NUM_HOSTAPD_MODES) { 11564bc52338SCy Schubert wpa_printf(MSG_WARNING, 11574bc52338SCy Schubert "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)", 11584bc52338SCy Schubert freq, chanwidth, sec_channel); 11594bc52338SCy Schubert return -1; 11604bc52338SCy Schubert } 11614bc52338SCy Schubert 11624bc52338SCy Schubert return 0; 11634bc52338SCy Schubert } 11644bc52338SCy Schubert 11654bc52338SCy Schubert 1166325151a3SRui Paulo static const char *const us_op_class_cc[] = { 11675b9c547cSRui Paulo "US", "CA", NULL 11685b9c547cSRui Paulo }; 11695b9c547cSRui Paulo 1170325151a3SRui Paulo static const char *const eu_op_class_cc[] = { 11715b9c547cSRui Paulo "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", 11725b9c547cSRui Paulo "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT", 11735b9c547cSRui Paulo "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", 11745b9c547cSRui Paulo "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL 11755b9c547cSRui Paulo }; 11765b9c547cSRui Paulo 1177325151a3SRui Paulo static const char *const jp_op_class_cc[] = { 11785b9c547cSRui Paulo "JP", NULL 11795b9c547cSRui Paulo }; 11805b9c547cSRui Paulo 1181325151a3SRui Paulo static const char *const cn_op_class_cc[] = { 1182325151a3SRui Paulo "CN", NULL 11835b9c547cSRui Paulo }; 11845b9c547cSRui Paulo 11855b9c547cSRui Paulo 1186325151a3SRui Paulo static int country_match(const char *const cc[], const char *const country) 11875b9c547cSRui Paulo { 11885b9c547cSRui Paulo int i; 11895b9c547cSRui Paulo 11905b9c547cSRui Paulo if (country == NULL) 11915b9c547cSRui Paulo return 0; 11925b9c547cSRui Paulo for (i = 0; cc[i]; i++) { 11935b9c547cSRui Paulo if (cc[i][0] == country[0] && cc[i][1] == country[1]) 11945b9c547cSRui Paulo return 1; 11955b9c547cSRui Paulo } 11965b9c547cSRui Paulo 11975b9c547cSRui Paulo return 0; 11985b9c547cSRui Paulo } 11995b9c547cSRui Paulo 12005b9c547cSRui Paulo 12015b9c547cSRui Paulo static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan) 12025b9c547cSRui Paulo { 12035b9c547cSRui Paulo switch (op_class) { 12045b9c547cSRui Paulo case 12: /* channels 1..11 */ 12055b9c547cSRui Paulo case 32: /* channels 1..7; 40 MHz */ 12065b9c547cSRui Paulo case 33: /* channels 5..11; 40 MHz */ 12075b9c547cSRui Paulo if (chan < 1 || chan > 11) 12085b9c547cSRui Paulo return -1; 12095b9c547cSRui Paulo return 2407 + 5 * chan; 12105b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 12115b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 12125b9c547cSRui Paulo case 22: /* channels 36,44; 40 MHz */ 12135b9c547cSRui Paulo case 23: /* channels 52,60; 40 MHz */ 12145b9c547cSRui Paulo case 27: /* channels 40,48; 40 MHz */ 12155b9c547cSRui Paulo case 28: /* channels 56,64; 40 MHz */ 12165b9c547cSRui Paulo if (chan < 36 || chan > 64) 12175b9c547cSRui Paulo return -1; 12185b9c547cSRui Paulo return 5000 + 5 * chan; 12195b9c547cSRui Paulo case 4: /* channels 100-144 */ 12205b9c547cSRui Paulo case 24: /* channels 100-140; 40 MHz */ 12215b9c547cSRui Paulo if (chan < 100 || chan > 144) 12225b9c547cSRui Paulo return -1; 12235b9c547cSRui Paulo return 5000 + 5 * chan; 12245b9c547cSRui Paulo case 3: /* channels 149,153,157,161 */ 12255b9c547cSRui Paulo case 25: /* channels 149,157; 40 MHz */ 12265b9c547cSRui Paulo case 26: /* channels 149,157; 40 MHz */ 12275b9c547cSRui Paulo case 30: /* channels 153,161; 40 MHz */ 12285b9c547cSRui Paulo case 31: /* channels 153,161; 40 MHz */ 12295b9c547cSRui Paulo if (chan < 149 || chan > 161) 12305b9c547cSRui Paulo return -1; 12315b9c547cSRui Paulo return 5000 + 5 * chan; 1232325151a3SRui Paulo case 5: /* channels 149,153,157,161,165 */ 1233325151a3SRui Paulo if (chan < 149 || chan > 165) 1234325151a3SRui Paulo return -1; 1235325151a3SRui Paulo return 5000 + 5 * chan; 1236c1d255d3SCy Schubert case 34: /* 60 GHz band, channels 1..8 */ 1237c1d255d3SCy Schubert if (chan < 1 || chan > 8) 12385b9c547cSRui Paulo return -1; 12395b9c547cSRui Paulo return 56160 + 2160 * chan; 1240c1d255d3SCy Schubert case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */ 1241c1d255d3SCy Schubert if (chan < 9 || chan > 15) 1242c1d255d3SCy Schubert return -1; 1243c1d255d3SCy Schubert return 56160 + 2160 * (chan - 8); 1244c1d255d3SCy Schubert case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */ 1245c1d255d3SCy Schubert if (chan < 17 || chan > 22) 1246c1d255d3SCy Schubert return -1; 1247c1d255d3SCy Schubert return 56160 + 2160 * (chan - 16); 1248c1d255d3SCy Schubert case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */ 1249c1d255d3SCy Schubert if (chan < 25 || chan > 29) 1250c1d255d3SCy Schubert return -1; 1251c1d255d3SCy Schubert return 56160 + 2160 * (chan - 24); 12525b9c547cSRui Paulo } 12535b9c547cSRui Paulo return -1; 12545b9c547cSRui Paulo } 12555b9c547cSRui Paulo 12565b9c547cSRui Paulo 12575b9c547cSRui Paulo static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan) 12585b9c547cSRui Paulo { 12595b9c547cSRui Paulo switch (op_class) { 12605b9c547cSRui Paulo case 4: /* channels 1..13 */ 12615b9c547cSRui Paulo case 11: /* channels 1..9; 40 MHz */ 12625b9c547cSRui Paulo case 12: /* channels 5..13; 40 MHz */ 12635b9c547cSRui Paulo if (chan < 1 || chan > 13) 12645b9c547cSRui Paulo return -1; 12655b9c547cSRui Paulo return 2407 + 5 * chan; 12665b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 12675b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 12685b9c547cSRui Paulo case 5: /* channels 36,44; 40 MHz */ 12695b9c547cSRui Paulo case 6: /* channels 52,60; 40 MHz */ 12705b9c547cSRui Paulo case 8: /* channels 40,48; 40 MHz */ 12715b9c547cSRui Paulo case 9: /* channels 56,64; 40 MHz */ 12725b9c547cSRui Paulo if (chan < 36 || chan > 64) 12735b9c547cSRui Paulo return -1; 12745b9c547cSRui Paulo return 5000 + 5 * chan; 12755b9c547cSRui Paulo case 3: /* channels 100-140 */ 12765b9c547cSRui Paulo case 7: /* channels 100-132; 40 MHz */ 12775b9c547cSRui Paulo case 10: /* channels 104-136; 40 MHz */ 12785b9c547cSRui Paulo case 16: /* channels 100-140 */ 12795b9c547cSRui Paulo if (chan < 100 || chan > 140) 12805b9c547cSRui Paulo return -1; 12815b9c547cSRui Paulo return 5000 + 5 * chan; 12825b9c547cSRui Paulo case 17: /* channels 149,153,157,161,165,169 */ 12835b9c547cSRui Paulo if (chan < 149 || chan > 169) 12845b9c547cSRui Paulo return -1; 12855b9c547cSRui Paulo return 5000 + 5 * chan; 1286c1d255d3SCy Schubert case 18: /* 60 GHz band, channels 1..6 */ 1287c1d255d3SCy Schubert if (chan < 1 || chan > 6) 12885b9c547cSRui Paulo return -1; 12895b9c547cSRui Paulo return 56160 + 2160 * chan; 1290c1d255d3SCy Schubert case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */ 1291c1d255d3SCy Schubert if (chan < 9 || chan > 11) 1292c1d255d3SCy Schubert return -1; 1293c1d255d3SCy Schubert return 56160 + 2160 * (chan - 8); 1294c1d255d3SCy Schubert case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */ 1295c1d255d3SCy Schubert if (chan < 17 || chan > 18) 1296c1d255d3SCy Schubert return -1; 1297c1d255d3SCy Schubert return 56160 + 2160 * (chan - 16); 1298c1d255d3SCy Schubert case 23: /* 60 GHz band, EDMG CB4, channels 25 */ 1299c1d255d3SCy Schubert if (chan != 25) 1300c1d255d3SCy Schubert return -1; 1301c1d255d3SCy Schubert return 56160 + 2160 * (chan - 24); 13025b9c547cSRui Paulo } 13035b9c547cSRui Paulo return -1; 13045b9c547cSRui Paulo } 13055b9c547cSRui Paulo 13065b9c547cSRui Paulo 13075b9c547cSRui Paulo static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) 13085b9c547cSRui Paulo { 13095b9c547cSRui Paulo switch (op_class) { 13105b9c547cSRui Paulo case 30: /* channels 1..13 */ 13115b9c547cSRui Paulo case 56: /* channels 1..9; 40 MHz */ 13125b9c547cSRui Paulo case 57: /* channels 5..13; 40 MHz */ 13135b9c547cSRui Paulo if (chan < 1 || chan > 13) 13145b9c547cSRui Paulo return -1; 13155b9c547cSRui Paulo return 2407 + 5 * chan; 13165b9c547cSRui Paulo case 31: /* channel 14 */ 13175b9c547cSRui Paulo if (chan != 14) 13185b9c547cSRui Paulo return -1; 13195b9c547cSRui Paulo return 2414 + 5 * chan; 13205b9c547cSRui Paulo case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */ 13215b9c547cSRui Paulo case 32: /* channels 52,56,60,64 */ 13225b9c547cSRui Paulo case 33: /* channels 52,56,60,64 */ 13235b9c547cSRui Paulo case 36: /* channels 36,44; 40 MHz */ 13245b9c547cSRui Paulo case 37: /* channels 52,60; 40 MHz */ 13255b9c547cSRui Paulo case 38: /* channels 52,60; 40 MHz */ 13265b9c547cSRui Paulo case 41: /* channels 40,48; 40 MHz */ 13275b9c547cSRui Paulo case 42: /* channels 56,64; 40 MHz */ 13285b9c547cSRui Paulo case 43: /* channels 56,64; 40 MHz */ 13295b9c547cSRui Paulo if (chan < 34 || chan > 64) 13305b9c547cSRui Paulo return -1; 13315b9c547cSRui Paulo return 5000 + 5 * chan; 13325b9c547cSRui Paulo case 34: /* channels 100-140 */ 13335b9c547cSRui Paulo case 35: /* channels 100-140 */ 13345b9c547cSRui Paulo case 39: /* channels 100-132; 40 MHz */ 13355b9c547cSRui Paulo case 40: /* channels 100-132; 40 MHz */ 13365b9c547cSRui Paulo case 44: /* channels 104-136; 40 MHz */ 13375b9c547cSRui Paulo case 45: /* channels 104-136; 40 MHz */ 13385b9c547cSRui Paulo case 58: /* channels 100-140 */ 13395b9c547cSRui Paulo if (chan < 100 || chan > 140) 13405b9c547cSRui Paulo return -1; 13415b9c547cSRui Paulo return 5000 + 5 * chan; 1342c1d255d3SCy Schubert case 59: /* 60 GHz band, channels 1..6 */ 1343c1d255d3SCy Schubert if (chan < 1 || chan > 6) 13445b9c547cSRui Paulo return -1; 13455b9c547cSRui Paulo return 56160 + 2160 * chan; 1346c1d255d3SCy Schubert case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */ 1347c1d255d3SCy Schubert if (chan < 9 || chan > 11) 1348c1d255d3SCy Schubert return -1; 1349c1d255d3SCy Schubert return 56160 + 2160 * (chan - 8); 1350c1d255d3SCy Schubert case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */ 1351c1d255d3SCy Schubert if (chan < 17 || chan > 18) 1352c1d255d3SCy Schubert return -1; 1353c1d255d3SCy Schubert return 56160 + 2160 * (chan - 16); 1354c1d255d3SCy Schubert case 64: /* 60 GHz band, EDMG CB4, channel 25 */ 1355c1d255d3SCy Schubert if (chan != 25) 1356c1d255d3SCy Schubert return -1; 1357c1d255d3SCy Schubert return 56160 + 2160 * (chan - 24); 13585b9c547cSRui Paulo } 13595b9c547cSRui Paulo return -1; 13605b9c547cSRui Paulo } 13615b9c547cSRui Paulo 13625b9c547cSRui Paulo 13635b9c547cSRui Paulo static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan) 13645b9c547cSRui Paulo { 13655b9c547cSRui Paulo switch (op_class) { 13665b9c547cSRui Paulo case 7: /* channels 1..13 */ 13675b9c547cSRui Paulo case 8: /* channels 1..9; 40 MHz */ 13685b9c547cSRui Paulo case 9: /* channels 5..13; 40 MHz */ 13695b9c547cSRui Paulo if (chan < 1 || chan > 13) 13705b9c547cSRui Paulo return -1; 13715b9c547cSRui Paulo return 2407 + 5 * chan; 13725b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 13735b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 13745b9c547cSRui Paulo case 4: /* channels 36,44; 40 MHz */ 13755b9c547cSRui Paulo case 5: /* channels 52,60; 40 MHz */ 13765b9c547cSRui Paulo if (chan < 36 || chan > 64) 13775b9c547cSRui Paulo return -1; 13785b9c547cSRui Paulo return 5000 + 5 * chan; 13795b9c547cSRui Paulo case 3: /* channels 149,153,157,161,165 */ 13805b9c547cSRui Paulo case 6: /* channels 149,157; 40 MHz */ 13815b9c547cSRui Paulo if (chan < 149 || chan > 165) 13825b9c547cSRui Paulo return -1; 13835b9c547cSRui Paulo return 5000 + 5 * chan; 13845b9c547cSRui Paulo } 13855b9c547cSRui Paulo return -1; 13865b9c547cSRui Paulo } 13875b9c547cSRui Paulo 13885b9c547cSRui Paulo 13895b9c547cSRui Paulo static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) 13905b9c547cSRui Paulo { 13915b9c547cSRui Paulo /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ 13925b9c547cSRui Paulo switch (op_class) { 13935b9c547cSRui Paulo case 81: 13945b9c547cSRui Paulo /* channels 1..13 */ 13955b9c547cSRui Paulo if (chan < 1 || chan > 13) 13965b9c547cSRui Paulo return -1; 13975b9c547cSRui Paulo return 2407 + 5 * chan; 13985b9c547cSRui Paulo case 82: 13995b9c547cSRui Paulo /* channel 14 */ 14005b9c547cSRui Paulo if (chan != 14) 14015b9c547cSRui Paulo return -1; 14025b9c547cSRui Paulo return 2414 + 5 * chan; 14035b9c547cSRui Paulo case 83: /* channels 1..9; 40 MHz */ 14045b9c547cSRui Paulo case 84: /* channels 5..13; 40 MHz */ 14055b9c547cSRui Paulo if (chan < 1 || chan > 13) 14065b9c547cSRui Paulo return -1; 14075b9c547cSRui Paulo return 2407 + 5 * chan; 14085b9c547cSRui Paulo case 115: /* channels 36,40,44,48; indoor only */ 14095b9c547cSRui Paulo case 116: /* channels 36,44; 40 MHz; indoor only */ 14105b9c547cSRui Paulo case 117: /* channels 40,48; 40 MHz; indoor only */ 14115b9c547cSRui Paulo case 118: /* channels 52,56,60,64; dfs */ 14125b9c547cSRui Paulo case 119: /* channels 52,60; 40 MHz; dfs */ 14135b9c547cSRui Paulo case 120: /* channels 56,64; 40 MHz; dfs */ 14145b9c547cSRui Paulo if (chan < 36 || chan > 64) 14155b9c547cSRui Paulo return -1; 14165b9c547cSRui Paulo return 5000 + 5 * chan; 14175b9c547cSRui Paulo case 121: /* channels 100-140 */ 14185b9c547cSRui Paulo case 122: /* channels 100-142; 40 MHz */ 14195b9c547cSRui Paulo case 123: /* channels 104-136; 40 MHz */ 14205b9c547cSRui Paulo if (chan < 100 || chan > 140) 14215b9c547cSRui Paulo return -1; 14225b9c547cSRui Paulo return 5000 + 5 * chan; 14235b9c547cSRui Paulo case 124: /* channels 149,153,157,161 */ 14245b9c547cSRui Paulo if (chan < 149 || chan > 161) 14255b9c547cSRui Paulo return -1; 14265b9c547cSRui Paulo return 5000 + 5 * chan; 1427c1d255d3SCy Schubert case 125: /* channels 149,153,157,161,165,169,173,177 */ 1428c1d255d3SCy Schubert case 126: /* channels 149,157,165,173; 40 MHz */ 1429c1d255d3SCy Schubert case 127: /* channels 153,161,169,177; 40 MHz */ 1430c1d255d3SCy Schubert if (chan < 149 || chan > 177) 1431325151a3SRui Paulo return -1; 1432325151a3SRui Paulo return 5000 + 5 * chan; 1433c1d255d3SCy Schubert case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */ 1434c1d255d3SCy Schubert case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */ 1435c1d255d3SCy Schubert if (chan < 36 || chan > 177) 14365b9c547cSRui Paulo return -1; 14375b9c547cSRui Paulo return 5000 + 5 * chan; 1438c1d255d3SCy Schubert case 129: /* center freqs 50, 114, 163; 160 MHz */ 1439c1d255d3SCy Schubert if (chan < 36 || chan > 177) 14405b9c547cSRui Paulo return -1; 14415b9c547cSRui Paulo return 5000 + 5 * chan; 1442c1d255d3SCy Schubert case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */ 1443c1d255d3SCy Schubert case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */ 1444c1d255d3SCy Schubert case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */ 1445c1d255d3SCy Schubert case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */ 1446c1d255d3SCy Schubert case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ 1447c1d255d3SCy Schubert if (chan < 1 || chan > 233) 1448c1d255d3SCy Schubert return -1; 1449c1d255d3SCy Schubert return 5950 + chan * 5; 1450c1d255d3SCy Schubert case 136: /* UHB channels, 20 MHz: 2 */ 1451c1d255d3SCy Schubert if (chan == 2) 1452c1d255d3SCy Schubert return 5935; 1453c1d255d3SCy Schubert return -1; 1454c1d255d3SCy Schubert case 180: /* 60 GHz band, channels 1..8 */ 1455c1d255d3SCy Schubert if (chan < 1 || chan > 8) 14565b9c547cSRui Paulo return -1; 14575b9c547cSRui Paulo return 56160 + 2160 * chan; 1458c1d255d3SCy Schubert case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ 1459c1d255d3SCy Schubert if (chan < 9 || chan > 15) 1460c1d255d3SCy Schubert return -1; 1461c1d255d3SCy Schubert return 56160 + 2160 * (chan - 8); 1462c1d255d3SCy Schubert case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */ 1463c1d255d3SCy Schubert if (chan < 17 || chan > 22) 1464c1d255d3SCy Schubert return -1; 1465c1d255d3SCy Schubert return 56160 + 2160 * (chan - 16); 1466c1d255d3SCy Schubert case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */ 1467c1d255d3SCy Schubert if (chan < 25 || chan > 29) 1468c1d255d3SCy Schubert return -1; 1469c1d255d3SCy Schubert return 56160 + 2160 * (chan - 24); 14705b9c547cSRui Paulo } 14715b9c547cSRui Paulo return -1; 14725b9c547cSRui Paulo } 14735b9c547cSRui Paulo 14745b9c547cSRui Paulo /** 14755b9c547cSRui Paulo * ieee80211_chan_to_freq - Convert channel info to frequency 14765b9c547cSRui Paulo * @country: Country code, if known; otherwise, global operating class is used 14775b9c547cSRui Paulo * @op_class: Operating class 14785b9c547cSRui Paulo * @chan: Channel number 14795b9c547cSRui Paulo * Returns: Frequency in MHz or -1 if the specified channel is unknown 14805b9c547cSRui Paulo */ 14815b9c547cSRui Paulo int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan) 14825b9c547cSRui Paulo { 14835b9c547cSRui Paulo int freq; 14845b9c547cSRui Paulo 14855b9c547cSRui Paulo if (country_match(us_op_class_cc, country)) { 14865b9c547cSRui Paulo freq = ieee80211_chan_to_freq_us(op_class, chan); 14875b9c547cSRui Paulo if (freq > 0) 14885b9c547cSRui Paulo return freq; 14895b9c547cSRui Paulo } 14905b9c547cSRui Paulo 14915b9c547cSRui Paulo if (country_match(eu_op_class_cc, country)) { 14925b9c547cSRui Paulo freq = ieee80211_chan_to_freq_eu(op_class, chan); 14935b9c547cSRui Paulo if (freq > 0) 14945b9c547cSRui Paulo return freq; 14955b9c547cSRui Paulo } 14965b9c547cSRui Paulo 14975b9c547cSRui Paulo if (country_match(jp_op_class_cc, country)) { 14985b9c547cSRui Paulo freq = ieee80211_chan_to_freq_jp(op_class, chan); 14995b9c547cSRui Paulo if (freq > 0) 15005b9c547cSRui Paulo return freq; 15015b9c547cSRui Paulo } 15025b9c547cSRui Paulo 15035b9c547cSRui Paulo if (country_match(cn_op_class_cc, country)) { 15045b9c547cSRui Paulo freq = ieee80211_chan_to_freq_cn(op_class, chan); 15055b9c547cSRui Paulo if (freq > 0) 15065b9c547cSRui Paulo return freq; 15075b9c547cSRui Paulo } 15085b9c547cSRui Paulo 15095b9c547cSRui Paulo return ieee80211_chan_to_freq_global(op_class, chan); 15105b9c547cSRui Paulo } 15115b9c547cSRui Paulo 15125b9c547cSRui Paulo 151385732ac8SCy Schubert int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, 151485732ac8SCy Schubert u16 num_modes) 15155b9c547cSRui Paulo { 151685732ac8SCy Schubert int i, j; 151785732ac8SCy Schubert 151885732ac8SCy Schubert if (!modes || !num_modes) 151985732ac8SCy Schubert return (freq >= 5260 && freq <= 5320) || 152085732ac8SCy Schubert (freq >= 5500 && freq <= 5700); 152185732ac8SCy Schubert 152285732ac8SCy Schubert for (i = 0; i < num_modes; i++) { 152385732ac8SCy Schubert for (j = 0; j < modes[i].num_channels; j++) { 152485732ac8SCy Schubert if (modes[i].channels[j].freq == freq && 152585732ac8SCy Schubert (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR)) 152685732ac8SCy Schubert return 1; 152785732ac8SCy Schubert } 152885732ac8SCy Schubert } 152985732ac8SCy Schubert 153085732ac8SCy Schubert return 0; 15315b9c547cSRui Paulo } 15325b9c547cSRui Paulo 15335b9c547cSRui Paulo 1534*4b72b91aSCy Schubert /* 1535*4b72b91aSCy Schubert * 802.11-2020: Table E-4 - Global operating classes 1536*4b72b91aSCy Schubert * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123 1537*4b72b91aSCy Schubert */ 1538*4b72b91aSCy Schubert int is_dfs_global_op_class(u8 op_class) 1539*4b72b91aSCy Schubert { 1540*4b72b91aSCy Schubert return (op_class >= 118) && (op_class <= 123); 1541*4b72b91aSCy Schubert } 1542*4b72b91aSCy Schubert 1543*4b72b91aSCy Schubert 15445b9c547cSRui Paulo static int is_11b(u8 rate) 15455b9c547cSRui Paulo { 15465b9c547cSRui Paulo return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; 15475b9c547cSRui Paulo } 15485b9c547cSRui Paulo 15495b9c547cSRui Paulo 15505b9c547cSRui Paulo int supp_rates_11b_only(struct ieee802_11_elems *elems) 15515b9c547cSRui Paulo { 15525b9c547cSRui Paulo int num_11b = 0, num_others = 0; 15535b9c547cSRui Paulo int i; 15545b9c547cSRui Paulo 15555b9c547cSRui Paulo if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) 15565b9c547cSRui Paulo return 0; 15575b9c547cSRui Paulo 15585b9c547cSRui Paulo for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { 15595b9c547cSRui Paulo if (is_11b(elems->supp_rates[i])) 15605b9c547cSRui Paulo num_11b++; 15615b9c547cSRui Paulo else 15625b9c547cSRui Paulo num_others++; 15635b9c547cSRui Paulo } 15645b9c547cSRui Paulo 15655b9c547cSRui Paulo for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; 15665b9c547cSRui Paulo i++) { 15675b9c547cSRui Paulo if (is_11b(elems->ext_supp_rates[i])) 15685b9c547cSRui Paulo num_11b++; 15695b9c547cSRui Paulo else 15705b9c547cSRui Paulo num_others++; 15715b9c547cSRui Paulo } 15725b9c547cSRui Paulo 15735b9c547cSRui Paulo return num_11b > 0 && num_others == 0; 15745b9c547cSRui Paulo } 15755b9c547cSRui Paulo 15765b9c547cSRui Paulo 15775b9c547cSRui Paulo const char * fc2str(u16 fc) 15785b9c547cSRui Paulo { 15795b9c547cSRui Paulo u16 stype = WLAN_FC_GET_STYPE(fc); 15805b9c547cSRui Paulo #define C2S(x) case x: return #x; 15815b9c547cSRui Paulo 15825b9c547cSRui Paulo switch (WLAN_FC_GET_TYPE(fc)) { 15835b9c547cSRui Paulo case WLAN_FC_TYPE_MGMT: 15845b9c547cSRui Paulo switch (stype) { 15855b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ASSOC_REQ) 15865b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ASSOC_RESP) 15875b9c547cSRui Paulo C2S(WLAN_FC_STYPE_REASSOC_REQ) 15885b9c547cSRui Paulo C2S(WLAN_FC_STYPE_REASSOC_RESP) 15895b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PROBE_REQ) 15905b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PROBE_RESP) 15915b9c547cSRui Paulo C2S(WLAN_FC_STYPE_BEACON) 15925b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ATIM) 15935b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DISASSOC) 15945b9c547cSRui Paulo C2S(WLAN_FC_STYPE_AUTH) 15955b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DEAUTH) 15965b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ACTION) 15975b9c547cSRui Paulo } 15985b9c547cSRui Paulo break; 15995b9c547cSRui Paulo case WLAN_FC_TYPE_CTRL: 16005b9c547cSRui Paulo switch (stype) { 16015b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PSPOLL) 16025b9c547cSRui Paulo C2S(WLAN_FC_STYPE_RTS) 16035b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CTS) 16045b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ACK) 16055b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFEND) 16065b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFENDACK) 16075b9c547cSRui Paulo } 16085b9c547cSRui Paulo break; 16095b9c547cSRui Paulo case WLAN_FC_TYPE_DATA: 16105b9c547cSRui Paulo switch (stype) { 16115b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA) 16125b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFACK) 16135b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFPOLL) 16145b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFACKPOLL) 16155b9c547cSRui Paulo C2S(WLAN_FC_STYPE_NULLFUNC) 16165b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFACK) 16175b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFPOLL) 16185b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFACKPOLL) 16195b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA) 16205b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACK) 16215b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL) 16225b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL) 16235b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_NULL) 16245b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_CFPOLL) 16255b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_CFACKPOLL) 16265b9c547cSRui Paulo } 16275b9c547cSRui Paulo break; 16285b9c547cSRui Paulo } 16295b9c547cSRui Paulo return "WLAN_FC_TYPE_UNKNOWN"; 16305b9c547cSRui Paulo #undef C2S 16315b9c547cSRui Paulo } 1632325151a3SRui Paulo 1633325151a3SRui Paulo 1634206b73d0SCy Schubert const char * reason2str(u16 reason) 1635206b73d0SCy Schubert { 1636206b73d0SCy Schubert #define R2S(r) case WLAN_REASON_ ## r: return #r; 1637206b73d0SCy Schubert switch (reason) { 1638206b73d0SCy Schubert R2S(UNSPECIFIED) 1639206b73d0SCy Schubert R2S(PREV_AUTH_NOT_VALID) 1640206b73d0SCy Schubert R2S(DEAUTH_LEAVING) 1641206b73d0SCy Schubert R2S(DISASSOC_DUE_TO_INACTIVITY) 1642206b73d0SCy Schubert R2S(DISASSOC_AP_BUSY) 1643206b73d0SCy Schubert R2S(CLASS2_FRAME_FROM_NONAUTH_STA) 1644206b73d0SCy Schubert R2S(CLASS3_FRAME_FROM_NONASSOC_STA) 1645206b73d0SCy Schubert R2S(DISASSOC_STA_HAS_LEFT) 1646206b73d0SCy Schubert R2S(STA_REQ_ASSOC_WITHOUT_AUTH) 1647206b73d0SCy Schubert R2S(PWR_CAPABILITY_NOT_VALID) 1648206b73d0SCy Schubert R2S(SUPPORTED_CHANNEL_NOT_VALID) 1649206b73d0SCy Schubert R2S(BSS_TRANSITION_DISASSOC) 1650206b73d0SCy Schubert R2S(INVALID_IE) 1651206b73d0SCy Schubert R2S(MICHAEL_MIC_FAILURE) 1652206b73d0SCy Schubert R2S(4WAY_HANDSHAKE_TIMEOUT) 1653206b73d0SCy Schubert R2S(GROUP_KEY_UPDATE_TIMEOUT) 1654206b73d0SCy Schubert R2S(IE_IN_4WAY_DIFFERS) 1655206b73d0SCy Schubert R2S(GROUP_CIPHER_NOT_VALID) 1656206b73d0SCy Schubert R2S(PAIRWISE_CIPHER_NOT_VALID) 1657206b73d0SCy Schubert R2S(AKMP_NOT_VALID) 1658206b73d0SCy Schubert R2S(UNSUPPORTED_RSN_IE_VERSION) 1659206b73d0SCy Schubert R2S(INVALID_RSN_IE_CAPAB) 1660206b73d0SCy Schubert R2S(IEEE_802_1X_AUTH_FAILED) 1661206b73d0SCy Schubert R2S(CIPHER_SUITE_REJECTED) 1662206b73d0SCy Schubert R2S(TDLS_TEARDOWN_UNREACHABLE) 1663206b73d0SCy Schubert R2S(TDLS_TEARDOWN_UNSPECIFIED) 1664206b73d0SCy Schubert R2S(SSP_REQUESTED_DISASSOC) 1665206b73d0SCy Schubert R2S(NO_SSP_ROAMING_AGREEMENT) 1666206b73d0SCy Schubert R2S(BAD_CIPHER_OR_AKM) 1667206b73d0SCy Schubert R2S(NOT_AUTHORIZED_THIS_LOCATION) 1668206b73d0SCy Schubert R2S(SERVICE_CHANGE_PRECLUDES_TS) 1669206b73d0SCy Schubert R2S(UNSPECIFIED_QOS_REASON) 1670206b73d0SCy Schubert R2S(NOT_ENOUGH_BANDWIDTH) 1671206b73d0SCy Schubert R2S(DISASSOC_LOW_ACK) 1672206b73d0SCy Schubert R2S(EXCEEDED_TXOP) 1673206b73d0SCy Schubert R2S(STA_LEAVING) 1674206b73d0SCy Schubert R2S(END_TS_BA_DLS) 1675206b73d0SCy Schubert R2S(UNKNOWN_TS_BA) 1676206b73d0SCy Schubert R2S(TIMEOUT) 1677206b73d0SCy Schubert R2S(PEERKEY_MISMATCH) 1678206b73d0SCy Schubert R2S(AUTHORIZED_ACCESS_LIMIT_REACHED) 1679206b73d0SCy Schubert R2S(EXTERNAL_SERVICE_REQUIREMENTS) 1680206b73d0SCy Schubert R2S(INVALID_FT_ACTION_FRAME_COUNT) 1681206b73d0SCy Schubert R2S(INVALID_PMKID) 1682206b73d0SCy Schubert R2S(INVALID_MDE) 1683206b73d0SCy Schubert R2S(INVALID_FTE) 1684206b73d0SCy Schubert R2S(MESH_PEERING_CANCELLED) 1685206b73d0SCy Schubert R2S(MESH_MAX_PEERS) 1686206b73d0SCy Schubert R2S(MESH_CONFIG_POLICY_VIOLATION) 1687206b73d0SCy Schubert R2S(MESH_CLOSE_RCVD) 1688206b73d0SCy Schubert R2S(MESH_MAX_RETRIES) 1689206b73d0SCy Schubert R2S(MESH_CONFIRM_TIMEOUT) 1690206b73d0SCy Schubert R2S(MESH_INVALID_GTK) 1691206b73d0SCy Schubert R2S(MESH_INCONSISTENT_PARAMS) 1692206b73d0SCy Schubert R2S(MESH_INVALID_SECURITY_CAP) 1693206b73d0SCy Schubert R2S(MESH_PATH_ERROR_NO_PROXY_INFO) 1694206b73d0SCy Schubert R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO) 1695206b73d0SCy Schubert R2S(MESH_PATH_ERROR_DEST_UNREACHABLE) 1696206b73d0SCy Schubert R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS) 1697206b73d0SCy Schubert R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ) 1698206b73d0SCy Schubert R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED) 1699206b73d0SCy Schubert } 1700206b73d0SCy Schubert return "UNKNOWN"; 1701206b73d0SCy Schubert #undef R2S 1702206b73d0SCy Schubert } 1703206b73d0SCy Schubert 1704206b73d0SCy Schubert 1705206b73d0SCy Schubert const char * status2str(u16 status) 1706206b73d0SCy Schubert { 1707206b73d0SCy Schubert #define S2S(s) case WLAN_STATUS_ ## s: return #s; 1708206b73d0SCy Schubert switch (status) { 1709206b73d0SCy Schubert S2S(SUCCESS) 1710206b73d0SCy Schubert S2S(UNSPECIFIED_FAILURE) 1711206b73d0SCy Schubert S2S(TDLS_WAKEUP_ALTERNATE) 1712206b73d0SCy Schubert S2S(TDLS_WAKEUP_REJECT) 1713206b73d0SCy Schubert S2S(SECURITY_DISABLED) 1714206b73d0SCy Schubert S2S(UNACCEPTABLE_LIFETIME) 1715206b73d0SCy Schubert S2S(NOT_IN_SAME_BSS) 1716206b73d0SCy Schubert S2S(CAPS_UNSUPPORTED) 1717206b73d0SCy Schubert S2S(REASSOC_NO_ASSOC) 1718206b73d0SCy Schubert S2S(ASSOC_DENIED_UNSPEC) 1719206b73d0SCy Schubert S2S(NOT_SUPPORTED_AUTH_ALG) 1720206b73d0SCy Schubert S2S(UNKNOWN_AUTH_TRANSACTION) 1721206b73d0SCy Schubert S2S(CHALLENGE_FAIL) 1722206b73d0SCy Schubert S2S(AUTH_TIMEOUT) 1723206b73d0SCy Schubert S2S(AP_UNABLE_TO_HANDLE_NEW_STA) 1724206b73d0SCy Schubert S2S(ASSOC_DENIED_RATES) 1725206b73d0SCy Schubert S2S(ASSOC_DENIED_NOSHORT) 1726206b73d0SCy Schubert S2S(SPEC_MGMT_REQUIRED) 1727206b73d0SCy Schubert S2S(PWR_CAPABILITY_NOT_VALID) 1728206b73d0SCy Schubert S2S(SUPPORTED_CHANNEL_NOT_VALID) 1729206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME) 1730206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_HT) 1731206b73d0SCy Schubert S2S(R0KH_UNREACHABLE) 1732206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_PCO) 1733206b73d0SCy Schubert S2S(ASSOC_REJECTED_TEMPORARILY) 1734206b73d0SCy Schubert S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION) 1735206b73d0SCy Schubert S2S(UNSPECIFIED_QOS_FAILURE) 1736206b73d0SCy Schubert S2S(DENIED_INSUFFICIENT_BANDWIDTH) 1737206b73d0SCy Schubert S2S(DENIED_POOR_CHANNEL_CONDITIONS) 1738206b73d0SCy Schubert S2S(DENIED_QOS_NOT_SUPPORTED) 1739206b73d0SCy Schubert S2S(REQUEST_DECLINED) 1740206b73d0SCy Schubert S2S(INVALID_PARAMETERS) 1741206b73d0SCy Schubert S2S(REJECTED_WITH_SUGGESTED_CHANGES) 1742206b73d0SCy Schubert S2S(INVALID_IE) 1743206b73d0SCy Schubert S2S(GROUP_CIPHER_NOT_VALID) 1744206b73d0SCy Schubert S2S(PAIRWISE_CIPHER_NOT_VALID) 1745206b73d0SCy Schubert S2S(AKMP_NOT_VALID) 1746206b73d0SCy Schubert S2S(UNSUPPORTED_RSN_IE_VERSION) 1747206b73d0SCy Schubert S2S(INVALID_RSN_IE_CAPAB) 1748206b73d0SCy Schubert S2S(CIPHER_REJECTED_PER_POLICY) 1749206b73d0SCy Schubert S2S(TS_NOT_CREATED) 1750206b73d0SCy Schubert S2S(DIRECT_LINK_NOT_ALLOWED) 1751206b73d0SCy Schubert S2S(DEST_STA_NOT_PRESENT) 1752206b73d0SCy Schubert S2S(DEST_STA_NOT_QOS_STA) 1753206b73d0SCy Schubert S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE) 1754206b73d0SCy Schubert S2S(INVALID_FT_ACTION_FRAME_COUNT) 1755206b73d0SCy Schubert S2S(INVALID_PMKID) 1756206b73d0SCy Schubert S2S(INVALID_MDIE) 1757206b73d0SCy Schubert S2S(INVALID_FTIE) 1758206b73d0SCy Schubert S2S(REQUESTED_TCLAS_NOT_SUPPORTED) 1759206b73d0SCy Schubert S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES) 1760206b73d0SCy Schubert S2S(TRY_ANOTHER_BSS) 1761206b73d0SCy Schubert S2S(GAS_ADV_PROTO_NOT_SUPPORTED) 1762206b73d0SCy Schubert S2S(NO_OUTSTANDING_GAS_REQ) 1763206b73d0SCy Schubert S2S(GAS_RESP_NOT_RECEIVED) 1764206b73d0SCy Schubert S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP) 1765206b73d0SCy Schubert S2S(GAS_RESP_LARGER_THAN_LIMIT) 1766206b73d0SCy Schubert S2S(REQ_REFUSED_HOME) 1767206b73d0SCy Schubert S2S(ADV_SRV_UNREACHABLE) 1768206b73d0SCy Schubert S2S(REQ_REFUSED_SSPN) 1769206b73d0SCy Schubert S2S(REQ_REFUSED_UNAUTH_ACCESS) 1770206b73d0SCy Schubert S2S(INVALID_RSNIE) 1771206b73d0SCy Schubert S2S(U_APSD_COEX_NOT_SUPPORTED) 1772206b73d0SCy Schubert S2S(U_APSD_COEX_MODE_NOT_SUPPORTED) 1773206b73d0SCy Schubert S2S(BAD_INTERVAL_WITH_U_APSD_COEX) 1774206b73d0SCy Schubert S2S(ANTI_CLOGGING_TOKEN_REQ) 1775206b73d0SCy Schubert S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED) 1776206b73d0SCy Schubert S2S(CANNOT_FIND_ALT_TBTT) 1777206b73d0SCy Schubert S2S(TRANSMISSION_FAILURE) 1778206b73d0SCy Schubert S2S(REQ_TCLAS_NOT_SUPPORTED) 1779206b73d0SCy Schubert S2S(TCLAS_RESOURCES_EXCHAUSTED) 1780206b73d0SCy Schubert S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION) 1781206b73d0SCy Schubert S2S(REJECT_WITH_SCHEDULE) 1782206b73d0SCy Schubert S2S(REJECT_NO_WAKEUP_SPECIFIED) 1783206b73d0SCy Schubert S2S(SUCCESS_POWER_SAVE_MODE) 1784206b73d0SCy Schubert S2S(PENDING_ADMITTING_FST_SESSION) 1785206b73d0SCy Schubert S2S(PERFORMING_FST_NOW) 1786206b73d0SCy Schubert S2S(PENDING_GAP_IN_BA_WINDOW) 1787206b73d0SCy Schubert S2S(REJECT_U_PID_SETTING) 1788206b73d0SCy Schubert S2S(REFUSED_EXTERNAL_REASON) 1789206b73d0SCy Schubert S2S(REFUSED_AP_OUT_OF_MEMORY) 1790206b73d0SCy Schubert S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED) 1791206b73d0SCy Schubert S2S(QUERY_RESP_OUTSTANDING) 1792206b73d0SCy Schubert S2S(REJECT_DSE_BAND) 1793206b73d0SCy Schubert S2S(TCLAS_PROCESSING_TERMINATED) 1794206b73d0SCy Schubert S2S(TS_SCHEDULE_CONFLICT) 1795206b73d0SCy Schubert S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL) 1796206b73d0SCy Schubert S2S(MCCAOP_RESERVATION_CONFLICT) 1797206b73d0SCy Schubert S2S(MAF_LIMIT_EXCEEDED) 1798206b73d0SCy Schubert S2S(MCCA_TRACK_LIMIT_EXCEEDED) 1799206b73d0SCy Schubert S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT) 1800206b73d0SCy Schubert S2S(ASSOC_DENIED_NO_VHT) 1801206b73d0SCy Schubert S2S(ENABLEMENT_DENIED) 1802206b73d0SCy Schubert S2S(RESTRICTION_FROM_AUTHORIZED_GDB) 1803206b73d0SCy Schubert S2S(AUTHORIZATION_DEENABLED) 1804206b73d0SCy Schubert S2S(FILS_AUTHENTICATION_FAILURE) 1805206b73d0SCy Schubert S2S(UNKNOWN_AUTHENTICATION_SERVER) 1806206b73d0SCy Schubert S2S(UNKNOWN_PASSWORD_IDENTIFIER) 1807c1d255d3SCy Schubert S2S(DENIED_HE_NOT_SUPPORTED) 1808c1d255d3SCy Schubert S2S(SAE_HASH_TO_ELEMENT) 1809c1d255d3SCy Schubert S2S(SAE_PK) 1810206b73d0SCy Schubert } 1811206b73d0SCy Schubert return "UNKNOWN"; 1812206b73d0SCy Schubert #undef S2S 1813206b73d0SCy Schubert } 1814206b73d0SCy Schubert 1815206b73d0SCy Schubert 1816325151a3SRui Paulo int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, 1817325151a3SRui Paulo size_t ies_len) 1818325151a3SRui Paulo { 18194bc52338SCy Schubert const struct element *elem; 18204bc52338SCy Schubert 1821325151a3SRui Paulo os_memset(info, 0, sizeof(*info)); 1822325151a3SRui Paulo 18234bc52338SCy Schubert if (!ies_buf) 18244bc52338SCy Schubert return 0; 1825325151a3SRui Paulo 18264bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) { 18274bc52338SCy Schubert if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED) 18284bc52338SCy Schubert return 0; 1829325151a3SRui Paulo 18304bc52338SCy Schubert wpa_printf(MSG_DEBUG, "MB IE of %u bytes found", 18314bc52338SCy Schubert elem->datalen + 2); 18324bc52338SCy Schubert info->ies[info->nof_ies].ie = elem->data; 18334bc52338SCy Schubert info->ies[info->nof_ies].ie_len = elem->datalen; 1834325151a3SRui Paulo info->nof_ies++; 1835325151a3SRui Paulo } 1836325151a3SRui Paulo 18374bc52338SCy Schubert if (!for_each_element_completed(elem, ies_buf, ies_len)) { 18384bc52338SCy Schubert wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len); 18394bc52338SCy Schubert return -1; 1840325151a3SRui Paulo } 1841325151a3SRui Paulo 1842325151a3SRui Paulo return 0; 1843325151a3SRui Paulo } 1844325151a3SRui Paulo 1845325151a3SRui Paulo 1846325151a3SRui Paulo struct wpabuf * mb_ies_by_info(struct mb_ies_info *info) 1847325151a3SRui Paulo { 1848325151a3SRui Paulo struct wpabuf *mb_ies = NULL; 1849325151a3SRui Paulo 1850325151a3SRui Paulo WPA_ASSERT(info != NULL); 1851325151a3SRui Paulo 1852325151a3SRui Paulo if (info->nof_ies) { 1853325151a3SRui Paulo u8 i; 1854325151a3SRui Paulo size_t mb_ies_size = 0; 1855325151a3SRui Paulo 1856325151a3SRui Paulo for (i = 0; i < info->nof_ies; i++) 1857325151a3SRui Paulo mb_ies_size += 2 + info->ies[i].ie_len; 1858325151a3SRui Paulo 1859325151a3SRui Paulo mb_ies = wpabuf_alloc(mb_ies_size); 1860325151a3SRui Paulo if (mb_ies) { 1861325151a3SRui Paulo for (i = 0; i < info->nof_ies; i++) { 1862325151a3SRui Paulo wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND); 1863325151a3SRui Paulo wpabuf_put_u8(mb_ies, info->ies[i].ie_len); 1864325151a3SRui Paulo wpabuf_put_data(mb_ies, 1865325151a3SRui Paulo info->ies[i].ie, 1866325151a3SRui Paulo info->ies[i].ie_len); 1867325151a3SRui Paulo } 1868325151a3SRui Paulo } 1869325151a3SRui Paulo } 1870325151a3SRui Paulo 1871325151a3SRui Paulo return mb_ies; 1872325151a3SRui Paulo } 1873780fb4a2SCy Schubert 1874780fb4a2SCy Schubert 1875780fb4a2SCy Schubert const struct oper_class_map global_op_class[] = { 1876780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP }, 1877780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP }, 1878780fb4a2SCy Schubert 1879780fb4a2SCy Schubert /* Do not enable HT40 on 2.4 GHz for P2P use for now */ 1880780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP }, 1881780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP }, 1882780fb4a2SCy Schubert 1883780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, 1884780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, 1885780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, 1886780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, 1887780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, 1888780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, 1889780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, 1890780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP }, 1891780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP }, 1892780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, 1893c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP }, 1894c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP }, 1895c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP }, 1896780fb4a2SCy Schubert 1897780fb4a2SCy Schubert /* 1898c1d255d3SCy Schubert * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center 1899c1d255d3SCy Schubert * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing 1900c1d255d3SCy Schubert * of 80 MHz, but currently use the following definition for simplicity 1901780fb4a2SCy Schubert * (these center frequencies are not actual channels, which makes 1902c1d255d3SCy Schubert * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take 1903780fb4a2SCy Schubert * care of removing invalid channels. 1904780fb4a2SCy Schubert */ 1905c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP }, 1906c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP }, 1907c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, 1908*4b72b91aSCy Schubert { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP }, 1909*4b72b91aSCy Schubert { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP }, 1910*4b72b91aSCy Schubert { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, P2P_SUPP }, 1911c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP }, 1912c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP }, 1913c1d255d3SCy Schubert 1914c1d255d3SCy Schubert /* 1915c1d255d3SCy Schubert * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. 1916c1d255d3SCy Schubert * Class 180 has the legacy channels 1-6. Classes 181-183 include 1917c1d255d3SCy Schubert * channels which implement channel bonding features. 1918c1d255d3SCy Schubert */ 1919c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211AD, 180, 1, 6, 1, BW2160, P2P_SUPP }, 1920c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP }, 1921c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP }, 1922c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP }, 1923c1d255d3SCy Schubert 1924c1d255d3SCy Schubert /* Keep the operating class 130 as the last entry as a workaround for 1925c1d255d3SCy Schubert * the OneHundredAndThirty Delimiter value used in the Supported 1926c1d255d3SCy Schubert * Operating Classes element to indicate the end of the Operating 1927c1d255d3SCy Schubert * Classes field. */ 1928c1d255d3SCy Schubert { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP }, 1929780fb4a2SCy Schubert { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } 1930780fb4a2SCy Schubert }; 1931780fb4a2SCy Schubert 1932780fb4a2SCy Schubert 1933780fb4a2SCy Schubert static enum phy_type ieee80211_phy_type_by_freq(int freq) 1934780fb4a2SCy Schubert { 1935780fb4a2SCy Schubert enum hostapd_hw_mode hw_mode; 1936780fb4a2SCy Schubert u8 channel; 1937780fb4a2SCy Schubert 1938780fb4a2SCy Schubert hw_mode = ieee80211_freq_to_chan(freq, &channel); 1939780fb4a2SCy Schubert 1940780fb4a2SCy Schubert switch (hw_mode) { 1941780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211A: 1942780fb4a2SCy Schubert return PHY_TYPE_OFDM; 1943780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211B: 1944780fb4a2SCy Schubert return PHY_TYPE_HRDSSS; 1945780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211G: 1946780fb4a2SCy Schubert return PHY_TYPE_ERP; 1947780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211AD: 1948780fb4a2SCy Schubert return PHY_TYPE_DMG; 1949780fb4a2SCy Schubert default: 1950780fb4a2SCy Schubert return PHY_TYPE_UNSPECIFIED; 1951780fb4a2SCy Schubert }; 1952780fb4a2SCy Schubert } 1953780fb4a2SCy Schubert 1954780fb4a2SCy Schubert 1955780fb4a2SCy Schubert /* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */ 1956780fb4a2SCy Schubert enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht) 1957780fb4a2SCy Schubert { 1958780fb4a2SCy Schubert if (vht) 1959780fb4a2SCy Schubert return PHY_TYPE_VHT; 1960780fb4a2SCy Schubert if (ht) 1961780fb4a2SCy Schubert return PHY_TYPE_HT; 1962780fb4a2SCy Schubert 1963780fb4a2SCy Schubert return ieee80211_phy_type_by_freq(freq); 1964780fb4a2SCy Schubert } 1965780fb4a2SCy Schubert 1966780fb4a2SCy Schubert 1967780fb4a2SCy Schubert size_t global_op_class_size = ARRAY_SIZE(global_op_class); 1968780fb4a2SCy Schubert 1969780fb4a2SCy Schubert 1970780fb4a2SCy Schubert /** 1971780fb4a2SCy Schubert * get_ie - Fetch a specified information element from IEs buffer 1972780fb4a2SCy Schubert * @ies: Information elements buffer 1973780fb4a2SCy Schubert * @len: Information elements buffer length 1974780fb4a2SCy Schubert * @eid: Information element identifier (WLAN_EID_*) 1975780fb4a2SCy Schubert * Returns: Pointer to the information element (id field) or %NULL if not found 1976780fb4a2SCy Schubert * 1977780fb4a2SCy Schubert * This function returns the first matching information element in the IEs 1978780fb4a2SCy Schubert * buffer or %NULL in case the element is not found. 1979780fb4a2SCy Schubert */ 1980780fb4a2SCy Schubert const u8 * get_ie(const u8 *ies, size_t len, u8 eid) 1981780fb4a2SCy Schubert { 19824bc52338SCy Schubert const struct element *elem; 1983780fb4a2SCy Schubert 1984780fb4a2SCy Schubert if (!ies) 1985780fb4a2SCy Schubert return NULL; 1986780fb4a2SCy Schubert 19874bc52338SCy Schubert for_each_element_id(elem, eid, ies, len) 19884bc52338SCy Schubert return &elem->id; 1989780fb4a2SCy Schubert 1990780fb4a2SCy Schubert return NULL; 1991780fb4a2SCy Schubert } 1992780fb4a2SCy Schubert 1993780fb4a2SCy Schubert 199485732ac8SCy Schubert /** 199585732ac8SCy Schubert * get_ie_ext - Fetch a specified extended information element from IEs buffer 199685732ac8SCy Schubert * @ies: Information elements buffer 199785732ac8SCy Schubert * @len: Information elements buffer length 199885732ac8SCy Schubert * @ext: Information element extension identifier (WLAN_EID_EXT_*) 199985732ac8SCy Schubert * Returns: Pointer to the information element (id field) or %NULL if not found 200085732ac8SCy Schubert * 200185732ac8SCy Schubert * This function returns the first matching information element in the IEs 200285732ac8SCy Schubert * buffer or %NULL in case the element is not found. 200385732ac8SCy Schubert */ 200485732ac8SCy Schubert const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext) 200585732ac8SCy Schubert { 20064bc52338SCy Schubert const struct element *elem; 200785732ac8SCy Schubert 200885732ac8SCy Schubert if (!ies) 200985732ac8SCy Schubert return NULL; 201085732ac8SCy Schubert 20114bc52338SCy Schubert for_each_element_extid(elem, ext, ies, len) 20124bc52338SCy Schubert return &elem->id; 201385732ac8SCy Schubert 20144bc52338SCy Schubert return NULL; 20154bc52338SCy Schubert } 201685732ac8SCy Schubert 201785732ac8SCy Schubert 20184bc52338SCy Schubert const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) 20194bc52338SCy Schubert { 20204bc52338SCy Schubert const struct element *elem; 20214bc52338SCy Schubert 20224bc52338SCy Schubert for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) { 20234bc52338SCy Schubert if (elem->datalen >= 4 && 20244bc52338SCy Schubert vendor_type == WPA_GET_BE32(elem->data)) 20254bc52338SCy Schubert return &elem->id; 202685732ac8SCy Schubert } 202785732ac8SCy Schubert 202885732ac8SCy Schubert return NULL; 202985732ac8SCy Schubert } 203085732ac8SCy Schubert 203185732ac8SCy Schubert 2032780fb4a2SCy Schubert size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) 2033780fb4a2SCy Schubert { 2034780fb4a2SCy Schubert /* 2035780fb4a2SCy Schubert * MBO IE requires 6 bytes without the attributes: EID (1), length (1), 2036780fb4a2SCy Schubert * OUI (3), OUI type (1). 2037780fb4a2SCy Schubert */ 2038780fb4a2SCy Schubert if (len < 6 + attr_len) { 2039780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 2040780fb4a2SCy Schubert "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu", 2041780fb4a2SCy Schubert len, attr_len); 2042780fb4a2SCy Schubert return 0; 2043780fb4a2SCy Schubert } 2044780fb4a2SCy Schubert 2045780fb4a2SCy Schubert *buf++ = WLAN_EID_VENDOR_SPECIFIC; 2046780fb4a2SCy Schubert *buf++ = attr_len + 4; 2047780fb4a2SCy Schubert WPA_PUT_BE24(buf, OUI_WFA); 2048780fb4a2SCy Schubert buf += 3; 2049780fb4a2SCy Schubert *buf++ = MBO_OUI_TYPE; 2050780fb4a2SCy Schubert os_memcpy(buf, attr, attr_len); 2051780fb4a2SCy Schubert 2052780fb4a2SCy Schubert return 6 + attr_len; 2053780fb4a2SCy Schubert } 205485732ac8SCy Schubert 205585732ac8SCy Schubert 20564bc52338SCy Schubert size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value) 20574bc52338SCy Schubert { 20584bc52338SCy Schubert u8 *pos = buf; 20594bc52338SCy Schubert 20604bc52338SCy Schubert if (len < 9) 20614bc52338SCy Schubert return 0; 20624bc52338SCy Schubert 20634bc52338SCy Schubert *pos++ = WLAN_EID_VENDOR_SPECIFIC; 20644bc52338SCy Schubert *pos++ = 7; /* len */ 20654bc52338SCy Schubert WPA_PUT_BE24(pos, OUI_WFA); 20664bc52338SCy Schubert pos += 3; 20674bc52338SCy Schubert *pos++ = MULTI_AP_OUI_TYPE; 20684bc52338SCy Schubert *pos++ = MULTI_AP_SUB_ELEM_TYPE; 20694bc52338SCy Schubert *pos++ = 1; /* len */ 20704bc52338SCy Schubert *pos++ = value; 20714bc52338SCy Schubert 20724bc52338SCy Schubert return pos - buf; 20734bc52338SCy Schubert } 20744bc52338SCy Schubert 20754bc52338SCy Schubert 207685732ac8SCy Schubert static const struct country_op_class us_op_class[] = { 207785732ac8SCy Schubert { 1, 115 }, 207885732ac8SCy Schubert { 2, 118 }, 207985732ac8SCy Schubert { 3, 124 }, 208085732ac8SCy Schubert { 4, 121 }, 208185732ac8SCy Schubert { 5, 125 }, 208285732ac8SCy Schubert { 12, 81 }, 208385732ac8SCy Schubert { 22, 116 }, 208485732ac8SCy Schubert { 23, 119 }, 208585732ac8SCy Schubert { 24, 122 }, 208685732ac8SCy Schubert { 25, 126 }, 208785732ac8SCy Schubert { 26, 126 }, 208885732ac8SCy Schubert { 27, 117 }, 208985732ac8SCy Schubert { 28, 120 }, 209085732ac8SCy Schubert { 29, 123 }, 209185732ac8SCy Schubert { 30, 127 }, 209285732ac8SCy Schubert { 31, 127 }, 209385732ac8SCy Schubert { 32, 83 }, 209485732ac8SCy Schubert { 33, 84 }, 209585732ac8SCy Schubert { 34, 180 }, 209685732ac8SCy Schubert }; 209785732ac8SCy Schubert 209885732ac8SCy Schubert static const struct country_op_class eu_op_class[] = { 209985732ac8SCy Schubert { 1, 115 }, 210085732ac8SCy Schubert { 2, 118 }, 210185732ac8SCy Schubert { 3, 121 }, 210285732ac8SCy Schubert { 4, 81 }, 210385732ac8SCy Schubert { 5, 116 }, 210485732ac8SCy Schubert { 6, 119 }, 210585732ac8SCy Schubert { 7, 122 }, 210685732ac8SCy Schubert { 8, 117 }, 210785732ac8SCy Schubert { 9, 120 }, 210885732ac8SCy Schubert { 10, 123 }, 210985732ac8SCy Schubert { 11, 83 }, 211085732ac8SCy Schubert { 12, 84 }, 211185732ac8SCy Schubert { 17, 125 }, 211285732ac8SCy Schubert { 18, 180 }, 211385732ac8SCy Schubert }; 211485732ac8SCy Schubert 211585732ac8SCy Schubert static const struct country_op_class jp_op_class[] = { 211685732ac8SCy Schubert { 1, 115 }, 211785732ac8SCy Schubert { 30, 81 }, 211885732ac8SCy Schubert { 31, 82 }, 211985732ac8SCy Schubert { 32, 118 }, 212085732ac8SCy Schubert { 33, 118 }, 212185732ac8SCy Schubert { 34, 121 }, 212285732ac8SCy Schubert { 35, 121 }, 212385732ac8SCy Schubert { 36, 116 }, 212485732ac8SCy Schubert { 37, 119 }, 212585732ac8SCy Schubert { 38, 119 }, 212685732ac8SCy Schubert { 39, 122 }, 212785732ac8SCy Schubert { 40, 122 }, 212885732ac8SCy Schubert { 41, 117 }, 212985732ac8SCy Schubert { 42, 120 }, 213085732ac8SCy Schubert { 43, 120 }, 213185732ac8SCy Schubert { 44, 123 }, 213285732ac8SCy Schubert { 45, 123 }, 213385732ac8SCy Schubert { 56, 83 }, 213485732ac8SCy Schubert { 57, 84 }, 213585732ac8SCy Schubert { 58, 121 }, 213685732ac8SCy Schubert { 59, 180 }, 213785732ac8SCy Schubert }; 213885732ac8SCy Schubert 213985732ac8SCy Schubert static const struct country_op_class cn_op_class[] = { 214085732ac8SCy Schubert { 1, 115 }, 214185732ac8SCy Schubert { 2, 118 }, 214285732ac8SCy Schubert { 3, 125 }, 214385732ac8SCy Schubert { 4, 116 }, 214485732ac8SCy Schubert { 5, 119 }, 214585732ac8SCy Schubert { 6, 126 }, 214685732ac8SCy Schubert { 7, 81 }, 214785732ac8SCy Schubert { 8, 83 }, 214885732ac8SCy Schubert { 9, 84 }, 214985732ac8SCy Schubert }; 215085732ac8SCy Schubert 215185732ac8SCy Schubert static u8 215285732ac8SCy Schubert global_op_class_from_country_array(u8 op_class, size_t array_size, 215385732ac8SCy Schubert const struct country_op_class *country_array) 215485732ac8SCy Schubert { 215585732ac8SCy Schubert size_t i; 215685732ac8SCy Schubert 215785732ac8SCy Schubert for (i = 0; i < array_size; i++) { 215885732ac8SCy Schubert if (country_array[i].country_op_class == op_class) 215985732ac8SCy Schubert return country_array[i].global_op_class; 216085732ac8SCy Schubert } 216185732ac8SCy Schubert 216285732ac8SCy Schubert return 0; 216385732ac8SCy Schubert } 216485732ac8SCy Schubert 216585732ac8SCy Schubert 216685732ac8SCy Schubert u8 country_to_global_op_class(const char *country, u8 op_class) 216785732ac8SCy Schubert { 216885732ac8SCy Schubert const struct country_op_class *country_array; 216985732ac8SCy Schubert size_t size; 217085732ac8SCy Schubert u8 g_op_class; 217185732ac8SCy Schubert 217285732ac8SCy Schubert if (country_match(us_op_class_cc, country)) { 217385732ac8SCy Schubert country_array = us_op_class; 217485732ac8SCy Schubert size = ARRAY_SIZE(us_op_class); 217585732ac8SCy Schubert } else if (country_match(eu_op_class_cc, country)) { 217685732ac8SCy Schubert country_array = eu_op_class; 217785732ac8SCy Schubert size = ARRAY_SIZE(eu_op_class); 217885732ac8SCy Schubert } else if (country_match(jp_op_class_cc, country)) { 217985732ac8SCy Schubert country_array = jp_op_class; 218085732ac8SCy Schubert size = ARRAY_SIZE(jp_op_class); 218185732ac8SCy Schubert } else if (country_match(cn_op_class_cc, country)) { 218285732ac8SCy Schubert country_array = cn_op_class; 218385732ac8SCy Schubert size = ARRAY_SIZE(cn_op_class); 218485732ac8SCy Schubert } else { 218585732ac8SCy Schubert /* 218685732ac8SCy Schubert * Countries that do not match any of the above countries use 218785732ac8SCy Schubert * global operating classes 218885732ac8SCy Schubert */ 218985732ac8SCy Schubert return op_class; 219085732ac8SCy Schubert } 219185732ac8SCy Schubert 219285732ac8SCy Schubert g_op_class = global_op_class_from_country_array(op_class, size, 219385732ac8SCy Schubert country_array); 219485732ac8SCy Schubert 219585732ac8SCy Schubert /* 219685732ac8SCy Schubert * If the given operating class did not match any of the country's 219785732ac8SCy Schubert * operating classes, assume that global operating class is used. 219885732ac8SCy Schubert */ 219985732ac8SCy Schubert return g_op_class ? g_op_class : op_class; 220085732ac8SCy Schubert } 220185732ac8SCy Schubert 220285732ac8SCy Schubert 220385732ac8SCy Schubert const struct oper_class_map * get_oper_class(const char *country, u8 op_class) 220485732ac8SCy Schubert { 220585732ac8SCy Schubert const struct oper_class_map *op; 220685732ac8SCy Schubert 220785732ac8SCy Schubert if (country) 220885732ac8SCy Schubert op_class = country_to_global_op_class(country, op_class); 220985732ac8SCy Schubert 221085732ac8SCy Schubert op = &global_op_class[0]; 221185732ac8SCy Schubert while (op->op_class && op->op_class != op_class) 221285732ac8SCy Schubert op++; 221385732ac8SCy Schubert 221485732ac8SCy Schubert if (!op->op_class) 221585732ac8SCy Schubert return NULL; 221685732ac8SCy Schubert 221785732ac8SCy Schubert return op; 221885732ac8SCy Schubert } 221985732ac8SCy Schubert 222085732ac8SCy Schubert 22214bc52338SCy Schubert int oper_class_bw_to_int(const struct oper_class_map *map) 22224bc52338SCy Schubert { 22234bc52338SCy Schubert switch (map->bw) { 22244bc52338SCy Schubert case BW20: 22254bc52338SCy Schubert return 20; 2226c1d255d3SCy Schubert case BW40: 22274bc52338SCy Schubert case BW40PLUS: 22284bc52338SCy Schubert case BW40MINUS: 22294bc52338SCy Schubert return 40; 22304bc52338SCy Schubert case BW80: 22314bc52338SCy Schubert return 80; 22324bc52338SCy Schubert case BW80P80: 22334bc52338SCy Schubert case BW160: 22344bc52338SCy Schubert return 160; 22354bc52338SCy Schubert case BW2160: 22364bc52338SCy Schubert return 2160; 22374bc52338SCy Schubert default: 22384bc52338SCy Schubert return 0; 22394bc52338SCy Schubert } 22404bc52338SCy Schubert } 22414bc52338SCy Schubert 22424bc52338SCy Schubert 2243c1d255d3SCy Schubert int center_idx_to_bw_6ghz(u8 idx) 2244c1d255d3SCy Schubert { 2245c1d255d3SCy Schubert /* Channel: 2 */ 2246c1d255d3SCy Schubert if (idx == 2) 2247c1d255d3SCy Schubert return 0; /* 20 MHz */ 2248c1d255d3SCy Schubert /* channels: 1, 5, 9, 13... */ 2249c1d255d3SCy Schubert if ((idx & 0x3) == 0x1) 2250c1d255d3SCy Schubert return 0; /* 20 MHz */ 2251c1d255d3SCy Schubert /* channels 3, 11, 19... */ 2252c1d255d3SCy Schubert if ((idx & 0x7) == 0x3) 2253c1d255d3SCy Schubert return 1; /* 40 MHz */ 2254c1d255d3SCy Schubert /* channels 7, 23, 39.. */ 2255c1d255d3SCy Schubert if ((idx & 0xf) == 0x7) 2256c1d255d3SCy Schubert return 2; /* 80 MHz */ 2257c1d255d3SCy Schubert /* channels 15, 47, 79...*/ 2258c1d255d3SCy Schubert if ((idx & 0x1f) == 0xf) 2259c1d255d3SCy Schubert return 3; /* 160 MHz */ 2260c1d255d3SCy Schubert 2261c1d255d3SCy Schubert return -1; 2262c1d255d3SCy Schubert } 2263c1d255d3SCy Schubert 2264c1d255d3SCy Schubert 2265c1d255d3SCy Schubert bool is_6ghz_freq(int freq) 2266c1d255d3SCy Schubert { 2267c1d255d3SCy Schubert if (freq < 5935 || freq > 7115) 2268c1d255d3SCy Schubert return false; 2269c1d255d3SCy Schubert 2270c1d255d3SCy Schubert if (freq == 5935) 2271c1d255d3SCy Schubert return true; 2272c1d255d3SCy Schubert 2273c1d255d3SCy Schubert if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0) 2274c1d255d3SCy Schubert return false; 2275c1d255d3SCy Schubert 2276c1d255d3SCy Schubert return true; 2277c1d255d3SCy Schubert } 2278c1d255d3SCy Schubert 2279c1d255d3SCy Schubert 2280c1d255d3SCy Schubert bool is_6ghz_op_class(u8 op_class) 2281c1d255d3SCy Schubert { 2282c1d255d3SCy Schubert return op_class >= 131 && op_class <= 136; 2283c1d255d3SCy Schubert } 2284c1d255d3SCy Schubert 2285c1d255d3SCy Schubert 2286c1d255d3SCy Schubert bool is_6ghz_psc_frequency(int freq) 2287c1d255d3SCy Schubert { 2288c1d255d3SCy Schubert int i; 2289c1d255d3SCy Schubert 2290c1d255d3SCy Schubert if (!is_6ghz_freq(freq) || freq == 5935) 2291c1d255d3SCy Schubert return false; 2292c1d255d3SCy Schubert if ((((freq - 5950) / 5) & 0x3) != 0x1) 2293c1d255d3SCy Schubert return false; 2294c1d255d3SCy Schubert 2295c1d255d3SCy Schubert i = (freq - 5950 + 55) % 80; 2296c1d255d3SCy Schubert if (i == 0) 2297c1d255d3SCy Schubert i = (freq - 5950 + 55) / 80; 2298c1d255d3SCy Schubert 2299c1d255d3SCy Schubert if (i >= 1 && i <= 15) 2300c1d255d3SCy Schubert return true; 2301c1d255d3SCy Schubert 2302c1d255d3SCy Schubert return false; 2303c1d255d3SCy Schubert } 2304c1d255d3SCy Schubert 2305c1d255d3SCy Schubert 2306*4b72b91aSCy Schubert /** 2307*4b72b91aSCy Schubert * get_6ghz_sec_channel - Get the relative position of the secondary channel 2308*4b72b91aSCy Schubert * to the primary channel in 6 GHz 2309*4b72b91aSCy Schubert * @channel: Primary channel to be checked for (in global op class 131) 2310*4b72b91aSCy Schubert * Returns: 1 = secondary channel above, -1 = secondary channel below 2311*4b72b91aSCy Schubert */ 2312*4b72b91aSCy Schubert 2313*4b72b91aSCy Schubert int get_6ghz_sec_channel(int channel) 2314*4b72b91aSCy Schubert { 2315*4b72b91aSCy Schubert /* 2316*4b72b91aSCy Schubert * In the 6 GHz band, primary channels are numbered as 1, 5, 9, 13.., so 2317*4b72b91aSCy Schubert * the 40 MHz channels are formed with the channel pairs as (1,5), 2318*4b72b91aSCy Schubert * (9,13), (17,21).. 2319*4b72b91aSCy Schubert * The secondary channel for a given primary channel is below the 2320*4b72b91aSCy Schubert * primary channel for the channels 5, 13, 21.. and it is above the 2321*4b72b91aSCy Schubert * primary channel for the channels 1, 9, 17.. 2322*4b72b91aSCy Schubert */ 2323*4b72b91aSCy Schubert 2324*4b72b91aSCy Schubert if (((channel - 1) / 4) % 2) 2325*4b72b91aSCy Schubert return -1; 2326*4b72b91aSCy Schubert return 1; 2327*4b72b91aSCy Schubert } 2328*4b72b91aSCy Schubert 2329*4b72b91aSCy Schubert 233085732ac8SCy Schubert int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, 233185732ac8SCy Schubert size_t nei_rep_len) 233285732ac8SCy Schubert { 233385732ac8SCy Schubert u8 *nei_pos = nei_rep; 233485732ac8SCy Schubert const char *end; 233585732ac8SCy Schubert 233685732ac8SCy Schubert /* 233785732ac8SCy Schubert * BSS Transition Candidate List Entries - Neighbor Report elements 233885732ac8SCy Schubert * neighbor=<BSSID>,<BSSID Information>,<Operating Class>, 233985732ac8SCy Schubert * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>] 234085732ac8SCy Schubert */ 234185732ac8SCy Schubert while (pos) { 234285732ac8SCy Schubert u8 *nei_start; 234385732ac8SCy Schubert long int val; 234485732ac8SCy Schubert char *endptr, *tmp; 234585732ac8SCy Schubert 234685732ac8SCy Schubert pos = os_strstr(pos, " neighbor="); 234785732ac8SCy Schubert if (!pos) 234885732ac8SCy Schubert break; 234985732ac8SCy Schubert if (nei_pos + 15 > nei_rep + nei_rep_len) { 235085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 235185732ac8SCy Schubert "Not enough room for additional neighbor"); 235285732ac8SCy Schubert return -1; 235385732ac8SCy Schubert } 235485732ac8SCy Schubert pos += 10; 235585732ac8SCy Schubert 235685732ac8SCy Schubert nei_start = nei_pos; 235785732ac8SCy Schubert *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT; 235885732ac8SCy Schubert nei_pos++; /* length to be filled in */ 235985732ac8SCy Schubert 236085732ac8SCy Schubert if (hwaddr_aton(pos, nei_pos)) { 236185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Invalid BSSID"); 236285732ac8SCy Schubert return -1; 236385732ac8SCy Schubert } 236485732ac8SCy Schubert nei_pos += ETH_ALEN; 236585732ac8SCy Schubert pos += 17; 236685732ac8SCy Schubert if (*pos != ',') { 236785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing BSSID Information"); 236885732ac8SCy Schubert return -1; 236985732ac8SCy Schubert } 237085732ac8SCy Schubert pos++; 237185732ac8SCy Schubert 237285732ac8SCy Schubert val = strtol(pos, &endptr, 0); 237385732ac8SCy Schubert WPA_PUT_LE32(nei_pos, val); 237485732ac8SCy Schubert nei_pos += 4; 237585732ac8SCy Schubert if (*endptr != ',') { 237685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing Operating Class"); 237785732ac8SCy Schubert return -1; 237885732ac8SCy Schubert } 237985732ac8SCy Schubert pos = endptr + 1; 238085732ac8SCy Schubert 238185732ac8SCy Schubert *nei_pos++ = atoi(pos); /* Operating Class */ 238285732ac8SCy Schubert pos = os_strchr(pos, ','); 238385732ac8SCy Schubert if (pos == NULL) { 238485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing Channel Number"); 238585732ac8SCy Schubert return -1; 238685732ac8SCy Schubert } 238785732ac8SCy Schubert pos++; 238885732ac8SCy Schubert 238985732ac8SCy Schubert *nei_pos++ = atoi(pos); /* Channel Number */ 239085732ac8SCy Schubert pos = os_strchr(pos, ','); 239185732ac8SCy Schubert if (pos == NULL) { 239285732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Missing PHY Type"); 239385732ac8SCy Schubert return -1; 239485732ac8SCy Schubert } 239585732ac8SCy Schubert pos++; 239685732ac8SCy Schubert 239785732ac8SCy Schubert *nei_pos++ = atoi(pos); /* PHY Type */ 239885732ac8SCy Schubert end = os_strchr(pos, ' '); 239985732ac8SCy Schubert tmp = os_strchr(pos, ','); 240085732ac8SCy Schubert if (tmp && (!end || tmp < end)) { 240185732ac8SCy Schubert /* Optional Subelements (hexdump) */ 240285732ac8SCy Schubert size_t len; 240385732ac8SCy Schubert 240485732ac8SCy Schubert pos = tmp + 1; 240585732ac8SCy Schubert end = os_strchr(pos, ' '); 240685732ac8SCy Schubert if (end) 240785732ac8SCy Schubert len = end - pos; 240885732ac8SCy Schubert else 240985732ac8SCy Schubert len = os_strlen(pos); 241085732ac8SCy Schubert if (nei_pos + len / 2 > nei_rep + nei_rep_len) { 241185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 241285732ac8SCy Schubert "Not enough room for neighbor subelements"); 241385732ac8SCy Schubert return -1; 241485732ac8SCy Schubert } 241585732ac8SCy Schubert if (len & 0x01 || 241685732ac8SCy Schubert hexstr2bin(pos, nei_pos, len / 2) < 0) { 241785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 241885732ac8SCy Schubert "Invalid neighbor subelement info"); 241985732ac8SCy Schubert return -1; 242085732ac8SCy Schubert } 242185732ac8SCy Schubert nei_pos += len / 2; 242285732ac8SCy Schubert pos = end; 242385732ac8SCy Schubert } 242485732ac8SCy Schubert 242585732ac8SCy Schubert nei_start[1] = nei_pos - nei_start - 2; 242685732ac8SCy Schubert } 242785732ac8SCy Schubert 242885732ac8SCy Schubert return nei_pos - nei_rep; 242985732ac8SCy Schubert } 24304bc52338SCy Schubert 24314bc52338SCy Schubert 24324bc52338SCy Schubert int ieee802_11_ext_capab(const u8 *ie, unsigned int capab) 24334bc52338SCy Schubert { 24344bc52338SCy Schubert if (!ie || ie[1] <= capab / 8) 24354bc52338SCy Schubert return 0; 24364bc52338SCy Schubert return !!(ie[2 + capab / 8] & BIT(capab % 8)); 24374bc52338SCy Schubert } 2438c1d255d3SCy Schubert 2439c1d255d3SCy Schubert 2440c1d255d3SCy Schubert bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, 2441c1d255d3SCy Schubert unsigned int capab) 2442c1d255d3SCy Schubert { 2443c1d255d3SCy Schubert const u8 *end; 2444c1d255d3SCy Schubert size_t flen, i; 2445c1d255d3SCy Schubert u32 capabs = 0; 2446c1d255d3SCy Schubert 2447c1d255d3SCy Schubert if (!rsnxe || rsnxe_len == 0) 2448c1d255d3SCy Schubert return false; 2449c1d255d3SCy Schubert end = rsnxe + rsnxe_len; 2450c1d255d3SCy Schubert flen = (rsnxe[0] & 0x0f) + 1; 2451c1d255d3SCy Schubert if (rsnxe + flen > end) 2452c1d255d3SCy Schubert return false; 2453c1d255d3SCy Schubert if (flen > 4) 2454c1d255d3SCy Schubert flen = 4; 2455c1d255d3SCy Schubert for (i = 0; i < flen; i++) 2456c1d255d3SCy Schubert capabs |= rsnxe[i] << (8 * i); 2457c1d255d3SCy Schubert 2458c1d255d3SCy Schubert return capabs & BIT(capab); 2459c1d255d3SCy Schubert } 2460c1d255d3SCy Schubert 2461c1d255d3SCy Schubert 2462c1d255d3SCy Schubert bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab) 2463c1d255d3SCy Schubert { 2464c1d255d3SCy Schubert return ieee802_11_rsnx_capab_len(rsnxe ? rsnxe + 2 : NULL, 2465c1d255d3SCy Schubert rsnxe ? rsnxe[1] : 0, capab); 2466c1d255d3SCy Schubert } 2467c1d255d3SCy Schubert 2468c1d255d3SCy Schubert 2469c1d255d3SCy Schubert void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel, 2470c1d255d3SCy Schubert int primary_channel, 2471c1d255d3SCy Schubert struct ieee80211_edmg_config *edmg) 2472c1d255d3SCy Schubert { 2473c1d255d3SCy Schubert if (!edmg_enable) { 2474c1d255d3SCy Schubert edmg->channels = 0; 2475c1d255d3SCy Schubert edmg->bw_config = 0; 2476c1d255d3SCy Schubert return; 2477c1d255d3SCy Schubert } 2478c1d255d3SCy Schubert 2479c1d255d3SCy Schubert /* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */ 2480c1d255d3SCy Schubert switch (edmg_channel) { 2481c1d255d3SCy Schubert case EDMG_CHANNEL_9: 2482c1d255d3SCy Schubert edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS; 2483c1d255d3SCy Schubert edmg->bw_config = EDMG_BW_CONFIG_5; 2484c1d255d3SCy Schubert return; 2485c1d255d3SCy Schubert case EDMG_CHANNEL_10: 2486c1d255d3SCy Schubert edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS; 2487c1d255d3SCy Schubert edmg->bw_config = EDMG_BW_CONFIG_5; 2488c1d255d3SCy Schubert return; 2489c1d255d3SCy Schubert case EDMG_CHANNEL_11: 2490c1d255d3SCy Schubert edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS; 2491c1d255d3SCy Schubert edmg->bw_config = EDMG_BW_CONFIG_5; 2492c1d255d3SCy Schubert return; 2493c1d255d3SCy Schubert case EDMG_CHANNEL_12: 2494c1d255d3SCy Schubert edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS; 2495c1d255d3SCy Schubert edmg->bw_config = EDMG_BW_CONFIG_5; 2496c1d255d3SCy Schubert return; 2497c1d255d3SCy Schubert case EDMG_CHANNEL_13: 2498c1d255d3SCy Schubert edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS; 2499c1d255d3SCy Schubert edmg->bw_config = EDMG_BW_CONFIG_5; 2500c1d255d3SCy Schubert return; 2501c1d255d3SCy Schubert default: 2502c1d255d3SCy Schubert if (primary_channel > 0 && primary_channel < 7) { 2503c1d255d3SCy Schubert edmg->channels = BIT(primary_channel - 1); 2504c1d255d3SCy Schubert edmg->bw_config = EDMG_BW_CONFIG_4; 2505c1d255d3SCy Schubert } else { 2506c1d255d3SCy Schubert edmg->channels = 0; 2507c1d255d3SCy Schubert edmg->bw_config = 0; 2508c1d255d3SCy Schubert } 2509c1d255d3SCy Schubert break; 2510c1d255d3SCy Schubert } 2511c1d255d3SCy Schubert } 2512c1d255d3SCy Schubert 2513c1d255d3SCy Schubert 2514c1d255d3SCy Schubert /* Check if the requested EDMG configuration is a subset of the allowed 2515c1d255d3SCy Schubert * EDMG configuration. */ 2516c1d255d3SCy Schubert int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed, 2517c1d255d3SCy Schubert struct ieee80211_edmg_config requested) 2518c1d255d3SCy Schubert { 2519c1d255d3SCy Schubert /* 2520c1d255d3SCy Schubert * The validation check if the requested EDMG configuration 2521c1d255d3SCy Schubert * is a subset of the allowed EDMG configuration: 2522c1d255d3SCy Schubert * 1. Check that the requested channels are part (set) of the allowed 2523c1d255d3SCy Schubert * channels. 2524c1d255d3SCy Schubert * 2. P802.11ay defines the values of bw_config between 4 and 15. 2525c1d255d3SCy Schubert * (bw config % 4) will give us 4 groups inside bw_config definition, 2526c1d255d3SCy Schubert * inside each group we can check the subset just by comparing the 2527c1d255d3SCy Schubert * bw_config value. 2528c1d255d3SCy Schubert * Between this 4 groups, there is no subset relation - as a result of 2529c1d255d3SCy Schubert * the P802.11ay definition. 2530c1d255d3SCy Schubert * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13. 2531c1d255d3SCy Schubert */ 2532c1d255d3SCy Schubert if (((requested.channels & allowed.channels) != requested.channels) || 2533c1d255d3SCy Schubert ((requested.bw_config % 4) > (allowed.bw_config % 4)) || 2534c1d255d3SCy Schubert requested.bw_config > allowed.bw_config) 2535c1d255d3SCy Schubert return 0; 2536c1d255d3SCy Schubert 2537c1d255d3SCy Schubert return 1; 2538c1d255d3SCy Schubert } 2539c1d255d3SCy Schubert 2540c1d255d3SCy Schubert 2541c1d255d3SCy Schubert int op_class_to_bandwidth(u8 op_class) 2542c1d255d3SCy Schubert { 2543c1d255d3SCy Schubert switch (op_class) { 2544c1d255d3SCy Schubert case 81: 2545c1d255d3SCy Schubert case 82: 2546c1d255d3SCy Schubert return 20; 2547c1d255d3SCy Schubert case 83: /* channels 1..9; 40 MHz */ 2548c1d255d3SCy Schubert case 84: /* channels 5..13; 40 MHz */ 2549c1d255d3SCy Schubert return 40; 2550c1d255d3SCy Schubert case 115: /* channels 36,40,44,48; indoor only */ 2551c1d255d3SCy Schubert return 20; 2552c1d255d3SCy Schubert case 116: /* channels 36,44; 40 MHz; indoor only */ 2553c1d255d3SCy Schubert case 117: /* channels 40,48; 40 MHz; indoor only */ 2554c1d255d3SCy Schubert return 40; 2555c1d255d3SCy Schubert case 118: /* channels 52,56,60,64; dfs */ 2556c1d255d3SCy Schubert return 20; 2557c1d255d3SCy Schubert case 119: /* channels 52,60; 40 MHz; dfs */ 2558c1d255d3SCy Schubert case 120: /* channels 56,64; 40 MHz; dfs */ 2559c1d255d3SCy Schubert return 40; 2560c1d255d3SCy Schubert case 121: /* channels 100-140 */ 2561c1d255d3SCy Schubert return 20; 2562c1d255d3SCy Schubert case 122: /* channels 100-142; 40 MHz */ 2563c1d255d3SCy Schubert case 123: /* channels 104-136; 40 MHz */ 2564c1d255d3SCy Schubert return 40; 2565c1d255d3SCy Schubert case 124: /* channels 149,153,157,161 */ 2566c1d255d3SCy Schubert case 125: /* channels 149,153,157,161,165,169,173,177 */ 2567c1d255d3SCy Schubert return 20; 2568c1d255d3SCy Schubert case 126: /* channels 149,157,161,165,169,173; 40 MHz */ 2569c1d255d3SCy Schubert case 127: /* channels 153..177; 40 MHz */ 2570c1d255d3SCy Schubert return 40; 2571c1d255d3SCy Schubert case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */ 2572c1d255d3SCy Schubert return 80; 2573c1d255d3SCy Schubert case 129: /* center freqs 50, 114, 163; 160 MHz */ 2574c1d255d3SCy Schubert return 160; 2575c1d255d3SCy Schubert case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */ 2576c1d255d3SCy Schubert return 80; 2577c1d255d3SCy Schubert case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */ 2578c1d255d3SCy Schubert return 20; 2579c1d255d3SCy Schubert case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */ 2580c1d255d3SCy Schubert return 40; 2581c1d255d3SCy Schubert case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */ 2582c1d255d3SCy Schubert return 80; 2583c1d255d3SCy Schubert case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */ 2584c1d255d3SCy Schubert case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ 2585c1d255d3SCy Schubert return 160; 2586c1d255d3SCy Schubert case 136: /* UHB channels, 20 MHz: 2 */ 2587c1d255d3SCy Schubert return 20; 2588c1d255d3SCy Schubert case 180: /* 60 GHz band, channels 1..8 */ 2589c1d255d3SCy Schubert return 2160; 2590c1d255d3SCy Schubert case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ 2591c1d255d3SCy Schubert return 4320; 2592c1d255d3SCy Schubert case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */ 2593c1d255d3SCy Schubert return 6480; 2594c1d255d3SCy Schubert case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */ 2595c1d255d3SCy Schubert return 8640; 2596c1d255d3SCy Schubert } 2597c1d255d3SCy Schubert 2598c1d255d3SCy Schubert return 20; 2599c1d255d3SCy Schubert } 2600c1d255d3SCy Schubert 2601c1d255d3SCy Schubert 2602c1d255d3SCy Schubert int op_class_to_ch_width(u8 op_class) 2603c1d255d3SCy Schubert { 2604c1d255d3SCy Schubert switch (op_class) { 2605c1d255d3SCy Schubert case 81: 2606c1d255d3SCy Schubert case 82: 2607c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2608c1d255d3SCy Schubert case 83: /* channels 1..9; 40 MHz */ 2609c1d255d3SCy Schubert case 84: /* channels 5..13; 40 MHz */ 2610c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2611c1d255d3SCy Schubert case 115: /* channels 36,40,44,48; indoor only */ 2612c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2613c1d255d3SCy Schubert case 116: /* channels 36,44; 40 MHz; indoor only */ 2614c1d255d3SCy Schubert case 117: /* channels 40,48; 40 MHz; indoor only */ 2615c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2616c1d255d3SCy Schubert case 118: /* channels 52,56,60,64; dfs */ 2617c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2618c1d255d3SCy Schubert case 119: /* channels 52,60; 40 MHz; dfs */ 2619c1d255d3SCy Schubert case 120: /* channels 56,64; 40 MHz; dfs */ 2620c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2621c1d255d3SCy Schubert case 121: /* channels 100-140 */ 2622c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2623c1d255d3SCy Schubert case 122: /* channels 100-142; 40 MHz */ 2624c1d255d3SCy Schubert case 123: /* channels 104-136; 40 MHz */ 2625c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2626c1d255d3SCy Schubert case 124: /* channels 149,153,157,161 */ 2627c1d255d3SCy Schubert case 125: /* channels 149,153,157,161,165,169,171 */ 2628c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2629c1d255d3SCy Schubert case 126: /* channels 149,157,165, 173; 40 MHz */ 2630c1d255d3SCy Schubert case 127: /* channels 153,161,169,177; 40 MHz */ 2631c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2632c1d255d3SCy Schubert case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */ 2633c1d255d3SCy Schubert return CHANWIDTH_80MHZ; 2634c1d255d3SCy Schubert case 129: /* center freqs 50, 114, 163; 160 MHz */ 2635c1d255d3SCy Schubert return CHANWIDTH_160MHZ; 2636c1d255d3SCy Schubert case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */ 2637c1d255d3SCy Schubert return CHANWIDTH_80P80MHZ; 2638c1d255d3SCy Schubert case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */ 2639c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2640c1d255d3SCy Schubert case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */ 2641c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2642c1d255d3SCy Schubert case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */ 2643c1d255d3SCy Schubert return CHANWIDTH_80MHZ; 2644c1d255d3SCy Schubert case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */ 2645c1d255d3SCy Schubert return CHANWIDTH_160MHZ; 2646c1d255d3SCy Schubert case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ 2647c1d255d3SCy Schubert return CHANWIDTH_80P80MHZ; 2648c1d255d3SCy Schubert case 136: /* UHB channels, 20 MHz: 2 */ 2649c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2650c1d255d3SCy Schubert case 180: /* 60 GHz band, channels 1..8 */ 2651c1d255d3SCy Schubert return CHANWIDTH_2160MHZ; 2652c1d255d3SCy Schubert case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ 2653c1d255d3SCy Schubert return CHANWIDTH_4320MHZ; 2654c1d255d3SCy Schubert case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */ 2655c1d255d3SCy Schubert return CHANWIDTH_6480MHZ; 2656c1d255d3SCy Schubert case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */ 2657c1d255d3SCy Schubert return CHANWIDTH_8640MHZ; 2658c1d255d3SCy Schubert } 2659c1d255d3SCy Schubert return CHANWIDTH_USE_HT; 2660c1d255d3SCy Schubert } 2661c1d255d3SCy Schubert 2662c1d255d3SCy Schubert 2663c1d255d3SCy Schubert struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems, 2664c1d255d3SCy Schubert u8 eid, u8 eid_ext, 2665c1d255d3SCy Schubert const u8 *data, u8 len) 2666c1d255d3SCy Schubert { 2667c1d255d3SCy Schubert struct frag_ies_info *frag_ies = &elems->frag_ies; 2668c1d255d3SCy Schubert struct wpabuf *buf; 2669c1d255d3SCy Schubert unsigned int i; 2670c1d255d3SCy Schubert 2671c1d255d3SCy Schubert if (!elems || !data || !len) 2672c1d255d3SCy Schubert return NULL; 2673c1d255d3SCy Schubert 2674c1d255d3SCy Schubert buf = wpabuf_alloc_copy(data, len); 2675c1d255d3SCy Schubert if (!buf) 2676c1d255d3SCy Schubert return NULL; 2677c1d255d3SCy Schubert 2678c1d255d3SCy Schubert for (i = 0; i < frag_ies->n_frags; i++) { 2679c1d255d3SCy Schubert int ret; 2680c1d255d3SCy Schubert 2681c1d255d3SCy Schubert if (frag_ies->frags[i].eid != eid || 2682c1d255d3SCy Schubert frag_ies->frags[i].eid_ext != eid_ext) 2683c1d255d3SCy Schubert continue; 2684c1d255d3SCy Schubert 2685c1d255d3SCy Schubert ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len); 2686c1d255d3SCy Schubert if (ret < 0) { 2687c1d255d3SCy Schubert wpabuf_free(buf); 2688c1d255d3SCy Schubert return NULL; 2689c1d255d3SCy Schubert } 2690c1d255d3SCy Schubert 2691c1d255d3SCy Schubert /* Copy only the fragment data (without the EID and length) */ 2692c1d255d3SCy Schubert wpabuf_put_data(buf, frag_ies->frags[i].ie, 2693c1d255d3SCy Schubert frag_ies->frags[i].ie_len); 2694c1d255d3SCy Schubert } 2695c1d255d3SCy Schubert 2696c1d255d3SCy Schubert return buf; 2697c1d255d3SCy Schubert } 2698c1d255d3SCy Schubert 2699c1d255d3SCy Schubert 2700c1d255d3SCy Schubert struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems, 2701c1d255d3SCy Schubert u8 eid, u8 eid_ext) 2702c1d255d3SCy Schubert { 2703c1d255d3SCy Schubert const u8 *data; 2704c1d255d3SCy Schubert u8 len; 2705c1d255d3SCy Schubert 2706c1d255d3SCy Schubert /* 2707c1d255d3SCy Schubert * TODO: Defragmentation mechanism can be supported for all IEs. For now 2708c1d255d3SCy Schubert * handle only those that are used (or use ieee802_11_defrag_data()). 2709c1d255d3SCy Schubert */ 2710c1d255d3SCy Schubert switch (eid) { 2711c1d255d3SCy Schubert case WLAN_EID_EXTENSION: 2712c1d255d3SCy Schubert switch (eid_ext) { 2713c1d255d3SCy Schubert case WLAN_EID_EXT_FILS_HLP_CONTAINER: 2714c1d255d3SCy Schubert data = elems->fils_hlp; 2715c1d255d3SCy Schubert len = elems->fils_hlp_len; 2716c1d255d3SCy Schubert break; 2717c1d255d3SCy Schubert case WLAN_EID_EXT_WRAPPED_DATA: 2718c1d255d3SCy Schubert data = elems->wrapped_data; 2719c1d255d3SCy Schubert len = elems->wrapped_data_len; 2720c1d255d3SCy Schubert break; 2721c1d255d3SCy Schubert default: 2722c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 2723c1d255d3SCy Schubert "Defragmentation not supported. eid_ext=%u", 2724c1d255d3SCy Schubert eid_ext); 2725c1d255d3SCy Schubert return NULL; 2726c1d255d3SCy Schubert } 2727c1d255d3SCy Schubert break; 2728c1d255d3SCy Schubert default: 2729c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 2730c1d255d3SCy Schubert "Defragmentation not supported. eid=%u", eid); 2731c1d255d3SCy Schubert return NULL; 2732c1d255d3SCy Schubert } 2733c1d255d3SCy Schubert 2734c1d255d3SCy Schubert return ieee802_11_defrag_data(elems, eid, eid_ext, data, len); 2735c1d255d3SCy Schubert } 2736