1189251Ssam/* 2189251Ssam * IEEE 802.11 Common routines 3346981Scy * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12281806Srpaulo#include "defs.h" 13289549Srpaulo#include "wpa_common.h" 14346981Scy#include "drivers/driver.h" 15289549Srpaulo#include "qca-vendor.h" 16189251Ssam#include "ieee802_11_defs.h" 17189251Ssam#include "ieee802_11_common.h" 18189251Ssam 19189251Ssam 20214734Srpaulostatic int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 21189251Ssam struct ieee802_11_elems *elems, 22189251Ssam int show_errors) 23189251Ssam{ 24189251Ssam unsigned int oui; 25189251Ssam 26189251Ssam /* first 3 bytes in vendor specific information element are the IEEE 27189251Ssam * OUI of the vendor. The following byte is used a vendor specific 28189251Ssam * sub-type. */ 29189251Ssam if (elen < 4) { 30189251Ssam if (show_errors) { 31189251Ssam wpa_printf(MSG_MSGDUMP, "short vendor specific " 32189251Ssam "information element ignored (len=%lu)", 33189251Ssam (unsigned long) elen); 34189251Ssam } 35189251Ssam return -1; 36189251Ssam } 37189251Ssam 38189251Ssam oui = WPA_GET_BE24(pos); 39189251Ssam switch (oui) { 40189251Ssam case OUI_MICROSOFT: 41189251Ssam /* Microsoft/Wi-Fi information elements are further typed and 42189251Ssam * subtyped */ 43189251Ssam switch (pos[3]) { 44189251Ssam case 1: 45189251Ssam /* Microsoft OUI (00:50:F2) with OUI Type 1: 46189251Ssam * real WPA information element */ 47189251Ssam elems->wpa_ie = pos; 48189251Ssam elems->wpa_ie_len = elen; 49189251Ssam break; 50209158Srpaulo case WMM_OUI_TYPE: 51209158Srpaulo /* WMM information element */ 52189251Ssam if (elen < 5) { 53209158Srpaulo wpa_printf(MSG_MSGDUMP, "short WMM " 54189251Ssam "information element ignored " 55189251Ssam "(len=%lu)", 56189251Ssam (unsigned long) elen); 57189251Ssam return -1; 58189251Ssam } 59189251Ssam switch (pos[4]) { 60209158Srpaulo case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 61209158Srpaulo case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 62209158Srpaulo /* 63209158Srpaulo * Share same pointer since only one of these 64209158Srpaulo * is used and they start with same data. 65209158Srpaulo * Length field can be used to distinguish the 66209158Srpaulo * IEs. 67209158Srpaulo */ 68209158Srpaulo elems->wmm = pos; 69209158Srpaulo elems->wmm_len = elen; 70189251Ssam break; 71209158Srpaulo case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 72209158Srpaulo elems->wmm_tspec = pos; 73209158Srpaulo elems->wmm_tspec_len = elen; 74189251Ssam break; 75189251Ssam default: 76252726Srpaulo wpa_printf(MSG_EXCESSIVE, "unknown WMM " 77189251Ssam "information element ignored " 78189251Ssam "(subtype=%d len=%lu)", 79189251Ssam pos[4], (unsigned long) elen); 80189251Ssam return -1; 81189251Ssam } 82189251Ssam break; 83189251Ssam case 4: 84189251Ssam /* Wi-Fi Protected Setup (WPS) IE */ 85189251Ssam elems->wps_ie = pos; 86189251Ssam elems->wps_ie_len = elen; 87189251Ssam break; 88189251Ssam default: 89252726Srpaulo wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 90189251Ssam "information element ignored " 91252726Srpaulo "(type=%d len=%lu)", 92252726Srpaulo pos[3], (unsigned long) elen); 93252726Srpaulo return -1; 94252726Srpaulo } 95252726Srpaulo break; 96252726Srpaulo 97252726Srpaulo case OUI_WFA: 98252726Srpaulo switch (pos[3]) { 99252726Srpaulo case P2P_OUI_TYPE: 100252726Srpaulo /* Wi-Fi Alliance - P2P IE */ 101252726Srpaulo elems->p2p = pos; 102252726Srpaulo elems->p2p_len = elen; 103252726Srpaulo break; 104252726Srpaulo case WFD_OUI_TYPE: 105252726Srpaulo /* Wi-Fi Alliance - WFD IE */ 106252726Srpaulo elems->wfd = pos; 107252726Srpaulo elems->wfd_len = elen; 108252726Srpaulo break; 109252726Srpaulo case HS20_INDICATION_OUI_TYPE: 110252726Srpaulo /* Hotspot 2.0 */ 111252726Srpaulo elems->hs20 = pos; 112252726Srpaulo elems->hs20_len = elen; 113252726Srpaulo break; 114281806Srpaulo case HS20_OSEN_OUI_TYPE: 115281806Srpaulo /* Hotspot 2.0 OSEN */ 116281806Srpaulo elems->osen = pos; 117281806Srpaulo elems->osen_len = elen; 118281806Srpaulo break; 119337817Scy case MBO_OUI_TYPE: 120337817Scy /* MBO-OCE */ 121337817Scy elems->mbo = pos; 122337817Scy elems->mbo_len = elen; 123337817Scy break; 124346981Scy case HS20_ROAMING_CONS_SEL_OUI_TYPE: 125346981Scy /* Hotspot 2.0 Roaming Consortium Selection */ 126346981Scy elems->roaming_cons_sel = pos; 127346981Scy elems->roaming_cons_sel_len = elen; 128346981Scy break; 129346981Scy case MULTI_AP_OUI_TYPE: 130346981Scy elems->multi_ap = pos; 131346981Scy elems->multi_ap_len = elen; 132346981Scy break; 133252726Srpaulo default: 134252726Srpaulo wpa_printf(MSG_MSGDUMP, "Unknown WFA " 135252726Srpaulo "information element ignored " 136281806Srpaulo "(type=%d len=%lu)", 137189251Ssam pos[3], (unsigned long) elen); 138189251Ssam return -1; 139189251Ssam } 140189251Ssam break; 141189251Ssam 142189251Ssam case OUI_BROADCOM: 143189251Ssam switch (pos[3]) { 144189251Ssam case VENDOR_HT_CAPAB_OUI_TYPE: 145189251Ssam elems->vendor_ht_cap = pos; 146189251Ssam elems->vendor_ht_cap_len = elen; 147189251Ssam break; 148281806Srpaulo case VENDOR_VHT_TYPE: 149281806Srpaulo if (elen > 4 && 150281806Srpaulo (pos[4] == VENDOR_VHT_SUBTYPE || 151281806Srpaulo pos[4] == VENDOR_VHT_SUBTYPE2)) { 152281806Srpaulo elems->vendor_vht = pos; 153281806Srpaulo elems->vendor_vht_len = elen; 154281806Srpaulo } else 155281806Srpaulo return -1; 156281806Srpaulo break; 157189251Ssam default: 158252726Srpaulo wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 159189251Ssam "information element ignored " 160252726Srpaulo "(type=%d len=%lu)", 161189251Ssam pos[3], (unsigned long) elen); 162189251Ssam return -1; 163189251Ssam } 164189251Ssam break; 165189251Ssam 166289549Srpaulo case OUI_QCA: 167289549Srpaulo switch (pos[3]) { 168289549Srpaulo case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: 169289549Srpaulo elems->pref_freq_list = pos; 170289549Srpaulo elems->pref_freq_list_len = elen; 171289549Srpaulo break; 172289549Srpaulo default: 173289549Srpaulo wpa_printf(MSG_EXCESSIVE, 174289549Srpaulo "Unknown QCA information element ignored (type=%d len=%lu)", 175289549Srpaulo pos[3], (unsigned long) elen); 176289549Srpaulo return -1; 177289549Srpaulo } 178289549Srpaulo break; 179289549Srpaulo 180189251Ssam default: 181252726Srpaulo wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 182252726Srpaulo "information element ignored (vendor OUI " 183252726Srpaulo "%02x:%02x:%02x len=%lu)", 184189251Ssam pos[0], pos[1], pos[2], (unsigned long) elen); 185189251Ssam return -1; 186189251Ssam } 187189251Ssam 188189251Ssam return 0; 189189251Ssam} 190189251Ssam 191189251Ssam 192346981Scystatic int ieee802_11_parse_extension(const u8 *pos, size_t elen, 193346981Scy struct ieee802_11_elems *elems, 194346981Scy int show_errors) 195346981Scy{ 196346981Scy u8 ext_id; 197346981Scy 198346981Scy if (elen < 1) { 199346981Scy if (show_errors) { 200346981Scy wpa_printf(MSG_MSGDUMP, 201346981Scy "short information element (Ext)"); 202346981Scy } 203346981Scy return -1; 204346981Scy } 205346981Scy 206346981Scy ext_id = *pos++; 207346981Scy elen--; 208346981Scy 209346981Scy switch (ext_id) { 210346981Scy case WLAN_EID_EXT_ASSOC_DELAY_INFO: 211346981Scy if (elen != 1) 212346981Scy break; 213346981Scy elems->assoc_delay_info = pos; 214346981Scy break; 215346981Scy case WLAN_EID_EXT_FILS_REQ_PARAMS: 216346981Scy if (elen < 3) 217346981Scy break; 218346981Scy elems->fils_req_params = pos; 219346981Scy elems->fils_req_params_len = elen; 220346981Scy break; 221346981Scy case WLAN_EID_EXT_FILS_KEY_CONFIRM: 222346981Scy elems->fils_key_confirm = pos; 223346981Scy elems->fils_key_confirm_len = elen; 224346981Scy break; 225346981Scy case WLAN_EID_EXT_FILS_SESSION: 226346981Scy if (elen != FILS_SESSION_LEN) 227346981Scy break; 228346981Scy elems->fils_session = pos; 229346981Scy break; 230346981Scy case WLAN_EID_EXT_FILS_HLP_CONTAINER: 231346981Scy if (elen < 2 * ETH_ALEN) 232346981Scy break; 233346981Scy elems->fils_hlp = pos; 234346981Scy elems->fils_hlp_len = elen; 235346981Scy break; 236346981Scy case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN: 237346981Scy if (elen < 1) 238346981Scy break; 239346981Scy elems->fils_ip_addr_assign = pos; 240346981Scy elems->fils_ip_addr_assign_len = elen; 241346981Scy break; 242346981Scy case WLAN_EID_EXT_KEY_DELIVERY: 243346981Scy if (elen < WPA_KEY_RSC_LEN) 244346981Scy break; 245346981Scy elems->key_delivery = pos; 246346981Scy elems->key_delivery_len = elen; 247346981Scy break; 248346981Scy case WLAN_EID_EXT_FILS_WRAPPED_DATA: 249346981Scy elems->fils_wrapped_data = pos; 250346981Scy elems->fils_wrapped_data_len = elen; 251346981Scy break; 252346981Scy case WLAN_EID_EXT_FILS_PUBLIC_KEY: 253346981Scy if (elen < 1) 254346981Scy break; 255346981Scy elems->fils_pk = pos; 256346981Scy elems->fils_pk_len = elen; 257346981Scy break; 258346981Scy case WLAN_EID_EXT_FILS_NONCE: 259346981Scy if (elen != FILS_NONCE_LEN) 260346981Scy break; 261346981Scy elems->fils_nonce = pos; 262346981Scy break; 263346981Scy case WLAN_EID_EXT_OWE_DH_PARAM: 264346981Scy if (elen < 2) 265346981Scy break; 266346981Scy elems->owe_dh = pos; 267346981Scy elems->owe_dh_len = elen; 268346981Scy break; 269346981Scy case WLAN_EID_EXT_PASSWORD_IDENTIFIER: 270346981Scy elems->password_id = pos; 271346981Scy elems->password_id_len = elen; 272346981Scy break; 273346981Scy case WLAN_EID_EXT_HE_CAPABILITIES: 274346981Scy elems->he_capabilities = pos; 275346981Scy elems->he_capabilities_len = elen; 276346981Scy break; 277351611Scy case WLAN_EID_EXT_HE_OPERATION: 278351611Scy elems->he_operation = pos; 279351611Scy elems->he_operation_len = elen; 280351611Scy break; 281346981Scy case WLAN_EID_EXT_OCV_OCI: 282346981Scy elems->oci = pos; 283346981Scy elems->oci_len = elen; 284346981Scy break; 285346981Scy default: 286346981Scy if (show_errors) { 287346981Scy wpa_printf(MSG_MSGDUMP, 288346981Scy "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)", 289346981Scy ext_id, (unsigned int) elen); 290346981Scy } 291346981Scy return -1; 292346981Scy } 293346981Scy 294346981Scy return 0; 295346981Scy} 296346981Scy 297346981Scy 298189251Ssam/** 299189251Ssam * ieee802_11_parse_elems - Parse information elements in management frames 300189251Ssam * @start: Pointer to the start of IEs 301189251Ssam * @len: Length of IE buffer in octets 302189251Ssam * @elems: Data structure for parsed elements 303189251Ssam * @show_errors: Whether to show parsing errors in debug log 304189251Ssam * Returns: Parsing result 305189251Ssam */ 306214734SrpauloParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 307189251Ssam struct ieee802_11_elems *elems, 308189251Ssam int show_errors) 309189251Ssam{ 310346981Scy const struct element *elem; 311189251Ssam int unknown = 0; 312189251Ssam 313189251Ssam os_memset(elems, 0, sizeof(*elems)); 314189251Ssam 315346981Scy if (!start) 316346981Scy return ParseOK; 317189251Ssam 318346981Scy for_each_element(elem, start, len) { 319346981Scy u8 id = elem->id, elen = elem->datalen; 320346981Scy const u8 *pos = elem->data; 321189251Ssam 322189251Ssam switch (id) { 323189251Ssam case WLAN_EID_SSID: 324289549Srpaulo if (elen > SSID_MAX_LEN) { 325289549Srpaulo wpa_printf(MSG_DEBUG, 326289549Srpaulo "Ignored too long SSID element (elen=%u)", 327289549Srpaulo elen); 328289549Srpaulo break; 329289549Srpaulo } 330189251Ssam elems->ssid = pos; 331189251Ssam elems->ssid_len = elen; 332189251Ssam break; 333189251Ssam case WLAN_EID_SUPP_RATES: 334189251Ssam elems->supp_rates = pos; 335189251Ssam elems->supp_rates_len = elen; 336189251Ssam break; 337189251Ssam case WLAN_EID_DS_PARAMS: 338289549Srpaulo if (elen < 1) 339289549Srpaulo break; 340189251Ssam elems->ds_params = pos; 341189251Ssam break; 342189251Ssam case WLAN_EID_CF_PARAMS: 343189251Ssam case WLAN_EID_TIM: 344189251Ssam break; 345189251Ssam case WLAN_EID_CHALLENGE: 346189251Ssam elems->challenge = pos; 347189251Ssam elems->challenge_len = elen; 348189251Ssam break; 349189251Ssam case WLAN_EID_ERP_INFO: 350289549Srpaulo if (elen < 1) 351289549Srpaulo break; 352189251Ssam elems->erp_info = pos; 353189251Ssam break; 354189251Ssam case WLAN_EID_EXT_SUPP_RATES: 355189251Ssam elems->ext_supp_rates = pos; 356189251Ssam elems->ext_supp_rates_len = elen; 357189251Ssam break; 358189251Ssam case WLAN_EID_VENDOR_SPECIFIC: 359189251Ssam if (ieee802_11_parse_vendor_specific(pos, elen, 360189251Ssam elems, 361189251Ssam show_errors)) 362189251Ssam unknown++; 363189251Ssam break; 364189251Ssam case WLAN_EID_RSN: 365189251Ssam elems->rsn_ie = pos; 366189251Ssam elems->rsn_ie_len = elen; 367189251Ssam break; 368189251Ssam case WLAN_EID_PWR_CAPABILITY: 369346981Scy if (elen < 2) 370346981Scy break; 371346981Scy elems->power_capab = pos; 372346981Scy elems->power_capab_len = elen; 373189251Ssam break; 374189251Ssam case WLAN_EID_SUPPORTED_CHANNELS: 375189251Ssam elems->supp_channels = pos; 376189251Ssam elems->supp_channels_len = elen; 377189251Ssam break; 378189251Ssam case WLAN_EID_MOBILITY_DOMAIN: 379289549Srpaulo if (elen < sizeof(struct rsn_mdie)) 380289549Srpaulo break; 381189251Ssam elems->mdie = pos; 382189251Ssam elems->mdie_len = elen; 383189251Ssam break; 384189251Ssam case WLAN_EID_FAST_BSS_TRANSITION: 385289549Srpaulo if (elen < sizeof(struct rsn_ftie)) 386289549Srpaulo break; 387189251Ssam elems->ftie = pos; 388189251Ssam elems->ftie_len = elen; 389189251Ssam break; 390189251Ssam case WLAN_EID_TIMEOUT_INTERVAL: 391289549Srpaulo if (elen != 5) 392289549Srpaulo break; 393189251Ssam elems->timeout_int = pos; 394189251Ssam break; 395189251Ssam case WLAN_EID_HT_CAP: 396289549Srpaulo if (elen < sizeof(struct ieee80211_ht_capabilities)) 397289549Srpaulo break; 398189251Ssam elems->ht_capabilities = pos; 399189251Ssam break; 400189251Ssam case WLAN_EID_HT_OPERATION: 401289549Srpaulo if (elen < sizeof(struct ieee80211_ht_operation)) 402289549Srpaulo break; 403189251Ssam elems->ht_operation = pos; 404189251Ssam break; 405281806Srpaulo case WLAN_EID_MESH_CONFIG: 406281806Srpaulo elems->mesh_config = pos; 407281806Srpaulo elems->mesh_config_len = elen; 408281806Srpaulo break; 409281806Srpaulo case WLAN_EID_MESH_ID: 410281806Srpaulo elems->mesh_id = pos; 411281806Srpaulo elems->mesh_id_len = elen; 412281806Srpaulo break; 413281806Srpaulo case WLAN_EID_PEER_MGMT: 414281806Srpaulo elems->peer_mgmt = pos; 415281806Srpaulo elems->peer_mgmt_len = elen; 416281806Srpaulo break; 417252726Srpaulo case WLAN_EID_VHT_CAP: 418289549Srpaulo if (elen < sizeof(struct ieee80211_vht_capabilities)) 419289549Srpaulo break; 420252726Srpaulo elems->vht_capabilities = pos; 421252726Srpaulo break; 422252726Srpaulo case WLAN_EID_VHT_OPERATION: 423289549Srpaulo if (elen < sizeof(struct ieee80211_vht_operation)) 424289549Srpaulo break; 425252726Srpaulo elems->vht_operation = pos; 426252726Srpaulo break; 427281806Srpaulo case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: 428281806Srpaulo if (elen != 1) 429281806Srpaulo break; 430281806Srpaulo elems->vht_opmode_notif = pos; 431281806Srpaulo break; 432252726Srpaulo case WLAN_EID_LINK_ID: 433252726Srpaulo if (elen < 18) 434252726Srpaulo break; 435252726Srpaulo elems->link_id = pos; 436252726Srpaulo break; 437252726Srpaulo case WLAN_EID_INTERWORKING: 438252726Srpaulo elems->interworking = pos; 439252726Srpaulo elems->interworking_len = elen; 440252726Srpaulo break; 441281806Srpaulo case WLAN_EID_QOS_MAP_SET: 442281806Srpaulo if (elen < 16) 443281806Srpaulo break; 444281806Srpaulo elems->qos_map_set = pos; 445281806Srpaulo elems->qos_map_set_len = elen; 446281806Srpaulo break; 447252726Srpaulo case WLAN_EID_EXT_CAPAB: 448252726Srpaulo elems->ext_capab = pos; 449252726Srpaulo elems->ext_capab_len = elen; 450252726Srpaulo break; 451252726Srpaulo case WLAN_EID_BSS_MAX_IDLE_PERIOD: 452252726Srpaulo if (elen < 3) 453252726Srpaulo break; 454252726Srpaulo elems->bss_max_idle_period = pos; 455252726Srpaulo break; 456252726Srpaulo case WLAN_EID_SSID_LIST: 457252726Srpaulo elems->ssid_list = pos; 458252726Srpaulo elems->ssid_list_len = elen; 459252726Srpaulo break; 460281806Srpaulo case WLAN_EID_AMPE: 461281806Srpaulo elems->ampe = pos; 462281806Srpaulo elems->ampe_len = elen; 463281806Srpaulo break; 464281806Srpaulo case WLAN_EID_MIC: 465281806Srpaulo elems->mic = pos; 466281806Srpaulo elems->mic_len = elen; 467281806Srpaulo /* after mic everything is encrypted, so stop. */ 468346981Scy goto done; 469289549Srpaulo case WLAN_EID_MULTI_BAND: 470289549Srpaulo if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) { 471289549Srpaulo wpa_printf(MSG_MSGDUMP, 472289549Srpaulo "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)", 473289549Srpaulo id, elen); 474289549Srpaulo break; 475289549Srpaulo } 476289549Srpaulo 477289549Srpaulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos; 478289549Srpaulo elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen; 479289549Srpaulo elems->mb_ies.nof_ies++; 480289549Srpaulo break; 481337817Scy case WLAN_EID_SUPPORTED_OPERATING_CLASSES: 482337817Scy elems->supp_op_classes = pos; 483337817Scy elems->supp_op_classes_len = elen; 484337817Scy break; 485337817Scy case WLAN_EID_RRM_ENABLED_CAPABILITIES: 486337817Scy elems->rrm_enabled = pos; 487337817Scy elems->rrm_enabled_len = elen; 488337817Scy break; 489346981Scy case WLAN_EID_CAG_NUMBER: 490346981Scy elems->cag_number = pos; 491346981Scy elems->cag_number_len = elen; 492346981Scy break; 493346981Scy case WLAN_EID_AP_CSN: 494346981Scy if (elen < 1) 495346981Scy break; 496346981Scy elems->ap_csn = pos; 497346981Scy break; 498346981Scy case WLAN_EID_FILS_INDICATION: 499346981Scy if (elen < 2) 500346981Scy break; 501346981Scy elems->fils_indic = pos; 502346981Scy elems->fils_indic_len = elen; 503346981Scy break; 504346981Scy case WLAN_EID_DILS: 505346981Scy if (elen < 2) 506346981Scy break; 507346981Scy elems->dils = pos; 508346981Scy elems->dils_len = elen; 509346981Scy break; 510346981Scy case WLAN_EID_FRAGMENT: 511346981Scy /* TODO */ 512346981Scy break; 513346981Scy case WLAN_EID_EXTENSION: 514346981Scy if (ieee802_11_parse_extension(pos, elen, elems, 515346981Scy show_errors)) 516346981Scy unknown++; 517346981Scy break; 518189251Ssam default: 519189251Ssam unknown++; 520189251Ssam if (!show_errors) 521189251Ssam break; 522189251Ssam wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 523189251Ssam "ignored unknown element (id=%d elen=%d)", 524189251Ssam id, elen); 525189251Ssam break; 526189251Ssam } 527189251Ssam } 528189251Ssam 529346981Scy if (!for_each_element_completed(elem, start, len)) { 530346981Scy if (show_errors) { 531346981Scy wpa_printf(MSG_DEBUG, 532346981Scy "IEEE 802.11 element parse failed @%d", 533346981Scy (int) (start + len - (const u8 *) elem)); 534346981Scy wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 535346981Scy } 536189251Ssam return ParseFailed; 537346981Scy } 538189251Ssam 539346981Scydone: 540189251Ssam return unknown ? ParseUnknown : ParseOK; 541189251Ssam} 542214734Srpaulo 543214734Srpaulo 544214734Srpauloint ieee802_11_ie_count(const u8 *ies, size_t ies_len) 545214734Srpaulo{ 546346981Scy const struct element *elem; 547214734Srpaulo int count = 0; 548214734Srpaulo 549214734Srpaulo if (ies == NULL) 550214734Srpaulo return 0; 551214734Srpaulo 552346981Scy for_each_element(elem, ies, ies_len) 553214734Srpaulo count++; 554214734Srpaulo 555214734Srpaulo return count; 556214734Srpaulo} 557214734Srpaulo 558214734Srpaulo 559214734Srpaulostruct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 560214734Srpaulo u32 oui_type) 561214734Srpaulo{ 562214734Srpaulo struct wpabuf *buf; 563346981Scy const struct element *elem, *found = NULL; 564214734Srpaulo 565346981Scy for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { 566346981Scy if (elem->datalen >= 4 && 567346981Scy WPA_GET_BE32(elem->data) == oui_type) { 568346981Scy found = elem; 569214734Srpaulo break; 570214734Srpaulo } 571214734Srpaulo } 572214734Srpaulo 573346981Scy if (!found) 574214734Srpaulo return NULL; /* No specified vendor IE found */ 575214734Srpaulo 576214734Srpaulo buf = wpabuf_alloc(ies_len); 577214734Srpaulo if (buf == NULL) 578214734Srpaulo return NULL; 579214734Srpaulo 580214734Srpaulo /* 581214734Srpaulo * There may be multiple vendor IEs in the message, so need to 582214734Srpaulo * concatenate their data fields. 583214734Srpaulo */ 584346981Scy for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { 585346981Scy if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type) 586346981Scy wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4); 587214734Srpaulo } 588214734Srpaulo 589214734Srpaulo return buf; 590214734Srpaulo} 591252726Srpaulo 592252726Srpaulo 593252726Srpauloconst u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 594252726Srpaulo{ 595252726Srpaulo u16 fc, type, stype; 596252726Srpaulo 597252726Srpaulo /* 598252726Srpaulo * PS-Poll frames are 16 bytes. All other frames are 599252726Srpaulo * 24 bytes or longer. 600252726Srpaulo */ 601252726Srpaulo if (len < 16) 602252726Srpaulo return NULL; 603252726Srpaulo 604252726Srpaulo fc = le_to_host16(hdr->frame_control); 605252726Srpaulo type = WLAN_FC_GET_TYPE(fc); 606252726Srpaulo stype = WLAN_FC_GET_STYPE(fc); 607252726Srpaulo 608252726Srpaulo switch (type) { 609252726Srpaulo case WLAN_FC_TYPE_DATA: 610252726Srpaulo if (len < 24) 611252726Srpaulo return NULL; 612252726Srpaulo switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 613252726Srpaulo case WLAN_FC_FROMDS | WLAN_FC_TODS: 614252726Srpaulo case WLAN_FC_TODS: 615252726Srpaulo return hdr->addr1; 616252726Srpaulo case WLAN_FC_FROMDS: 617252726Srpaulo return hdr->addr2; 618252726Srpaulo default: 619252726Srpaulo return NULL; 620252726Srpaulo } 621252726Srpaulo case WLAN_FC_TYPE_CTRL: 622252726Srpaulo if (stype != WLAN_FC_STYPE_PSPOLL) 623252726Srpaulo return NULL; 624252726Srpaulo return hdr->addr1; 625252726Srpaulo case WLAN_FC_TYPE_MGMT: 626252726Srpaulo return hdr->addr3; 627252726Srpaulo default: 628252726Srpaulo return NULL; 629252726Srpaulo } 630252726Srpaulo} 631252726Srpaulo 632252726Srpaulo 633252726Srpauloint hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 634252726Srpaulo const char *name, const char *val) 635252726Srpaulo{ 636252726Srpaulo int num, v; 637252726Srpaulo const char *pos; 638252726Srpaulo struct hostapd_wmm_ac_params *ac; 639252726Srpaulo 640252726Srpaulo /* skip 'wme_ac_' or 'wmm_ac_' prefix */ 641252726Srpaulo pos = name + 7; 642252726Srpaulo if (os_strncmp(pos, "be_", 3) == 0) { 643252726Srpaulo num = 0; 644252726Srpaulo pos += 3; 645252726Srpaulo } else if (os_strncmp(pos, "bk_", 3) == 0) { 646252726Srpaulo num = 1; 647252726Srpaulo pos += 3; 648252726Srpaulo } else if (os_strncmp(pos, "vi_", 3) == 0) { 649252726Srpaulo num = 2; 650252726Srpaulo pos += 3; 651252726Srpaulo } else if (os_strncmp(pos, "vo_", 3) == 0) { 652252726Srpaulo num = 3; 653252726Srpaulo pos += 3; 654252726Srpaulo } else { 655252726Srpaulo wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); 656252726Srpaulo return -1; 657252726Srpaulo } 658252726Srpaulo 659252726Srpaulo ac = &wmm_ac_params[num]; 660252726Srpaulo 661252726Srpaulo if (os_strcmp(pos, "aifs") == 0) { 662252726Srpaulo v = atoi(val); 663252726Srpaulo if (v < 1 || v > 255) { 664252726Srpaulo wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); 665252726Srpaulo return -1; 666252726Srpaulo } 667252726Srpaulo ac->aifs = v; 668252726Srpaulo } else if (os_strcmp(pos, "cwmin") == 0) { 669252726Srpaulo v = atoi(val); 670289549Srpaulo if (v < 0 || v > 15) { 671252726Srpaulo wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); 672252726Srpaulo return -1; 673252726Srpaulo } 674252726Srpaulo ac->cwmin = v; 675252726Srpaulo } else if (os_strcmp(pos, "cwmax") == 0) { 676252726Srpaulo v = atoi(val); 677289549Srpaulo if (v < 0 || v > 15) { 678252726Srpaulo wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); 679252726Srpaulo return -1; 680252726Srpaulo } 681252726Srpaulo ac->cwmax = v; 682252726Srpaulo } else if (os_strcmp(pos, "txop_limit") == 0) { 683252726Srpaulo v = atoi(val); 684252726Srpaulo if (v < 0 || v > 0xffff) { 685252726Srpaulo wpa_printf(MSG_ERROR, "Invalid txop value %d", v); 686252726Srpaulo return -1; 687252726Srpaulo } 688252726Srpaulo ac->txop_limit = v; 689252726Srpaulo } else if (os_strcmp(pos, "acm") == 0) { 690252726Srpaulo v = atoi(val); 691252726Srpaulo if (v < 0 || v > 1) { 692252726Srpaulo wpa_printf(MSG_ERROR, "Invalid acm value %d", v); 693252726Srpaulo return -1; 694252726Srpaulo } 695252726Srpaulo ac->admission_control_mandatory = v; 696252726Srpaulo } else { 697252726Srpaulo wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); 698252726Srpaulo return -1; 699252726Srpaulo } 700252726Srpaulo 701252726Srpaulo return 0; 702252726Srpaulo} 703281806Srpaulo 704281806Srpaulo 705281806Srpauloenum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) 706281806Srpaulo{ 707289549Srpaulo u8 op_class; 708281806Srpaulo 709351611Scy return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT, 710337817Scy &op_class, channel); 711289549Srpaulo} 712289549Srpaulo 713289549Srpaulo 714289549Srpaulo/** 715289549Srpaulo * ieee80211_freq_to_channel_ext - Convert frequency into channel info 716289549Srpaulo * for HT40 and VHT. DFS channels are not covered. 717289549Srpaulo * @freq: Frequency (MHz) to convert 718289549Srpaulo * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below 719351611Scy * @vht: VHT channel width (CHANWIDTH_*) 720289549Srpaulo * @op_class: Buffer for returning operating class 721289549Srpaulo * @channel: Buffer for returning channel number 722289549Srpaulo * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure 723289549Srpaulo */ 724289549Srpauloenum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, 725289549Srpaulo int sec_channel, int vht, 726289549Srpaulo u8 *op_class, u8 *channel) 727289549Srpaulo{ 728337817Scy u8 vht_opclass; 729337817Scy 730289549Srpaulo /* TODO: more operating classes */ 731289549Srpaulo 732289549Srpaulo if (sec_channel > 1 || sec_channel < -1) 733289549Srpaulo return NUM_HOSTAPD_MODES; 734289549Srpaulo 735281806Srpaulo if (freq >= 2412 && freq <= 2472) { 736289549Srpaulo if ((freq - 2407) % 5) 737289549Srpaulo return NUM_HOSTAPD_MODES; 738289549Srpaulo 739289549Srpaulo if (vht) 740289549Srpaulo return NUM_HOSTAPD_MODES; 741289549Srpaulo 742289549Srpaulo /* 2.407 GHz, channels 1..13 */ 743289549Srpaulo if (sec_channel == 1) 744289549Srpaulo *op_class = 83; 745289549Srpaulo else if (sec_channel == -1) 746289549Srpaulo *op_class = 84; 747289549Srpaulo else 748289549Srpaulo *op_class = 81; 749289549Srpaulo 750281806Srpaulo *channel = (freq - 2407) / 5; 751289549Srpaulo 752289549Srpaulo return HOSTAPD_MODE_IEEE80211G; 753289549Srpaulo } 754289549Srpaulo 755289549Srpaulo if (freq == 2484) { 756289549Srpaulo if (sec_channel || vht) 757289549Srpaulo return NUM_HOSTAPD_MODES; 758289549Srpaulo 759289549Srpaulo *op_class = 82; /* channel 14 */ 760281806Srpaulo *channel = 14; 761289549Srpaulo 762289549Srpaulo return HOSTAPD_MODE_IEEE80211B; 763289549Srpaulo } 764289549Srpaulo 765289549Srpaulo if (freq >= 4900 && freq < 5000) { 766289549Srpaulo if ((freq - 4000) % 5) 767289549Srpaulo return NUM_HOSTAPD_MODES; 768281806Srpaulo *channel = (freq - 4000) / 5; 769289549Srpaulo *op_class = 0; /* TODO */ 770289549Srpaulo return HOSTAPD_MODE_IEEE80211A; 771289549Srpaulo } 772289549Srpaulo 773337817Scy switch (vht) { 774351611Scy case CHANWIDTH_80MHZ: 775337817Scy vht_opclass = 128; 776337817Scy break; 777351611Scy case CHANWIDTH_160MHZ: 778337817Scy vht_opclass = 129; 779337817Scy break; 780351611Scy case CHANWIDTH_80P80MHZ: 781337817Scy vht_opclass = 130; 782337817Scy break; 783337817Scy default: 784337817Scy vht_opclass = 0; 785337817Scy break; 786337817Scy } 787337817Scy 788289549Srpaulo /* 5 GHz, channels 36..48 */ 789289549Srpaulo if (freq >= 5180 && freq <= 5240) { 790289549Srpaulo if ((freq - 5000) % 5) 791289549Srpaulo return NUM_HOSTAPD_MODES; 792289549Srpaulo 793337817Scy if (vht_opclass) 794337817Scy *op_class = vht_opclass; 795337817Scy else if (sec_channel == 1) 796289549Srpaulo *op_class = 116; 797289549Srpaulo else if (sec_channel == -1) 798289549Srpaulo *op_class = 117; 799289549Srpaulo else 800289549Srpaulo *op_class = 115; 801289549Srpaulo 802281806Srpaulo *channel = (freq - 5000) / 5; 803289549Srpaulo 804289549Srpaulo return HOSTAPD_MODE_IEEE80211A; 805289549Srpaulo } 806289549Srpaulo 807346981Scy /* 5 GHz, channels 52..64 */ 808346981Scy if (freq >= 5260 && freq <= 5320) { 809346981Scy if ((freq - 5000) % 5) 810346981Scy return NUM_HOSTAPD_MODES; 811346981Scy 812346981Scy if (vht_opclass) 813346981Scy *op_class = vht_opclass; 814346981Scy else if (sec_channel == 1) 815346981Scy *op_class = 119; 816346981Scy else if (sec_channel == -1) 817346981Scy *op_class = 120; 818346981Scy else 819346981Scy *op_class = 118; 820346981Scy 821346981Scy *channel = (freq - 5000) / 5; 822346981Scy 823346981Scy return HOSTAPD_MODE_IEEE80211A; 824346981Scy } 825346981Scy 826337817Scy /* 5 GHz, channels 149..169 */ 827337817Scy if (freq >= 5745 && freq <= 5845) { 828289549Srpaulo if ((freq - 5000) % 5) 829289549Srpaulo return NUM_HOSTAPD_MODES; 830289549Srpaulo 831337817Scy if (vht_opclass) 832337817Scy *op_class = vht_opclass; 833337817Scy else if (sec_channel == 1) 834289549Srpaulo *op_class = 126; 835289549Srpaulo else if (sec_channel == -1) 836289549Srpaulo *op_class = 127; 837337817Scy else if (freq <= 5805) 838337817Scy *op_class = 124; 839289549Srpaulo else 840337817Scy *op_class = 125; 841289549Srpaulo 842289549Srpaulo *channel = (freq - 5000) / 5; 843289549Srpaulo 844289549Srpaulo return HOSTAPD_MODE_IEEE80211A; 845289549Srpaulo } 846289549Srpaulo 847337817Scy /* 5 GHz, channels 100..140 */ 848337817Scy if (freq >= 5000 && freq <= 5700) { 849289549Srpaulo if ((freq - 5000) % 5) 850289549Srpaulo return NUM_HOSTAPD_MODES; 851289549Srpaulo 852337817Scy if (vht_opclass) 853337817Scy *op_class = vht_opclass; 854337817Scy else if (sec_channel == 1) 855337817Scy *op_class = 122; 856337817Scy else if (sec_channel == -1) 857337817Scy *op_class = 123; 858337817Scy else 859337817Scy *op_class = 121; 860289549Srpaulo 861289549Srpaulo *channel = (freq - 5000) / 5; 862289549Srpaulo 863289549Srpaulo return HOSTAPD_MODE_IEEE80211A; 864289549Srpaulo } 865289549Srpaulo 866289549Srpaulo if (freq >= 5000 && freq < 5900) { 867289549Srpaulo if ((freq - 5000) % 5) 868289549Srpaulo return NUM_HOSTAPD_MODES; 869289549Srpaulo *channel = (freq - 5000) / 5; 870289549Srpaulo *op_class = 0; /* TODO */ 871289549Srpaulo return HOSTAPD_MODE_IEEE80211A; 872289549Srpaulo } 873289549Srpaulo 874289549Srpaulo /* 56.16 GHz, channel 1..4 */ 875289549Srpaulo if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { 876289549Srpaulo if (sec_channel || vht) 877289549Srpaulo return NUM_HOSTAPD_MODES; 878289549Srpaulo 879281806Srpaulo *channel = (freq - 56160) / 2160; 880289549Srpaulo *op_class = 180; 881289549Srpaulo 882289549Srpaulo return HOSTAPD_MODE_IEEE80211AD; 883281806Srpaulo } 884281806Srpaulo 885289549Srpaulo return NUM_HOSTAPD_MODES; 886281806Srpaulo} 887281806Srpaulo 888281806Srpaulo 889346981Scyint ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, 890346981Scy int sec_channel, u8 *op_class, u8 *channel) 891346981Scy{ 892346981Scy int vht = CHAN_WIDTH_UNKNOWN; 893346981Scy 894346981Scy switch (chanwidth) { 895346981Scy case CHAN_WIDTH_UNKNOWN: 896346981Scy case CHAN_WIDTH_20_NOHT: 897346981Scy case CHAN_WIDTH_20: 898346981Scy case CHAN_WIDTH_40: 899351611Scy vht = CHANWIDTH_USE_HT; 900346981Scy break; 901346981Scy case CHAN_WIDTH_80: 902351611Scy vht = CHANWIDTH_80MHZ; 903346981Scy break; 904346981Scy case CHAN_WIDTH_80P80: 905351611Scy vht = CHANWIDTH_80P80MHZ; 906346981Scy break; 907346981Scy case CHAN_WIDTH_160: 908351611Scy vht = CHANWIDTH_160MHZ; 909346981Scy break; 910346981Scy } 911346981Scy 912346981Scy if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class, 913346981Scy channel) == NUM_HOSTAPD_MODES) { 914346981Scy wpa_printf(MSG_WARNING, 915346981Scy "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)", 916346981Scy freq, chanwidth, sec_channel); 917346981Scy return -1; 918346981Scy } 919346981Scy 920346981Scy return 0; 921346981Scy} 922346981Scy 923346981Scy 924289549Srpaulostatic const char *const us_op_class_cc[] = { 925281806Srpaulo "US", "CA", NULL 926281806Srpaulo}; 927281806Srpaulo 928289549Srpaulostatic const char *const eu_op_class_cc[] = { 929281806Srpaulo "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", 930281806Srpaulo "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT", 931281806Srpaulo "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", 932281806Srpaulo "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL 933281806Srpaulo}; 934281806Srpaulo 935289549Srpaulostatic const char *const jp_op_class_cc[] = { 936281806Srpaulo "JP", NULL 937281806Srpaulo}; 938281806Srpaulo 939289549Srpaulostatic const char *const cn_op_class_cc[] = { 940289549Srpaulo "CN", NULL 941281806Srpaulo}; 942281806Srpaulo 943281806Srpaulo 944289549Srpaulostatic int country_match(const char *const cc[], const char *const country) 945281806Srpaulo{ 946281806Srpaulo int i; 947281806Srpaulo 948281806Srpaulo if (country == NULL) 949281806Srpaulo return 0; 950281806Srpaulo for (i = 0; cc[i]; i++) { 951281806Srpaulo if (cc[i][0] == country[0] && cc[i][1] == country[1]) 952281806Srpaulo return 1; 953281806Srpaulo } 954281806Srpaulo 955281806Srpaulo return 0; 956281806Srpaulo} 957281806Srpaulo 958281806Srpaulo 959281806Srpaulostatic int ieee80211_chan_to_freq_us(u8 op_class, u8 chan) 960281806Srpaulo{ 961281806Srpaulo switch (op_class) { 962281806Srpaulo case 12: /* channels 1..11 */ 963281806Srpaulo case 32: /* channels 1..7; 40 MHz */ 964281806Srpaulo case 33: /* channels 5..11; 40 MHz */ 965281806Srpaulo if (chan < 1 || chan > 11) 966281806Srpaulo return -1; 967281806Srpaulo return 2407 + 5 * chan; 968281806Srpaulo case 1: /* channels 36,40,44,48 */ 969281806Srpaulo case 2: /* channels 52,56,60,64; dfs */ 970281806Srpaulo case 22: /* channels 36,44; 40 MHz */ 971281806Srpaulo case 23: /* channels 52,60; 40 MHz */ 972281806Srpaulo case 27: /* channels 40,48; 40 MHz */ 973281806Srpaulo case 28: /* channels 56,64; 40 MHz */ 974281806Srpaulo if (chan < 36 || chan > 64) 975281806Srpaulo return -1; 976281806Srpaulo return 5000 + 5 * chan; 977281806Srpaulo case 4: /* channels 100-144 */ 978281806Srpaulo case 24: /* channels 100-140; 40 MHz */ 979281806Srpaulo if (chan < 100 || chan > 144) 980281806Srpaulo return -1; 981281806Srpaulo return 5000 + 5 * chan; 982281806Srpaulo case 3: /* channels 149,153,157,161 */ 983281806Srpaulo case 25: /* channels 149,157; 40 MHz */ 984281806Srpaulo case 26: /* channels 149,157; 40 MHz */ 985281806Srpaulo case 30: /* channels 153,161; 40 MHz */ 986281806Srpaulo case 31: /* channels 153,161; 40 MHz */ 987281806Srpaulo if (chan < 149 || chan > 161) 988281806Srpaulo return -1; 989281806Srpaulo return 5000 + 5 * chan; 990289549Srpaulo case 5: /* channels 149,153,157,161,165 */ 991289549Srpaulo if (chan < 149 || chan > 165) 992289549Srpaulo return -1; 993289549Srpaulo return 5000 + 5 * chan; 994281806Srpaulo case 34: /* 60 GHz band, channels 1..3 */ 995281806Srpaulo if (chan < 1 || chan > 3) 996281806Srpaulo return -1; 997281806Srpaulo return 56160 + 2160 * chan; 998281806Srpaulo } 999281806Srpaulo return -1; 1000281806Srpaulo} 1001281806Srpaulo 1002281806Srpaulo 1003281806Srpaulostatic int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan) 1004281806Srpaulo{ 1005281806Srpaulo switch (op_class) { 1006281806Srpaulo case 4: /* channels 1..13 */ 1007281806Srpaulo case 11: /* channels 1..9; 40 MHz */ 1008281806Srpaulo case 12: /* channels 5..13; 40 MHz */ 1009281806Srpaulo if (chan < 1 || chan > 13) 1010281806Srpaulo return -1; 1011281806Srpaulo return 2407 + 5 * chan; 1012281806Srpaulo case 1: /* channels 36,40,44,48 */ 1013281806Srpaulo case 2: /* channels 52,56,60,64; dfs */ 1014281806Srpaulo case 5: /* channels 36,44; 40 MHz */ 1015281806Srpaulo case 6: /* channels 52,60; 40 MHz */ 1016281806Srpaulo case 8: /* channels 40,48; 40 MHz */ 1017281806Srpaulo case 9: /* channels 56,64; 40 MHz */ 1018281806Srpaulo if (chan < 36 || chan > 64) 1019281806Srpaulo return -1; 1020281806Srpaulo return 5000 + 5 * chan; 1021281806Srpaulo case 3: /* channels 100-140 */ 1022281806Srpaulo case 7: /* channels 100-132; 40 MHz */ 1023281806Srpaulo case 10: /* channels 104-136; 40 MHz */ 1024281806Srpaulo case 16: /* channels 100-140 */ 1025281806Srpaulo if (chan < 100 || chan > 140) 1026281806Srpaulo return -1; 1027281806Srpaulo return 5000 + 5 * chan; 1028281806Srpaulo case 17: /* channels 149,153,157,161,165,169 */ 1029281806Srpaulo if (chan < 149 || chan > 169) 1030281806Srpaulo return -1; 1031281806Srpaulo return 5000 + 5 * chan; 1032281806Srpaulo case 18: /* 60 GHz band, channels 1..4 */ 1033281806Srpaulo if (chan < 1 || chan > 4) 1034281806Srpaulo return -1; 1035281806Srpaulo return 56160 + 2160 * chan; 1036281806Srpaulo } 1037281806Srpaulo return -1; 1038281806Srpaulo} 1039281806Srpaulo 1040281806Srpaulo 1041281806Srpaulostatic int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) 1042281806Srpaulo{ 1043281806Srpaulo switch (op_class) { 1044281806Srpaulo case 30: /* channels 1..13 */ 1045281806Srpaulo case 56: /* channels 1..9; 40 MHz */ 1046281806Srpaulo case 57: /* channels 5..13; 40 MHz */ 1047281806Srpaulo if (chan < 1 || chan > 13) 1048281806Srpaulo return -1; 1049281806Srpaulo return 2407 + 5 * chan; 1050281806Srpaulo case 31: /* channel 14 */ 1051281806Srpaulo if (chan != 14) 1052281806Srpaulo return -1; 1053281806Srpaulo return 2414 + 5 * chan; 1054281806Srpaulo case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */ 1055281806Srpaulo case 32: /* channels 52,56,60,64 */ 1056281806Srpaulo case 33: /* channels 52,56,60,64 */ 1057281806Srpaulo case 36: /* channels 36,44; 40 MHz */ 1058281806Srpaulo case 37: /* channels 52,60; 40 MHz */ 1059281806Srpaulo case 38: /* channels 52,60; 40 MHz */ 1060281806Srpaulo case 41: /* channels 40,48; 40 MHz */ 1061281806Srpaulo case 42: /* channels 56,64; 40 MHz */ 1062281806Srpaulo case 43: /* channels 56,64; 40 MHz */ 1063281806Srpaulo if (chan < 34 || chan > 64) 1064281806Srpaulo return -1; 1065281806Srpaulo return 5000 + 5 * chan; 1066281806Srpaulo case 34: /* channels 100-140 */ 1067281806Srpaulo case 35: /* channels 100-140 */ 1068281806Srpaulo case 39: /* channels 100-132; 40 MHz */ 1069281806Srpaulo case 40: /* channels 100-132; 40 MHz */ 1070281806Srpaulo case 44: /* channels 104-136; 40 MHz */ 1071281806Srpaulo case 45: /* channels 104-136; 40 MHz */ 1072281806Srpaulo case 58: /* channels 100-140 */ 1073281806Srpaulo if (chan < 100 || chan > 140) 1074281806Srpaulo return -1; 1075281806Srpaulo return 5000 + 5 * chan; 1076281806Srpaulo case 59: /* 60 GHz band, channels 1..4 */ 1077281806Srpaulo if (chan < 1 || chan > 3) 1078281806Srpaulo return -1; 1079281806Srpaulo return 56160 + 2160 * chan; 1080281806Srpaulo } 1081281806Srpaulo return -1; 1082281806Srpaulo} 1083281806Srpaulo 1084281806Srpaulo 1085281806Srpaulostatic int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan) 1086281806Srpaulo{ 1087281806Srpaulo switch (op_class) { 1088281806Srpaulo case 7: /* channels 1..13 */ 1089281806Srpaulo case 8: /* channels 1..9; 40 MHz */ 1090281806Srpaulo case 9: /* channels 5..13; 40 MHz */ 1091281806Srpaulo if (chan < 1 || chan > 13) 1092281806Srpaulo return -1; 1093281806Srpaulo return 2407 + 5 * chan; 1094281806Srpaulo case 1: /* channels 36,40,44,48 */ 1095281806Srpaulo case 2: /* channels 52,56,60,64; dfs */ 1096281806Srpaulo case 4: /* channels 36,44; 40 MHz */ 1097281806Srpaulo case 5: /* channels 52,60; 40 MHz */ 1098281806Srpaulo if (chan < 36 || chan > 64) 1099281806Srpaulo return -1; 1100281806Srpaulo return 5000 + 5 * chan; 1101281806Srpaulo case 3: /* channels 149,153,157,161,165 */ 1102281806Srpaulo case 6: /* channels 149,157; 40 MHz */ 1103281806Srpaulo if (chan < 149 || chan > 165) 1104281806Srpaulo return -1; 1105281806Srpaulo return 5000 + 5 * chan; 1106281806Srpaulo } 1107281806Srpaulo return -1; 1108281806Srpaulo} 1109281806Srpaulo 1110281806Srpaulo 1111281806Srpaulostatic int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) 1112281806Srpaulo{ 1113281806Srpaulo /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ 1114281806Srpaulo switch (op_class) { 1115281806Srpaulo case 81: 1116281806Srpaulo /* channels 1..13 */ 1117281806Srpaulo if (chan < 1 || chan > 13) 1118281806Srpaulo return -1; 1119281806Srpaulo return 2407 + 5 * chan; 1120281806Srpaulo case 82: 1121281806Srpaulo /* channel 14 */ 1122281806Srpaulo if (chan != 14) 1123281806Srpaulo return -1; 1124281806Srpaulo return 2414 + 5 * chan; 1125281806Srpaulo case 83: /* channels 1..9; 40 MHz */ 1126281806Srpaulo case 84: /* channels 5..13; 40 MHz */ 1127281806Srpaulo if (chan < 1 || chan > 13) 1128281806Srpaulo return -1; 1129281806Srpaulo return 2407 + 5 * chan; 1130281806Srpaulo case 115: /* channels 36,40,44,48; indoor only */ 1131281806Srpaulo case 116: /* channels 36,44; 40 MHz; indoor only */ 1132281806Srpaulo case 117: /* channels 40,48; 40 MHz; indoor only */ 1133281806Srpaulo case 118: /* channels 52,56,60,64; dfs */ 1134281806Srpaulo case 119: /* channels 52,60; 40 MHz; dfs */ 1135281806Srpaulo case 120: /* channels 56,64; 40 MHz; dfs */ 1136281806Srpaulo if (chan < 36 || chan > 64) 1137281806Srpaulo return -1; 1138281806Srpaulo return 5000 + 5 * chan; 1139281806Srpaulo case 121: /* channels 100-140 */ 1140281806Srpaulo case 122: /* channels 100-142; 40 MHz */ 1141281806Srpaulo case 123: /* channels 104-136; 40 MHz */ 1142281806Srpaulo if (chan < 100 || chan > 140) 1143281806Srpaulo return -1; 1144281806Srpaulo return 5000 + 5 * chan; 1145281806Srpaulo case 124: /* channels 149,153,157,161 */ 1146281806Srpaulo case 126: /* channels 149,157; 40 MHz */ 1147281806Srpaulo case 127: /* channels 153,161; 40 MHz */ 1148281806Srpaulo if (chan < 149 || chan > 161) 1149281806Srpaulo return -1; 1150281806Srpaulo return 5000 + 5 * chan; 1151289549Srpaulo case 125: /* channels 149,153,157,161,165,169 */ 1152289549Srpaulo if (chan < 149 || chan > 169) 1153289549Srpaulo return -1; 1154289549Srpaulo return 5000 + 5 * chan; 1155281806Srpaulo case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ 1156281806Srpaulo case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */ 1157281806Srpaulo if (chan < 36 || chan > 161) 1158281806Srpaulo return -1; 1159281806Srpaulo return 5000 + 5 * chan; 1160281806Srpaulo case 129: /* center freqs 50, 114; 160 MHz */ 1161346981Scy if (chan < 36 || chan > 128) 1162281806Srpaulo return -1; 1163281806Srpaulo return 5000 + 5 * chan; 1164281806Srpaulo case 180: /* 60 GHz band, channels 1..4 */ 1165281806Srpaulo if (chan < 1 || chan > 4) 1166281806Srpaulo return -1; 1167281806Srpaulo return 56160 + 2160 * chan; 1168281806Srpaulo } 1169281806Srpaulo return -1; 1170281806Srpaulo} 1171281806Srpaulo 1172281806Srpaulo/** 1173281806Srpaulo * ieee80211_chan_to_freq - Convert channel info to frequency 1174281806Srpaulo * @country: Country code, if known; otherwise, global operating class is used 1175281806Srpaulo * @op_class: Operating class 1176281806Srpaulo * @chan: Channel number 1177281806Srpaulo * Returns: Frequency in MHz or -1 if the specified channel is unknown 1178281806Srpaulo */ 1179281806Srpauloint ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan) 1180281806Srpaulo{ 1181281806Srpaulo int freq; 1182281806Srpaulo 1183281806Srpaulo if (country_match(us_op_class_cc, country)) { 1184281806Srpaulo freq = ieee80211_chan_to_freq_us(op_class, chan); 1185281806Srpaulo if (freq > 0) 1186281806Srpaulo return freq; 1187281806Srpaulo } 1188281806Srpaulo 1189281806Srpaulo if (country_match(eu_op_class_cc, country)) { 1190281806Srpaulo freq = ieee80211_chan_to_freq_eu(op_class, chan); 1191281806Srpaulo if (freq > 0) 1192281806Srpaulo return freq; 1193281806Srpaulo } 1194281806Srpaulo 1195281806Srpaulo if (country_match(jp_op_class_cc, country)) { 1196281806Srpaulo freq = ieee80211_chan_to_freq_jp(op_class, chan); 1197281806Srpaulo if (freq > 0) 1198281806Srpaulo return freq; 1199281806Srpaulo } 1200281806Srpaulo 1201281806Srpaulo if (country_match(cn_op_class_cc, country)) { 1202281806Srpaulo freq = ieee80211_chan_to_freq_cn(op_class, chan); 1203281806Srpaulo if (freq > 0) 1204281806Srpaulo return freq; 1205281806Srpaulo } 1206281806Srpaulo 1207281806Srpaulo return ieee80211_chan_to_freq_global(op_class, chan); 1208281806Srpaulo} 1209281806Srpaulo 1210281806Srpaulo 1211346981Scyint ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, 1212346981Scy u16 num_modes) 1213281806Srpaulo{ 1214346981Scy int i, j; 1215346981Scy 1216346981Scy if (!modes || !num_modes) 1217346981Scy return (freq >= 5260 && freq <= 5320) || 1218346981Scy (freq >= 5500 && freq <= 5700); 1219346981Scy 1220346981Scy for (i = 0; i < num_modes; i++) { 1221346981Scy for (j = 0; j < modes[i].num_channels; j++) { 1222346981Scy if (modes[i].channels[j].freq == freq && 1223346981Scy (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR)) 1224346981Scy return 1; 1225346981Scy } 1226346981Scy } 1227346981Scy 1228346981Scy return 0; 1229281806Srpaulo} 1230281806Srpaulo 1231281806Srpaulo 1232281806Srpaulostatic int is_11b(u8 rate) 1233281806Srpaulo{ 1234281806Srpaulo return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; 1235281806Srpaulo} 1236281806Srpaulo 1237281806Srpaulo 1238281806Srpauloint supp_rates_11b_only(struct ieee802_11_elems *elems) 1239281806Srpaulo{ 1240281806Srpaulo int num_11b = 0, num_others = 0; 1241281806Srpaulo int i; 1242281806Srpaulo 1243281806Srpaulo if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL) 1244281806Srpaulo return 0; 1245281806Srpaulo 1246281806Srpaulo for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { 1247281806Srpaulo if (is_11b(elems->supp_rates[i])) 1248281806Srpaulo num_11b++; 1249281806Srpaulo else 1250281806Srpaulo num_others++; 1251281806Srpaulo } 1252281806Srpaulo 1253281806Srpaulo for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; 1254281806Srpaulo i++) { 1255281806Srpaulo if (is_11b(elems->ext_supp_rates[i])) 1256281806Srpaulo num_11b++; 1257281806Srpaulo else 1258281806Srpaulo num_others++; 1259281806Srpaulo } 1260281806Srpaulo 1261281806Srpaulo return num_11b > 0 && num_others == 0; 1262281806Srpaulo} 1263281806Srpaulo 1264281806Srpaulo 1265281806Srpauloconst char * fc2str(u16 fc) 1266281806Srpaulo{ 1267281806Srpaulo u16 stype = WLAN_FC_GET_STYPE(fc); 1268281806Srpaulo#define C2S(x) case x: return #x; 1269281806Srpaulo 1270281806Srpaulo switch (WLAN_FC_GET_TYPE(fc)) { 1271281806Srpaulo case WLAN_FC_TYPE_MGMT: 1272281806Srpaulo switch (stype) { 1273281806Srpaulo C2S(WLAN_FC_STYPE_ASSOC_REQ) 1274281806Srpaulo C2S(WLAN_FC_STYPE_ASSOC_RESP) 1275281806Srpaulo C2S(WLAN_FC_STYPE_REASSOC_REQ) 1276281806Srpaulo C2S(WLAN_FC_STYPE_REASSOC_RESP) 1277281806Srpaulo C2S(WLAN_FC_STYPE_PROBE_REQ) 1278281806Srpaulo C2S(WLAN_FC_STYPE_PROBE_RESP) 1279281806Srpaulo C2S(WLAN_FC_STYPE_BEACON) 1280281806Srpaulo C2S(WLAN_FC_STYPE_ATIM) 1281281806Srpaulo C2S(WLAN_FC_STYPE_DISASSOC) 1282281806Srpaulo C2S(WLAN_FC_STYPE_AUTH) 1283281806Srpaulo C2S(WLAN_FC_STYPE_DEAUTH) 1284281806Srpaulo C2S(WLAN_FC_STYPE_ACTION) 1285281806Srpaulo } 1286281806Srpaulo break; 1287281806Srpaulo case WLAN_FC_TYPE_CTRL: 1288281806Srpaulo switch (stype) { 1289281806Srpaulo C2S(WLAN_FC_STYPE_PSPOLL) 1290281806Srpaulo C2S(WLAN_FC_STYPE_RTS) 1291281806Srpaulo C2S(WLAN_FC_STYPE_CTS) 1292281806Srpaulo C2S(WLAN_FC_STYPE_ACK) 1293281806Srpaulo C2S(WLAN_FC_STYPE_CFEND) 1294281806Srpaulo C2S(WLAN_FC_STYPE_CFENDACK) 1295281806Srpaulo } 1296281806Srpaulo break; 1297281806Srpaulo case WLAN_FC_TYPE_DATA: 1298281806Srpaulo switch (stype) { 1299281806Srpaulo C2S(WLAN_FC_STYPE_DATA) 1300281806Srpaulo C2S(WLAN_FC_STYPE_DATA_CFACK) 1301281806Srpaulo C2S(WLAN_FC_STYPE_DATA_CFPOLL) 1302281806Srpaulo C2S(WLAN_FC_STYPE_DATA_CFACKPOLL) 1303281806Srpaulo C2S(WLAN_FC_STYPE_NULLFUNC) 1304281806Srpaulo C2S(WLAN_FC_STYPE_CFACK) 1305281806Srpaulo C2S(WLAN_FC_STYPE_CFPOLL) 1306281806Srpaulo C2S(WLAN_FC_STYPE_CFACKPOLL) 1307281806Srpaulo C2S(WLAN_FC_STYPE_QOS_DATA) 1308281806Srpaulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACK) 1309281806Srpaulo C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL) 1310281806Srpaulo C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL) 1311281806Srpaulo C2S(WLAN_FC_STYPE_QOS_NULL) 1312281806Srpaulo C2S(WLAN_FC_STYPE_QOS_CFPOLL) 1313281806Srpaulo C2S(WLAN_FC_STYPE_QOS_CFACKPOLL) 1314281806Srpaulo } 1315281806Srpaulo break; 1316281806Srpaulo } 1317281806Srpaulo return "WLAN_FC_TYPE_UNKNOWN"; 1318281806Srpaulo#undef C2S 1319281806Srpaulo} 1320289549Srpaulo 1321289549Srpaulo 1322351611Scyconst char * reason2str(u16 reason) 1323351611Scy{ 1324351611Scy#define R2S(r) case WLAN_REASON_ ## r: return #r; 1325351611Scy switch (reason) { 1326351611Scy R2S(UNSPECIFIED) 1327351611Scy R2S(PREV_AUTH_NOT_VALID) 1328351611Scy R2S(DEAUTH_LEAVING) 1329351611Scy R2S(DISASSOC_DUE_TO_INACTIVITY) 1330351611Scy R2S(DISASSOC_AP_BUSY) 1331351611Scy R2S(CLASS2_FRAME_FROM_NONAUTH_STA) 1332351611Scy R2S(CLASS3_FRAME_FROM_NONASSOC_STA) 1333351611Scy R2S(DISASSOC_STA_HAS_LEFT) 1334351611Scy R2S(STA_REQ_ASSOC_WITHOUT_AUTH) 1335351611Scy R2S(PWR_CAPABILITY_NOT_VALID) 1336351611Scy R2S(SUPPORTED_CHANNEL_NOT_VALID) 1337351611Scy R2S(BSS_TRANSITION_DISASSOC) 1338351611Scy R2S(INVALID_IE) 1339351611Scy R2S(MICHAEL_MIC_FAILURE) 1340351611Scy R2S(4WAY_HANDSHAKE_TIMEOUT) 1341351611Scy R2S(GROUP_KEY_UPDATE_TIMEOUT) 1342351611Scy R2S(IE_IN_4WAY_DIFFERS) 1343351611Scy R2S(GROUP_CIPHER_NOT_VALID) 1344351611Scy R2S(PAIRWISE_CIPHER_NOT_VALID) 1345351611Scy R2S(AKMP_NOT_VALID) 1346351611Scy R2S(UNSUPPORTED_RSN_IE_VERSION) 1347351611Scy R2S(INVALID_RSN_IE_CAPAB) 1348351611Scy R2S(IEEE_802_1X_AUTH_FAILED) 1349351611Scy R2S(CIPHER_SUITE_REJECTED) 1350351611Scy R2S(TDLS_TEARDOWN_UNREACHABLE) 1351351611Scy R2S(TDLS_TEARDOWN_UNSPECIFIED) 1352351611Scy R2S(SSP_REQUESTED_DISASSOC) 1353351611Scy R2S(NO_SSP_ROAMING_AGREEMENT) 1354351611Scy R2S(BAD_CIPHER_OR_AKM) 1355351611Scy R2S(NOT_AUTHORIZED_THIS_LOCATION) 1356351611Scy R2S(SERVICE_CHANGE_PRECLUDES_TS) 1357351611Scy R2S(UNSPECIFIED_QOS_REASON) 1358351611Scy R2S(NOT_ENOUGH_BANDWIDTH) 1359351611Scy R2S(DISASSOC_LOW_ACK) 1360351611Scy R2S(EXCEEDED_TXOP) 1361351611Scy R2S(STA_LEAVING) 1362351611Scy R2S(END_TS_BA_DLS) 1363351611Scy R2S(UNKNOWN_TS_BA) 1364351611Scy R2S(TIMEOUT) 1365351611Scy R2S(PEERKEY_MISMATCH) 1366351611Scy R2S(AUTHORIZED_ACCESS_LIMIT_REACHED) 1367351611Scy R2S(EXTERNAL_SERVICE_REQUIREMENTS) 1368351611Scy R2S(INVALID_FT_ACTION_FRAME_COUNT) 1369351611Scy R2S(INVALID_PMKID) 1370351611Scy R2S(INVALID_MDE) 1371351611Scy R2S(INVALID_FTE) 1372351611Scy R2S(MESH_PEERING_CANCELLED) 1373351611Scy R2S(MESH_MAX_PEERS) 1374351611Scy R2S(MESH_CONFIG_POLICY_VIOLATION) 1375351611Scy R2S(MESH_CLOSE_RCVD) 1376351611Scy R2S(MESH_MAX_RETRIES) 1377351611Scy R2S(MESH_CONFIRM_TIMEOUT) 1378351611Scy R2S(MESH_INVALID_GTK) 1379351611Scy R2S(MESH_INCONSISTENT_PARAMS) 1380351611Scy R2S(MESH_INVALID_SECURITY_CAP) 1381351611Scy R2S(MESH_PATH_ERROR_NO_PROXY_INFO) 1382351611Scy R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO) 1383351611Scy R2S(MESH_PATH_ERROR_DEST_UNREACHABLE) 1384351611Scy R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS) 1385351611Scy R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ) 1386351611Scy R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED) 1387351611Scy } 1388351611Scy return "UNKNOWN"; 1389351611Scy#undef R2S 1390351611Scy} 1391351611Scy 1392351611Scy 1393351611Scyconst char * status2str(u16 status) 1394351611Scy{ 1395351611Scy#define S2S(s) case WLAN_STATUS_ ## s: return #s; 1396351611Scy switch (status) { 1397351611Scy S2S(SUCCESS) 1398351611Scy S2S(UNSPECIFIED_FAILURE) 1399351611Scy S2S(TDLS_WAKEUP_ALTERNATE) 1400351611Scy S2S(TDLS_WAKEUP_REJECT) 1401351611Scy S2S(SECURITY_DISABLED) 1402351611Scy S2S(UNACCEPTABLE_LIFETIME) 1403351611Scy S2S(NOT_IN_SAME_BSS) 1404351611Scy S2S(CAPS_UNSUPPORTED) 1405351611Scy S2S(REASSOC_NO_ASSOC) 1406351611Scy S2S(ASSOC_DENIED_UNSPEC) 1407351611Scy S2S(NOT_SUPPORTED_AUTH_ALG) 1408351611Scy S2S(UNKNOWN_AUTH_TRANSACTION) 1409351611Scy S2S(CHALLENGE_FAIL) 1410351611Scy S2S(AUTH_TIMEOUT) 1411351611Scy S2S(AP_UNABLE_TO_HANDLE_NEW_STA) 1412351611Scy S2S(ASSOC_DENIED_RATES) 1413351611Scy S2S(ASSOC_DENIED_NOSHORT) 1414351611Scy S2S(SPEC_MGMT_REQUIRED) 1415351611Scy S2S(PWR_CAPABILITY_NOT_VALID) 1416351611Scy S2S(SUPPORTED_CHANNEL_NOT_VALID) 1417351611Scy S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME) 1418351611Scy S2S(ASSOC_DENIED_NO_HT) 1419351611Scy S2S(R0KH_UNREACHABLE) 1420351611Scy S2S(ASSOC_DENIED_NO_PCO) 1421351611Scy S2S(ASSOC_REJECTED_TEMPORARILY) 1422351611Scy S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION) 1423351611Scy S2S(UNSPECIFIED_QOS_FAILURE) 1424351611Scy S2S(DENIED_INSUFFICIENT_BANDWIDTH) 1425351611Scy S2S(DENIED_POOR_CHANNEL_CONDITIONS) 1426351611Scy S2S(DENIED_QOS_NOT_SUPPORTED) 1427351611Scy S2S(REQUEST_DECLINED) 1428351611Scy S2S(INVALID_PARAMETERS) 1429351611Scy S2S(REJECTED_WITH_SUGGESTED_CHANGES) 1430351611Scy S2S(INVALID_IE) 1431351611Scy S2S(GROUP_CIPHER_NOT_VALID) 1432351611Scy S2S(PAIRWISE_CIPHER_NOT_VALID) 1433351611Scy S2S(AKMP_NOT_VALID) 1434351611Scy S2S(UNSUPPORTED_RSN_IE_VERSION) 1435351611Scy S2S(INVALID_RSN_IE_CAPAB) 1436351611Scy S2S(CIPHER_REJECTED_PER_POLICY) 1437351611Scy S2S(TS_NOT_CREATED) 1438351611Scy S2S(DIRECT_LINK_NOT_ALLOWED) 1439351611Scy S2S(DEST_STA_NOT_PRESENT) 1440351611Scy S2S(DEST_STA_NOT_QOS_STA) 1441351611Scy S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE) 1442351611Scy S2S(INVALID_FT_ACTION_FRAME_COUNT) 1443351611Scy S2S(INVALID_PMKID) 1444351611Scy S2S(INVALID_MDIE) 1445351611Scy S2S(INVALID_FTIE) 1446351611Scy S2S(REQUESTED_TCLAS_NOT_SUPPORTED) 1447351611Scy S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES) 1448351611Scy S2S(TRY_ANOTHER_BSS) 1449351611Scy S2S(GAS_ADV_PROTO_NOT_SUPPORTED) 1450351611Scy S2S(NO_OUTSTANDING_GAS_REQ) 1451351611Scy S2S(GAS_RESP_NOT_RECEIVED) 1452351611Scy S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP) 1453351611Scy S2S(GAS_RESP_LARGER_THAN_LIMIT) 1454351611Scy S2S(REQ_REFUSED_HOME) 1455351611Scy S2S(ADV_SRV_UNREACHABLE) 1456351611Scy S2S(REQ_REFUSED_SSPN) 1457351611Scy S2S(REQ_REFUSED_UNAUTH_ACCESS) 1458351611Scy S2S(INVALID_RSNIE) 1459351611Scy S2S(U_APSD_COEX_NOT_SUPPORTED) 1460351611Scy S2S(U_APSD_COEX_MODE_NOT_SUPPORTED) 1461351611Scy S2S(BAD_INTERVAL_WITH_U_APSD_COEX) 1462351611Scy S2S(ANTI_CLOGGING_TOKEN_REQ) 1463351611Scy S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED) 1464351611Scy S2S(CANNOT_FIND_ALT_TBTT) 1465351611Scy S2S(TRANSMISSION_FAILURE) 1466351611Scy S2S(REQ_TCLAS_NOT_SUPPORTED) 1467351611Scy S2S(TCLAS_RESOURCES_EXCHAUSTED) 1468351611Scy S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION) 1469351611Scy S2S(REJECT_WITH_SCHEDULE) 1470351611Scy S2S(REJECT_NO_WAKEUP_SPECIFIED) 1471351611Scy S2S(SUCCESS_POWER_SAVE_MODE) 1472351611Scy S2S(PENDING_ADMITTING_FST_SESSION) 1473351611Scy S2S(PERFORMING_FST_NOW) 1474351611Scy S2S(PENDING_GAP_IN_BA_WINDOW) 1475351611Scy S2S(REJECT_U_PID_SETTING) 1476351611Scy S2S(REFUSED_EXTERNAL_REASON) 1477351611Scy S2S(REFUSED_AP_OUT_OF_MEMORY) 1478351611Scy S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED) 1479351611Scy S2S(QUERY_RESP_OUTSTANDING) 1480351611Scy S2S(REJECT_DSE_BAND) 1481351611Scy S2S(TCLAS_PROCESSING_TERMINATED) 1482351611Scy S2S(TS_SCHEDULE_CONFLICT) 1483351611Scy S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL) 1484351611Scy S2S(MCCAOP_RESERVATION_CONFLICT) 1485351611Scy S2S(MAF_LIMIT_EXCEEDED) 1486351611Scy S2S(MCCA_TRACK_LIMIT_EXCEEDED) 1487351611Scy S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT) 1488351611Scy S2S(ASSOC_DENIED_NO_VHT) 1489351611Scy S2S(ENABLEMENT_DENIED) 1490351611Scy S2S(RESTRICTION_FROM_AUTHORIZED_GDB) 1491351611Scy S2S(AUTHORIZATION_DEENABLED) 1492351611Scy S2S(FILS_AUTHENTICATION_FAILURE) 1493351611Scy S2S(UNKNOWN_AUTHENTICATION_SERVER) 1494351611Scy S2S(UNKNOWN_PASSWORD_IDENTIFIER) 1495351611Scy } 1496351611Scy return "UNKNOWN"; 1497351611Scy#undef S2S 1498351611Scy} 1499351611Scy 1500351611Scy 1501289549Srpauloint mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, 1502289549Srpaulo size_t ies_len) 1503289549Srpaulo{ 1504346981Scy const struct element *elem; 1505346981Scy 1506289549Srpaulo os_memset(info, 0, sizeof(*info)); 1507289549Srpaulo 1508346981Scy if (!ies_buf) 1509346981Scy return 0; 1510289549Srpaulo 1511346981Scy for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) { 1512346981Scy if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED) 1513346981Scy return 0; 1514289549Srpaulo 1515346981Scy wpa_printf(MSG_DEBUG, "MB IE of %u bytes found", 1516346981Scy elem->datalen + 2); 1517346981Scy info->ies[info->nof_ies].ie = elem->data; 1518346981Scy info->ies[info->nof_ies].ie_len = elem->datalen; 1519346981Scy info->nof_ies++; 1520346981Scy } 1521289549Srpaulo 1522346981Scy if (!for_each_element_completed(elem, ies_buf, ies_len)) { 1523346981Scy wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len); 1524346981Scy return -1; 1525289549Srpaulo } 1526289549Srpaulo 1527289549Srpaulo return 0; 1528289549Srpaulo} 1529289549Srpaulo 1530289549Srpaulo 1531289549Srpaulostruct wpabuf * mb_ies_by_info(struct mb_ies_info *info) 1532289549Srpaulo{ 1533289549Srpaulo struct wpabuf *mb_ies = NULL; 1534289549Srpaulo 1535289549Srpaulo WPA_ASSERT(info != NULL); 1536289549Srpaulo 1537289549Srpaulo if (info->nof_ies) { 1538289549Srpaulo u8 i; 1539289549Srpaulo size_t mb_ies_size = 0; 1540289549Srpaulo 1541289549Srpaulo for (i = 0; i < info->nof_ies; i++) 1542289549Srpaulo mb_ies_size += 2 + info->ies[i].ie_len; 1543289549Srpaulo 1544289549Srpaulo mb_ies = wpabuf_alloc(mb_ies_size); 1545289549Srpaulo if (mb_ies) { 1546289549Srpaulo for (i = 0; i < info->nof_ies; i++) { 1547289549Srpaulo wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND); 1548289549Srpaulo wpabuf_put_u8(mb_ies, info->ies[i].ie_len); 1549289549Srpaulo wpabuf_put_data(mb_ies, 1550289549Srpaulo info->ies[i].ie, 1551289549Srpaulo info->ies[i].ie_len); 1552289549Srpaulo } 1553289549Srpaulo } 1554289549Srpaulo } 1555289549Srpaulo 1556289549Srpaulo return mb_ies; 1557289549Srpaulo} 1558337817Scy 1559337817Scy 1560337817Scyconst struct oper_class_map global_op_class[] = { 1561337817Scy { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP }, 1562337817Scy { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP }, 1563337817Scy 1564337817Scy /* Do not enable HT40 on 2.4 GHz for P2P use for now */ 1565337817Scy { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP }, 1566337817Scy { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP }, 1567337817Scy 1568337817Scy { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, 1569337817Scy { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, 1570337817Scy { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, 1571337817Scy { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, 1572337817Scy { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, 1573337817Scy { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, 1574337817Scy { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, 1575337817Scy { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP }, 1576337817Scy { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP }, 1577337817Scy { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, 1578337817Scy { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP }, 1579337817Scy { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP }, 1580337817Scy { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP }, 1581337817Scy 1582337817Scy /* 1583337817Scy * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center 1584337817Scy * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of 1585337817Scy * 80 MHz, but currently use the following definition for simplicity 1586337817Scy * (these center frequencies are not actual channels, which makes 1587337817Scy * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take 1588337817Scy * care of removing invalid channels. 1589337817Scy */ 1590337817Scy { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP }, 1591337817Scy { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP }, 1592337817Scy { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP }, 1593337817Scy { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP }, 1594337817Scy { -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP } 1595337817Scy}; 1596337817Scy 1597337817Scy 1598337817Scystatic enum phy_type ieee80211_phy_type_by_freq(int freq) 1599337817Scy{ 1600337817Scy enum hostapd_hw_mode hw_mode; 1601337817Scy u8 channel; 1602337817Scy 1603337817Scy hw_mode = ieee80211_freq_to_chan(freq, &channel); 1604337817Scy 1605337817Scy switch (hw_mode) { 1606337817Scy case HOSTAPD_MODE_IEEE80211A: 1607337817Scy return PHY_TYPE_OFDM; 1608337817Scy case HOSTAPD_MODE_IEEE80211B: 1609337817Scy return PHY_TYPE_HRDSSS; 1610337817Scy case HOSTAPD_MODE_IEEE80211G: 1611337817Scy return PHY_TYPE_ERP; 1612337817Scy case HOSTAPD_MODE_IEEE80211AD: 1613337817Scy return PHY_TYPE_DMG; 1614337817Scy default: 1615337817Scy return PHY_TYPE_UNSPECIFIED; 1616337817Scy }; 1617337817Scy} 1618337817Scy 1619337817Scy 1620337817Scy/* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */ 1621337817Scyenum phy_type ieee80211_get_phy_type(int freq, int ht, int vht) 1622337817Scy{ 1623337817Scy if (vht) 1624337817Scy return PHY_TYPE_VHT; 1625337817Scy if (ht) 1626337817Scy return PHY_TYPE_HT; 1627337817Scy 1628337817Scy return ieee80211_phy_type_by_freq(freq); 1629337817Scy} 1630337817Scy 1631337817Scy 1632337817Scysize_t global_op_class_size = ARRAY_SIZE(global_op_class); 1633337817Scy 1634337817Scy 1635337817Scy/** 1636337817Scy * get_ie - Fetch a specified information element from IEs buffer 1637337817Scy * @ies: Information elements buffer 1638337817Scy * @len: Information elements buffer length 1639337817Scy * @eid: Information element identifier (WLAN_EID_*) 1640337817Scy * Returns: Pointer to the information element (id field) or %NULL if not found 1641337817Scy * 1642337817Scy * This function returns the first matching information element in the IEs 1643337817Scy * buffer or %NULL in case the element is not found. 1644337817Scy */ 1645337817Scyconst u8 * get_ie(const u8 *ies, size_t len, u8 eid) 1646337817Scy{ 1647346981Scy const struct element *elem; 1648337817Scy 1649337817Scy if (!ies) 1650337817Scy return NULL; 1651337817Scy 1652346981Scy for_each_element_id(elem, eid, ies, len) 1653346981Scy return &elem->id; 1654337817Scy 1655346981Scy return NULL; 1656346981Scy} 1657337817Scy 1658337817Scy 1659346981Scy/** 1660346981Scy * get_ie_ext - Fetch a specified extended information element from IEs buffer 1661346981Scy * @ies: Information elements buffer 1662346981Scy * @len: Information elements buffer length 1663346981Scy * @ext: Information element extension identifier (WLAN_EID_EXT_*) 1664346981Scy * Returns: Pointer to the information element (id field) or %NULL if not found 1665346981Scy * 1666346981Scy * This function returns the first matching information element in the IEs 1667346981Scy * buffer or %NULL in case the element is not found. 1668346981Scy */ 1669346981Scyconst u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext) 1670346981Scy{ 1671346981Scy const struct element *elem; 1672346981Scy 1673346981Scy if (!ies) 1674346981Scy return NULL; 1675346981Scy 1676346981Scy for_each_element_extid(elem, ext, ies, len) 1677346981Scy return &elem->id; 1678346981Scy 1679346981Scy return NULL; 1680346981Scy} 1681346981Scy 1682346981Scy 1683346981Scyconst u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) 1684346981Scy{ 1685346981Scy const struct element *elem; 1686346981Scy 1687346981Scy for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) { 1688346981Scy if (elem->datalen >= 4 && 1689346981Scy vendor_type == WPA_GET_BE32(elem->data)) 1690346981Scy return &elem->id; 1691337817Scy } 1692337817Scy 1693337817Scy return NULL; 1694337817Scy} 1695337817Scy 1696337817Scy 1697337817Scysize_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) 1698337817Scy{ 1699337817Scy /* 1700337817Scy * MBO IE requires 6 bytes without the attributes: EID (1), length (1), 1701337817Scy * OUI (3), OUI type (1). 1702337817Scy */ 1703337817Scy if (len < 6 + attr_len) { 1704337817Scy wpa_printf(MSG_DEBUG, 1705337817Scy "MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu", 1706337817Scy len, attr_len); 1707337817Scy return 0; 1708337817Scy } 1709337817Scy 1710337817Scy *buf++ = WLAN_EID_VENDOR_SPECIFIC; 1711337817Scy *buf++ = attr_len + 4; 1712337817Scy WPA_PUT_BE24(buf, OUI_WFA); 1713337817Scy buf += 3; 1714337817Scy *buf++ = MBO_OUI_TYPE; 1715337817Scy os_memcpy(buf, attr, attr_len); 1716337817Scy 1717337817Scy return 6 + attr_len; 1718337817Scy} 1719346981Scy 1720346981Scy 1721346981Scysize_t add_multi_ap_ie(u8 *buf, size_t len, u8 value) 1722346981Scy{ 1723346981Scy u8 *pos = buf; 1724346981Scy 1725346981Scy if (len < 9) 1726346981Scy return 0; 1727346981Scy 1728346981Scy *pos++ = WLAN_EID_VENDOR_SPECIFIC; 1729346981Scy *pos++ = 7; /* len */ 1730346981Scy WPA_PUT_BE24(pos, OUI_WFA); 1731346981Scy pos += 3; 1732346981Scy *pos++ = MULTI_AP_OUI_TYPE; 1733346981Scy *pos++ = MULTI_AP_SUB_ELEM_TYPE; 1734346981Scy *pos++ = 1; /* len */ 1735346981Scy *pos++ = value; 1736346981Scy 1737346981Scy return pos - buf; 1738346981Scy} 1739346981Scy 1740346981Scy 1741346981Scystatic const struct country_op_class us_op_class[] = { 1742346981Scy { 1, 115 }, 1743346981Scy { 2, 118 }, 1744346981Scy { 3, 124 }, 1745346981Scy { 4, 121 }, 1746346981Scy { 5, 125 }, 1747346981Scy { 12, 81 }, 1748346981Scy { 22, 116 }, 1749346981Scy { 23, 119 }, 1750346981Scy { 24, 122 }, 1751346981Scy { 25, 126 }, 1752346981Scy { 26, 126 }, 1753346981Scy { 27, 117 }, 1754346981Scy { 28, 120 }, 1755346981Scy { 29, 123 }, 1756346981Scy { 30, 127 }, 1757346981Scy { 31, 127 }, 1758346981Scy { 32, 83 }, 1759346981Scy { 33, 84 }, 1760346981Scy { 34, 180 }, 1761346981Scy}; 1762346981Scy 1763346981Scystatic const struct country_op_class eu_op_class[] = { 1764346981Scy { 1, 115 }, 1765346981Scy { 2, 118 }, 1766346981Scy { 3, 121 }, 1767346981Scy { 4, 81 }, 1768346981Scy { 5, 116 }, 1769346981Scy { 6, 119 }, 1770346981Scy { 7, 122 }, 1771346981Scy { 8, 117 }, 1772346981Scy { 9, 120 }, 1773346981Scy { 10, 123 }, 1774346981Scy { 11, 83 }, 1775346981Scy { 12, 84 }, 1776346981Scy { 17, 125 }, 1777346981Scy { 18, 180 }, 1778346981Scy}; 1779346981Scy 1780346981Scystatic const struct country_op_class jp_op_class[] = { 1781346981Scy { 1, 115 }, 1782346981Scy { 30, 81 }, 1783346981Scy { 31, 82 }, 1784346981Scy { 32, 118 }, 1785346981Scy { 33, 118 }, 1786346981Scy { 34, 121 }, 1787346981Scy { 35, 121 }, 1788346981Scy { 36, 116 }, 1789346981Scy { 37, 119 }, 1790346981Scy { 38, 119 }, 1791346981Scy { 39, 122 }, 1792346981Scy { 40, 122 }, 1793346981Scy { 41, 117 }, 1794346981Scy { 42, 120 }, 1795346981Scy { 43, 120 }, 1796346981Scy { 44, 123 }, 1797346981Scy { 45, 123 }, 1798346981Scy { 56, 83 }, 1799346981Scy { 57, 84 }, 1800346981Scy { 58, 121 }, 1801346981Scy { 59, 180 }, 1802346981Scy}; 1803346981Scy 1804346981Scystatic const struct country_op_class cn_op_class[] = { 1805346981Scy { 1, 115 }, 1806346981Scy { 2, 118 }, 1807346981Scy { 3, 125 }, 1808346981Scy { 4, 116 }, 1809346981Scy { 5, 119 }, 1810346981Scy { 6, 126 }, 1811346981Scy { 7, 81 }, 1812346981Scy { 8, 83 }, 1813346981Scy { 9, 84 }, 1814346981Scy}; 1815346981Scy 1816346981Scystatic u8 1817346981Scyglobal_op_class_from_country_array(u8 op_class, size_t array_size, 1818346981Scy const struct country_op_class *country_array) 1819346981Scy{ 1820346981Scy size_t i; 1821346981Scy 1822346981Scy for (i = 0; i < array_size; i++) { 1823346981Scy if (country_array[i].country_op_class == op_class) 1824346981Scy return country_array[i].global_op_class; 1825346981Scy } 1826346981Scy 1827346981Scy return 0; 1828346981Scy} 1829346981Scy 1830346981Scy 1831346981Scyu8 country_to_global_op_class(const char *country, u8 op_class) 1832346981Scy{ 1833346981Scy const struct country_op_class *country_array; 1834346981Scy size_t size; 1835346981Scy u8 g_op_class; 1836346981Scy 1837346981Scy if (country_match(us_op_class_cc, country)) { 1838346981Scy country_array = us_op_class; 1839346981Scy size = ARRAY_SIZE(us_op_class); 1840346981Scy } else if (country_match(eu_op_class_cc, country)) { 1841346981Scy country_array = eu_op_class; 1842346981Scy size = ARRAY_SIZE(eu_op_class); 1843346981Scy } else if (country_match(jp_op_class_cc, country)) { 1844346981Scy country_array = jp_op_class; 1845346981Scy size = ARRAY_SIZE(jp_op_class); 1846346981Scy } else if (country_match(cn_op_class_cc, country)) { 1847346981Scy country_array = cn_op_class; 1848346981Scy size = ARRAY_SIZE(cn_op_class); 1849346981Scy } else { 1850346981Scy /* 1851346981Scy * Countries that do not match any of the above countries use 1852346981Scy * global operating classes 1853346981Scy */ 1854346981Scy return op_class; 1855346981Scy } 1856346981Scy 1857346981Scy g_op_class = global_op_class_from_country_array(op_class, size, 1858346981Scy country_array); 1859346981Scy 1860346981Scy /* 1861346981Scy * If the given operating class did not match any of the country's 1862346981Scy * operating classes, assume that global operating class is used. 1863346981Scy */ 1864346981Scy return g_op_class ? g_op_class : op_class; 1865346981Scy} 1866346981Scy 1867346981Scy 1868346981Scyconst struct oper_class_map * get_oper_class(const char *country, u8 op_class) 1869346981Scy{ 1870346981Scy const struct oper_class_map *op; 1871346981Scy 1872346981Scy if (country) 1873346981Scy op_class = country_to_global_op_class(country, op_class); 1874346981Scy 1875346981Scy op = &global_op_class[0]; 1876346981Scy while (op->op_class && op->op_class != op_class) 1877346981Scy op++; 1878346981Scy 1879346981Scy if (!op->op_class) 1880346981Scy return NULL; 1881346981Scy 1882346981Scy return op; 1883346981Scy} 1884346981Scy 1885346981Scy 1886346981Scyint oper_class_bw_to_int(const struct oper_class_map *map) 1887346981Scy{ 1888346981Scy switch (map->bw) { 1889346981Scy case BW20: 1890346981Scy return 20; 1891346981Scy case BW40PLUS: 1892346981Scy case BW40MINUS: 1893346981Scy return 40; 1894346981Scy case BW80: 1895346981Scy return 80; 1896346981Scy case BW80P80: 1897346981Scy case BW160: 1898346981Scy return 160; 1899346981Scy case BW2160: 1900346981Scy return 2160; 1901346981Scy default: 1902346981Scy return 0; 1903346981Scy } 1904346981Scy} 1905346981Scy 1906346981Scy 1907346981Scyint ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, 1908346981Scy size_t nei_rep_len) 1909346981Scy{ 1910346981Scy u8 *nei_pos = nei_rep; 1911346981Scy const char *end; 1912346981Scy 1913346981Scy /* 1914346981Scy * BSS Transition Candidate List Entries - Neighbor Report elements 1915346981Scy * neighbor=<BSSID>,<BSSID Information>,<Operating Class>, 1916346981Scy * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>] 1917346981Scy */ 1918346981Scy while (pos) { 1919346981Scy u8 *nei_start; 1920346981Scy long int val; 1921346981Scy char *endptr, *tmp; 1922346981Scy 1923346981Scy pos = os_strstr(pos, " neighbor="); 1924346981Scy if (!pos) 1925346981Scy break; 1926346981Scy if (nei_pos + 15 > nei_rep + nei_rep_len) { 1927346981Scy wpa_printf(MSG_DEBUG, 1928346981Scy "Not enough room for additional neighbor"); 1929346981Scy return -1; 1930346981Scy } 1931346981Scy pos += 10; 1932346981Scy 1933346981Scy nei_start = nei_pos; 1934346981Scy *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT; 1935346981Scy nei_pos++; /* length to be filled in */ 1936346981Scy 1937346981Scy if (hwaddr_aton(pos, nei_pos)) { 1938346981Scy wpa_printf(MSG_DEBUG, "Invalid BSSID"); 1939346981Scy return -1; 1940346981Scy } 1941346981Scy nei_pos += ETH_ALEN; 1942346981Scy pos += 17; 1943346981Scy if (*pos != ',') { 1944346981Scy wpa_printf(MSG_DEBUG, "Missing BSSID Information"); 1945346981Scy return -1; 1946346981Scy } 1947346981Scy pos++; 1948346981Scy 1949346981Scy val = strtol(pos, &endptr, 0); 1950346981Scy WPA_PUT_LE32(nei_pos, val); 1951346981Scy nei_pos += 4; 1952346981Scy if (*endptr != ',') { 1953346981Scy wpa_printf(MSG_DEBUG, "Missing Operating Class"); 1954346981Scy return -1; 1955346981Scy } 1956346981Scy pos = endptr + 1; 1957346981Scy 1958346981Scy *nei_pos++ = atoi(pos); /* Operating Class */ 1959346981Scy pos = os_strchr(pos, ','); 1960346981Scy if (pos == NULL) { 1961346981Scy wpa_printf(MSG_DEBUG, "Missing Channel Number"); 1962346981Scy return -1; 1963346981Scy } 1964346981Scy pos++; 1965346981Scy 1966346981Scy *nei_pos++ = atoi(pos); /* Channel Number */ 1967346981Scy pos = os_strchr(pos, ','); 1968346981Scy if (pos == NULL) { 1969346981Scy wpa_printf(MSG_DEBUG, "Missing PHY Type"); 1970346981Scy return -1; 1971346981Scy } 1972346981Scy pos++; 1973346981Scy 1974346981Scy *nei_pos++ = atoi(pos); /* PHY Type */ 1975346981Scy end = os_strchr(pos, ' '); 1976346981Scy tmp = os_strchr(pos, ','); 1977346981Scy if (tmp && (!end || tmp < end)) { 1978346981Scy /* Optional Subelements (hexdump) */ 1979346981Scy size_t len; 1980346981Scy 1981346981Scy pos = tmp + 1; 1982346981Scy end = os_strchr(pos, ' '); 1983346981Scy if (end) 1984346981Scy len = end - pos; 1985346981Scy else 1986346981Scy len = os_strlen(pos); 1987346981Scy if (nei_pos + len / 2 > nei_rep + nei_rep_len) { 1988346981Scy wpa_printf(MSG_DEBUG, 1989346981Scy "Not enough room for neighbor subelements"); 1990346981Scy return -1; 1991346981Scy } 1992346981Scy if (len & 0x01 || 1993346981Scy hexstr2bin(pos, nei_pos, len / 2) < 0) { 1994346981Scy wpa_printf(MSG_DEBUG, 1995346981Scy "Invalid neighbor subelement info"); 1996346981Scy return -1; 1997346981Scy } 1998346981Scy nei_pos += len / 2; 1999346981Scy pos = end; 2000346981Scy } 2001346981Scy 2002346981Scy nei_start[1] = nei_pos - nei_start - 2; 2003346981Scy } 2004346981Scy 2005346981Scy return nei_pos - nei_rep; 2006346981Scy} 2007346981Scy 2008346981Scy 2009346981Scyint ieee802_11_ext_capab(const u8 *ie, unsigned int capab) 2010346981Scy{ 2011346981Scy if (!ie || ie[1] <= capab / 8) 2012346981Scy return 0; 2013346981Scy return !!(ie[2 + capab / 8] & BIT(capab % 8)); 2014346981Scy} 2015