139beb93cSSam Leffler /* 239beb93cSSam Leffler * IEEE 802.11 Common routines 3325151a3SRui Paulo * Copyright (c) 2002-2015, 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" 14325151a3SRui Paulo #include "qca-vendor.h" 1539beb93cSSam Leffler #include "ieee802_11_defs.h" 1639beb93cSSam Leffler #include "ieee802_11_common.h" 1739beb93cSSam Leffler 1839beb93cSSam Leffler 19e28a4053SRui Paulo static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 2039beb93cSSam Leffler struct ieee802_11_elems *elems, 2139beb93cSSam Leffler int show_errors) 2239beb93cSSam Leffler { 2339beb93cSSam Leffler unsigned int oui; 2439beb93cSSam Leffler 2539beb93cSSam Leffler /* first 3 bytes in vendor specific information element are the IEEE 2639beb93cSSam Leffler * OUI of the vendor. The following byte is used a vendor specific 2739beb93cSSam Leffler * sub-type. */ 2839beb93cSSam Leffler if (elen < 4) { 2939beb93cSSam Leffler if (show_errors) { 3039beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "short vendor specific " 3139beb93cSSam Leffler "information element ignored (len=%lu)", 3239beb93cSSam Leffler (unsigned long) elen); 3339beb93cSSam Leffler } 3439beb93cSSam Leffler return -1; 3539beb93cSSam Leffler } 3639beb93cSSam Leffler 3739beb93cSSam Leffler oui = WPA_GET_BE24(pos); 3839beb93cSSam Leffler switch (oui) { 3939beb93cSSam Leffler case OUI_MICROSOFT: 4039beb93cSSam Leffler /* Microsoft/Wi-Fi information elements are further typed and 4139beb93cSSam Leffler * subtyped */ 4239beb93cSSam Leffler switch (pos[3]) { 4339beb93cSSam Leffler case 1: 4439beb93cSSam Leffler /* Microsoft OUI (00:50:F2) with OUI Type 1: 4539beb93cSSam Leffler * real WPA information element */ 4639beb93cSSam Leffler elems->wpa_ie = pos; 4739beb93cSSam Leffler elems->wpa_ie_len = elen; 4839beb93cSSam Leffler break; 493157ba21SRui Paulo case WMM_OUI_TYPE: 503157ba21SRui Paulo /* WMM information element */ 5139beb93cSSam Leffler if (elen < 5) { 523157ba21SRui Paulo wpa_printf(MSG_MSGDUMP, "short WMM " 5339beb93cSSam Leffler "information element ignored " 5439beb93cSSam Leffler "(len=%lu)", 5539beb93cSSam Leffler (unsigned long) elen); 5639beb93cSSam Leffler return -1; 5739beb93cSSam Leffler } 5839beb93cSSam Leffler switch (pos[4]) { 593157ba21SRui Paulo case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 603157ba21SRui Paulo case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 613157ba21SRui Paulo /* 623157ba21SRui Paulo * Share same pointer since only one of these 633157ba21SRui Paulo * is used and they start with same data. 643157ba21SRui Paulo * Length field can be used to distinguish the 653157ba21SRui Paulo * IEs. 663157ba21SRui Paulo */ 673157ba21SRui Paulo elems->wmm = pos; 683157ba21SRui Paulo elems->wmm_len = elen; 6939beb93cSSam Leffler break; 703157ba21SRui Paulo case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 713157ba21SRui Paulo elems->wmm_tspec = pos; 723157ba21SRui Paulo elems->wmm_tspec_len = elen; 7339beb93cSSam Leffler break; 7439beb93cSSam Leffler default: 75f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown WMM " 7639beb93cSSam Leffler "information element ignored " 7739beb93cSSam Leffler "(subtype=%d len=%lu)", 7839beb93cSSam Leffler pos[4], (unsigned long) elen); 7939beb93cSSam Leffler return -1; 8039beb93cSSam Leffler } 8139beb93cSSam Leffler break; 8239beb93cSSam Leffler case 4: 8339beb93cSSam Leffler /* Wi-Fi Protected Setup (WPS) IE */ 8439beb93cSSam Leffler elems->wps_ie = pos; 8539beb93cSSam Leffler elems->wps_ie_len = elen; 8639beb93cSSam Leffler break; 8739beb93cSSam Leffler default: 88f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 89f05cddf9SRui Paulo "information element ignored " 90f05cddf9SRui Paulo "(type=%d len=%lu)", 91f05cddf9SRui Paulo pos[3], (unsigned long) elen); 92f05cddf9SRui Paulo return -1; 93f05cddf9SRui Paulo } 94f05cddf9SRui Paulo break; 95f05cddf9SRui Paulo 96f05cddf9SRui Paulo case OUI_WFA: 97f05cddf9SRui Paulo switch (pos[3]) { 98f05cddf9SRui Paulo case P2P_OUI_TYPE: 99f05cddf9SRui Paulo /* Wi-Fi Alliance - P2P IE */ 100f05cddf9SRui Paulo elems->p2p = pos; 101f05cddf9SRui Paulo elems->p2p_len = elen; 102f05cddf9SRui Paulo break; 103f05cddf9SRui Paulo case WFD_OUI_TYPE: 104f05cddf9SRui Paulo /* Wi-Fi Alliance - WFD IE */ 105f05cddf9SRui Paulo elems->wfd = pos; 106f05cddf9SRui Paulo elems->wfd_len = elen; 107f05cddf9SRui Paulo break; 108f05cddf9SRui Paulo case HS20_INDICATION_OUI_TYPE: 109f05cddf9SRui Paulo /* Hotspot 2.0 */ 110f05cddf9SRui Paulo elems->hs20 = pos; 111f05cddf9SRui Paulo elems->hs20_len = elen; 112f05cddf9SRui Paulo break; 1135b9c547cSRui Paulo case HS20_OSEN_OUI_TYPE: 1145b9c547cSRui Paulo /* Hotspot 2.0 OSEN */ 1155b9c547cSRui Paulo elems->osen = pos; 1165b9c547cSRui Paulo elems->osen_len = elen; 1175b9c547cSRui Paulo break; 118*780fb4a2SCy Schubert case MBO_OUI_TYPE: 119*780fb4a2SCy Schubert /* MBO-OCE */ 120*780fb4a2SCy Schubert elems->mbo = pos; 121*780fb4a2SCy Schubert elems->mbo_len = elen; 122*780fb4a2SCy Schubert break; 123f05cddf9SRui Paulo default: 124f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "Unknown WFA " 12539beb93cSSam Leffler "information element ignored " 1265b9c547cSRui Paulo "(type=%d len=%lu)", 12739beb93cSSam Leffler pos[3], (unsigned long) elen); 12839beb93cSSam Leffler return -1; 12939beb93cSSam Leffler } 13039beb93cSSam Leffler break; 13139beb93cSSam Leffler 13239beb93cSSam Leffler case OUI_BROADCOM: 13339beb93cSSam Leffler switch (pos[3]) { 13439beb93cSSam Leffler case VENDOR_HT_CAPAB_OUI_TYPE: 13539beb93cSSam Leffler elems->vendor_ht_cap = pos; 13639beb93cSSam Leffler elems->vendor_ht_cap_len = elen; 13739beb93cSSam Leffler break; 1385b9c547cSRui Paulo case VENDOR_VHT_TYPE: 1395b9c547cSRui Paulo if (elen > 4 && 1405b9c547cSRui Paulo (pos[4] == VENDOR_VHT_SUBTYPE || 1415b9c547cSRui Paulo pos[4] == VENDOR_VHT_SUBTYPE2)) { 1425b9c547cSRui Paulo elems->vendor_vht = pos; 1435b9c547cSRui Paulo elems->vendor_vht_len = elen; 1445b9c547cSRui Paulo } else 1455b9c547cSRui Paulo return -1; 1465b9c547cSRui Paulo break; 14739beb93cSSam Leffler default: 148f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 14939beb93cSSam Leffler "information element ignored " 150f05cddf9SRui Paulo "(type=%d len=%lu)", 15139beb93cSSam Leffler pos[3], (unsigned long) elen); 15239beb93cSSam Leffler return -1; 15339beb93cSSam Leffler } 15439beb93cSSam Leffler break; 15539beb93cSSam Leffler 156325151a3SRui Paulo case OUI_QCA: 157325151a3SRui Paulo switch (pos[3]) { 158325151a3SRui Paulo case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: 159325151a3SRui Paulo elems->pref_freq_list = pos; 160325151a3SRui Paulo elems->pref_freq_list_len = elen; 161325151a3SRui Paulo break; 162325151a3SRui Paulo default: 163325151a3SRui Paulo wpa_printf(MSG_EXCESSIVE, 164325151a3SRui Paulo "Unknown QCA information element ignored (type=%d len=%lu)", 165325151a3SRui Paulo pos[3], (unsigned long) elen); 166325151a3SRui Paulo return -1; 167325151a3SRui Paulo } 168325151a3SRui Paulo break; 169325151a3SRui Paulo 17039beb93cSSam Leffler default: 171f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 172f05cddf9SRui Paulo "information element ignored (vendor OUI " 173f05cddf9SRui Paulo "%02x:%02x:%02x len=%lu)", 17439beb93cSSam Leffler pos[0], pos[1], pos[2], (unsigned long) elen); 17539beb93cSSam Leffler return -1; 17639beb93cSSam Leffler } 17739beb93cSSam Leffler 17839beb93cSSam Leffler return 0; 17939beb93cSSam Leffler } 18039beb93cSSam Leffler 18139beb93cSSam Leffler 18239beb93cSSam Leffler /** 18339beb93cSSam Leffler * ieee802_11_parse_elems - Parse information elements in management frames 18439beb93cSSam Leffler * @start: Pointer to the start of IEs 18539beb93cSSam Leffler * @len: Length of IE buffer in octets 18639beb93cSSam Leffler * @elems: Data structure for parsed elements 18739beb93cSSam Leffler * @show_errors: Whether to show parsing errors in debug log 18839beb93cSSam Leffler * Returns: Parsing result 18939beb93cSSam Leffler */ 190e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 19139beb93cSSam Leffler struct ieee802_11_elems *elems, 19239beb93cSSam Leffler int show_errors) 19339beb93cSSam Leffler { 19439beb93cSSam Leffler size_t left = len; 195e28a4053SRui Paulo const u8 *pos = start; 19639beb93cSSam Leffler int unknown = 0; 19739beb93cSSam Leffler 19839beb93cSSam Leffler os_memset(elems, 0, sizeof(*elems)); 19939beb93cSSam Leffler 20039beb93cSSam Leffler while (left >= 2) { 20139beb93cSSam Leffler u8 id, elen; 20239beb93cSSam Leffler 20339beb93cSSam Leffler id = *pos++; 20439beb93cSSam Leffler elen = *pos++; 20539beb93cSSam Leffler left -= 2; 20639beb93cSSam Leffler 20739beb93cSSam Leffler if (elen > left) { 20839beb93cSSam Leffler if (show_errors) { 20939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 21039beb93cSSam Leffler "parse failed (id=%d elen=%d " 21139beb93cSSam Leffler "left=%lu)", 21239beb93cSSam Leffler id, elen, (unsigned long) left); 21339beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 21439beb93cSSam Leffler } 21539beb93cSSam Leffler return ParseFailed; 21639beb93cSSam Leffler } 21739beb93cSSam Leffler 21839beb93cSSam Leffler switch (id) { 21939beb93cSSam Leffler case WLAN_EID_SSID: 220325151a3SRui Paulo if (elen > SSID_MAX_LEN) { 221325151a3SRui Paulo wpa_printf(MSG_DEBUG, 222325151a3SRui Paulo "Ignored too long SSID element (elen=%u)", 223325151a3SRui Paulo elen); 224325151a3SRui Paulo break; 225325151a3SRui Paulo } 22639beb93cSSam Leffler elems->ssid = pos; 22739beb93cSSam Leffler elems->ssid_len = elen; 22839beb93cSSam Leffler break; 22939beb93cSSam Leffler case WLAN_EID_SUPP_RATES: 23039beb93cSSam Leffler elems->supp_rates = pos; 23139beb93cSSam Leffler elems->supp_rates_len = elen; 23239beb93cSSam Leffler break; 23339beb93cSSam Leffler case WLAN_EID_DS_PARAMS: 234325151a3SRui Paulo if (elen < 1) 235325151a3SRui Paulo break; 23639beb93cSSam Leffler elems->ds_params = pos; 23739beb93cSSam Leffler break; 23839beb93cSSam Leffler case WLAN_EID_CF_PARAMS: 23939beb93cSSam Leffler case WLAN_EID_TIM: 24039beb93cSSam Leffler break; 24139beb93cSSam Leffler case WLAN_EID_CHALLENGE: 24239beb93cSSam Leffler elems->challenge = pos; 24339beb93cSSam Leffler elems->challenge_len = elen; 24439beb93cSSam Leffler break; 24539beb93cSSam Leffler case WLAN_EID_ERP_INFO: 246325151a3SRui Paulo if (elen < 1) 247325151a3SRui Paulo break; 24839beb93cSSam Leffler elems->erp_info = pos; 24939beb93cSSam Leffler break; 25039beb93cSSam Leffler case WLAN_EID_EXT_SUPP_RATES: 25139beb93cSSam Leffler elems->ext_supp_rates = pos; 25239beb93cSSam Leffler elems->ext_supp_rates_len = elen; 25339beb93cSSam Leffler break; 25439beb93cSSam Leffler case WLAN_EID_VENDOR_SPECIFIC: 25539beb93cSSam Leffler if (ieee802_11_parse_vendor_specific(pos, elen, 25639beb93cSSam Leffler elems, 25739beb93cSSam Leffler show_errors)) 25839beb93cSSam Leffler unknown++; 25939beb93cSSam Leffler break; 26039beb93cSSam Leffler case WLAN_EID_RSN: 26139beb93cSSam Leffler elems->rsn_ie = pos; 26239beb93cSSam Leffler elems->rsn_ie_len = elen; 26339beb93cSSam Leffler break; 26439beb93cSSam Leffler case WLAN_EID_PWR_CAPABILITY: 26539beb93cSSam Leffler break; 26639beb93cSSam Leffler case WLAN_EID_SUPPORTED_CHANNELS: 26739beb93cSSam Leffler elems->supp_channels = pos; 26839beb93cSSam Leffler elems->supp_channels_len = elen; 26939beb93cSSam Leffler break; 27039beb93cSSam Leffler case WLAN_EID_MOBILITY_DOMAIN: 271325151a3SRui Paulo if (elen < sizeof(struct rsn_mdie)) 272325151a3SRui Paulo break; 27339beb93cSSam Leffler elems->mdie = pos; 27439beb93cSSam Leffler elems->mdie_len = elen; 27539beb93cSSam Leffler break; 27639beb93cSSam Leffler case WLAN_EID_FAST_BSS_TRANSITION: 277325151a3SRui Paulo if (elen < sizeof(struct rsn_ftie)) 278325151a3SRui Paulo break; 27939beb93cSSam Leffler elems->ftie = pos; 28039beb93cSSam Leffler elems->ftie_len = elen; 28139beb93cSSam Leffler break; 28239beb93cSSam Leffler case WLAN_EID_TIMEOUT_INTERVAL: 283325151a3SRui Paulo if (elen != 5) 284325151a3SRui Paulo break; 28539beb93cSSam Leffler elems->timeout_int = pos; 28639beb93cSSam Leffler break; 28739beb93cSSam Leffler case WLAN_EID_HT_CAP: 288325151a3SRui Paulo if (elen < sizeof(struct ieee80211_ht_capabilities)) 289325151a3SRui Paulo break; 29039beb93cSSam Leffler elems->ht_capabilities = pos; 29139beb93cSSam Leffler break; 29239beb93cSSam Leffler case WLAN_EID_HT_OPERATION: 293325151a3SRui Paulo if (elen < sizeof(struct ieee80211_ht_operation)) 294325151a3SRui Paulo break; 29539beb93cSSam Leffler elems->ht_operation = pos; 29639beb93cSSam Leffler break; 2975b9c547cSRui Paulo case WLAN_EID_MESH_CONFIG: 2985b9c547cSRui Paulo elems->mesh_config = pos; 2995b9c547cSRui Paulo elems->mesh_config_len = elen; 3005b9c547cSRui Paulo break; 3015b9c547cSRui Paulo case WLAN_EID_MESH_ID: 3025b9c547cSRui Paulo elems->mesh_id = pos; 3035b9c547cSRui Paulo elems->mesh_id_len = elen; 3045b9c547cSRui Paulo break; 3055b9c547cSRui Paulo case WLAN_EID_PEER_MGMT: 3065b9c547cSRui Paulo elems->peer_mgmt = pos; 3075b9c547cSRui Paulo elems->peer_mgmt_len = elen; 3085b9c547cSRui Paulo break; 309f05cddf9SRui Paulo case WLAN_EID_VHT_CAP: 310325151a3SRui Paulo if (elen < sizeof(struct ieee80211_vht_capabilities)) 311325151a3SRui Paulo break; 312f05cddf9SRui Paulo elems->vht_capabilities = pos; 313f05cddf9SRui Paulo break; 314f05cddf9SRui Paulo case WLAN_EID_VHT_OPERATION: 315325151a3SRui Paulo if (elen < sizeof(struct ieee80211_vht_operation)) 316325151a3SRui Paulo break; 317f05cddf9SRui Paulo elems->vht_operation = pos; 318f05cddf9SRui Paulo break; 3195b9c547cSRui Paulo case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: 3205b9c547cSRui Paulo if (elen != 1) 3215b9c547cSRui Paulo break; 3225b9c547cSRui Paulo elems->vht_opmode_notif = pos; 3235b9c547cSRui Paulo break; 324f05cddf9SRui Paulo case WLAN_EID_LINK_ID: 325f05cddf9SRui Paulo if (elen < 18) 326f05cddf9SRui Paulo break; 327f05cddf9SRui Paulo elems->link_id = pos; 328f05cddf9SRui Paulo break; 329f05cddf9SRui Paulo case WLAN_EID_INTERWORKING: 330f05cddf9SRui Paulo elems->interworking = pos; 331f05cddf9SRui Paulo elems->interworking_len = elen; 332f05cddf9SRui Paulo break; 3335b9c547cSRui Paulo case WLAN_EID_QOS_MAP_SET: 3345b9c547cSRui Paulo if (elen < 16) 3355b9c547cSRui Paulo break; 3365b9c547cSRui Paulo elems->qos_map_set = pos; 3375b9c547cSRui Paulo elems->qos_map_set_len = elen; 3385b9c547cSRui Paulo break; 339f05cddf9SRui Paulo case WLAN_EID_EXT_CAPAB: 340f05cddf9SRui Paulo elems->ext_capab = pos; 341f05cddf9SRui Paulo elems->ext_capab_len = elen; 342f05cddf9SRui Paulo break; 343f05cddf9SRui Paulo case WLAN_EID_BSS_MAX_IDLE_PERIOD: 344f05cddf9SRui Paulo if (elen < 3) 345f05cddf9SRui Paulo break; 346f05cddf9SRui Paulo elems->bss_max_idle_period = pos; 347f05cddf9SRui Paulo break; 348f05cddf9SRui Paulo case WLAN_EID_SSID_LIST: 349f05cddf9SRui Paulo elems->ssid_list = pos; 350f05cddf9SRui Paulo elems->ssid_list_len = elen; 351f05cddf9SRui Paulo break; 3525b9c547cSRui Paulo case WLAN_EID_AMPE: 3535b9c547cSRui Paulo elems->ampe = pos; 3545b9c547cSRui Paulo elems->ampe_len = elen; 3555b9c547cSRui Paulo break; 3565b9c547cSRui Paulo case WLAN_EID_MIC: 3575b9c547cSRui Paulo elems->mic = pos; 3585b9c547cSRui Paulo elems->mic_len = elen; 3595b9c547cSRui Paulo /* after mic everything is encrypted, so stop. */ 3605b9c547cSRui Paulo left = elen; 3615b9c547cSRui Paulo break; 362325151a3SRui Paulo case WLAN_EID_MULTI_BAND: 363325151a3SRui Paulo if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) { 364325151a3SRui Paulo wpa_printf(MSG_MSGDUMP, 365325151a3SRui Paulo "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)", 366325151a3SRui Paulo id, elen); 367325151a3SRui Paulo break; 368325151a3SRui Paulo } 369325151a3SRui Paulo 370325151a3SRui Paulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos; 371325151a3SRui Paulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen; 372325151a3SRui Paulo elems->mb_ies.nof_ies++; 373325151a3SRui Paulo break; 374*780fb4a2SCy Schubert case WLAN_EID_SUPPORTED_OPERATING_CLASSES: 375*780fb4a2SCy Schubert elems->supp_op_classes = pos; 376*780fb4a2SCy Schubert elems->supp_op_classes_len = elen; 377*780fb4a2SCy Schubert break; 378*780fb4a2SCy Schubert case WLAN_EID_RRM_ENABLED_CAPABILITIES: 379*780fb4a2SCy Schubert elems->rrm_enabled = pos; 380*780fb4a2SCy Schubert elems->rrm_enabled_len = elen; 381*780fb4a2SCy Schubert break; 38239beb93cSSam Leffler default: 38339beb93cSSam Leffler unknown++; 38439beb93cSSam Leffler if (!show_errors) 38539beb93cSSam Leffler break; 38639beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 38739beb93cSSam Leffler "ignored unknown element (id=%d elen=%d)", 38839beb93cSSam Leffler id, elen); 38939beb93cSSam Leffler break; 39039beb93cSSam Leffler } 39139beb93cSSam Leffler 39239beb93cSSam Leffler left -= elen; 39339beb93cSSam Leffler pos += elen; 39439beb93cSSam Leffler } 39539beb93cSSam Leffler 39639beb93cSSam Leffler if (left) 39739beb93cSSam Leffler return ParseFailed; 39839beb93cSSam Leffler 39939beb93cSSam Leffler return unknown ? ParseUnknown : ParseOK; 40039beb93cSSam Leffler } 401e28a4053SRui Paulo 402e28a4053SRui Paulo 403e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 404e28a4053SRui Paulo { 405e28a4053SRui Paulo int count = 0; 406e28a4053SRui Paulo const u8 *pos, *end; 407e28a4053SRui Paulo 408e28a4053SRui Paulo if (ies == NULL) 409e28a4053SRui Paulo return 0; 410e28a4053SRui Paulo 411e28a4053SRui Paulo pos = ies; 412e28a4053SRui Paulo end = ies + ies_len; 413e28a4053SRui Paulo 414*780fb4a2SCy Schubert while (end - pos >= 2) { 415*780fb4a2SCy Schubert if (2 + pos[1] > end - pos) 416e28a4053SRui Paulo break; 417e28a4053SRui Paulo count++; 418e28a4053SRui Paulo pos += 2 + pos[1]; 419e28a4053SRui Paulo } 420e28a4053SRui Paulo 421e28a4053SRui Paulo return count; 422e28a4053SRui Paulo } 423e28a4053SRui Paulo 424e28a4053SRui Paulo 425e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 426e28a4053SRui Paulo u32 oui_type) 427e28a4053SRui Paulo { 428e28a4053SRui Paulo struct wpabuf *buf; 429e28a4053SRui Paulo const u8 *end, *pos, *ie; 430e28a4053SRui Paulo 431e28a4053SRui Paulo pos = ies; 432e28a4053SRui Paulo end = ies + ies_len; 433e28a4053SRui Paulo ie = NULL; 434e28a4053SRui Paulo 435*780fb4a2SCy Schubert while (end - pos > 1) { 436*780fb4a2SCy Schubert if (2 + pos[1] > end - pos) 437e28a4053SRui Paulo return NULL; 438e28a4053SRui Paulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 439e28a4053SRui Paulo WPA_GET_BE32(&pos[2]) == oui_type) { 440e28a4053SRui Paulo ie = pos; 441e28a4053SRui Paulo break; 442e28a4053SRui Paulo } 443e28a4053SRui Paulo pos += 2 + pos[1]; 444e28a4053SRui Paulo } 445e28a4053SRui Paulo 446e28a4053SRui Paulo if (ie == NULL) 447e28a4053SRui Paulo return NULL; /* No specified vendor IE found */ 448e28a4053SRui Paulo 449e28a4053SRui Paulo buf = wpabuf_alloc(ies_len); 450e28a4053SRui Paulo if (buf == NULL) 451e28a4053SRui Paulo return NULL; 452e28a4053SRui Paulo 453e28a4053SRui Paulo /* 454e28a4053SRui Paulo * There may be multiple vendor IEs in the message, so need to 455e28a4053SRui Paulo * concatenate their data fields. 456e28a4053SRui Paulo */ 457*780fb4a2SCy Schubert while (end - pos > 1) { 458*780fb4a2SCy Schubert if (2 + pos[1] > end - pos) 459e28a4053SRui Paulo break; 460e28a4053SRui Paulo if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 461e28a4053SRui Paulo WPA_GET_BE32(&pos[2]) == oui_type) 462e28a4053SRui Paulo wpabuf_put_data(buf, pos + 6, pos[1] - 4); 463e28a4053SRui Paulo pos += 2 + pos[1]; 464e28a4053SRui Paulo } 465e28a4053SRui Paulo 466e28a4053SRui Paulo return buf; 467e28a4053SRui Paulo } 468f05cddf9SRui Paulo 469f05cddf9SRui Paulo 470f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 471f05cddf9SRui Paulo { 472f05cddf9SRui Paulo u16 fc, type, stype; 473f05cddf9SRui Paulo 474f05cddf9SRui Paulo /* 475f05cddf9SRui Paulo * PS-Poll frames are 16 bytes. All other frames are 476f05cddf9SRui Paulo * 24 bytes or longer. 477f05cddf9SRui Paulo */ 478f05cddf9SRui Paulo if (len < 16) 479f05cddf9SRui Paulo return NULL; 480f05cddf9SRui Paulo 481f05cddf9SRui Paulo fc = le_to_host16(hdr->frame_control); 482f05cddf9SRui Paulo type = WLAN_FC_GET_TYPE(fc); 483f05cddf9SRui Paulo stype = WLAN_FC_GET_STYPE(fc); 484f05cddf9SRui Paulo 485f05cddf9SRui Paulo switch (type) { 486f05cddf9SRui Paulo case WLAN_FC_TYPE_DATA: 487f05cddf9SRui Paulo if (len < 24) 488f05cddf9SRui Paulo return NULL; 489f05cddf9SRui Paulo switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 490f05cddf9SRui Paulo case WLAN_FC_FROMDS | WLAN_FC_TODS: 491f05cddf9SRui Paulo case WLAN_FC_TODS: 492f05cddf9SRui Paulo return hdr->addr1; 493f05cddf9SRui Paulo case WLAN_FC_FROMDS: 494f05cddf9SRui Paulo return hdr->addr2; 495f05cddf9SRui Paulo default: 496f05cddf9SRui Paulo return NULL; 497f05cddf9SRui Paulo } 498f05cddf9SRui Paulo case WLAN_FC_TYPE_CTRL: 499f05cddf9SRui Paulo if (stype != WLAN_FC_STYPE_PSPOLL) 500f05cddf9SRui Paulo return NULL; 501f05cddf9SRui Paulo return hdr->addr1; 502f05cddf9SRui Paulo case WLAN_FC_TYPE_MGMT: 503f05cddf9SRui Paulo return hdr->addr3; 504f05cddf9SRui Paulo default: 505f05cddf9SRui Paulo return NULL; 506f05cddf9SRui Paulo } 507f05cddf9SRui Paulo } 508f05cddf9SRui Paulo 509f05cddf9SRui Paulo 510f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 511f05cddf9SRui Paulo const char *name, const char *val) 512f05cddf9SRui Paulo { 513f05cddf9SRui Paulo int num, v; 514f05cddf9SRui Paulo const char *pos; 515f05cddf9SRui Paulo struct hostapd_wmm_ac_params *ac; 516f05cddf9SRui Paulo 517f05cddf9SRui Paulo /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 518f05cddf9SRui Paulo pos = name + 7; 519f05cddf9SRui Paulo if (os_strncmp(pos, "be_", 3) == 0) { 520f05cddf9SRui Paulo num = 0; 521f05cddf9SRui Paulo pos += 3; 522f05cddf9SRui Paulo } else if (os_strncmp(pos, "bk_", 3) == 0) { 523f05cddf9SRui Paulo num = 1; 524f05cddf9SRui Paulo pos += 3; 525f05cddf9SRui Paulo } else if (os_strncmp(pos, "vi_", 3) == 0) { 526f05cddf9SRui Paulo num = 2; 527f05cddf9SRui Paulo pos += 3; 528f05cddf9SRui Paulo } else if (os_strncmp(pos, "vo_", 3) == 0) { 529f05cddf9SRui Paulo num = 3; 530f05cddf9SRui Paulo pos += 3; 531f05cddf9SRui Paulo } else { 532f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 533f05cddf9SRui Paulo return -1; 534f05cddf9SRui Paulo } 535f05cddf9SRui Paulo 536f05cddf9SRui Paulo ac = &wmm_ac_params[num]; 537f05cddf9SRui Paulo 538f05cddf9SRui Paulo if (os_strcmp(pos, "aifs") == 0) { 539f05cddf9SRui Paulo v = atoi(val); 540f05cddf9SRui Paulo if (v < 1 || v > 255) { 541f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 542f05cddf9SRui Paulo return -1; 543f05cddf9SRui Paulo } 544f05cddf9SRui Paulo ac->aifs = v; 545f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmin") == 0) { 546f05cddf9SRui Paulo v = atoi(val); 547325151a3SRui Paulo if (v < 0 || v > 15) { 548f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 549f05cddf9SRui Paulo return -1; 550f05cddf9SRui Paulo } 551f05cddf9SRui Paulo ac->cwmin = v; 552f05cddf9SRui Paulo } else if (os_strcmp(pos, "cwmax") == 0) { 553f05cddf9SRui Paulo v = atoi(val); 554325151a3SRui Paulo if (v < 0 || v > 15) { 555f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 556f05cddf9SRui Paulo return -1; 557f05cddf9SRui Paulo } 558f05cddf9SRui Paulo ac->cwmax = v; 559f05cddf9SRui Paulo } else if (os_strcmp(pos, "txop_limit") == 0) { 560f05cddf9SRui Paulo v = atoi(val); 561f05cddf9SRui Paulo if (v < 0 || v > 0xffff) { 562f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 563f05cddf9SRui Paulo return -1; 564f05cddf9SRui Paulo } 565f05cddf9SRui Paulo ac->txop_limit = v; 566f05cddf9SRui Paulo } else if (os_strcmp(pos, "acm") == 0) { 567f05cddf9SRui Paulo v = atoi(val); 568f05cddf9SRui Paulo if (v < 0 || v > 1) { 569f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 570f05cddf9SRui Paulo return -1; 571f05cddf9SRui Paulo } 572f05cddf9SRui Paulo ac->admission_control_mandatory = v; 573f05cddf9SRui Paulo } else { 574f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 575f05cddf9SRui Paulo return -1; 576f05cddf9SRui Paulo } 577f05cddf9SRui Paulo 578f05cddf9SRui Paulo return 0; 579f05cddf9SRui Paulo } 5805b9c547cSRui Paulo 5815b9c547cSRui Paulo 5825b9c547cSRui Paulo enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) 5835b9c547cSRui Paulo { 584325151a3SRui Paulo u8 op_class; 585325151a3SRui Paulo 586*780fb4a2SCy Schubert return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT, 587*780fb4a2SCy Schubert &op_class, channel); 588325151a3SRui Paulo } 589325151a3SRui Paulo 590325151a3SRui Paulo 591325151a3SRui Paulo /** 592325151a3SRui Paulo * ieee80211_freq_to_channel_ext - Convert frequency into channel info 593325151a3SRui Paulo * for HT40 and VHT. DFS channels are not covered. 594325151a3SRui Paulo * @freq: Frequency (MHz) to convert 595325151a3SRui Paulo * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below 596*780fb4a2SCy Schubert * @vht: VHT channel width (VHT_CHANWIDTH_*) 597325151a3SRui Paulo * @op_class: Buffer for returning operating class 598325151a3SRui Paulo * @channel: Buffer for returning channel number 599325151a3SRui Paulo * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure 600325151a3SRui Paulo */ 601325151a3SRui Paulo enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, 602325151a3SRui Paulo int sec_channel, int vht, 603325151a3SRui Paulo u8 *op_class, u8 *channel) 604325151a3SRui Paulo { 605*780fb4a2SCy Schubert u8 vht_opclass; 606*780fb4a2SCy Schubert 607325151a3SRui Paulo /* TODO: more operating classes */ 608325151a3SRui Paulo 609325151a3SRui Paulo if (sec_channel > 1 || sec_channel < -1) 610325151a3SRui Paulo return NUM_HOSTAPD_MODES; 6115b9c547cSRui Paulo 6125b9c547cSRui Paulo if (freq >= 2412 && freq <= 2472) { 613325151a3SRui Paulo if ((freq - 2407) % 5) 614325151a3SRui Paulo return NUM_HOSTAPD_MODES; 615325151a3SRui Paulo 616325151a3SRui Paulo if (vht) 617325151a3SRui Paulo return NUM_HOSTAPD_MODES; 618325151a3SRui Paulo 619325151a3SRui Paulo /* 2.407 GHz, channels 1..13 */ 620325151a3SRui Paulo if (sec_channel == 1) 621325151a3SRui Paulo *op_class = 83; 622325151a3SRui Paulo else if (sec_channel == -1) 623325151a3SRui Paulo *op_class = 84; 624325151a3SRui Paulo else 625325151a3SRui Paulo *op_class = 81; 626325151a3SRui Paulo 6275b9c547cSRui Paulo *channel = (freq - 2407) / 5; 628325151a3SRui Paulo 629325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211G; 630325151a3SRui Paulo } 631325151a3SRui Paulo 632325151a3SRui Paulo if (freq == 2484) { 633325151a3SRui Paulo if (sec_channel || vht) 634325151a3SRui Paulo return NUM_HOSTAPD_MODES; 635325151a3SRui Paulo 636325151a3SRui Paulo *op_class = 82; /* channel 14 */ 6375b9c547cSRui Paulo *channel = 14; 638325151a3SRui Paulo 639325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211B; 640325151a3SRui Paulo } 641325151a3SRui Paulo 642325151a3SRui Paulo if (freq >= 4900 && freq < 5000) { 643325151a3SRui Paulo if ((freq - 4000) % 5) 644325151a3SRui Paulo return NUM_HOSTAPD_MODES; 6455b9c547cSRui Paulo *channel = (freq - 4000) / 5; 646325151a3SRui Paulo *op_class = 0; /* TODO */ 647325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 648325151a3SRui Paulo } 649325151a3SRui Paulo 650*780fb4a2SCy Schubert switch (vht) { 651*780fb4a2SCy Schubert case VHT_CHANWIDTH_80MHZ: 652*780fb4a2SCy Schubert vht_opclass = 128; 653*780fb4a2SCy Schubert break; 654*780fb4a2SCy Schubert case VHT_CHANWIDTH_160MHZ: 655*780fb4a2SCy Schubert vht_opclass = 129; 656*780fb4a2SCy Schubert break; 657*780fb4a2SCy Schubert case VHT_CHANWIDTH_80P80MHZ: 658*780fb4a2SCy Schubert vht_opclass = 130; 659*780fb4a2SCy Schubert break; 660*780fb4a2SCy Schubert default: 661*780fb4a2SCy Schubert vht_opclass = 0; 662*780fb4a2SCy Schubert break; 663*780fb4a2SCy Schubert } 664*780fb4a2SCy Schubert 665325151a3SRui Paulo /* 5 GHz, channels 36..48 */ 666325151a3SRui Paulo if (freq >= 5180 && freq <= 5240) { 667325151a3SRui Paulo if ((freq - 5000) % 5) 668325151a3SRui Paulo return NUM_HOSTAPD_MODES; 669325151a3SRui Paulo 670*780fb4a2SCy Schubert if (vht_opclass) 671*780fb4a2SCy Schubert *op_class = vht_opclass; 672*780fb4a2SCy Schubert else if (sec_channel == 1) 673325151a3SRui Paulo *op_class = 116; 674325151a3SRui Paulo else if (sec_channel == -1) 675325151a3SRui Paulo *op_class = 117; 676325151a3SRui Paulo else 677325151a3SRui Paulo *op_class = 115; 678325151a3SRui Paulo 6795b9c547cSRui Paulo *channel = (freq - 5000) / 5; 680325151a3SRui Paulo 681325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 682325151a3SRui Paulo } 683325151a3SRui Paulo 684325151a3SRui Paulo /* 5 GHz, channels 149..169 */ 685325151a3SRui Paulo if (freq >= 5745 && freq <= 5845) { 686325151a3SRui Paulo if ((freq - 5000) % 5) 687325151a3SRui Paulo return NUM_HOSTAPD_MODES; 688325151a3SRui Paulo 689*780fb4a2SCy Schubert if (vht_opclass) 690*780fb4a2SCy Schubert *op_class = vht_opclass; 691*780fb4a2SCy Schubert else if (sec_channel == 1) 692*780fb4a2SCy Schubert *op_class = 126; 693*780fb4a2SCy Schubert else if (sec_channel == -1) 694*780fb4a2SCy Schubert *op_class = 127; 695*780fb4a2SCy Schubert else if (freq <= 5805) 696*780fb4a2SCy Schubert *op_class = 124; 697*780fb4a2SCy Schubert else 698325151a3SRui Paulo *op_class = 125; 699325151a3SRui Paulo 700325151a3SRui Paulo *channel = (freq - 5000) / 5; 701325151a3SRui Paulo 702325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 703325151a3SRui Paulo } 704325151a3SRui Paulo 705*780fb4a2SCy Schubert /* 5 GHz, channels 100..140 */ 706*780fb4a2SCy Schubert if (freq >= 5000 && freq <= 5700) { 707*780fb4a2SCy Schubert if ((freq - 5000) % 5) 708*780fb4a2SCy Schubert return NUM_HOSTAPD_MODES; 709*780fb4a2SCy Schubert 710*780fb4a2SCy Schubert if (vht_opclass) 711*780fb4a2SCy Schubert *op_class = vht_opclass; 712*780fb4a2SCy Schubert else if (sec_channel == 1) 713*780fb4a2SCy Schubert *op_class = 122; 714*780fb4a2SCy Schubert else if (sec_channel == -1) 715*780fb4a2SCy Schubert *op_class = 123; 716*780fb4a2SCy Schubert else 717*780fb4a2SCy Schubert *op_class = 121; 718*780fb4a2SCy Schubert 719*780fb4a2SCy Schubert *channel = (freq - 5000) / 5; 720*780fb4a2SCy Schubert 721*780fb4a2SCy Schubert return HOSTAPD_MODE_IEEE80211A; 722*780fb4a2SCy Schubert } 723*780fb4a2SCy Schubert 724325151a3SRui Paulo if (freq >= 5000 && freq < 5900) { 725325151a3SRui Paulo if ((freq - 5000) % 5) 726325151a3SRui Paulo return NUM_HOSTAPD_MODES; 727325151a3SRui Paulo *channel = (freq - 5000) / 5; 728325151a3SRui Paulo *op_class = 0; /* TODO */ 729325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211A; 730325151a3SRui Paulo } 731325151a3SRui Paulo 732325151a3SRui Paulo /* 56.16 GHz, channel 1..4 */ 733325151a3SRui Paulo if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { 734325151a3SRui Paulo if (sec_channel || vht) 735325151a3SRui Paulo return NUM_HOSTAPD_MODES; 736325151a3SRui Paulo 7375b9c547cSRui Paulo *channel = (freq - 56160) / 2160; 738325151a3SRui Paulo *op_class = 180; 739325151a3SRui Paulo 740325151a3SRui Paulo return HOSTAPD_MODE_IEEE80211AD; 7415b9c547cSRui Paulo } 7425b9c547cSRui Paulo 743325151a3SRui Paulo return NUM_HOSTAPD_MODES; 7445b9c547cSRui Paulo } 7455b9c547cSRui Paulo 7465b9c547cSRui Paulo 747325151a3SRui Paulo static const char *const us_op_class_cc[] = { 7485b9c547cSRui Paulo "US", "CA", NULL 7495b9c547cSRui Paulo }; 7505b9c547cSRui Paulo 751325151a3SRui Paulo static const char *const eu_op_class_cc[] = { 7525b9c547cSRui Paulo "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", 7535b9c547cSRui Paulo "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT", 7545b9c547cSRui Paulo "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", 7555b9c547cSRui Paulo "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL 7565b9c547cSRui Paulo }; 7575b9c547cSRui Paulo 758325151a3SRui Paulo static const char *const jp_op_class_cc[] = { 7595b9c547cSRui Paulo "JP", NULL 7605b9c547cSRui Paulo }; 7615b9c547cSRui Paulo 762325151a3SRui Paulo static const char *const cn_op_class_cc[] = { 763325151a3SRui Paulo "CN", NULL 7645b9c547cSRui Paulo }; 7655b9c547cSRui Paulo 7665b9c547cSRui Paulo 767325151a3SRui Paulo static int country_match(const char *const cc[], const char *const country) 7685b9c547cSRui Paulo { 7695b9c547cSRui Paulo int i; 7705b9c547cSRui Paulo 7715b9c547cSRui Paulo if (country == NULL) 7725b9c547cSRui Paulo return 0; 7735b9c547cSRui Paulo for (i = 0; cc[i]; i++) { 7745b9c547cSRui Paulo if (cc[i][0] == country[0] && cc[i][1] == country[1]) 7755b9c547cSRui Paulo return 1; 7765b9c547cSRui Paulo } 7775b9c547cSRui Paulo 7785b9c547cSRui Paulo return 0; 7795b9c547cSRui Paulo } 7805b9c547cSRui Paulo 7815b9c547cSRui Paulo 7825b9c547cSRui Paulo static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan) 7835b9c547cSRui Paulo { 7845b9c547cSRui Paulo switch (op_class) { 7855b9c547cSRui Paulo case 12: /* channels 1..11 */ 7865b9c547cSRui Paulo case 32: /* channels 1..7; 40 MHz */ 7875b9c547cSRui Paulo case 33: /* channels 5..11; 40 MHz */ 7885b9c547cSRui Paulo if (chan < 1 || chan > 11) 7895b9c547cSRui Paulo return -1; 7905b9c547cSRui Paulo return 2407 + 5 * chan; 7915b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 7925b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 7935b9c547cSRui Paulo case 22: /* channels 36,44; 40 MHz */ 7945b9c547cSRui Paulo case 23: /* channels 52,60; 40 MHz */ 7955b9c547cSRui Paulo case 27: /* channels 40,48; 40 MHz */ 7965b9c547cSRui Paulo case 28: /* channels 56,64; 40 MHz */ 7975b9c547cSRui Paulo if (chan < 36 || chan > 64) 7985b9c547cSRui Paulo return -1; 7995b9c547cSRui Paulo return 5000 + 5 * chan; 8005b9c547cSRui Paulo case 4: /* channels 100-144 */ 8015b9c547cSRui Paulo case 24: /* channels 100-140; 40 MHz */ 8025b9c547cSRui Paulo if (chan < 100 || chan > 144) 8035b9c547cSRui Paulo return -1; 8045b9c547cSRui Paulo return 5000 + 5 * chan; 8055b9c547cSRui Paulo case 3: /* channels 149,153,157,161 */ 8065b9c547cSRui Paulo case 25: /* channels 149,157; 40 MHz */ 8075b9c547cSRui Paulo case 26: /* channels 149,157; 40 MHz */ 8085b9c547cSRui Paulo case 30: /* channels 153,161; 40 MHz */ 8095b9c547cSRui Paulo case 31: /* channels 153,161; 40 MHz */ 8105b9c547cSRui Paulo if (chan < 149 || chan > 161) 8115b9c547cSRui Paulo return -1; 8125b9c547cSRui Paulo return 5000 + 5 * chan; 813325151a3SRui Paulo case 5: /* channels 149,153,157,161,165 */ 814325151a3SRui Paulo if (chan < 149 || chan > 165) 815325151a3SRui Paulo return -1; 816325151a3SRui Paulo return 5000 + 5 * chan; 8175b9c547cSRui Paulo case 34: /* 60 GHz band, channels 1..3 */ 8185b9c547cSRui Paulo if (chan < 1 || chan > 3) 8195b9c547cSRui Paulo return -1; 8205b9c547cSRui Paulo return 56160 + 2160 * chan; 8215b9c547cSRui Paulo } 8225b9c547cSRui Paulo return -1; 8235b9c547cSRui Paulo } 8245b9c547cSRui Paulo 8255b9c547cSRui Paulo 8265b9c547cSRui Paulo static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan) 8275b9c547cSRui Paulo { 8285b9c547cSRui Paulo switch (op_class) { 8295b9c547cSRui Paulo case 4: /* channels 1..13 */ 8305b9c547cSRui Paulo case 11: /* channels 1..9; 40 MHz */ 8315b9c547cSRui Paulo case 12: /* channels 5..13; 40 MHz */ 8325b9c547cSRui Paulo if (chan < 1 || chan > 13) 8335b9c547cSRui Paulo return -1; 8345b9c547cSRui Paulo return 2407 + 5 * chan; 8355b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 8365b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 8375b9c547cSRui Paulo case 5: /* channels 36,44; 40 MHz */ 8385b9c547cSRui Paulo case 6: /* channels 52,60; 40 MHz */ 8395b9c547cSRui Paulo case 8: /* channels 40,48; 40 MHz */ 8405b9c547cSRui Paulo case 9: /* channels 56,64; 40 MHz */ 8415b9c547cSRui Paulo if (chan < 36 || chan > 64) 8425b9c547cSRui Paulo return -1; 8435b9c547cSRui Paulo return 5000 + 5 * chan; 8445b9c547cSRui Paulo case 3: /* channels 100-140 */ 8455b9c547cSRui Paulo case 7: /* channels 100-132; 40 MHz */ 8465b9c547cSRui Paulo case 10: /* channels 104-136; 40 MHz */ 8475b9c547cSRui Paulo case 16: /* channels 100-140 */ 8485b9c547cSRui Paulo if (chan < 100 || chan > 140) 8495b9c547cSRui Paulo return -1; 8505b9c547cSRui Paulo return 5000 + 5 * chan; 8515b9c547cSRui Paulo case 17: /* channels 149,153,157,161,165,169 */ 8525b9c547cSRui Paulo if (chan < 149 || chan > 169) 8535b9c547cSRui Paulo return -1; 8545b9c547cSRui Paulo return 5000 + 5 * chan; 8555b9c547cSRui Paulo case 18: /* 60 GHz band, channels 1..4 */ 8565b9c547cSRui Paulo if (chan < 1 || chan > 4) 8575b9c547cSRui Paulo return -1; 8585b9c547cSRui Paulo return 56160 + 2160 * chan; 8595b9c547cSRui Paulo } 8605b9c547cSRui Paulo return -1; 8615b9c547cSRui Paulo } 8625b9c547cSRui Paulo 8635b9c547cSRui Paulo 8645b9c547cSRui Paulo static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) 8655b9c547cSRui Paulo { 8665b9c547cSRui Paulo switch (op_class) { 8675b9c547cSRui Paulo case 30: /* channels 1..13 */ 8685b9c547cSRui Paulo case 56: /* channels 1..9; 40 MHz */ 8695b9c547cSRui Paulo case 57: /* channels 5..13; 40 MHz */ 8705b9c547cSRui Paulo if (chan < 1 || chan > 13) 8715b9c547cSRui Paulo return -1; 8725b9c547cSRui Paulo return 2407 + 5 * chan; 8735b9c547cSRui Paulo case 31: /* channel 14 */ 8745b9c547cSRui Paulo if (chan != 14) 8755b9c547cSRui Paulo return -1; 8765b9c547cSRui Paulo return 2414 + 5 * chan; 8775b9c547cSRui Paulo case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */ 8785b9c547cSRui Paulo case 32: /* channels 52,56,60,64 */ 8795b9c547cSRui Paulo case 33: /* channels 52,56,60,64 */ 8805b9c547cSRui Paulo case 36: /* channels 36,44; 40 MHz */ 8815b9c547cSRui Paulo case 37: /* channels 52,60; 40 MHz */ 8825b9c547cSRui Paulo case 38: /* channels 52,60; 40 MHz */ 8835b9c547cSRui Paulo case 41: /* channels 40,48; 40 MHz */ 8845b9c547cSRui Paulo case 42: /* channels 56,64; 40 MHz */ 8855b9c547cSRui Paulo case 43: /* channels 56,64; 40 MHz */ 8865b9c547cSRui Paulo if (chan < 34 || chan > 64) 8875b9c547cSRui Paulo return -1; 8885b9c547cSRui Paulo return 5000 + 5 * chan; 8895b9c547cSRui Paulo case 34: /* channels 100-140 */ 8905b9c547cSRui Paulo case 35: /* channels 100-140 */ 8915b9c547cSRui Paulo case 39: /* channels 100-132; 40 MHz */ 8925b9c547cSRui Paulo case 40: /* channels 100-132; 40 MHz */ 8935b9c547cSRui Paulo case 44: /* channels 104-136; 40 MHz */ 8945b9c547cSRui Paulo case 45: /* channels 104-136; 40 MHz */ 8955b9c547cSRui Paulo case 58: /* channels 100-140 */ 8965b9c547cSRui Paulo if (chan < 100 || chan > 140) 8975b9c547cSRui Paulo return -1; 8985b9c547cSRui Paulo return 5000 + 5 * chan; 8995b9c547cSRui Paulo case 59: /* 60 GHz band, channels 1..4 */ 9005b9c547cSRui Paulo if (chan < 1 || chan > 3) 9015b9c547cSRui Paulo return -1; 9025b9c547cSRui Paulo return 56160 + 2160 * chan; 9035b9c547cSRui Paulo } 9045b9c547cSRui Paulo return -1; 9055b9c547cSRui Paulo } 9065b9c547cSRui Paulo 9075b9c547cSRui Paulo 9085b9c547cSRui Paulo static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan) 9095b9c547cSRui Paulo { 9105b9c547cSRui Paulo switch (op_class) { 9115b9c547cSRui Paulo case 7: /* channels 1..13 */ 9125b9c547cSRui Paulo case 8: /* channels 1..9; 40 MHz */ 9135b9c547cSRui Paulo case 9: /* channels 5..13; 40 MHz */ 9145b9c547cSRui Paulo if (chan < 1 || chan > 13) 9155b9c547cSRui Paulo return -1; 9165b9c547cSRui Paulo return 2407 + 5 * chan; 9175b9c547cSRui Paulo case 1: /* channels 36,40,44,48 */ 9185b9c547cSRui Paulo case 2: /* channels 52,56,60,64; dfs */ 9195b9c547cSRui Paulo case 4: /* channels 36,44; 40 MHz */ 9205b9c547cSRui Paulo case 5: /* channels 52,60; 40 MHz */ 9215b9c547cSRui Paulo if (chan < 36 || chan > 64) 9225b9c547cSRui Paulo return -1; 9235b9c547cSRui Paulo return 5000 + 5 * chan; 9245b9c547cSRui Paulo case 3: /* channels 149,153,157,161,165 */ 9255b9c547cSRui Paulo case 6: /* channels 149,157; 40 MHz */ 9265b9c547cSRui Paulo if (chan < 149 || chan > 165) 9275b9c547cSRui Paulo return -1; 9285b9c547cSRui Paulo return 5000 + 5 * chan; 9295b9c547cSRui Paulo } 9305b9c547cSRui Paulo return -1; 9315b9c547cSRui Paulo } 9325b9c547cSRui Paulo 9335b9c547cSRui Paulo 9345b9c547cSRui Paulo static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) 9355b9c547cSRui Paulo { 9365b9c547cSRui Paulo /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ 9375b9c547cSRui Paulo switch (op_class) { 9385b9c547cSRui Paulo case 81: 9395b9c547cSRui Paulo /* channels 1..13 */ 9405b9c547cSRui Paulo if (chan < 1 || chan > 13) 9415b9c547cSRui Paulo return -1; 9425b9c547cSRui Paulo return 2407 + 5 * chan; 9435b9c547cSRui Paulo case 82: 9445b9c547cSRui Paulo /* channel 14 */ 9455b9c547cSRui Paulo if (chan != 14) 9465b9c547cSRui Paulo return -1; 9475b9c547cSRui Paulo return 2414 + 5 * chan; 9485b9c547cSRui Paulo case 83: /* channels 1..9; 40 MHz */ 9495b9c547cSRui Paulo case 84: /* channels 5..13; 40 MHz */ 9505b9c547cSRui Paulo if (chan < 1 || chan > 13) 9515b9c547cSRui Paulo return -1; 9525b9c547cSRui Paulo return 2407 + 5 * chan; 9535b9c547cSRui Paulo case 115: /* channels 36,40,44,48; indoor only */ 9545b9c547cSRui Paulo case 116: /* channels 36,44; 40 MHz; indoor only */ 9555b9c547cSRui Paulo case 117: /* channels 40,48; 40 MHz; indoor only */ 9565b9c547cSRui Paulo case 118: /* channels 52,56,60,64; dfs */ 9575b9c547cSRui Paulo case 119: /* channels 52,60; 40 MHz; dfs */ 9585b9c547cSRui Paulo case 120: /* channels 56,64; 40 MHz; dfs */ 9595b9c547cSRui Paulo if (chan < 36 || chan > 64) 9605b9c547cSRui Paulo return -1; 9615b9c547cSRui Paulo return 5000 + 5 * chan; 9625b9c547cSRui Paulo case 121: /* channels 100-140 */ 9635b9c547cSRui Paulo case 122: /* channels 100-142; 40 MHz */ 9645b9c547cSRui Paulo case 123: /* channels 104-136; 40 MHz */ 9655b9c547cSRui Paulo if (chan < 100 || chan > 140) 9665b9c547cSRui Paulo return -1; 9675b9c547cSRui Paulo return 5000 + 5 * chan; 9685b9c547cSRui Paulo case 124: /* channels 149,153,157,161 */ 9695b9c547cSRui Paulo case 126: /* channels 149,157; 40 MHz */ 9705b9c547cSRui Paulo case 127: /* channels 153,161; 40 MHz */ 9715b9c547cSRui Paulo if (chan < 149 || chan > 161) 9725b9c547cSRui Paulo return -1; 9735b9c547cSRui Paulo return 5000 + 5 * chan; 974325151a3SRui Paulo case 125: /* channels 149,153,157,161,165,169 */ 975325151a3SRui Paulo if (chan < 149 || chan > 169) 976325151a3SRui Paulo return -1; 977325151a3SRui Paulo return 5000 + 5 * chan; 9785b9c547cSRui Paulo case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ 9795b9c547cSRui Paulo case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ 9805b9c547cSRui Paulo if (chan < 36 || chan > 161) 9815b9c547cSRui Paulo return -1; 9825b9c547cSRui Paulo return 5000 + 5 * chan; 9835b9c547cSRui Paulo case 129: /* center freqs 50, 114; 160 MHz */ 9845b9c547cSRui Paulo if (chan < 50 || chan > 114) 9855b9c547cSRui Paulo return -1; 9865b9c547cSRui Paulo return 5000 + 5 * chan; 9875b9c547cSRui Paulo case 180: /* 60 GHz band, channels 1..4 */ 9885b9c547cSRui Paulo if (chan < 1 || chan > 4) 9895b9c547cSRui Paulo return -1; 9905b9c547cSRui Paulo return 56160 + 2160 * chan; 9915b9c547cSRui Paulo } 9925b9c547cSRui Paulo return -1; 9935b9c547cSRui Paulo } 9945b9c547cSRui Paulo 9955b9c547cSRui Paulo /** 9965b9c547cSRui Paulo * ieee80211_chan_to_freq - Convert channel info to frequency 9975b9c547cSRui Paulo * @country: Country code, if known; otherwise, global operating class is used 9985b9c547cSRui Paulo * @op_class: Operating class 9995b9c547cSRui Paulo * @chan: Channel number 10005b9c547cSRui Paulo * Returns: Frequency in MHz or -1 if the specified channel is unknown 10015b9c547cSRui Paulo */ 10025b9c547cSRui Paulo int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan) 10035b9c547cSRui Paulo { 10045b9c547cSRui Paulo int freq; 10055b9c547cSRui Paulo 10065b9c547cSRui Paulo if (country_match(us_op_class_cc, country)) { 10075b9c547cSRui Paulo freq = ieee80211_chan_to_freq_us(op_class, chan); 10085b9c547cSRui Paulo if (freq > 0) 10095b9c547cSRui Paulo return freq; 10105b9c547cSRui Paulo } 10115b9c547cSRui Paulo 10125b9c547cSRui Paulo if (country_match(eu_op_class_cc, country)) { 10135b9c547cSRui Paulo freq = ieee80211_chan_to_freq_eu(op_class, chan); 10145b9c547cSRui Paulo if (freq > 0) 10155b9c547cSRui Paulo return freq; 10165b9c547cSRui Paulo } 10175b9c547cSRui Paulo 10185b9c547cSRui Paulo if (country_match(jp_op_class_cc, country)) { 10195b9c547cSRui Paulo freq = ieee80211_chan_to_freq_jp(op_class, chan); 10205b9c547cSRui Paulo if (freq > 0) 10215b9c547cSRui Paulo return freq; 10225b9c547cSRui Paulo } 10235b9c547cSRui Paulo 10245b9c547cSRui Paulo if (country_match(cn_op_class_cc, country)) { 10255b9c547cSRui Paulo freq = ieee80211_chan_to_freq_cn(op_class, chan); 10265b9c547cSRui Paulo if (freq > 0) 10275b9c547cSRui Paulo return freq; 10285b9c547cSRui Paulo } 10295b9c547cSRui Paulo 10305b9c547cSRui Paulo return ieee80211_chan_to_freq_global(op_class, chan); 10315b9c547cSRui Paulo } 10325b9c547cSRui Paulo 10335b9c547cSRui Paulo 10345b9c547cSRui Paulo int ieee80211_is_dfs(int freq) 10355b9c547cSRui Paulo { 10365b9c547cSRui Paulo /* TODO: this could be more accurate to better cover all domains */ 10375b9c547cSRui Paulo return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700); 10385b9c547cSRui Paulo } 10395b9c547cSRui Paulo 10405b9c547cSRui Paulo 10415b9c547cSRui Paulo static int is_11b(u8 rate) 10425b9c547cSRui Paulo { 10435b9c547cSRui Paulo return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; 10445b9c547cSRui Paulo } 10455b9c547cSRui Paulo 10465b9c547cSRui Paulo 10475b9c547cSRui Paulo int supp_rates_11b_only(struct ieee802_11_elems *elems) 10485b9c547cSRui Paulo { 10495b9c547cSRui Paulo int num_11b = 0, num_others = 0; 10505b9c547cSRui Paulo int i; 10515b9c547cSRui Paulo 10525b9c547cSRui Paulo if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) 10535b9c547cSRui Paulo return 0; 10545b9c547cSRui Paulo 10555b9c547cSRui Paulo for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { 10565b9c547cSRui Paulo if (is_11b(elems->supp_rates[i])) 10575b9c547cSRui Paulo num_11b++; 10585b9c547cSRui Paulo else 10595b9c547cSRui Paulo num_others++; 10605b9c547cSRui Paulo } 10615b9c547cSRui Paulo 10625b9c547cSRui Paulo for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; 10635b9c547cSRui Paulo i++) { 10645b9c547cSRui Paulo if (is_11b(elems->ext_supp_rates[i])) 10655b9c547cSRui Paulo num_11b++; 10665b9c547cSRui Paulo else 10675b9c547cSRui Paulo num_others++; 10685b9c547cSRui Paulo } 10695b9c547cSRui Paulo 10705b9c547cSRui Paulo return num_11b > 0 && num_others == 0; 10715b9c547cSRui Paulo } 10725b9c547cSRui Paulo 10735b9c547cSRui Paulo 10745b9c547cSRui Paulo const char * fc2str(u16 fc) 10755b9c547cSRui Paulo { 10765b9c547cSRui Paulo u16 stype = WLAN_FC_GET_STYPE(fc); 10775b9c547cSRui Paulo #define C2S(x) case x: return #x; 10785b9c547cSRui Paulo 10795b9c547cSRui Paulo switch (WLAN_FC_GET_TYPE(fc)) { 10805b9c547cSRui Paulo case WLAN_FC_TYPE_MGMT: 10815b9c547cSRui Paulo switch (stype) { 10825b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ASSOC_REQ) 10835b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ASSOC_RESP) 10845b9c547cSRui Paulo C2S(WLAN_FC_STYPE_REASSOC_REQ) 10855b9c547cSRui Paulo C2S(WLAN_FC_STYPE_REASSOC_RESP) 10865b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PROBE_REQ) 10875b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PROBE_RESP) 10885b9c547cSRui Paulo C2S(WLAN_FC_STYPE_BEACON) 10895b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ATIM) 10905b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DISASSOC) 10915b9c547cSRui Paulo C2S(WLAN_FC_STYPE_AUTH) 10925b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DEAUTH) 10935b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ACTION) 10945b9c547cSRui Paulo } 10955b9c547cSRui Paulo break; 10965b9c547cSRui Paulo case WLAN_FC_TYPE_CTRL: 10975b9c547cSRui Paulo switch (stype) { 10985b9c547cSRui Paulo C2S(WLAN_FC_STYPE_PSPOLL) 10995b9c547cSRui Paulo C2S(WLAN_FC_STYPE_RTS) 11005b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CTS) 11015b9c547cSRui Paulo C2S(WLAN_FC_STYPE_ACK) 11025b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFEND) 11035b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFENDACK) 11045b9c547cSRui Paulo } 11055b9c547cSRui Paulo break; 11065b9c547cSRui Paulo case WLAN_FC_TYPE_DATA: 11075b9c547cSRui Paulo switch (stype) { 11085b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA) 11095b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFACK) 11105b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFPOLL) 11115b9c547cSRui Paulo C2S(WLAN_FC_STYPE_DATA_CFACKPOLL) 11125b9c547cSRui Paulo C2S(WLAN_FC_STYPE_NULLFUNC) 11135b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFACK) 11145b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFPOLL) 11155b9c547cSRui Paulo C2S(WLAN_FC_STYPE_CFACKPOLL) 11165b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA) 11175b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACK) 11185b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL) 11195b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL) 11205b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_NULL) 11215b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_CFPOLL) 11225b9c547cSRui Paulo C2S(WLAN_FC_STYPE_QOS_CFACKPOLL) 11235b9c547cSRui Paulo } 11245b9c547cSRui Paulo break; 11255b9c547cSRui Paulo } 11265b9c547cSRui Paulo return "WLAN_FC_TYPE_UNKNOWN"; 11275b9c547cSRui Paulo #undef C2S 11285b9c547cSRui Paulo } 1129325151a3SRui Paulo 1130325151a3SRui Paulo 1131325151a3SRui Paulo int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, 1132325151a3SRui Paulo size_t ies_len) 1133325151a3SRui Paulo { 1134325151a3SRui Paulo os_memset(info, 0, sizeof(*info)); 1135325151a3SRui Paulo 1136325151a3SRui Paulo while (ies_buf && ies_len >= 2 && 1137325151a3SRui Paulo info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) { 1138325151a3SRui Paulo size_t len = 2 + ies_buf[1]; 1139325151a3SRui Paulo 1140325151a3SRui Paulo if (len > ies_len) { 1141325151a3SRui Paulo wpa_hexdump(MSG_DEBUG, "Truncated IEs", 1142325151a3SRui Paulo ies_buf, ies_len); 1143325151a3SRui Paulo return -1; 1144325151a3SRui Paulo } 1145325151a3SRui Paulo 1146325151a3SRui Paulo if (ies_buf[0] == WLAN_EID_MULTI_BAND) { 1147325151a3SRui Paulo wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len); 1148325151a3SRui Paulo info->ies[info->nof_ies].ie = ies_buf + 2; 1149325151a3SRui Paulo info->ies[info->nof_ies].ie_len = ies_buf[1]; 1150325151a3SRui Paulo info->nof_ies++; 1151325151a3SRui Paulo } 1152325151a3SRui Paulo 1153325151a3SRui Paulo ies_len -= len; 1154325151a3SRui Paulo ies_buf += len; 1155325151a3SRui Paulo } 1156325151a3SRui Paulo 1157325151a3SRui Paulo return 0; 1158325151a3SRui Paulo } 1159325151a3SRui Paulo 1160325151a3SRui Paulo 1161325151a3SRui Paulo struct wpabuf * mb_ies_by_info(struct mb_ies_info *info) 1162325151a3SRui Paulo { 1163325151a3SRui Paulo struct wpabuf *mb_ies = NULL; 1164325151a3SRui Paulo 1165325151a3SRui Paulo WPA_ASSERT(info != NULL); 1166325151a3SRui Paulo 1167325151a3SRui Paulo if (info->nof_ies) { 1168325151a3SRui Paulo u8 i; 1169325151a3SRui Paulo size_t mb_ies_size = 0; 1170325151a3SRui Paulo 1171325151a3SRui Paulo for (i = 0; i < info->nof_ies; i++) 1172325151a3SRui Paulo mb_ies_size += 2 + info->ies[i].ie_len; 1173325151a3SRui Paulo 1174325151a3SRui Paulo mb_ies = wpabuf_alloc(mb_ies_size); 1175325151a3SRui Paulo if (mb_ies) { 1176325151a3SRui Paulo for (i = 0; i < info->nof_ies; i++) { 1177325151a3SRui Paulo wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND); 1178325151a3SRui Paulo wpabuf_put_u8(mb_ies, info->ies[i].ie_len); 1179325151a3SRui Paulo wpabuf_put_data(mb_ies, 1180325151a3SRui Paulo info->ies[i].ie, 1181325151a3SRui Paulo info->ies[i].ie_len); 1182325151a3SRui Paulo } 1183325151a3SRui Paulo } 1184325151a3SRui Paulo } 1185325151a3SRui Paulo 1186325151a3SRui Paulo return mb_ies; 1187325151a3SRui Paulo } 1188*780fb4a2SCy Schubert 1189*780fb4a2SCy Schubert 1190*780fb4a2SCy Schubert const struct oper_class_map global_op_class[] = { 1191*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP }, 1192*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP }, 1193*780fb4a2SCy Schubert 1194*780fb4a2SCy Schubert /* Do not enable HT40 on 2.4 GHz for P2P use for now */ 1195*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP }, 1196*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP }, 1197*780fb4a2SCy Schubert 1198*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, 1199*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, 1200*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, 1201*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, 1202*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, 1203*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, 1204*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, 1205*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP }, 1206*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP }, 1207*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, 1208*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP }, 1209*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP }, 1210*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP }, 1211*780fb4a2SCy Schubert 1212*780fb4a2SCy Schubert /* 1213*780fb4a2SCy Schubert * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center 1214*780fb4a2SCy Schubert * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of 1215*780fb4a2SCy Schubert * 80 MHz, but currently use the following definition for simplicity 1216*780fb4a2SCy Schubert * (these center frequencies are not actual channels, which makes 1217*780fb4a2SCy Schubert * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take 1218*780fb4a2SCy Schubert * care of removing invalid channels. 1219*780fb4a2SCy Schubert */ 1220*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP }, 1221*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP }, 1222*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP }, 1223*780fb4a2SCy Schubert { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP }, 1224*780fb4a2SCy Schubert { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } 1225*780fb4a2SCy Schubert }; 1226*780fb4a2SCy Schubert 1227*780fb4a2SCy Schubert 1228*780fb4a2SCy Schubert static enum phy_type ieee80211_phy_type_by_freq(int freq) 1229*780fb4a2SCy Schubert { 1230*780fb4a2SCy Schubert enum hostapd_hw_mode hw_mode; 1231*780fb4a2SCy Schubert u8 channel; 1232*780fb4a2SCy Schubert 1233*780fb4a2SCy Schubert hw_mode = ieee80211_freq_to_chan(freq, &channel); 1234*780fb4a2SCy Schubert 1235*780fb4a2SCy Schubert switch (hw_mode) { 1236*780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211A: 1237*780fb4a2SCy Schubert return PHY_TYPE_OFDM; 1238*780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211B: 1239*780fb4a2SCy Schubert return PHY_TYPE_HRDSSS; 1240*780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211G: 1241*780fb4a2SCy Schubert return PHY_TYPE_ERP; 1242*780fb4a2SCy Schubert case HOSTAPD_MODE_IEEE80211AD: 1243*780fb4a2SCy Schubert return PHY_TYPE_DMG; 1244*780fb4a2SCy Schubert default: 1245*780fb4a2SCy Schubert return PHY_TYPE_UNSPECIFIED; 1246*780fb4a2SCy Schubert }; 1247*780fb4a2SCy Schubert } 1248*780fb4a2SCy Schubert 1249*780fb4a2SCy Schubert 1250*780fb4a2SCy Schubert /* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */ 1251*780fb4a2SCy Schubert enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht) 1252*780fb4a2SCy Schubert { 1253*780fb4a2SCy Schubert if (vht) 1254*780fb4a2SCy Schubert return PHY_TYPE_VHT; 1255*780fb4a2SCy Schubert if (ht) 1256*780fb4a2SCy Schubert return PHY_TYPE_HT; 1257*780fb4a2SCy Schubert 1258*780fb4a2SCy Schubert return ieee80211_phy_type_by_freq(freq); 1259*780fb4a2SCy Schubert } 1260*780fb4a2SCy Schubert 1261*780fb4a2SCy Schubert 1262*780fb4a2SCy Schubert size_t global_op_class_size = ARRAY_SIZE(global_op_class); 1263*780fb4a2SCy Schubert 1264*780fb4a2SCy Schubert 1265*780fb4a2SCy Schubert /** 1266*780fb4a2SCy Schubert * get_ie - Fetch a specified information element from IEs buffer 1267*780fb4a2SCy Schubert * @ies: Information elements buffer 1268*780fb4a2SCy Schubert * @len: Information elements buffer length 1269*780fb4a2SCy Schubert * @eid: Information element identifier (WLAN_EID_*) 1270*780fb4a2SCy Schubert * Returns: Pointer to the information element (id field) or %NULL if not found 1271*780fb4a2SCy Schubert * 1272*780fb4a2SCy Schubert * This function returns the first matching information element in the IEs 1273*780fb4a2SCy Schubert * buffer or %NULL in case the element is not found. 1274*780fb4a2SCy Schubert */ 1275*780fb4a2SCy Schubert const u8 * get_ie(const u8 *ies, size_t len, u8 eid) 1276*780fb4a2SCy Schubert { 1277*780fb4a2SCy Schubert const u8 *end; 1278*780fb4a2SCy Schubert 1279*780fb4a2SCy Schubert if (!ies) 1280*780fb4a2SCy Schubert return NULL; 1281*780fb4a2SCy Schubert 1282*780fb4a2SCy Schubert end = ies + len; 1283*780fb4a2SCy Schubert 1284*780fb4a2SCy Schubert while (end - ies > 1) { 1285*780fb4a2SCy Schubert if (2 + ies[1] > end - ies) 1286*780fb4a2SCy Schubert break; 1287*780fb4a2SCy Schubert 1288*780fb4a2SCy Schubert if (ies[0] == eid) 1289*780fb4a2SCy Schubert return ies; 1290*780fb4a2SCy Schubert 1291*780fb4a2SCy Schubert ies += 2 + ies[1]; 1292*780fb4a2SCy Schubert } 1293*780fb4a2SCy Schubert 1294*780fb4a2SCy Schubert return NULL; 1295*780fb4a2SCy Schubert } 1296*780fb4a2SCy Schubert 1297*780fb4a2SCy Schubert 1298*780fb4a2SCy Schubert size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) 1299*780fb4a2SCy Schubert { 1300*780fb4a2SCy Schubert /* 1301*780fb4a2SCy Schubert * MBO IE requires 6 bytes without the attributes: EID (1), length (1), 1302*780fb4a2SCy Schubert * OUI (3), OUI type (1). 1303*780fb4a2SCy Schubert */ 1304*780fb4a2SCy Schubert if (len < 6 + attr_len) { 1305*780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1306*780fb4a2SCy Schubert "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu", 1307*780fb4a2SCy Schubert len, attr_len); 1308*780fb4a2SCy Schubert return 0; 1309*780fb4a2SCy Schubert } 1310*780fb4a2SCy Schubert 1311*780fb4a2SCy Schubert *buf++ = WLAN_EID_VENDOR_SPECIFIC; 1312*780fb4a2SCy Schubert *buf++ = attr_len + 4; 1313*780fb4a2SCy Schubert WPA_PUT_BE24(buf, OUI_WFA); 1314*780fb4a2SCy Schubert buf += 3; 1315*780fb4a2SCy Schubert *buf++ = MBO_OUI_TYPE; 1316*780fb4a2SCy Schubert os_memcpy(buf, attr, attr_len); 1317*780fb4a2SCy Schubert 1318*780fb4a2SCy Schubert return 6 + attr_len; 1319*780fb4a2SCy Schubert } 1320