| /* |
| * Common driver-related functions |
| * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "includes.h" |
| #include "utils/common.h" |
| #include "driver.h" |
| |
| void wpa_scan_results_free(struct wpa_scan_results *res) |
| { |
| size_t i; |
| |
| if (res == NULL) |
| return; |
| |
| for (i = 0; i < res->num; i++) |
| os_free(res->res[i]); |
| os_free(res->res); |
| os_free(res); |
| } |
| |
| |
| const char * event_to_string(enum wpa_event_type event) |
| { |
| #define E2S(n) case EVENT_ ## n: return #n |
| switch (event) { |
| E2S(ASSOC); |
| E2S(DISASSOC); |
| E2S(MICHAEL_MIC_FAILURE); |
| E2S(SCAN_RESULTS); |
| E2S(ASSOCINFO); |
| E2S(INTERFACE_STATUS); |
| E2S(PMKID_CANDIDATE); |
| E2S(TDLS); |
| E2S(FT_RESPONSE); |
| E2S(IBSS_RSN_START); |
| E2S(AUTH); |
| E2S(DEAUTH); |
| E2S(ASSOC_REJECT); |
| E2S(AUTH_TIMED_OUT); |
| E2S(ASSOC_TIMED_OUT); |
| E2S(WPS_BUTTON_PUSHED); |
| E2S(TX_STATUS); |
| E2S(RX_FROM_UNKNOWN); |
| E2S(RX_MGMT); |
| E2S(REMAIN_ON_CHANNEL); |
| E2S(CANCEL_REMAIN_ON_CHANNEL); |
| E2S(RX_PROBE_REQ); |
| E2S(NEW_STA); |
| E2S(EAPOL_RX); |
| E2S(SIGNAL_CHANGE); |
| E2S(INTERFACE_ENABLED); |
| E2S(INTERFACE_DISABLED); |
| E2S(CHANNEL_LIST_CHANGED); |
| E2S(INTERFACE_UNAVAILABLE); |
| E2S(BEST_CHANNEL); |
| E2S(UNPROT_DEAUTH); |
| E2S(UNPROT_DISASSOC); |
| E2S(STATION_LOW_ACK); |
| E2S(IBSS_PEER_LOST); |
| E2S(DRIVER_GTK_REKEY); |
| E2S(SCHED_SCAN_STOPPED); |
| E2S(DRIVER_CLIENT_POLL_OK); |
| E2S(EAPOL_TX_STATUS); |
| E2S(CH_SWITCH); |
| E2S(CH_SWITCH_STARTED); |
| E2S(WNM); |
| E2S(CONNECT_FAILED_REASON); |
| E2S(DFS_RADAR_DETECTED); |
| E2S(DFS_CAC_FINISHED); |
| E2S(DFS_CAC_ABORTED); |
| E2S(DFS_NOP_FINISHED); |
| E2S(SURVEY); |
| E2S(SCAN_STARTED); |
| E2S(AVOID_FREQUENCIES); |
| E2S(NEW_PEER_CANDIDATE); |
| E2S(ACS_CHANNEL_SELECTED); |
| E2S(DFS_CAC_STARTED); |
| E2S(P2P_LO_STOP); |
| E2S(BEACON_LOSS); |
| E2S(DFS_PRE_CAC_EXPIRED); |
| E2S(EXTERNAL_AUTH); |
| E2S(PORT_AUTHORIZED); |
| E2S(STATION_OPMODE_CHANGED); |
| E2S(INTERFACE_MAC_CHANGED); |
| E2S(WDS_STA_INTERFACE_STATUS); |
| E2S(UPDATE_DH); |
| E2S(UNPROT_BEACON); |
| E2S(TX_WAIT_EXPIRE); |
| E2S(BSS_COLOR_COLLISION); |
| E2S(CCA_STARTED_NOTIFY); |
| E2S(CCA_ABORTED_NOTIFY); |
| E2S(CCA_NOTIFY); |
| E2S(PASN_AUTH); |
| E2S(LINK_CH_SWITCH); |
| E2S(LINK_CH_SWITCH_STARTED); |
| E2S(TID_LINK_MAP); |
| E2S(LINK_RECONFIG); |
| } |
| |
| return "UNKNOWN"; |
| #undef E2S |
| } |
| |
| |
| const char * channel_width_to_string(enum chan_width width) |
| { |
| switch (width) { |
| case CHAN_WIDTH_20_NOHT: |
| return "20 MHz (no HT)"; |
| case CHAN_WIDTH_20: |
| return "20 MHz"; |
| case CHAN_WIDTH_40: |
| return "40 MHz"; |
| case CHAN_WIDTH_80: |
| return "80 MHz"; |
| case CHAN_WIDTH_80P80: |
| return "80+80 MHz"; |
| case CHAN_WIDTH_160: |
| return "160 MHz"; |
| case CHAN_WIDTH_320: |
| return "320 MHz"; |
| default: |
| return "unknown"; |
| } |
| } |
| |
| |
| int channel_width_to_int(enum chan_width width) |
| { |
| switch (width) { |
| case CHAN_WIDTH_20_NOHT: |
| case CHAN_WIDTH_20: |
| return 20; |
| case CHAN_WIDTH_40: |
| return 40; |
| case CHAN_WIDTH_80: |
| return 80; |
| case CHAN_WIDTH_80P80: |
| case CHAN_WIDTH_160: |
| return 160; |
| case CHAN_WIDTH_320: |
| return 320; |
| default: |
| return 0; |
| } |
| } |
| |
| |
| int ht_supported(const struct hostapd_hw_modes *mode) |
| { |
| if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) { |
| /* |
| * The driver did not indicate whether it supports HT. Assume |
| * it does to avoid connection issues. |
| */ |
| return 1; |
| } |
| |
| /* |
| * IEEE Std 802.11n-2009 20.1.1: |
| * An HT non-AP STA shall support all EQM rates for one spatial stream. |
| */ |
| return mode->mcs_set[0] == 0xff; |
| } |
| |
| |
| int vht_supported(const struct hostapd_hw_modes *mode) |
| { |
| if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { |
| /* |
| * The driver did not indicate whether it supports VHT. Assume |
| * it does to avoid connection issues. |
| */ |
| return 1; |
| } |
| |
| /* |
| * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. |
| * TODO: Verify if this complies with the standard |
| */ |
| return (mode->vht_mcs_set[0] & 0x3) != 3; |
| } |
| |
| |
| bool he_supported(const struct hostapd_hw_modes *hw_mode, |
| enum ieee80211_op_mode op_mode) |
| { |
| if (!(hw_mode->flags & HOSTAPD_MODE_FLAG_HE_INFO_KNOWN)) { |
| /* |
| * The driver did not indicate whether it supports HE. Assume |
| * it does to avoid connection issues. |
| */ |
| return true; |
| } |
| |
| return hw_mode->he_capab[op_mode].he_supported; |
| } |
| |
| |
| static int wpa_check_wowlan_trigger(const char *start, const char *trigger, |
| int capa_trigger, u8 *param_trigger) |
| { |
| if (os_strcmp(start, trigger) != 0) |
| return 0; |
| if (!capa_trigger) |
| return 0; |
| |
| *param_trigger = 1; |
| return 1; |
| } |
| |
| |
| struct wowlan_triggers * |
| wpa_get_wowlan_triggers(const char *wowlan_triggers, |
| const struct wpa_driver_capa *capa) |
| { |
| struct wowlan_triggers *triggers; |
| char *start, *end, *buf; |
| int last; |
| |
| if (!wowlan_triggers) |
| return NULL; |
| |
| buf = os_strdup(wowlan_triggers); |
| if (buf == NULL) |
| return NULL; |
| |
| triggers = os_zalloc(sizeof(*triggers)); |
| if (triggers == NULL) |
| goto out; |
| |
| #define CHECK_TRIGGER(trigger) \ |
| wpa_check_wowlan_trigger(start, #trigger, \ |
| capa->wowlan_triggers.trigger, \ |
| &triggers->trigger) |
| |
| start = buf; |
| while (*start != '\0') { |
| while (isblank((unsigned char) *start)) |
| start++; |
| if (*start == '\0') |
| break; |
| end = start; |
| while (!isblank((unsigned char) *end) && *end != '\0') |
| end++; |
| last = *end == '\0'; |
| *end = '\0'; |
| |
| if (!CHECK_TRIGGER(any) && |
| !CHECK_TRIGGER(disconnect) && |
| !CHECK_TRIGGER(magic_pkt) && |
| !CHECK_TRIGGER(gtk_rekey_failure) && |
| !CHECK_TRIGGER(eap_identity_req) && |
| !CHECK_TRIGGER(four_way_handshake) && |
| !CHECK_TRIGGER(rfkill_release)) { |
| wpa_printf(MSG_DEBUG, |
| "Unknown/unsupported wowlan trigger '%s'", |
| start); |
| os_free(triggers); |
| triggers = NULL; |
| goto out; |
| } |
| |
| if (last) |
| break; |
| start = end + 1; |
| } |
| #undef CHECK_TRIGGER |
| |
| out: |
| os_free(buf); |
| return triggers; |
| } |
| |
| |
| const char * driver_flag_to_string(u64 flag) |
| { |
| #define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x |
| switch (flag) { |
| DF2S(DRIVER_IE); |
| DF2S(SET_KEYS_AFTER_ASSOC); |
| DF2S(DFS_OFFLOAD); |
| DF2S(4WAY_HANDSHAKE_PSK); |
| DF2S(4WAY_HANDSHAKE_8021X); |
| DF2S(WIRED); |
| DF2S(SME); |
| DF2S(AP); |
| DF2S(SET_KEYS_AFTER_ASSOC_DONE); |
| DF2S(HT_2040_COEX); |
| DF2S(P2P_CONCURRENT); |
| DF2S(P2P_DEDICATED_INTERFACE); |
| DF2S(P2P_CAPABLE); |
| DF2S(AP_TEARDOWN_SUPPORT); |
| DF2S(P2P_MGMT_AND_NON_P2P); |
| DF2S(VALID_ERROR_CODES); |
| DF2S(OFFCHANNEL_TX); |
| DF2S(EAPOL_TX_STATUS); |
| DF2S(DEAUTH_TX_STATUS); |
| DF2S(BSS_SELECTION); |
| DF2S(TDLS_SUPPORT); |
| DF2S(TDLS_EXTERNAL_SETUP); |
| DF2S(PROBE_RESP_OFFLOAD); |
| DF2S(AP_UAPSD); |
| DF2S(INACTIVITY_TIMER); |
| DF2S(AP_MLME); |
| DF2S(SAE); |
| DF2S(OBSS_SCAN); |
| DF2S(IBSS); |
| DF2S(RADAR); |
| DF2S(DEDICATED_P2P_DEVICE); |
| DF2S(QOS_MAPPING); |
| DF2S(AP_CSA); |
| DF2S(MESH); |
| DF2S(ACS_OFFLOAD); |
| DF2S(KEY_MGMT_OFFLOAD); |
| DF2S(TDLS_CHANNEL_SWITCH); |
| DF2S(HT_IBSS); |
| DF2S(VHT_IBSS); |
| DF2S(SUPPORT_HW_MODE_ANY); |
| DF2S(OFFCHANNEL_SIMULTANEOUS); |
| DF2S(FULL_AP_CLIENT_STATE); |
| DF2S(P2P_LISTEN_OFFLOAD); |
| DF2S(SUPPORT_FILS); |
| DF2S(BEACON_RATE_LEGACY); |
| DF2S(BEACON_RATE_HT); |
| DF2S(BEACON_RATE_VHT); |
| DF2S(MGMT_TX_RANDOM_TA); |
| DF2S(MGMT_TX_RANDOM_TA_CONNECTED); |
| DF2S(SCHED_SCAN_RELATIVE_RSSI); |
| DF2S(HE_CAPABILITIES); |
| DF2S(FILS_SK_OFFLOAD); |
| DF2S(OCE_STA); |
| DF2S(OCE_AP); |
| DF2S(OCE_STA_CFON); |
| DF2S(MFP_OPTIONAL); |
| DF2S(SELF_MANAGED_REGULATORY); |
| DF2S(FTM_RESPONDER); |
| DF2S(CONTROL_PORT); |
| DF2S(VLAN_OFFLOAD); |
| DF2S(UPDATE_FT_IES); |
| DF2S(SAFE_PTK0_REKEYS); |
| DF2S(BEACON_PROTECTION); |
| DF2S(EXTENDED_KEY_ID); |
| } |
| return "UNKNOWN"; |
| #undef DF2S |
| } |
| |
| |
| const char * driver_flag2_to_string(u64 flag2) |
| { |
| #define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x |
| switch (flag2) { |
| DF2S(CONTROL_PORT_RX); |
| DF2S(CONTROL_PORT_TX_STATUS); |
| } |
| return "UNKNOWN"; |
| #undef DF2S |
| } |