1252190Srpaulo/* 2252190Srpaulo * Common driver-related functions 3252190Srpaulo * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> 4252190Srpaulo * 5252190Srpaulo * This software may be distributed under the terms of the BSD license. 6252190Srpaulo * See README for more details. 7252190Srpaulo */ 8252190Srpaulo 9252190Srpaulo#include "includes.h" 10252190Srpaulo#include "utils/common.h" 11252190Srpaulo#include "driver.h" 12252190Srpaulo 13252190Srpaulovoid wpa_scan_results_free(struct wpa_scan_results *res) 14252190Srpaulo{ 15252190Srpaulo size_t i; 16252190Srpaulo 17252190Srpaulo if (res == NULL) 18252190Srpaulo return; 19252190Srpaulo 20252190Srpaulo for (i = 0; i < res->num; i++) 21252190Srpaulo os_free(res->res[i]); 22252190Srpaulo os_free(res->res); 23252190Srpaulo os_free(res); 24252190Srpaulo} 25252190Srpaulo 26252190Srpaulo 27252190Srpauloconst char * event_to_string(enum wpa_event_type event) 28252190Srpaulo{ 29252190Srpaulo#define E2S(n) case EVENT_ ## n: return #n 30252190Srpaulo switch (event) { 31252190Srpaulo E2S(ASSOC); 32252190Srpaulo E2S(DISASSOC); 33252190Srpaulo E2S(MICHAEL_MIC_FAILURE); 34252190Srpaulo E2S(SCAN_RESULTS); 35252190Srpaulo E2S(ASSOCINFO); 36252190Srpaulo E2S(INTERFACE_STATUS); 37252190Srpaulo E2S(PMKID_CANDIDATE); 38252190Srpaulo E2S(STKSTART); 39252190Srpaulo E2S(TDLS); 40252190Srpaulo E2S(FT_RESPONSE); 41252190Srpaulo E2S(IBSS_RSN_START); 42252190Srpaulo E2S(AUTH); 43252190Srpaulo E2S(DEAUTH); 44252190Srpaulo E2S(ASSOC_REJECT); 45252190Srpaulo E2S(AUTH_TIMED_OUT); 46252190Srpaulo E2S(ASSOC_TIMED_OUT); 47252190Srpaulo E2S(WPS_BUTTON_PUSHED); 48252190Srpaulo E2S(TX_STATUS); 49252190Srpaulo E2S(RX_FROM_UNKNOWN); 50252190Srpaulo E2S(RX_MGMT); 51252190Srpaulo E2S(REMAIN_ON_CHANNEL); 52252190Srpaulo E2S(CANCEL_REMAIN_ON_CHANNEL); 53252190Srpaulo E2S(RX_PROBE_REQ); 54252190Srpaulo E2S(NEW_STA); 55252190Srpaulo E2S(EAPOL_RX); 56252190Srpaulo E2S(SIGNAL_CHANGE); 57252190Srpaulo E2S(INTERFACE_ENABLED); 58252190Srpaulo E2S(INTERFACE_DISABLED); 59252190Srpaulo E2S(CHANNEL_LIST_CHANGED); 60252190Srpaulo E2S(INTERFACE_UNAVAILABLE); 61252190Srpaulo E2S(BEST_CHANNEL); 62252190Srpaulo E2S(UNPROT_DEAUTH); 63252190Srpaulo E2S(UNPROT_DISASSOC); 64252190Srpaulo E2S(STATION_LOW_ACK); 65252190Srpaulo E2S(IBSS_PEER_LOST); 66252190Srpaulo E2S(DRIVER_GTK_REKEY); 67252190Srpaulo E2S(SCHED_SCAN_STOPPED); 68252190Srpaulo E2S(DRIVER_CLIENT_POLL_OK); 69252190Srpaulo E2S(EAPOL_TX_STATUS); 70252190Srpaulo E2S(CH_SWITCH); 71252190Srpaulo E2S(WNM); 72281806Srpaulo E2S(CONNECT_FAILED_REASON); 73281806Srpaulo E2S(DFS_RADAR_DETECTED); 74281806Srpaulo E2S(DFS_CAC_FINISHED); 75281806Srpaulo E2S(DFS_CAC_ABORTED); 76281806Srpaulo E2S(DFS_NOP_FINISHED); 77281806Srpaulo E2S(SURVEY); 78281806Srpaulo E2S(SCAN_STARTED); 79281806Srpaulo E2S(AVOID_FREQUENCIES); 80281806Srpaulo E2S(NEW_PEER_CANDIDATE); 81281806Srpaulo E2S(ACS_CHANNEL_SELECTED); 82281806Srpaulo E2S(DFS_CAC_STARTED); 83252190Srpaulo } 84252190Srpaulo 85252190Srpaulo return "UNKNOWN"; 86252190Srpaulo#undef E2S 87252190Srpaulo} 88281806Srpaulo 89281806Srpaulo 90281806Srpauloconst char * channel_width_to_string(enum chan_width width) 91281806Srpaulo{ 92281806Srpaulo switch (width) { 93281806Srpaulo case CHAN_WIDTH_20_NOHT: 94281806Srpaulo return "20 MHz (no HT)"; 95281806Srpaulo case CHAN_WIDTH_20: 96281806Srpaulo return "20 MHz"; 97281806Srpaulo case CHAN_WIDTH_40: 98281806Srpaulo return "40 MHz"; 99281806Srpaulo case CHAN_WIDTH_80: 100281806Srpaulo return "80 MHz"; 101281806Srpaulo case CHAN_WIDTH_80P80: 102281806Srpaulo return "80+80 MHz"; 103281806Srpaulo case CHAN_WIDTH_160: 104281806Srpaulo return "160 MHz"; 105281806Srpaulo default: 106281806Srpaulo return "unknown"; 107281806Srpaulo } 108281806Srpaulo} 109281806Srpaulo 110281806Srpaulo 111281806Srpauloint ht_supported(const struct hostapd_hw_modes *mode) 112281806Srpaulo{ 113281806Srpaulo if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) { 114281806Srpaulo /* 115281806Srpaulo * The driver did not indicate whether it supports HT. Assume 116281806Srpaulo * it does to avoid connection issues. 117281806Srpaulo */ 118281806Srpaulo return 1; 119281806Srpaulo } 120281806Srpaulo 121281806Srpaulo /* 122281806Srpaulo * IEEE Std 802.11n-2009 20.1.1: 123281806Srpaulo * An HT non-AP STA shall support all EQM rates for one spatial stream. 124281806Srpaulo */ 125281806Srpaulo return mode->mcs_set[0] == 0xff; 126281806Srpaulo} 127281806Srpaulo 128281806Srpaulo 129281806Srpauloint vht_supported(const struct hostapd_hw_modes *mode) 130281806Srpaulo{ 131281806Srpaulo if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { 132281806Srpaulo /* 133281806Srpaulo * The driver did not indicate whether it supports VHT. Assume 134281806Srpaulo * it does to avoid connection issues. 135281806Srpaulo */ 136281806Srpaulo return 1; 137281806Srpaulo } 138281806Srpaulo 139281806Srpaulo /* 140281806Srpaulo * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. 141281806Srpaulo * TODO: Verify if this complies with the standard 142281806Srpaulo */ 143281806Srpaulo return (mode->vht_mcs_set[0] & 0x3) != 3; 144281806Srpaulo} 145281806Srpaulo 146281806Srpaulo 147281806Srpaulostatic int wpa_check_wowlan_trigger(const char *start, const char *trigger, 148281806Srpaulo int capa_trigger, u8 *param_trigger) 149281806Srpaulo{ 150281806Srpaulo if (os_strcmp(start, trigger) != 0) 151281806Srpaulo return 0; 152281806Srpaulo if (!capa_trigger) 153281806Srpaulo return 0; 154281806Srpaulo 155281806Srpaulo *param_trigger = 1; 156281806Srpaulo return 1; 157281806Srpaulo} 158281806Srpaulo 159281806Srpaulo 160281806Srpaulostruct wowlan_triggers * 161281806Srpaulowpa_get_wowlan_triggers(const char *wowlan_triggers, 162281806Srpaulo const struct wpa_driver_capa *capa) 163281806Srpaulo{ 164281806Srpaulo struct wowlan_triggers *triggers; 165281806Srpaulo char *start, *end, *buf; 166281806Srpaulo int last; 167281806Srpaulo 168281806Srpaulo if (!wowlan_triggers) 169281806Srpaulo return NULL; 170281806Srpaulo 171281806Srpaulo buf = os_strdup(wowlan_triggers); 172281806Srpaulo if (buf == NULL) 173281806Srpaulo return NULL; 174281806Srpaulo 175281806Srpaulo triggers = os_zalloc(sizeof(*triggers)); 176281806Srpaulo if (triggers == NULL) 177281806Srpaulo goto out; 178281806Srpaulo 179281806Srpaulo#define CHECK_TRIGGER(trigger) \ 180281806Srpaulo wpa_check_wowlan_trigger(start, #trigger, \ 181281806Srpaulo capa->wowlan_triggers.trigger, \ 182281806Srpaulo &triggers->trigger) 183281806Srpaulo 184281806Srpaulo start = buf; 185281806Srpaulo while (*start != '\0') { 186281806Srpaulo while (isblank(*start)) 187281806Srpaulo start++; 188281806Srpaulo if (*start == '\0') 189281806Srpaulo break; 190281806Srpaulo end = start; 191281806Srpaulo while (!isblank(*end) && *end != '\0') 192281806Srpaulo end++; 193281806Srpaulo last = *end == '\0'; 194281806Srpaulo *end = '\0'; 195281806Srpaulo 196281806Srpaulo if (!CHECK_TRIGGER(any) && 197281806Srpaulo !CHECK_TRIGGER(disconnect) && 198281806Srpaulo !CHECK_TRIGGER(magic_pkt) && 199281806Srpaulo !CHECK_TRIGGER(gtk_rekey_failure) && 200281806Srpaulo !CHECK_TRIGGER(eap_identity_req) && 201281806Srpaulo !CHECK_TRIGGER(four_way_handshake) && 202281806Srpaulo !CHECK_TRIGGER(rfkill_release)) { 203281806Srpaulo wpa_printf(MSG_DEBUG, 204281806Srpaulo "Unknown/unsupported wowlan trigger '%s'", 205281806Srpaulo start); 206281806Srpaulo os_free(triggers); 207281806Srpaulo triggers = NULL; 208281806Srpaulo goto out; 209281806Srpaulo } 210281806Srpaulo 211281806Srpaulo if (last) 212281806Srpaulo break; 213281806Srpaulo start = end + 1; 214281806Srpaulo } 215281806Srpaulo#undef CHECK_TRIGGER 216281806Srpaulo 217281806Srpauloout: 218281806Srpaulo os_free(buf); 219281806Srpaulo return triggers; 220281806Srpaulo} 221