1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * Common driver-related functions 3f05cddf9SRui Paulo * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "includes.h" 10f05cddf9SRui Paulo #include "utils/common.h" 11f05cddf9SRui Paulo #include "driver.h" 12f05cddf9SRui Paulo 13f05cddf9SRui Paulo void wpa_scan_results_free(struct wpa_scan_results *res) 14f05cddf9SRui Paulo { 15f05cddf9SRui Paulo size_t i; 16f05cddf9SRui Paulo 17f05cddf9SRui Paulo if (res == NULL) 18f05cddf9SRui Paulo return; 19f05cddf9SRui Paulo 20f05cddf9SRui Paulo for (i = 0; i < res->num; i++) 21f05cddf9SRui Paulo os_free(res->res[i]); 22f05cddf9SRui Paulo os_free(res->res); 23f05cddf9SRui Paulo os_free(res); 24f05cddf9SRui Paulo } 25f05cddf9SRui Paulo 26f05cddf9SRui Paulo 27f05cddf9SRui Paulo const char * event_to_string(enum wpa_event_type event) 28f05cddf9SRui Paulo { 29f05cddf9SRui Paulo #define E2S(n) case EVENT_ ## n: return #n 30f05cddf9SRui Paulo switch (event) { 31f05cddf9SRui Paulo E2S(ASSOC); 32f05cddf9SRui Paulo E2S(DISASSOC); 33f05cddf9SRui Paulo E2S(MICHAEL_MIC_FAILURE); 34f05cddf9SRui Paulo E2S(SCAN_RESULTS); 35f05cddf9SRui Paulo E2S(ASSOCINFO); 36f05cddf9SRui Paulo E2S(INTERFACE_STATUS); 37f05cddf9SRui Paulo E2S(PMKID_CANDIDATE); 38f05cddf9SRui Paulo E2S(STKSTART); 39f05cddf9SRui Paulo E2S(TDLS); 40f05cddf9SRui Paulo E2S(FT_RESPONSE); 41f05cddf9SRui Paulo E2S(IBSS_RSN_START); 42f05cddf9SRui Paulo E2S(AUTH); 43f05cddf9SRui Paulo E2S(DEAUTH); 44f05cddf9SRui Paulo E2S(ASSOC_REJECT); 45f05cddf9SRui Paulo E2S(AUTH_TIMED_OUT); 46f05cddf9SRui Paulo E2S(ASSOC_TIMED_OUT); 47f05cddf9SRui Paulo E2S(WPS_BUTTON_PUSHED); 48f05cddf9SRui Paulo E2S(TX_STATUS); 49f05cddf9SRui Paulo E2S(RX_FROM_UNKNOWN); 50f05cddf9SRui Paulo E2S(RX_MGMT); 51f05cddf9SRui Paulo E2S(REMAIN_ON_CHANNEL); 52f05cddf9SRui Paulo E2S(CANCEL_REMAIN_ON_CHANNEL); 53f05cddf9SRui Paulo E2S(RX_PROBE_REQ); 54f05cddf9SRui Paulo E2S(NEW_STA); 55f05cddf9SRui Paulo E2S(EAPOL_RX); 56f05cddf9SRui Paulo E2S(SIGNAL_CHANGE); 57f05cddf9SRui Paulo E2S(INTERFACE_ENABLED); 58f05cddf9SRui Paulo E2S(INTERFACE_DISABLED); 59f05cddf9SRui Paulo E2S(CHANNEL_LIST_CHANGED); 60f05cddf9SRui Paulo E2S(INTERFACE_UNAVAILABLE); 61f05cddf9SRui Paulo E2S(BEST_CHANNEL); 62f05cddf9SRui Paulo E2S(UNPROT_DEAUTH); 63f05cddf9SRui Paulo E2S(UNPROT_DISASSOC); 64f05cddf9SRui Paulo E2S(STATION_LOW_ACK); 65f05cddf9SRui Paulo E2S(IBSS_PEER_LOST); 66f05cddf9SRui Paulo E2S(DRIVER_GTK_REKEY); 67f05cddf9SRui Paulo E2S(SCHED_SCAN_STOPPED); 68f05cddf9SRui Paulo E2S(DRIVER_CLIENT_POLL_OK); 69f05cddf9SRui Paulo E2S(EAPOL_TX_STATUS); 70f05cddf9SRui Paulo E2S(CH_SWITCH); 71f05cddf9SRui Paulo E2S(WNM); 725b9c547cSRui Paulo E2S(CONNECT_FAILED_REASON); 735b9c547cSRui Paulo E2S(DFS_RADAR_DETECTED); 745b9c547cSRui Paulo E2S(DFS_CAC_FINISHED); 755b9c547cSRui Paulo E2S(DFS_CAC_ABORTED); 765b9c547cSRui Paulo E2S(DFS_NOP_FINISHED); 775b9c547cSRui Paulo E2S(SURVEY); 785b9c547cSRui Paulo E2S(SCAN_STARTED); 795b9c547cSRui Paulo E2S(AVOID_FREQUENCIES); 805b9c547cSRui Paulo E2S(NEW_PEER_CANDIDATE); 815b9c547cSRui Paulo E2S(ACS_CHANNEL_SELECTED); 825b9c547cSRui Paulo E2S(DFS_CAC_STARTED); 83*780fb4a2SCy Schubert E2S(P2P_LO_STOP); 84f05cddf9SRui Paulo } 85f05cddf9SRui Paulo 86f05cddf9SRui Paulo return "UNKNOWN"; 87f05cddf9SRui Paulo #undef E2S 88f05cddf9SRui Paulo } 895b9c547cSRui Paulo 905b9c547cSRui Paulo 915b9c547cSRui Paulo const char * channel_width_to_string(enum chan_width width) 925b9c547cSRui Paulo { 935b9c547cSRui Paulo switch (width) { 945b9c547cSRui Paulo case CHAN_WIDTH_20_NOHT: 955b9c547cSRui Paulo return "20 MHz (no HT)"; 965b9c547cSRui Paulo case CHAN_WIDTH_20: 975b9c547cSRui Paulo return "20 MHz"; 985b9c547cSRui Paulo case CHAN_WIDTH_40: 995b9c547cSRui Paulo return "40 MHz"; 1005b9c547cSRui Paulo case CHAN_WIDTH_80: 1015b9c547cSRui Paulo return "80 MHz"; 1025b9c547cSRui Paulo case CHAN_WIDTH_80P80: 1035b9c547cSRui Paulo return "80+80 MHz"; 1045b9c547cSRui Paulo case CHAN_WIDTH_160: 1055b9c547cSRui Paulo return "160 MHz"; 1065b9c547cSRui Paulo default: 1075b9c547cSRui Paulo return "unknown"; 1085b9c547cSRui Paulo } 1095b9c547cSRui Paulo } 1105b9c547cSRui Paulo 1115b9c547cSRui Paulo 1125b9c547cSRui Paulo int ht_supported(const struct hostapd_hw_modes *mode) 1135b9c547cSRui Paulo { 1145b9c547cSRui Paulo if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) { 1155b9c547cSRui Paulo /* 1165b9c547cSRui Paulo * The driver did not indicate whether it supports HT. Assume 1175b9c547cSRui Paulo * it does to avoid connection issues. 1185b9c547cSRui Paulo */ 1195b9c547cSRui Paulo return 1; 1205b9c547cSRui Paulo } 1215b9c547cSRui Paulo 1225b9c547cSRui Paulo /* 1235b9c547cSRui Paulo * IEEE Std 802.11n-2009 20.1.1: 1245b9c547cSRui Paulo * An HT non-AP STA shall support all EQM rates for one spatial stream. 1255b9c547cSRui Paulo */ 1265b9c547cSRui Paulo return mode->mcs_set[0] == 0xff; 1275b9c547cSRui Paulo } 1285b9c547cSRui Paulo 1295b9c547cSRui Paulo 1305b9c547cSRui Paulo int vht_supported(const struct hostapd_hw_modes *mode) 1315b9c547cSRui Paulo { 1325b9c547cSRui Paulo if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { 1335b9c547cSRui Paulo /* 1345b9c547cSRui Paulo * The driver did not indicate whether it supports VHT. Assume 1355b9c547cSRui Paulo * it does to avoid connection issues. 1365b9c547cSRui Paulo */ 1375b9c547cSRui Paulo return 1; 1385b9c547cSRui Paulo } 1395b9c547cSRui Paulo 1405b9c547cSRui Paulo /* 1415b9c547cSRui Paulo * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. 1425b9c547cSRui Paulo * TODO: Verify if this complies with the standard 1435b9c547cSRui Paulo */ 1445b9c547cSRui Paulo return (mode->vht_mcs_set[0] & 0x3) != 3; 1455b9c547cSRui Paulo } 1465b9c547cSRui Paulo 1475b9c547cSRui Paulo 1485b9c547cSRui Paulo static int wpa_check_wowlan_trigger(const char *start, const char *trigger, 1495b9c547cSRui Paulo int capa_trigger, u8 *param_trigger) 1505b9c547cSRui Paulo { 1515b9c547cSRui Paulo if (os_strcmp(start, trigger) != 0) 1525b9c547cSRui Paulo return 0; 1535b9c547cSRui Paulo if (!capa_trigger) 1545b9c547cSRui Paulo return 0; 1555b9c547cSRui Paulo 1565b9c547cSRui Paulo *param_trigger = 1; 1575b9c547cSRui Paulo return 1; 1585b9c547cSRui Paulo } 1595b9c547cSRui Paulo 1605b9c547cSRui Paulo 1615b9c547cSRui Paulo struct wowlan_triggers * 1625b9c547cSRui Paulo wpa_get_wowlan_triggers(const char *wowlan_triggers, 1635b9c547cSRui Paulo const struct wpa_driver_capa *capa) 1645b9c547cSRui Paulo { 1655b9c547cSRui Paulo struct wowlan_triggers *triggers; 1665b9c547cSRui Paulo char *start, *end, *buf; 1675b9c547cSRui Paulo int last; 1685b9c547cSRui Paulo 1695b9c547cSRui Paulo if (!wowlan_triggers) 1705b9c547cSRui Paulo return NULL; 1715b9c547cSRui Paulo 1725b9c547cSRui Paulo buf = os_strdup(wowlan_triggers); 1735b9c547cSRui Paulo if (buf == NULL) 1745b9c547cSRui Paulo return NULL; 1755b9c547cSRui Paulo 1765b9c547cSRui Paulo triggers = os_zalloc(sizeof(*triggers)); 1775b9c547cSRui Paulo if (triggers == NULL) 1785b9c547cSRui Paulo goto out; 1795b9c547cSRui Paulo 1805b9c547cSRui Paulo #define CHECK_TRIGGER(trigger) \ 1815b9c547cSRui Paulo wpa_check_wowlan_trigger(start, #trigger, \ 1825b9c547cSRui Paulo capa->wowlan_triggers.trigger, \ 1835b9c547cSRui Paulo &triggers->trigger) 1845b9c547cSRui Paulo 1855b9c547cSRui Paulo start = buf; 1865b9c547cSRui Paulo while (*start != '\0') { 187*780fb4a2SCy Schubert while (isblank((unsigned char) *start)) 1885b9c547cSRui Paulo start++; 1895b9c547cSRui Paulo if (*start == '\0') 1905b9c547cSRui Paulo break; 1915b9c547cSRui Paulo end = start; 192*780fb4a2SCy Schubert while (!isblank((unsigned char) *end) && *end != '\0') 1935b9c547cSRui Paulo end++; 1945b9c547cSRui Paulo last = *end == '\0'; 1955b9c547cSRui Paulo *end = '\0'; 1965b9c547cSRui Paulo 1975b9c547cSRui Paulo if (!CHECK_TRIGGER(any) && 1985b9c547cSRui Paulo !CHECK_TRIGGER(disconnect) && 1995b9c547cSRui Paulo !CHECK_TRIGGER(magic_pkt) && 2005b9c547cSRui Paulo !CHECK_TRIGGER(gtk_rekey_failure) && 2015b9c547cSRui Paulo !CHECK_TRIGGER(eap_identity_req) && 2025b9c547cSRui Paulo !CHECK_TRIGGER(four_way_handshake) && 2035b9c547cSRui Paulo !CHECK_TRIGGER(rfkill_release)) { 2045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2055b9c547cSRui Paulo "Unknown/unsupported wowlan trigger '%s'", 2065b9c547cSRui Paulo start); 2075b9c547cSRui Paulo os_free(triggers); 2085b9c547cSRui Paulo triggers = NULL; 2095b9c547cSRui Paulo goto out; 2105b9c547cSRui Paulo } 2115b9c547cSRui Paulo 2125b9c547cSRui Paulo if (last) 2135b9c547cSRui Paulo break; 2145b9c547cSRui Paulo start = end + 1; 2155b9c547cSRui Paulo } 2165b9c547cSRui Paulo #undef CHECK_TRIGGER 2175b9c547cSRui Paulo 2185b9c547cSRui Paulo out: 2195b9c547cSRui Paulo os_free(buf); 2205b9c547cSRui Paulo return triggers; 2215b9c547cSRui Paulo } 222*780fb4a2SCy Schubert 223*780fb4a2SCy Schubert 224*780fb4a2SCy Schubert const char * driver_flag_to_string(u64 flag) 225*780fb4a2SCy Schubert { 226*780fb4a2SCy Schubert #define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x 227*780fb4a2SCy Schubert switch (flag) { 228*780fb4a2SCy Schubert DF2S(DRIVER_IE); 229*780fb4a2SCy Schubert DF2S(SET_KEYS_AFTER_ASSOC); 230*780fb4a2SCy Schubert DF2S(DFS_OFFLOAD); 231*780fb4a2SCy Schubert DF2S(4WAY_HANDSHAKE); 232*780fb4a2SCy Schubert DF2S(WIRED); 233*780fb4a2SCy Schubert DF2S(SME); 234*780fb4a2SCy Schubert DF2S(AP); 235*780fb4a2SCy Schubert DF2S(SET_KEYS_AFTER_ASSOC_DONE); 236*780fb4a2SCy Schubert DF2S(HT_2040_COEX); 237*780fb4a2SCy Schubert DF2S(P2P_CONCURRENT); 238*780fb4a2SCy Schubert DF2S(P2P_DEDICATED_INTERFACE); 239*780fb4a2SCy Schubert DF2S(P2P_CAPABLE); 240*780fb4a2SCy Schubert DF2S(AP_TEARDOWN_SUPPORT); 241*780fb4a2SCy Schubert DF2S(P2P_MGMT_AND_NON_P2P); 242*780fb4a2SCy Schubert DF2S(SANE_ERROR_CODES); 243*780fb4a2SCy Schubert DF2S(OFFCHANNEL_TX); 244*780fb4a2SCy Schubert DF2S(EAPOL_TX_STATUS); 245*780fb4a2SCy Schubert DF2S(DEAUTH_TX_STATUS); 246*780fb4a2SCy Schubert DF2S(BSS_SELECTION); 247*780fb4a2SCy Schubert DF2S(TDLS_SUPPORT); 248*780fb4a2SCy Schubert DF2S(TDLS_EXTERNAL_SETUP); 249*780fb4a2SCy Schubert DF2S(PROBE_RESP_OFFLOAD); 250*780fb4a2SCy Schubert DF2S(AP_UAPSD); 251*780fb4a2SCy Schubert DF2S(INACTIVITY_TIMER); 252*780fb4a2SCy Schubert DF2S(AP_MLME); 253*780fb4a2SCy Schubert DF2S(SAE); 254*780fb4a2SCy Schubert DF2S(OBSS_SCAN); 255*780fb4a2SCy Schubert DF2S(IBSS); 256*780fb4a2SCy Schubert DF2S(RADAR); 257*780fb4a2SCy Schubert DF2S(DEDICATED_P2P_DEVICE); 258*780fb4a2SCy Schubert DF2S(QOS_MAPPING); 259*780fb4a2SCy Schubert DF2S(AP_CSA); 260*780fb4a2SCy Schubert DF2S(MESH); 261*780fb4a2SCy Schubert DF2S(ACS_OFFLOAD); 262*780fb4a2SCy Schubert DF2S(KEY_MGMT_OFFLOAD); 263*780fb4a2SCy Schubert DF2S(TDLS_CHANNEL_SWITCH); 264*780fb4a2SCy Schubert DF2S(HT_IBSS); 265*780fb4a2SCy Schubert DF2S(VHT_IBSS); 266*780fb4a2SCy Schubert DF2S(SUPPORT_HW_MODE_ANY); 267*780fb4a2SCy Schubert DF2S(OFFCHANNEL_SIMULTANEOUS); 268*780fb4a2SCy Schubert DF2S(FULL_AP_CLIENT_STATE); 269*780fb4a2SCy Schubert DF2S(P2P_LISTEN_OFFLOAD); 270*780fb4a2SCy Schubert } 271*780fb4a2SCy Schubert return "UNKNOWN"; 272*780fb4a2SCy Schubert #undef DF2S 273*780fb4a2SCy Schubert } 274