1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * Common driver-related functions 385732ac8SCy Schubert * Copyright (c) 2003-2017, 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(TDLS); 39f05cddf9SRui Paulo E2S(FT_RESPONSE); 40f05cddf9SRui Paulo E2S(IBSS_RSN_START); 41f05cddf9SRui Paulo E2S(AUTH); 42f05cddf9SRui Paulo E2S(DEAUTH); 43f05cddf9SRui Paulo E2S(ASSOC_REJECT); 44f05cddf9SRui Paulo E2S(AUTH_TIMED_OUT); 45f05cddf9SRui Paulo E2S(ASSOC_TIMED_OUT); 46f05cddf9SRui Paulo E2S(WPS_BUTTON_PUSHED); 47f05cddf9SRui Paulo E2S(TX_STATUS); 48f05cddf9SRui Paulo E2S(RX_FROM_UNKNOWN); 49f05cddf9SRui Paulo E2S(RX_MGMT); 50f05cddf9SRui Paulo E2S(REMAIN_ON_CHANNEL); 51f05cddf9SRui Paulo E2S(CANCEL_REMAIN_ON_CHANNEL); 52f05cddf9SRui Paulo E2S(RX_PROBE_REQ); 53f05cddf9SRui Paulo E2S(NEW_STA); 54f05cddf9SRui Paulo E2S(EAPOL_RX); 55f05cddf9SRui Paulo E2S(SIGNAL_CHANGE); 56f05cddf9SRui Paulo E2S(INTERFACE_ENABLED); 57f05cddf9SRui Paulo E2S(INTERFACE_DISABLED); 58f05cddf9SRui Paulo E2S(CHANNEL_LIST_CHANGED); 59f05cddf9SRui Paulo E2S(INTERFACE_UNAVAILABLE); 60f05cddf9SRui Paulo E2S(BEST_CHANNEL); 61f05cddf9SRui Paulo E2S(UNPROT_DEAUTH); 62f05cddf9SRui Paulo E2S(UNPROT_DISASSOC); 63f05cddf9SRui Paulo E2S(STATION_LOW_ACK); 64f05cddf9SRui Paulo E2S(IBSS_PEER_LOST); 65f05cddf9SRui Paulo E2S(DRIVER_GTK_REKEY); 66f05cddf9SRui Paulo E2S(SCHED_SCAN_STOPPED); 67f05cddf9SRui Paulo E2S(DRIVER_CLIENT_POLL_OK); 68f05cddf9SRui Paulo E2S(EAPOL_TX_STATUS); 69f05cddf9SRui Paulo E2S(CH_SWITCH); 70206b73d0SCy Schubert E2S(CH_SWITCH_STARTED); 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); 83780fb4a2SCy Schubert E2S(P2P_LO_STOP); 8485732ac8SCy Schubert E2S(BEACON_LOSS); 8585732ac8SCy Schubert E2S(DFS_PRE_CAC_EXPIRED); 8685732ac8SCy Schubert E2S(EXTERNAL_AUTH); 8785732ac8SCy Schubert E2S(PORT_AUTHORIZED); 8885732ac8SCy Schubert E2S(STATION_OPMODE_CHANGED); 8985732ac8SCy Schubert E2S(INTERFACE_MAC_CHANGED); 9085732ac8SCy Schubert E2S(WDS_STA_INTERFACE_STATUS); 91206b73d0SCy Schubert E2S(UPDATE_DH); 92c1d255d3SCy Schubert E2S(UNPROT_BEACON); 93*a90b9d01SCy Schubert E2S(TX_WAIT_EXPIRE); 94*a90b9d01SCy Schubert E2S(BSS_COLOR_COLLISION); 95*a90b9d01SCy Schubert E2S(CCA_STARTED_NOTIFY); 96*a90b9d01SCy Schubert E2S(CCA_ABORTED_NOTIFY); 97*a90b9d01SCy Schubert E2S(CCA_NOTIFY); 98*a90b9d01SCy Schubert E2S(PASN_AUTH); 99*a90b9d01SCy Schubert E2S(LINK_CH_SWITCH); 100*a90b9d01SCy Schubert E2S(LINK_CH_SWITCH_STARTED); 101*a90b9d01SCy Schubert E2S(TID_LINK_MAP); 102*a90b9d01SCy Schubert E2S(LINK_RECONFIG); 103f05cddf9SRui Paulo } 104f05cddf9SRui Paulo 105f05cddf9SRui Paulo return "UNKNOWN"; 106f05cddf9SRui Paulo #undef E2S 107f05cddf9SRui Paulo } 1085b9c547cSRui Paulo 1095b9c547cSRui Paulo 1105b9c547cSRui Paulo const char * channel_width_to_string(enum chan_width width) 1115b9c547cSRui Paulo { 1125b9c547cSRui Paulo switch (width) { 1135b9c547cSRui Paulo case CHAN_WIDTH_20_NOHT: 1145b9c547cSRui Paulo return "20 MHz (no HT)"; 1155b9c547cSRui Paulo case CHAN_WIDTH_20: 1165b9c547cSRui Paulo return "20 MHz"; 1175b9c547cSRui Paulo case CHAN_WIDTH_40: 1185b9c547cSRui Paulo return "40 MHz"; 1195b9c547cSRui Paulo case CHAN_WIDTH_80: 1205b9c547cSRui Paulo return "80 MHz"; 1215b9c547cSRui Paulo case CHAN_WIDTH_80P80: 1225b9c547cSRui Paulo return "80+80 MHz"; 1235b9c547cSRui Paulo case CHAN_WIDTH_160: 1245b9c547cSRui Paulo return "160 MHz"; 125*a90b9d01SCy Schubert case CHAN_WIDTH_320: 126*a90b9d01SCy Schubert return "320 MHz"; 1275b9c547cSRui Paulo default: 1285b9c547cSRui Paulo return "unknown"; 1295b9c547cSRui Paulo } 1305b9c547cSRui Paulo } 1315b9c547cSRui Paulo 1325b9c547cSRui Paulo 1334bc52338SCy Schubert int channel_width_to_int(enum chan_width width) 1344bc52338SCy Schubert { 1354bc52338SCy Schubert switch (width) { 1364bc52338SCy Schubert case CHAN_WIDTH_20_NOHT: 1374bc52338SCy Schubert case CHAN_WIDTH_20: 1384bc52338SCy Schubert return 20; 1394bc52338SCy Schubert case CHAN_WIDTH_40: 1404bc52338SCy Schubert return 40; 1414bc52338SCy Schubert case CHAN_WIDTH_80: 1424bc52338SCy Schubert return 80; 1434bc52338SCy Schubert case CHAN_WIDTH_80P80: 1444bc52338SCy Schubert case CHAN_WIDTH_160: 1454bc52338SCy Schubert return 160; 146*a90b9d01SCy Schubert case CHAN_WIDTH_320: 147*a90b9d01SCy Schubert return 320; 1484bc52338SCy Schubert default: 1494bc52338SCy Schubert return 0; 1504bc52338SCy Schubert } 1514bc52338SCy Schubert } 1524bc52338SCy Schubert 1534bc52338SCy Schubert 1545b9c547cSRui Paulo int ht_supported(const struct hostapd_hw_modes *mode) 1555b9c547cSRui Paulo { 1565b9c547cSRui Paulo if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) { 1575b9c547cSRui Paulo /* 1585b9c547cSRui Paulo * The driver did not indicate whether it supports HT. Assume 1595b9c547cSRui Paulo * it does to avoid connection issues. 1605b9c547cSRui Paulo */ 1615b9c547cSRui Paulo return 1; 1625b9c547cSRui Paulo } 1635b9c547cSRui Paulo 1645b9c547cSRui Paulo /* 1655b9c547cSRui Paulo * IEEE Std 802.11n-2009 20.1.1: 1665b9c547cSRui Paulo * An HT non-AP STA shall support all EQM rates for one spatial stream. 1675b9c547cSRui Paulo */ 1685b9c547cSRui Paulo return mode->mcs_set[0] == 0xff; 1695b9c547cSRui Paulo } 1705b9c547cSRui Paulo 1715b9c547cSRui Paulo 1725b9c547cSRui Paulo int vht_supported(const struct hostapd_hw_modes *mode) 1735b9c547cSRui Paulo { 1745b9c547cSRui Paulo if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { 1755b9c547cSRui Paulo /* 1765b9c547cSRui Paulo * The driver did not indicate whether it supports VHT. Assume 1775b9c547cSRui Paulo * it does to avoid connection issues. 1785b9c547cSRui Paulo */ 1795b9c547cSRui Paulo return 1; 1805b9c547cSRui Paulo } 1815b9c547cSRui Paulo 1825b9c547cSRui Paulo /* 1835b9c547cSRui Paulo * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. 1845b9c547cSRui Paulo * TODO: Verify if this complies with the standard 1855b9c547cSRui Paulo */ 1865b9c547cSRui Paulo return (mode->vht_mcs_set[0] & 0x3) != 3; 1875b9c547cSRui Paulo } 1885b9c547cSRui Paulo 1895b9c547cSRui Paulo 190*a90b9d01SCy Schubert bool he_supported(const struct hostapd_hw_modes *hw_mode, 191*a90b9d01SCy Schubert enum ieee80211_op_mode op_mode) 192*a90b9d01SCy Schubert { 193*a90b9d01SCy Schubert if (!(hw_mode->flags & HOSTAPD_MODE_FLAG_HE_INFO_KNOWN)) { 194*a90b9d01SCy Schubert /* 195*a90b9d01SCy Schubert * The driver did not indicate whether it supports HE. Assume 196*a90b9d01SCy Schubert * it does to avoid connection issues. 197*a90b9d01SCy Schubert */ 198*a90b9d01SCy Schubert return true; 199*a90b9d01SCy Schubert } 200*a90b9d01SCy Schubert 201*a90b9d01SCy Schubert return hw_mode->he_capab[op_mode].he_supported; 202*a90b9d01SCy Schubert } 203*a90b9d01SCy Schubert 204*a90b9d01SCy Schubert 2055b9c547cSRui Paulo static int wpa_check_wowlan_trigger(const char *start, const char *trigger, 2065b9c547cSRui Paulo int capa_trigger, u8 *param_trigger) 2075b9c547cSRui Paulo { 2085b9c547cSRui Paulo if (os_strcmp(start, trigger) != 0) 2095b9c547cSRui Paulo return 0; 2105b9c547cSRui Paulo if (!capa_trigger) 2115b9c547cSRui Paulo return 0; 2125b9c547cSRui Paulo 2135b9c547cSRui Paulo *param_trigger = 1; 2145b9c547cSRui Paulo return 1; 2155b9c547cSRui Paulo } 2165b9c547cSRui Paulo 2175b9c547cSRui Paulo 2185b9c547cSRui Paulo struct wowlan_triggers * 2195b9c547cSRui Paulo wpa_get_wowlan_triggers(const char *wowlan_triggers, 2205b9c547cSRui Paulo const struct wpa_driver_capa *capa) 2215b9c547cSRui Paulo { 2225b9c547cSRui Paulo struct wowlan_triggers *triggers; 2235b9c547cSRui Paulo char *start, *end, *buf; 2245b9c547cSRui Paulo int last; 2255b9c547cSRui Paulo 2265b9c547cSRui Paulo if (!wowlan_triggers) 2275b9c547cSRui Paulo return NULL; 2285b9c547cSRui Paulo 2295b9c547cSRui Paulo buf = os_strdup(wowlan_triggers); 2305b9c547cSRui Paulo if (buf == NULL) 2315b9c547cSRui Paulo return NULL; 2325b9c547cSRui Paulo 2335b9c547cSRui Paulo triggers = os_zalloc(sizeof(*triggers)); 2345b9c547cSRui Paulo if (triggers == NULL) 2355b9c547cSRui Paulo goto out; 2365b9c547cSRui Paulo 2375b9c547cSRui Paulo #define CHECK_TRIGGER(trigger) \ 2385b9c547cSRui Paulo wpa_check_wowlan_trigger(start, #trigger, \ 2395b9c547cSRui Paulo capa->wowlan_triggers.trigger, \ 2405b9c547cSRui Paulo &triggers->trigger) 2415b9c547cSRui Paulo 2425b9c547cSRui Paulo start = buf; 2435b9c547cSRui Paulo while (*start != '\0') { 244780fb4a2SCy Schubert while (isblank((unsigned char) *start)) 2455b9c547cSRui Paulo start++; 2465b9c547cSRui Paulo if (*start == '\0') 2475b9c547cSRui Paulo break; 2485b9c547cSRui Paulo end = start; 249780fb4a2SCy Schubert while (!isblank((unsigned char) *end) && *end != '\0') 2505b9c547cSRui Paulo end++; 2515b9c547cSRui Paulo last = *end == '\0'; 2525b9c547cSRui Paulo *end = '\0'; 2535b9c547cSRui Paulo 2545b9c547cSRui Paulo if (!CHECK_TRIGGER(any) && 2555b9c547cSRui Paulo !CHECK_TRIGGER(disconnect) && 2565b9c547cSRui Paulo !CHECK_TRIGGER(magic_pkt) && 2575b9c547cSRui Paulo !CHECK_TRIGGER(gtk_rekey_failure) && 2585b9c547cSRui Paulo !CHECK_TRIGGER(eap_identity_req) && 2595b9c547cSRui Paulo !CHECK_TRIGGER(four_way_handshake) && 2605b9c547cSRui Paulo !CHECK_TRIGGER(rfkill_release)) { 2615b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2625b9c547cSRui Paulo "Unknown/unsupported wowlan trigger '%s'", 2635b9c547cSRui Paulo start); 2645b9c547cSRui Paulo os_free(triggers); 2655b9c547cSRui Paulo triggers = NULL; 2665b9c547cSRui Paulo goto out; 2675b9c547cSRui Paulo } 2685b9c547cSRui Paulo 2695b9c547cSRui Paulo if (last) 2705b9c547cSRui Paulo break; 2715b9c547cSRui Paulo start = end + 1; 2725b9c547cSRui Paulo } 2735b9c547cSRui Paulo #undef CHECK_TRIGGER 2745b9c547cSRui Paulo 2755b9c547cSRui Paulo out: 2765b9c547cSRui Paulo os_free(buf); 2775b9c547cSRui Paulo return triggers; 2785b9c547cSRui Paulo } 279780fb4a2SCy Schubert 280780fb4a2SCy Schubert 281780fb4a2SCy Schubert const char * driver_flag_to_string(u64 flag) 282780fb4a2SCy Schubert { 283780fb4a2SCy Schubert #define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x 284780fb4a2SCy Schubert switch (flag) { 285780fb4a2SCy Schubert DF2S(DRIVER_IE); 286780fb4a2SCy Schubert DF2S(SET_KEYS_AFTER_ASSOC); 287780fb4a2SCy Schubert DF2S(DFS_OFFLOAD); 2884bc52338SCy Schubert DF2S(4WAY_HANDSHAKE_PSK); 2894bc52338SCy Schubert DF2S(4WAY_HANDSHAKE_8021X); 290780fb4a2SCy Schubert DF2S(WIRED); 291780fb4a2SCy Schubert DF2S(SME); 292780fb4a2SCy Schubert DF2S(AP); 293780fb4a2SCy Schubert DF2S(SET_KEYS_AFTER_ASSOC_DONE); 294780fb4a2SCy Schubert DF2S(HT_2040_COEX); 295780fb4a2SCy Schubert DF2S(P2P_CONCURRENT); 296780fb4a2SCy Schubert DF2S(P2P_DEDICATED_INTERFACE); 297780fb4a2SCy Schubert DF2S(P2P_CAPABLE); 298780fb4a2SCy Schubert DF2S(AP_TEARDOWN_SUPPORT); 299780fb4a2SCy Schubert DF2S(P2P_MGMT_AND_NON_P2P); 3004b72b91aSCy Schubert DF2S(VALID_ERROR_CODES); 301780fb4a2SCy Schubert DF2S(OFFCHANNEL_TX); 302780fb4a2SCy Schubert DF2S(EAPOL_TX_STATUS); 303780fb4a2SCy Schubert DF2S(DEAUTH_TX_STATUS); 304780fb4a2SCy Schubert DF2S(BSS_SELECTION); 305780fb4a2SCy Schubert DF2S(TDLS_SUPPORT); 306780fb4a2SCy Schubert DF2S(TDLS_EXTERNAL_SETUP); 307780fb4a2SCy Schubert DF2S(PROBE_RESP_OFFLOAD); 308780fb4a2SCy Schubert DF2S(AP_UAPSD); 309780fb4a2SCy Schubert DF2S(INACTIVITY_TIMER); 310780fb4a2SCy Schubert DF2S(AP_MLME); 311780fb4a2SCy Schubert DF2S(SAE); 312780fb4a2SCy Schubert DF2S(OBSS_SCAN); 313780fb4a2SCy Schubert DF2S(IBSS); 314780fb4a2SCy Schubert DF2S(RADAR); 315780fb4a2SCy Schubert DF2S(DEDICATED_P2P_DEVICE); 316780fb4a2SCy Schubert DF2S(QOS_MAPPING); 317780fb4a2SCy Schubert DF2S(AP_CSA); 318780fb4a2SCy Schubert DF2S(MESH); 319780fb4a2SCy Schubert DF2S(ACS_OFFLOAD); 320780fb4a2SCy Schubert DF2S(KEY_MGMT_OFFLOAD); 321780fb4a2SCy Schubert DF2S(TDLS_CHANNEL_SWITCH); 322780fb4a2SCy Schubert DF2S(HT_IBSS); 323780fb4a2SCy Schubert DF2S(VHT_IBSS); 324780fb4a2SCy Schubert DF2S(SUPPORT_HW_MODE_ANY); 325780fb4a2SCy Schubert DF2S(OFFCHANNEL_SIMULTANEOUS); 326780fb4a2SCy Schubert DF2S(FULL_AP_CLIENT_STATE); 327780fb4a2SCy Schubert DF2S(P2P_LISTEN_OFFLOAD); 32885732ac8SCy Schubert DF2S(SUPPORT_FILS); 32985732ac8SCy Schubert DF2S(BEACON_RATE_LEGACY); 33085732ac8SCy Schubert DF2S(BEACON_RATE_HT); 33185732ac8SCy Schubert DF2S(BEACON_RATE_VHT); 33285732ac8SCy Schubert DF2S(MGMT_TX_RANDOM_TA); 33385732ac8SCy Schubert DF2S(MGMT_TX_RANDOM_TA_CONNECTED); 33485732ac8SCy Schubert DF2S(SCHED_SCAN_RELATIVE_RSSI); 33585732ac8SCy Schubert DF2S(HE_CAPABILITIES); 33685732ac8SCy Schubert DF2S(FILS_SK_OFFLOAD); 33785732ac8SCy Schubert DF2S(OCE_STA); 33885732ac8SCy Schubert DF2S(OCE_AP); 33985732ac8SCy Schubert DF2S(OCE_STA_CFON); 34085732ac8SCy Schubert DF2S(MFP_OPTIONAL); 341c1d255d3SCy Schubert DF2S(SELF_MANAGED_REGULATORY); 342c1d255d3SCy Schubert DF2S(FTM_RESPONDER); 343c1d255d3SCy Schubert DF2S(CONTROL_PORT); 344c1d255d3SCy Schubert DF2S(VLAN_OFFLOAD); 345c1d255d3SCy Schubert DF2S(UPDATE_FT_IES); 346c1d255d3SCy Schubert DF2S(SAFE_PTK0_REKEYS); 347c1d255d3SCy Schubert DF2S(BEACON_PROTECTION); 348c1d255d3SCy Schubert DF2S(EXTENDED_KEY_ID); 349c1d255d3SCy Schubert } 350c1d255d3SCy Schubert return "UNKNOWN"; 351c1d255d3SCy Schubert #undef DF2S 352c1d255d3SCy Schubert } 353c1d255d3SCy Schubert 354c1d255d3SCy Schubert 355c1d255d3SCy Schubert const char * driver_flag2_to_string(u64 flag2) 356c1d255d3SCy Schubert { 357c1d255d3SCy Schubert #define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x 358c1d255d3SCy Schubert switch (flag2) { 359c1d255d3SCy Schubert DF2S(CONTROL_PORT_RX); 360c1d255d3SCy Schubert DF2S(CONTROL_PORT_TX_STATUS); 361*a90b9d01SCy Schubert DF2S(SEC_LTF_AP); 362*a90b9d01SCy Schubert DF2S(SEC_RTT_AP); 363*a90b9d01SCy Schubert DF2S(PROT_RANGE_NEG_AP); 364*a90b9d01SCy Schubert DF2S(BEACON_RATE_HE); 365*a90b9d01SCy Schubert DF2S(BEACON_PROTECTION_CLIENT); 366*a90b9d01SCy Schubert DF2S(OCV); 367*a90b9d01SCy Schubert DF2S(AP_SME); 368*a90b9d01SCy Schubert DF2S(SA_QUERY_OFFLOAD_AP); 369*a90b9d01SCy Schubert DF2S(RADAR_BACKGROUND); 370*a90b9d01SCy Schubert DF2S(SEC_LTF_STA); 371*a90b9d01SCy Schubert DF2S(SEC_RTT_STA); 372*a90b9d01SCy Schubert DF2S(PROT_RANGE_NEG_STA); 373*a90b9d01SCy Schubert DF2S(MLO); 374*a90b9d01SCy Schubert DF2S(SCAN_MIN_PREQ); 375*a90b9d01SCy Schubert DF2S(SAE_OFFLOAD_STA); 376780fb4a2SCy Schubert } 377780fb4a2SCy Schubert return "UNKNOWN"; 378780fb4a2SCy Schubert #undef DF2S 379780fb4a2SCy Schubert } 380