diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2015-04-21 01:45:11 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2015-04-21 01:45:11 +0000 |
commit | 842f4520d0888b29092df5d0d02c98cf458d22f7 (patch) | |
tree | 2cc3a30a65916dde45972adbf0d20263dbd38514 /contrib/wpa/hostapd | |
parent | 2b5cce437990f63ca2ad7e2ec6f65e2d91d98f43 (diff) | |
parent | 30dc5ae44f65d272ea1e32635149befdbf9833cf (diff) | |
download | FreeBSD-src-842f4520d0888b29092df5d0d02c98cf458d22f7.zip FreeBSD-src-842f4520d0888b29092df5d0d02c98cf458d22f7.tar.gz |
Merge wpa_supplicant/hostapd 2.4.
Major changes are: SAE, Suite B, RFC 7268, EAP-PKE, ACS, and tons of
bug fixes.
Relnotes: yes
Diffstat (limited to 'contrib/wpa/hostapd')
-rw-r--r-- | contrib/wpa/hostapd/ChangeLog | 186 | ||||
-rw-r--r-- | contrib/wpa/hostapd/README | 8 | ||||
-rw-r--r-- | contrib/wpa/hostapd/README-WPS | 24 | ||||
-rw-r--r-- | contrib/wpa/hostapd/config_file.c | 3202 | ||||
-rw-r--r-- | contrib/wpa/hostapd/ctrl_iface.c | 1518 | ||||
-rw-r--r-- | contrib/wpa/hostapd/defconfig | 79 | ||||
-rw-r--r-- | contrib/wpa/hostapd/dump_state.c | 180 | ||||
-rw-r--r-- | contrib/wpa/hostapd/dump_state.h | 14 | ||||
-rw-r--r-- | contrib/wpa/hostapd/eap_register.c | 12 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hapd_module_tests.c | 17 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hlr_auc_gw.c | 250 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hostapd.8 | 2 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hostapd.conf | 289 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hostapd.eap_user | 6 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hostapd.eap_user_sqlite | 9 | ||||
-rw-r--r-- | contrib/wpa/hostapd/hostapd_cli.c | 332 | ||||
-rw-r--r-- | contrib/wpa/hostapd/main.c | 311 | ||||
-rwxr-xr-x | contrib/wpa/hostapd/wps-ap-nfc.py | 342 |
18 files changed, 4714 insertions, 2067 deletions
diff --git a/contrib/wpa/hostapd/ChangeLog b/contrib/wpa/hostapd/ChangeLog index 6824e5a..e6f8c6a 100644 --- a/contrib/wpa/hostapd/ChangeLog +++ b/contrib/wpa/hostapd/ChangeLog @@ -1,5 +1,191 @@ ChangeLog for hostapd +2015-03-15 - v2.4 + * allow OpenSSL cipher configuration to be set for internal EAP server + (openssl_ciphers parameter) + * fixed number of small issues based on hwsim test case failures and + static analyzer reports + * fixed Accounting-Request to not include duplicated Acct-Session-Id + * add support for Acct-Multi-Session-Id in RADIUS Accounting messages + * add support for PMKSA caching with SAE + * add support for generating BSS Load element (bss_load_update_period) + * fixed channel switch from VHT to HT + * add INTERFACE-ENABLED and INTERFACE-DISABLED ctrl_iface events + * add support for learning STA IPv4/IPv6 addresses and configuring + ProxyARP support + * dropped support for the madwifi driver interface + * add support for Suite B (128-bit and 192-bit level) key management and + cipher suites + * fixed a regression with driver=wired + * extend EAPOL-Key msg 1/4 retry workaround for changing SNonce + * add BSS_TM_REQ ctrl_iface command to send BSS Transition Management + Request frames and BSS-TM-RESP event to indicate response to such + frame + * add support for EAP Re-Authentication Protocol (ERP) + * fixed AP IE in EAPOL-Key 3/4 when both WPA and FT was enabled + * fixed a regression in HT 20/40 coex Action frame parsing + * set stdout to be line-buffered + * add support for vendor specific VHT extension to enable 256 QAM rates + (VHT-MCS 8 and 9) on 2.4 GHz band + * RADIUS DAS: + - extend Disconnect-Request processing to allow matching of multiple + sessions + - support Acct-Multi-Session-Id as an identifier + - allow PMKSA cache entry to be removed without association + * expire hostapd STA entry if kernel does not have a matching entry + * allow chanlist to be used to specify a subset of channels for ACS + * improve ACS behavior on 2.4 GHz band and allow channel bias to be + configured with acs_chan_bias parameter + * do not reply to a Probe Request frame that includes DSS Parameter Set + element in which the channel does not match the current operating + channel + * add UPDATE_BEACON ctrl_iface command; this can be used to force Beacon + frame contents to be updated and to start beaconing on an interface + that used start_disabled=1 + * fixed some RADIUS server failover cases + +2014-10-09 - v2.3 + * fixed number of minor issues identified in static analyzer warnings + * fixed DFS and channel switch operation for multi-BSS cases + * started to use constant time comparison for various password and hash + values to reduce possibility of any externally measurable timing + differences + * extended explicit clearing of freed memory and expired keys to avoid + keeping private data in memory longer than necessary + * added support for number of new RADIUS attributes from RFC 7268 + (Mobility-Domain-Id, WLAN-HESSID, WLAN-Pairwise-Cipher, + WLAN-Group-Cipher, WLAN-AKM-Suite, WLAN-Group-Mgmt-Pairwise-Cipher) + * fixed GET_CONFIG wpa_pairwise_cipher value + * added code to clear bridge FDB entry on station disconnection + * fixed PMKSA cache timeout from Session-Timeout for WPA/WPA2 cases + * fixed OKC PMKSA cache entry fetch to avoid a possible infinite loop + in case the first entry does not match + * fixed hostapd_cli action script execution to use more robust mechanism + (CVE-2014-3686) + +2014-06-04 - v2.2 + * fixed SAE confirm-before-commit validation to avoid a potential + segmentation fault in an unexpected message sequence that could be + triggered remotely + * extended VHT support + - Operating Mode Notification + - Power Constraint element (local_pwr_constraint) + - Spectrum management capability (spectrum_mgmt_required=1) + - fix VHT80 segment picking in ACS + - fix vht_capab 'Maximum A-MPDU Length Exponent' handling + - fix VHT20 + * fixed HT40 co-ex scan for some pri/sec channel switches + * extended HT40 co-ex support to allow dynamic channel width changes + during the lifetime of the BSS + * fixed HT40 co-ex support to check for overlapping 20 MHz BSS + * fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding; + this fixes password with include UTF-8 characters that use + three-byte encoding EAP methods that use NtPasswordHash + * reverted TLS certificate validation step change in v2.1 that rejected + any AAA server certificate with id-kp-clientAuth even if + id-kp-serverAuth EKU was included + * fixed STA validation step for WPS ER commands to prevent a potential + crash if an ER sends an unexpected PutWLANResponse to a station that + is disassociated, but not fully removed + * enforce full EAP authentication after RADIUS Disconnect-Request by + removing the PMKSA cache entry + * added support for NAS-IP-Address, NAS-identifier, and NAS-IPv6-Address + in RADIUS Disconnect-Request + * added mechanism for removing addresses for MAC ACLs by prefixing an + entry with "-" + * Interworking/Hotspot 2.0 enhancements + - support Hotspot 2.0 Release 2 + * OSEN network for online signup connection + * subscription remediation (based on RADIUS server request or + control interface HS20_WNM_NOTIF for testing purposes) + * Hotspot 2.0 release number indication in WFA RADIUS VSA + * deauthentication request (based on RADIUS server request or + control interface WNM_DEAUTH_REQ for testing purposes) + * Session Info URL RADIUS AVP to trigger ESS Disassociation Imminent + * hs20_icon config parameter to configure icon files for OSU + * osu_* config parameters for OSU Providers list + - do not use Interworking filtering rules on Probe Request if + Interworking is disabled to avoid interop issues + * added/fixed nl80211 functionality + - AP interface teardown optimization + - support vendor specific driver command + (VENDOR <vendor id> <sub command id> [<hex formatted data>]) + * fixed PMF protection of Deauthentication frame when this is triggered + by session timeout + * internal TLS implementation enhancements/fixes + - add SHA256-based cipher suites + - add DHE-RSA cipher suites + - fix X.509 validation of PKCS#1 signature to check for extra data + * RADIUS server functionality + - add minimal RADIUS accounting server support (hostapd-as-server); + this is mainly to enable testing coverage with hwsim scripts + - allow authentication log to be written into SQLite databse + - added option for TLS protocol testing of an EAP peer by simulating + various misbehaviors/known attacks + - MAC ACL support for testing purposes + * fixed PTK derivation for CCMP-256 and GCMP-256 + * extended WPS per-station PSK to support ER case + * added option to configure the management group cipher + (group_mgmt_cipher=AES-128-CMAC (default), BIP-GMAC-128, BIP-GMAC-256, + BIP-CMAC-256) + * fixed AP mode default TXOP Limit values for AC_VI and AC_VO (these + were rounded incorrectly) + * added support for postponing FT response in case PMK-R1 needs to be + pulled from R0KH + * added option to advertise 40 MHz intolerant HT capability with + ht_capab=[40-INTOLERANT] + * remove WPS 1.0 only support, i.e., WSC 2.0 support is now enabled + whenever CONFIG_WPS=y is set + * EAP-pwd fixes + - fix possible segmentation fault on EAP method deinit if an invalid + group is negotiated + * fixed RADIUS client retransmit/failover behavior + - there was a potential ctash due to freed memory being accessed + - failover to a backup server mechanism did not work properly + * fixed a possible crash on double DISABLE command when multiple BSSes + are enabled + * fixed a memory leak in SAE random number generation + * fixed GTK rekeying when the station uses FT protocol + * fixed off-by-one bounds checking in printf_encode() + - this could result in deinial of service in some EAP server cases + * various bug fixes + +2014-02-04 - v2.1 + * added support for simultaneous authentication of equals (SAE) for + stronger password-based authentication with WPA2-Personal + * added nl80211 functionality + - VHT configuration for nl80211 + - support split wiphy dump + - driver-based MAC ACL + - QoS Mapping configuration + * added fully automated regression testing with mac80211_hwsim + * allow ctrl_iface group to be specified on command line (-G<group>) + * allow single hostapd process to control independent WPS interfaces + (wps_independent=1) instead of synchronized operations through all + configured interfaces within a process + * avoid processing received management frames multiple times when using + nl80211 with multiple BSSes + * added support for DFS (processing radar detection events, CAC, channel + re-selection) + * added EAP-EKE server + * added automatic channel selection (ACS) + * added option for using per-BSS (vif) configuration files with + -b<phyname>:<config file name> + * extended global control interface ADD/REMOVE commands to allow BSSes + of a radio to be removed individually without having to add/remove all + other BSSes of the radio at the same time + * added support for sending debug info to Linux tracing (-T on command + line) + * replace dump_file functionality with same information being available + through the hostapd control interface + * added support for using Protected Dual of Public Action frames for + GAS/ANQP exchanges when PMF is enabled + * added support for WPS+NFC updates + - improved protocol + - option to fetch and report alternative carrier records for external + NFC operations + * various bug fixes + 2013-01-12 - v2.0 * added AP-STA-DISCONNECTED ctrl_iface event * improved debug logging (human readable event names, interface name diff --git a/contrib/wpa/hostapd/README b/contrib/wpa/hostapd/README index 34dad30..366b199 100644 --- a/contrib/wpa/hostapd/README +++ b/contrib/wpa/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with @@ -74,12 +74,6 @@ Current hardware/software requirements: Please note that station firmware version needs to be 1.7.0 or newer to work in WPA mode. - madwifi driver for cards based on Atheros chip set (ar521x) - (http://sourceforge.net/projects/madwifi/) - Please note that you will need to add the correct path for - madwifi driver root directory in .config (see defconfig file for - an example: CFLAGS += -I<path>) - mac80211-based drivers that support AP mode (with driver=nl80211). This includes drivers for Atheros (ath9k) and Broadcom (b43) chipsets. diff --git a/contrib/wpa/hostapd/README-WPS b/contrib/wpa/hostapd/README-WPS index 87a6f91..d5f713a 100644 --- a/contrib/wpa/hostapd/README-WPS +++ b/contrib/wpa/hostapd/README-WPS @@ -58,12 +58,10 @@ hostapd configuration WPS is an optional component that needs to be enabled in hostapd build configuration (.config). Here is an example configuration that -includes WPS support and uses madwifi driver interface: +includes WPS support and uses nl80211 driver interface: -CONFIG_DRIVER_MADWIFI=y -CFLAGS += -I/usr/src/madwifi-0.9.3 +CONFIG_DRIVER_NL80211=y CONFIG_WPS=y -CONFIG_WPS2=y CONFIG_WPS_UPNP=y Following parameter can be used to enable support for NFC config method: @@ -75,8 +73,8 @@ Following section shows an example runtime configuration (hostapd.conf) that enables WPS: # Configure the driver and network interface -driver=madwifi -interface=ath0 +driver=nl80211 +interface=wlan0 # WPA2-Personal configuration for the AP ssid=wps-test @@ -338,3 +336,17 @@ If the NFC tag contains a password token, the token is added to the internal Registrar. This allows station Enrollee from which the password token was received to run through WPS protocol to provision the credential. + +"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the +contents of a Handover Select Message for connection handover when this +does not depend on the contents of the Handover Request Message. The +first argument selects the format of the output data and the second +argument selects which type of connection handover is requested (WPS = +Wi-Fi handover as specified in WSC 2.0). + +"nfc_report_handover <INIT/RESP> WPS <carrier from handover request> +<carrier from handover select>" is used to report completed NFC +connection handover. The first parameter indicates whether the local +device initiated or responded to the connection handover and the carrier +records are the selected carrier from the handover request and select +messages as a hexdump. diff --git a/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c index 2ba7cc1..53143f7 100644 --- a/contrib/wpa/hostapd/config_file.c +++ b/contrib/wpa/hostapd/config_file.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration file parser - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -22,7 +22,12 @@ #include "config_file.h" -extern struct wpa_driver_ops *wpa_drivers[]; +#ifndef CONFIG_NO_RADIUS +#ifdef EAP_SERVER +static struct hostapd_radius_attr * +hostapd_parse_radius_attr(const char *value); +#endif /* EAP_SERVER */ +#endif /* CONFIG_NO_RADIUS */ #ifndef CONFIG_NO_VLAN @@ -83,7 +88,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, return -1; } - vlan = os_malloc(sizeof(*vlan)); + vlan = os_zalloc(sizeof(*vlan)); if (vlan == NULL) { wpa_printf(MSG_ERROR, "Out of memory while reading " "VLAN interfaces from '%s'", fname); @@ -91,14 +96,10 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, return -1; } - os_memset(vlan, 0, sizeof(*vlan)); vlan->vlan_id = vlan_id; os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname)); - if (bss->vlan_tail) - bss->vlan_tail->next = vlan; - else - bss->vlan = vlan; - bss->vlan_tail = vlan; + vlan->next = bss->vlan; + bss->vlan = vlan; } fclose(f); @@ -136,6 +137,8 @@ static int hostapd_config_read_maclist(const char *fname, } while (fgets(buf, sizeof(buf), f)) { + int i, rem = 0; + line++; if (buf[0] == '#') @@ -150,14 +153,32 @@ static int hostapd_config_read_maclist(const char *fname, } if (buf[0] == '\0') continue; + pos = buf; + if (buf[0] == '-') { + rem = 1; + pos++; + } - if (hwaddr_aton(buf, addr)) { + if (hwaddr_aton(pos, addr)) { wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at " - "line %d in '%s'", buf, line, fname); + "line %d in '%s'", pos, line, fname); fclose(f); return -1; } + if (rem) { + i = 0; + while (i < *num) { + if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == + 0) { + os_remove_in_array(*acl, *num, + sizeof(**acl), i); + (*num)--; + } else + i++; + } + continue; + } vlan_id = 0; pos = buf; while (*pos != '\0' && *pos != ' ' && *pos != '\t') @@ -195,7 +216,7 @@ static int hostapd_config_read_eap_user(const char *fname, FILE *f; char buf[512], *pos, *start, *pos2; int line = 0, ret = 0, num_methods; - struct hostapd_eap_user *user, *tail = NULL; + struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL; if (!fname) return 0; @@ -229,6 +250,28 @@ static int hostapd_config_read_eap_user(const char *fname, if (buf[0] == '\0') continue; +#ifndef CONFIG_NO_RADIUS + if (user && os_strncmp(buf, "radius_accept_attr=", 19) == 0) { + struct hostapd_radius_attr *attr, *a; + attr = hostapd_parse_radius_attr(buf + 19); + if (attr == NULL) { + wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s", + buf + 19); + user = NULL; /* already in the BSS list */ + goto failed; + } + if (user->accept_attr == NULL) { + user->accept_attr = attr; + } else { + a = user->accept_attr; + while (a->next) + a = a->next; + a->next = attr; + } + continue; + } +#endif /* CONFIG_NO_RADIUS */ + user = NULL; if (buf[0] != '"' && buf[0] != '*') { @@ -323,6 +366,10 @@ static int hostapd_config_read_eap_user(const char *fname, EAP_TTLS_AUTH_MSCHAPV2; goto skip_eap; } + if (os_strcmp(start, "MACACL") == 0) { + user->macacl = 1; + goto skip_eap; + } wpa_printf(MSG_ERROR, "Unsupported EAP type " "'%s' on line %d in '%s'", start, line, fname); @@ -337,7 +384,7 @@ static int hostapd_config_read_eap_user(const char *fname, break; start = pos3; } - if (num_methods == 0 && user->ttls_auth == 0) { + if (num_methods == 0 && user->ttls_auth == 0 && !user->macacl) { wpa_printf(MSG_ERROR, "No EAP types configured on " "line %d in '%s'", line, fname); goto failed; @@ -447,7 +494,7 @@ static int hostapd_config_read_eap_user(const char *fname, done: if (tail == NULL) { - tail = conf->eap_user = user; + tail = new_user = user; } else { tail->next = user; tail = user; @@ -455,17 +502,26 @@ static int hostapd_config_read_eap_user(const char *fname, continue; failed: - if (user) { - os_free(user->password); - os_free(user->identity); - os_free(user); - } + if (user) + hostapd_config_free_eap_user(user); ret = -1; break; } fclose(f); + if (ret == 0) { + user = conf->eap_user; + while (user) { + struct hostapd_eap_user *prev; + + prev = user; + user = user->next; + hostapd_config_free_eap_user(prev); + } + conf->eap_user = new_user; + } + return ret; } #endif /* EAP_SERVER */ @@ -636,6 +692,14 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) else if (os_strcmp(start, "FT-SAE") == 0) val |= WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ +#ifdef CONFIG_SUITEB + else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B; +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; +#endif /* CONFIG_SUITEB192 */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); @@ -661,49 +725,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) static int hostapd_config_parse_cipher(int line, const char *value) { - int val = 0, last; - char *start, *end, *buf; - - buf = os_strdup(value); - if (buf == NULL) + int val = wpa_parse_cipher(value); + if (val < 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", + line, value); return -1; - start = buf; - - while (*start != '\0') { - while (*start == ' ' || *start == '\t') - start++; - if (*start == '\0') - break; - end = start; - while (*end != ' ' && *end != '\t' && *end != '\0') - end++; - last = *end == '\0'; - *end = '\0'; - if (os_strcmp(start, "CCMP") == 0) - val |= WPA_CIPHER_CCMP; - else if (os_strcmp(start, "GCMP") == 0) - val |= WPA_CIPHER_GCMP; - else if (os_strcmp(start, "TKIP") == 0) - val |= WPA_CIPHER_TKIP; - else if (os_strcmp(start, "WEP104") == 0) - val |= WPA_CIPHER_WEP104; - else if (os_strcmp(start, "WEP40") == 0) - val |= WPA_CIPHER_WEP40; - else if (os_strcmp(start, "NONE") == 0) - val |= WPA_CIPHER_NONE; - else { - wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", - line, start); - os_free(buf); - return -1; - } - - if (last) - break; - start = end + 1; } - os_free(buf); - if (val == 0) { wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", line); @@ -748,14 +775,14 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, } -static int hostapd_parse_rates(int **rate_list, char *val) +static int hostapd_parse_intlist(int **int_list, char *val) { int *list; int count; char *pos, *end; - os_free(*rate_list); - *rate_list = NULL; + os_free(*int_list); + *int_list = NULL; pos = val; count = 0; @@ -782,37 +809,39 @@ static int hostapd_parse_rates(int **rate_list, char *val) } list[count] = -1; - *rate_list = list; + *int_list = list; return 0; } static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname) { - struct hostapd_bss_config *bss; + struct hostapd_bss_config **all, *bss; if (*ifname == '\0') return -1; - bss = os_realloc_array(conf->bss, conf->num_bss + 1, - sizeof(struct hostapd_bss_config)); - if (bss == NULL) { + all = os_realloc_array(conf->bss, conf->num_bss + 1, + sizeof(struct hostapd_bss_config *)); + if (all == NULL) { wpa_printf(MSG_ERROR, "Failed to allocate memory for " "multi-BSS entry"); return -1; } - conf->bss = bss; + conf->bss = all; - bss = &(conf->bss[conf->num_bss]); - os_memset(bss, 0, sizeof(*bss)); + bss = os_zalloc(sizeof(*bss)); + if (bss == NULL) + return -1; bss->radius = os_zalloc(sizeof(*bss->radius)); if (bss->radius == NULL) { wpa_printf(MSG_ERROR, "Failed to allocate memory for " "multi-BSS RADIUS data"); + os_free(bss); return -1; } - conf->num_bss++; + conf->bss[conf->num_bss++] = bss; conf->last_bss = bss; hostapd_config_defaults_bss(bss); @@ -1060,8 +1089,8 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf, conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE; if (os_strstr(capab, "[DSSS_CCK-40]")) conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ; - if (os_strstr(capab, "[PSMP]")) - conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP; + if (os_strstr(capab, "[40-INTOLERANT]")) + conf->ht_capab |= HT_CAP_INFO_40MHZ_INTOLERANT; if (os_strstr(capab, "[LSIG-TXOP-PROT]")) conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT; @@ -1082,8 +1111,6 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf, conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; if (os_strstr(capab, "[VHT160-80PLUS80]")) conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - if (os_strstr(capab, "[VHT160-80PLUS80]")) - conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; if (os_strstr(capab, "[RXLDPC]")) conf->vht_capab |= VHT_CAP_RXLDPC; if (os_strstr(capab, "[SHORT-GI-80]")) @@ -1101,15 +1128,15 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf, if (os_strstr(capab, "[RX-STBC-1234]")) conf->vht_capab |= VHT_CAP_RXSTBC_4; if (os_strstr(capab, "[SU-BEAMFORMER]")) - conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE; + conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE; if (os_strstr(capab, "[SU-BEAMFORMEE]")) - conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE; + conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE; if (os_strstr(capab, "[BF-ANTENNA-2]") && - (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE)) - conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX; + (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE)) + conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET); if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") && - (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE)) - conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX; + (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE)) + conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET); if (os_strstr(capab, "[MU-BEAMFORMER]")) conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE; if (os_strstr(capab, "[MU-BEAMFORMEE]")) @@ -1118,8 +1145,20 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf, conf->vht_capab |= VHT_CAP_VHT_TXOP_PS; if (os_strstr(capab, "[HTC-VHT]")) conf->vht_capab |= VHT_CAP_HTC_VHT; - if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]")) - conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT; + if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP7]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX; + else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP6]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6; + else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP5]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_5; + else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP4]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_4; + else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP3]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_3; + else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP2]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_2; + else if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP1]")) + conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_1; if (os_strstr(capab, "[VHT-LINK-ADAPT2]") && (conf->vht_capab & VHT_CAP_HTC_VHT)) conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB; @@ -1135,141 +1174,6 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf, #endif /* CONFIG_IEEE80211AC */ -static int hostapd_config_check_bss(struct hostapd_bss_config *bss, - struct hostapd_config *conf) -{ - if (bss->ieee802_1x && !bss->eap_server && - !bss->radius->auth_servers) { - wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no " - "EAP authenticator configured)."); - return -1; - } - - if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED && - bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { - wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no " - "RADIUS checking (macaddr_acl=2) enabled."); - return -1; - } - - if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) && - bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL && - bss->ssid.wpa_psk_file == NULL && - (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED || - bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) { - wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase " - "is not configured."); - return -1; - } - - if (hostapd_mac_comp_empty(bss->bssid) != 0) { - size_t i; - - for (i = 0; i < conf->num_bss; i++) { - if ((&conf->bss[i] != bss) && - (hostapd_mac_comp(conf->bss[i].bssid, - bss->bssid) == 0)) { - wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR - " on interface '%s' and '%s'.", - MAC2STR(bss->bssid), - conf->bss[i].iface, bss->iface); - return -1; - } - } - } - -#ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) && - (bss->nas_identifier == NULL || - os_strlen(bss->nas_identifier) < 1 || - os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) { - wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires " - "nas_identifier to be configured as a 1..48 octet " - "string"); - return -1; - } -#endif /* CONFIG_IEEE80211R */ - -#ifdef CONFIG_IEEE80211N - if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) { - bss->disable_11n = 1; - wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not " - "allowed, disabling HT capabilites"); - } - - if (conf->ieee80211n && - bss->ssid.security_policy == SECURITY_STATIC_WEP) { - bss->disable_11n = 1; - wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not " - "allowed, disabling HT capabilities"); - } - - if (conf->ieee80211n && bss->wpa && - !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) { - bss->disable_11n = 1; - wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " - "requires CCMP/GCMP to be enabled, disabling HT " - "capabilities"); - } -#endif /* CONFIG_IEEE80211N */ - -#ifdef CONFIG_WPS2 - if (bss->wps_state && bss->ignore_broadcast_ssid) { - wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid " - "configuration forced WPS to be disabled"); - bss->wps_state = 0; - } - - if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) { - wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be " - "disabled"); - bss->wps_state = 0; - } - - if (bss->wps_state && bss->wpa && - (!(bss->wpa & 2) || - !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) { - wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without " - "WPA2/CCMP forced WPS to be disabled"); - bss->wps_state = 0; - } -#endif /* CONFIG_WPS2 */ - -#ifdef CONFIG_HS20 - if (bss->hs20 && - (!(bss->wpa & 2) || - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) { - wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP " - "configuration is required for Hotspot 2.0 " - "functionality"); - return -1; - } -#endif /* CONFIG_HS20 */ - - return 0; -} - - -static int hostapd_config_check(struct hostapd_config *conf) -{ - size_t i; - - if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) { - wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without " - "setting the country_code"); - return -1; - } - - for (i = 0; i < conf->num_bss; i++) { - if (hostapd_config_check_bss(&conf->bss[i], conf)) - return -1; - } - - return 0; -} - - #ifdef CONFIG_INTERWORKING static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos, int line) @@ -1306,26 +1210,34 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos, static int parse_lang_string(struct hostapd_lang_string **array, unsigned int *count, char *pos) { - char *sep; - size_t clen, nlen; + char *sep, *str = NULL; + size_t clen, nlen, slen; struct hostapd_lang_string *ls; + int ret = -1; + + if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) { + str = wpa_config_parse_string(pos, &slen); + if (!str) + return -1; + pos = str; + } sep = os_strchr(pos, ':'); if (sep == NULL) - return -1; + goto fail; *sep++ = '\0'; clen = os_strlen(pos); - if (clen < 2) - return -1; + if (clen < 2 || clen > sizeof(ls->lang)) + goto fail; nlen = os_strlen(sep); if (nlen > 252) - return -1; + goto fail; ls = os_realloc_array(*array, *count + 1, sizeof(struct hostapd_lang_string)); if (ls == NULL) - return -1; + goto fail; *array = ls; ls = &(*array)[*count]; @@ -1336,7 +1248,10 @@ static int parse_lang_string(struct hostapd_lang_string **array, ls->name_len = nlen; os_memcpy(ls->name, sep, nlen); - return 0; + ret = 0; +fail: + os_free(str); + return ret; } @@ -1363,7 +1278,7 @@ static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf, count = 1; for (pos = buf; *pos; pos++) { - if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',') + if ((*pos < '0' || *pos > '9') && *pos != ';' && *pos != ',') goto fail; if (*pos == ';') count++; @@ -1567,6 +1482,47 @@ fail: return -1; } + +static int parse_qos_map_set(struct hostapd_bss_config *bss, + char *buf, int line) +{ + u8 qos_map_set[16 + 2 * 21], count = 0; + char *pos = buf; + int val; + + for (;;) { + if (count == sizeof(qos_map_set)) { + wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set " + "parameters '%s'", line, buf); + return -1; + } + + val = atoi(pos); + if (val > 255 || val < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set " + "'%s'", line, buf); + return -1; + } + + qos_map_set[count++] = val; + pos = os_strchr(pos, ','); + if (!pos) + break; + pos++; + } + + if (count < 16 || count & 1) { + wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'", + line, buf); + return -1; + } + + os_memcpy(bss->qos_map_set, qos_map_set, count); + bss->qos_map_set_len = count; + + return 0; +} + #endif /* CONFIG_INTERWORKING */ @@ -1664,7 +1620,7 @@ static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf, fail: wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'", - line, pos); + line, buf); os_free(wan_metrics); return -1; } @@ -1681,6 +1637,197 @@ static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss, } return 0; } + + +static int hs20_parse_icon(struct hostapd_bss_config *bss, char *pos) +{ + struct hs20_icon *icon; + char *end; + + icon = os_realloc_array(bss->hs20_icons, bss->hs20_icons_count + 1, + sizeof(struct hs20_icon)); + if (icon == NULL) + return -1; + bss->hs20_icons = icon; + icon = &bss->hs20_icons[bss->hs20_icons_count]; + os_memset(icon, 0, sizeof(*icon)); + + icon->width = atoi(pos); + pos = os_strchr(pos, ':'); + if (pos == NULL) + return -1; + pos++; + + icon->height = atoi(pos); + pos = os_strchr(pos, ':'); + if (pos == NULL) + return -1; + pos++; + + end = os_strchr(pos, ':'); + if (end == NULL || end - pos > 3) + return -1; + os_memcpy(icon->language, pos, end - pos); + pos = end + 1; + + end = os_strchr(pos, ':'); + if (end == NULL || end - pos > 255) + return -1; + os_memcpy(icon->type, pos, end - pos); + pos = end + 1; + + end = os_strchr(pos, ':'); + if (end == NULL || end - pos > 255) + return -1; + os_memcpy(icon->name, pos, end - pos); + pos = end + 1; + + if (os_strlen(pos) > 255) + return -1; + os_memcpy(icon->file, pos, os_strlen(pos)); + + bss->hs20_icons_count++; + + return 0; +} + + +static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss, + char *pos, int line) +{ + size_t slen; + char *str; + + str = wpa_config_parse_string(pos, &slen); + if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) { + wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos); + os_free(str); + return -1; + } + + os_memcpy(bss->osu_ssid, str, slen); + bss->osu_ssid_len = slen; + os_free(str); + + return 0; +} + + +static int hs20_parse_osu_server_uri(struct hostapd_bss_config *bss, + char *pos, int line) +{ + struct hs20_osu_provider *p; + + p = os_realloc_array(bss->hs20_osu_providers, + bss->hs20_osu_providers_count + 1, sizeof(*p)); + if (p == NULL) + return -1; + + bss->hs20_osu_providers = p; + bss->last_osu = &bss->hs20_osu_providers[bss->hs20_osu_providers_count]; + bss->hs20_osu_providers_count++; + os_memset(bss->last_osu, 0, sizeof(*p)); + bss->last_osu->server_uri = os_strdup(pos); + + return 0; +} + + +static int hs20_parse_osu_friendly_name(struct hostapd_bss_config *bss, + char *pos, int line) +{ + if (bss->last_osu == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line); + return -1; + } + + if (parse_lang_string(&bss->last_osu->friendly_name, + &bss->last_osu->friendly_name_count, pos)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid osu_friendly_name '%s'", + line, pos); + return -1; + } + + return 0; +} + + +static int hs20_parse_osu_nai(struct hostapd_bss_config *bss, + char *pos, int line) +{ + if (bss->last_osu == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line); + return -1; + } + + os_free(bss->last_osu->osu_nai); + bss->last_osu->osu_nai = os_strdup(pos); + if (bss->last_osu->osu_nai == NULL) + return -1; + + return 0; +} + + +static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos, + int line) +{ + if (bss->last_osu == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line); + return -1; + } + + if (hostapd_parse_intlist(&bss->last_osu->method_list, pos)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid osu_method_list", line); + return -1; + } + + return 0; +} + + +static int hs20_parse_osu_icon(struct hostapd_bss_config *bss, char *pos, + int line) +{ + char **n; + struct hs20_osu_provider *p = bss->last_osu; + + if (p == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line); + return -1; + } + + n = os_realloc_array(p->icons, p->icons_count + 1, sizeof(char *)); + if (n == NULL) + return -1; + p->icons = n; + p->icons[p->icons_count] = os_strdup(pos); + if (p->icons[p->icons_count] == NULL) + return -1; + p->icons_count++; + + return 0; +} + + +static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss, + char *pos, int line) +{ + if (bss->last_osu == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line); + return -1; + } + + if (parse_lang_string(&bss->last_osu->service_desc, + &bss->last_osu->service_desc_count, pos)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid osu_service_desc '%s'", + line, pos); + return -1; + } + + return 0; +} + #endif /* CONFIG_HS20 */ @@ -1709,1302 +1856,1434 @@ static struct wpabuf * hostapd_parse_bin(const char *buf) #endif /* CONFIG_WPS_NFC */ +#ifdef CONFIG_ACS +static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf, + char *pos) +{ + struct acs_bias *bias = NULL, *tmp; + unsigned int num = 0; + char *end; + + while (*pos) { + tmp = os_realloc_array(bias, num + 1, sizeof(*bias)); + if (!tmp) + goto fail; + bias = tmp; + + bias[num].channel = atoi(pos); + if (bias[num].channel <= 0) + goto fail; + pos = os_strchr(pos, ':'); + if (!pos) + goto fail; + pos++; + bias[num].bias = strtod(pos, &end); + if (end == pos || bias[num].bias < 0.0) + goto fail; + pos = end; + if (*pos != ' ' && *pos != '\0') + goto fail; + num++; + } + + os_free(conf->acs_chan_bias); + conf->acs_chan_bias = bias; + conf->num_acs_chan_bias = num; + + return 0; +fail: + os_free(bias); + return -1; +} +#endif /* CONFIG_ACS */ + + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, char *buf, char *pos, int line) { - int errors = 0; - - { - if (os_strcmp(buf, "interface") == 0) { - os_strlcpy(conf->bss[0].iface, pos, - sizeof(conf->bss[0].iface)); - } else if (os_strcmp(buf, "bridge") == 0) { - os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); - } else if (os_strcmp(buf, "wds_bridge") == 0) { - os_strlcpy(bss->wds_bridge, pos, - sizeof(bss->wds_bridge)); - } else if (os_strcmp(buf, "driver") == 0) { - int j; - /* clear to get error below if setting is invalid */ - conf->driver = NULL; - for (j = 0; wpa_drivers[j]; j++) { - if (os_strcmp(pos, wpa_drivers[j]->name) == 0) - { - conf->driver = wpa_drivers[j]; - break; - } - } - if (conf->driver == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid/" - "unknown driver '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "debug") == 0) { - wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' " - "configuration variable is not used " - "anymore", line); - } else if (os_strcmp(buf, "logger_syslog_level") == 0) { - bss->logger_syslog_level = atoi(pos); - } else if (os_strcmp(buf, "logger_stdout_level") == 0) { - bss->logger_stdout_level = atoi(pos); - } else if (os_strcmp(buf, "logger_syslog") == 0) { - bss->logger_syslog = atoi(pos); - } else if (os_strcmp(buf, "logger_stdout") == 0) { - bss->logger_stdout = atoi(pos); - } else if (os_strcmp(buf, "dump_file") == 0) { - bss->dump_log_name = os_strdup(pos); - } else if (os_strcmp(buf, "ssid") == 0) { - bss->ssid.ssid_len = os_strlen(pos); - if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || - bss->ssid.ssid_len < 1) { - wpa_printf(MSG_ERROR, "Line %d: invalid SSID " - "'%s'", line, pos); - errors++; - } else { - os_memcpy(bss->ssid.ssid, pos, - bss->ssid.ssid_len); - bss->ssid.ssid_set = 1; - } - } else if (os_strcmp(buf, "ssid2") == 0) { - size_t slen; - char *str = wpa_config_parse_string(pos, &slen); - if (str == NULL || slen < 1 || - slen > HOSTAPD_MAX_SSID_LEN) { - wpa_printf(MSG_ERROR, "Line %d: invalid SSID " - "'%s'", line, pos); - errors++; - } else { - os_memcpy(bss->ssid.ssid, str, slen); - bss->ssid.ssid_len = slen; - bss->ssid.ssid_set = 1; + if (os_strcmp(buf, "interface") == 0) { + os_strlcpy(conf->bss[0]->iface, pos, + sizeof(conf->bss[0]->iface)); + } else if (os_strcmp(buf, "bridge") == 0) { + os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); + } else if (os_strcmp(buf, "vlan_bridge") == 0) { + os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); + } else if (os_strcmp(buf, "wds_bridge") == 0) { + os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge)); + } else if (os_strcmp(buf, "driver") == 0) { + int j; + /* clear to get error below if setting is invalid */ + conf->driver = NULL; + for (j = 0; wpa_drivers[j]; j++) { + if (os_strcmp(pos, wpa_drivers[j]->name) == 0) { + conf->driver = wpa_drivers[j]; + break; } + } + if (conf->driver == NULL) { + wpa_printf(MSG_ERROR, + "Line %d: invalid/unknown driver '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "driver_params") == 0) { + os_free(conf->driver_params); + conf->driver_params = os_strdup(pos); + } else if (os_strcmp(buf, "debug") == 0) { + wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' configuration variable is not used anymore", + line); + } else if (os_strcmp(buf, "logger_syslog_level") == 0) { + bss->logger_syslog_level = atoi(pos); + } else if (os_strcmp(buf, "logger_stdout_level") == 0) { + bss->logger_stdout_level = atoi(pos); + } else if (os_strcmp(buf, "logger_syslog") == 0) { + bss->logger_syslog = atoi(pos); + } else if (os_strcmp(buf, "logger_stdout") == 0) { + bss->logger_stdout = atoi(pos); + } else if (os_strcmp(buf, "dump_file") == 0) { + wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore", + line); + } else if (os_strcmp(buf, "ssid") == 0) { + bss->ssid.ssid_len = os_strlen(pos); + if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || + bss->ssid.ssid_len < 1) { + wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'", + line, pos); + return 1; + } + os_memcpy(bss->ssid.ssid, pos, bss->ssid.ssid_len); + bss->ssid.ssid_set = 1; + } else if (os_strcmp(buf, "ssid2") == 0) { + size_t slen; + char *str = wpa_config_parse_string(pos, &slen); + if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) { + wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'", + line, pos); os_free(str); - } else if (os_strcmp(buf, "utf8_ssid") == 0) { - bss->ssid.utf8_ssid = atoi(pos) > 0; - } else if (os_strcmp(buf, "macaddr_acl") == 0) { - bss->macaddr_acl = atoi(pos); - if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED && - bss->macaddr_acl != DENY_UNLESS_ACCEPTED && - bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "macaddr_acl %d", - line, bss->macaddr_acl); - } - } else if (os_strcmp(buf, "accept_mac_file") == 0) { - if (hostapd_config_read_maclist(pos, &bss->accept_mac, - &bss->num_accept_mac)) - { - wpa_printf(MSG_ERROR, "Line %d: Failed to " - "read accept_mac_file '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "deny_mac_file") == 0) { - if (hostapd_config_read_maclist(pos, &bss->deny_mac, - &bss->num_deny_mac)) { - wpa_printf(MSG_ERROR, "Line %d: Failed to " - "read deny_mac_file '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "wds_sta") == 0) { - bss->wds_sta = atoi(pos); - } else if (os_strcmp(buf, "ap_isolate") == 0) { - bss->isolate = atoi(pos); - } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { - bss->ap_max_inactivity = atoi(pos); - } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { - bss->skip_inactivity_poll = atoi(pos); - } else if (os_strcmp(buf, "country_code") == 0) { - os_memcpy(conf->country, pos, 2); - /* FIX: make this configurable */ - conf->country[2] = ' '; - } else if (os_strcmp(buf, "ieee80211d") == 0) { - conf->ieee80211d = atoi(pos); - } else if (os_strcmp(buf, "ieee8021x") == 0) { - bss->ieee802_1x = atoi(pos); - } else if (os_strcmp(buf, "eapol_version") == 0) { - bss->eapol_version = atoi(pos); - if (bss->eapol_version < 1 || - bss->eapol_version > 2) { - wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL " - "version (%d): '%s'.", - line, bss->eapol_version, pos); - errors++; - } else - wpa_printf(MSG_DEBUG, "eapol_version=%d", - bss->eapol_version); + return 1; + } + os_memcpy(bss->ssid.ssid, str, slen); + bss->ssid.ssid_len = slen; + bss->ssid.ssid_set = 1; + os_free(str); + } else if (os_strcmp(buf, "utf8_ssid") == 0) { + bss->ssid.utf8_ssid = atoi(pos) > 0; + } else if (os_strcmp(buf, "macaddr_acl") == 0) { + bss->macaddr_acl = atoi(pos); + if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED && + bss->macaddr_acl != DENY_UNLESS_ACCEPTED && + bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { + wpa_printf(MSG_ERROR, "Line %d: unknown macaddr_acl %d", + line, bss->macaddr_acl); + } + } else if (os_strcmp(buf, "accept_mac_file") == 0) { + if (hostapd_config_read_maclist(pos, &bss->accept_mac, + &bss->num_accept_mac)) { + wpa_printf(MSG_ERROR, "Line %d: Failed to read accept_mac_file '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "deny_mac_file") == 0) { + if (hostapd_config_read_maclist(pos, &bss->deny_mac, + &bss->num_deny_mac)) { + wpa_printf(MSG_ERROR, "Line %d: Failed to read deny_mac_file '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "wds_sta") == 0) { + bss->wds_sta = atoi(pos); + } else if (os_strcmp(buf, "start_disabled") == 0) { + bss->start_disabled = atoi(pos); + } else if (os_strcmp(buf, "ap_isolate") == 0) { + bss->isolate = atoi(pos); + } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { + bss->ap_max_inactivity = atoi(pos); + } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { + bss->skip_inactivity_poll = atoi(pos); + } else if (os_strcmp(buf, "country_code") == 0) { + os_memcpy(conf->country, pos, 2); + /* FIX: make this configurable */ + conf->country[2] = ' '; + } else if (os_strcmp(buf, "ieee80211d") == 0) { + conf->ieee80211d = atoi(pos); + } else if (os_strcmp(buf, "ieee80211h") == 0) { + conf->ieee80211h = atoi(pos); + } else if (os_strcmp(buf, "ieee8021x") == 0) { + bss->ieee802_1x = atoi(pos); + } else if (os_strcmp(buf, "eapol_version") == 0) { + bss->eapol_version = atoi(pos); + if (bss->eapol_version < 1 || bss->eapol_version > 2) { + wpa_printf(MSG_ERROR, + "Line %d: invalid EAPOL version (%d): '%s'.", + line, bss->eapol_version, pos); + return 1; + } + wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version); #ifdef EAP_SERVER - } else if (os_strcmp(buf, "eap_authenticator") == 0) { - bss->eap_server = atoi(pos); - wpa_printf(MSG_ERROR, "Line %d: obsolete " - "eap_authenticator used; this has been " - "renamed to eap_server", line); - } else if (os_strcmp(buf, "eap_server") == 0) { - bss->eap_server = atoi(pos); - } else if (os_strcmp(buf, "eap_user_file") == 0) { - if (hostapd_config_read_eap_user(pos, bss)) - errors++; - } else if (os_strcmp(buf, "ca_cert") == 0) { - os_free(bss->ca_cert); - bss->ca_cert = os_strdup(pos); - } else if (os_strcmp(buf, "server_cert") == 0) { - os_free(bss->server_cert); - bss->server_cert = os_strdup(pos); - } else if (os_strcmp(buf, "private_key") == 0) { - os_free(bss->private_key); - bss->private_key = os_strdup(pos); - } else if (os_strcmp(buf, "private_key_passwd") == 0) { - os_free(bss->private_key_passwd); - bss->private_key_passwd = os_strdup(pos); - } else if (os_strcmp(buf, "check_crl") == 0) { - bss->check_crl = atoi(pos); - } else if (os_strcmp(buf, "dh_file") == 0) { - os_free(bss->dh_file); - bss->dh_file = os_strdup(pos); - } else if (os_strcmp(buf, "fragment_size") == 0) { - bss->fragment_size = atoi(pos); + } else if (os_strcmp(buf, "eap_authenticator") == 0) { + bss->eap_server = atoi(pos); + wpa_printf(MSG_ERROR, "Line %d: obsolete eap_authenticator used; this has been renamed to eap_server", line); + } else if (os_strcmp(buf, "eap_server") == 0) { + bss->eap_server = atoi(pos); + } else if (os_strcmp(buf, "eap_user_file") == 0) { + if (hostapd_config_read_eap_user(pos, bss)) + return 1; + } else if (os_strcmp(buf, "ca_cert") == 0) { + os_free(bss->ca_cert); + bss->ca_cert = os_strdup(pos); + } else if (os_strcmp(buf, "server_cert") == 0) { + os_free(bss->server_cert); + bss->server_cert = os_strdup(pos); + } else if (os_strcmp(buf, "private_key") == 0) { + os_free(bss->private_key); + bss->private_key = os_strdup(pos); + } else if (os_strcmp(buf, "private_key_passwd") == 0) { + os_free(bss->private_key_passwd); + bss->private_key_passwd = os_strdup(pos); + } else if (os_strcmp(buf, "check_crl") == 0) { + bss->check_crl = atoi(pos); + } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) { + os_free(bss->ocsp_stapling_response); + bss->ocsp_stapling_response = os_strdup(pos); + } else if (os_strcmp(buf, "dh_file") == 0) { + os_free(bss->dh_file); + bss->dh_file = os_strdup(pos); + } else if (os_strcmp(buf, "openssl_ciphers") == 0) { + os_free(bss->openssl_ciphers); + bss->openssl_ciphers = os_strdup(pos); + } else if (os_strcmp(buf, "fragment_size") == 0) { + bss->fragment_size = atoi(pos); #ifdef EAP_SERVER_FAST - } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) { - os_free(bss->pac_opaque_encr_key); - bss->pac_opaque_encr_key = os_malloc(16); - if (bss->pac_opaque_encr_key == NULL) { - wpa_printf(MSG_ERROR, "Line %d: No memory for " - "pac_opaque_encr_key", line); - errors++; - } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, - 16)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "pac_opaque_encr_key", line); - errors++; - } - } else if (os_strcmp(buf, "eap_fast_a_id") == 0) { - size_t idlen = os_strlen(pos); - if (idlen & 1) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "eap_fast_a_id", line); - errors++; - } else { - os_free(bss->eap_fast_a_id); - bss->eap_fast_a_id = os_malloc(idlen / 2); - if (bss->eap_fast_a_id == NULL || - hexstr2bin(pos, bss->eap_fast_a_id, - idlen / 2)) { - wpa_printf(MSG_ERROR, "Line %d: " - "Failed to parse " - "eap_fast_a_id", line); - errors++; - } else - bss->eap_fast_a_id_len = idlen / 2; - } - } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) { - os_free(bss->eap_fast_a_id_info); - bss->eap_fast_a_id_info = os_strdup(pos); - } else if (os_strcmp(buf, "eap_fast_prov") == 0) { - bss->eap_fast_prov = atoi(pos); - } else if (os_strcmp(buf, "pac_key_lifetime") == 0) { - bss->pac_key_lifetime = atoi(pos); - } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) { - bss->pac_key_refresh_time = atoi(pos); + } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) { + os_free(bss->pac_opaque_encr_key); + bss->pac_opaque_encr_key = os_malloc(16); + if (bss->pac_opaque_encr_key == NULL) { + wpa_printf(MSG_ERROR, + "Line %d: No memory for pac_opaque_encr_key", + line); + return 1; + } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, 16)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid pac_opaque_encr_key", + line); + return 1; + } + } else if (os_strcmp(buf, "eap_fast_a_id") == 0) { + size_t idlen = os_strlen(pos); + if (idlen & 1) { + wpa_printf(MSG_ERROR, "Line %d: Invalid eap_fast_a_id", + line); + return 1; + } + os_free(bss->eap_fast_a_id); + bss->eap_fast_a_id = os_malloc(idlen / 2); + if (bss->eap_fast_a_id == NULL || + hexstr2bin(pos, bss->eap_fast_a_id, idlen / 2)) { + wpa_printf(MSG_ERROR, "Line %d: Failed to parse eap_fast_a_id", + line); + os_free(bss->eap_fast_a_id); + bss->eap_fast_a_id = NULL; + return 1; + } else { + bss->eap_fast_a_id_len = idlen / 2; + } + } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) { + os_free(bss->eap_fast_a_id_info); + bss->eap_fast_a_id_info = os_strdup(pos); + } else if (os_strcmp(buf, "eap_fast_prov") == 0) { + bss->eap_fast_prov = atoi(pos); + } else if (os_strcmp(buf, "pac_key_lifetime") == 0) { + bss->pac_key_lifetime = atoi(pos); + } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) { + bss->pac_key_refresh_time = atoi(pos); #endif /* EAP_SERVER_FAST */ #ifdef EAP_SERVER_SIM - } else if (os_strcmp(buf, "eap_sim_db") == 0) { - os_free(bss->eap_sim_db); - bss->eap_sim_db = os_strdup(pos); - } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) { - bss->eap_sim_aka_result_ind = atoi(pos); + } else if (os_strcmp(buf, "eap_sim_db") == 0) { + os_free(bss->eap_sim_db); + bss->eap_sim_db = os_strdup(pos); + } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) { + bss->eap_sim_aka_result_ind = atoi(pos); #endif /* EAP_SERVER_SIM */ #ifdef EAP_SERVER_TNC - } else if (os_strcmp(buf, "tnc") == 0) { - bss->tnc = atoi(pos); + } else if (os_strcmp(buf, "tnc") == 0) { + bss->tnc = atoi(pos); #endif /* EAP_SERVER_TNC */ #ifdef EAP_SERVER_PWD - } else if (os_strcmp(buf, "pwd_group") == 0) { - bss->pwd_group = atoi(pos); + } else if (os_strcmp(buf, "pwd_group") == 0) { + bss->pwd_group = atoi(pos); #endif /* EAP_SERVER_PWD */ + } else if (os_strcmp(buf, "eap_server_erp") == 0) { + bss->eap_server_erp = atoi(pos); #endif /* EAP_SERVER */ - } else if (os_strcmp(buf, "eap_message") == 0) { - char *term; - bss->eap_req_id_text = os_strdup(pos); - if (bss->eap_req_id_text == NULL) { - wpa_printf(MSG_ERROR, "Line %d: Failed to " - "allocate memory for " - "eap_req_id_text", line); - errors++; - return errors; - } - bss->eap_req_id_text_len = - os_strlen(bss->eap_req_id_text); - term = os_strstr(bss->eap_req_id_text, "\\0"); - if (term) { - *term++ = '\0'; - os_memmove(term, term + 1, - bss->eap_req_id_text_len - - (term - bss->eap_req_id_text) - 1); - bss->eap_req_id_text_len--; - } - } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { - bss->default_wep_key_len = atoi(pos); - if (bss->default_wep_key_len > 13) { - wpa_printf(MSG_ERROR, "Line %d: invalid WEP " - "key len %lu (= %lu bits)", line, - (unsigned long) - bss->default_wep_key_len, - (unsigned long) - bss->default_wep_key_len * 8); - errors++; - } - } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) { - bss->individual_wep_key_len = atoi(pos); - if (bss->individual_wep_key_len < 0 || - bss->individual_wep_key_len > 13) { - wpa_printf(MSG_ERROR, "Line %d: invalid WEP " - "key len %d (= %d bits)", line, - bss->individual_wep_key_len, - bss->individual_wep_key_len * 8); - errors++; - } - } else if (os_strcmp(buf, "wep_rekey_period") == 0) { - bss->wep_rekeying_period = atoi(pos); - if (bss->wep_rekeying_period < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "period %d", - line, bss->wep_rekeying_period); - errors++; - } - } else if (os_strcmp(buf, "eap_reauth_period") == 0) { - bss->eap_reauth_period = atoi(pos); - if (bss->eap_reauth_period < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "period %d", - line, bss->eap_reauth_period); - errors++; - } - } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) { - bss->eapol_key_index_workaround = atoi(pos); + } else if (os_strcmp(buf, "eap_message") == 0) { + char *term; + os_free(bss->eap_req_id_text); + bss->eap_req_id_text = os_strdup(pos); + if (bss->eap_req_id_text == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Failed to allocate memory for eap_req_id_text", + line); + return 1; + } + bss->eap_req_id_text_len = os_strlen(bss->eap_req_id_text); + term = os_strstr(bss->eap_req_id_text, "\\0"); + if (term) { + *term++ = '\0'; + os_memmove(term, term + 1, + bss->eap_req_id_text_len - + (term - bss->eap_req_id_text) - 1); + bss->eap_req_id_text_len--; + } + } else if (os_strcmp(buf, "erp_send_reauth_start") == 0) { + bss->erp_send_reauth_start = atoi(pos); + } else if (os_strcmp(buf, "erp_domain") == 0) { + os_free(bss->erp_domain); + bss->erp_domain = os_strdup(pos); + } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { + bss->default_wep_key_len = atoi(pos); + if (bss->default_wep_key_len > 13) { + wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %lu (= %lu bits)", + line, + (unsigned long) bss->default_wep_key_len, + (unsigned long) + bss->default_wep_key_len * 8); + return 1; + } + } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) { + bss->individual_wep_key_len = atoi(pos); + if (bss->individual_wep_key_len < 0 || + bss->individual_wep_key_len > 13) { + wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %d (= %d bits)", + line, bss->individual_wep_key_len, + bss->individual_wep_key_len * 8); + return 1; + } + } else if (os_strcmp(buf, "wep_rekey_period") == 0) { + bss->wep_rekeying_period = atoi(pos); + if (bss->wep_rekeying_period < 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid period %d", + line, bss->wep_rekeying_period); + return 1; + } + } else if (os_strcmp(buf, "eap_reauth_period") == 0) { + bss->eap_reauth_period = atoi(pos); + if (bss->eap_reauth_period < 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid period %d", + line, bss->eap_reauth_period); + return 1; + } + } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) { + bss->eapol_key_index_workaround = atoi(pos); #ifdef CONFIG_IAPP - } else if (os_strcmp(buf, "iapp_interface") == 0) { - bss->ieee802_11f = 1; - os_strlcpy(bss->iapp_iface, pos, - sizeof(bss->iapp_iface)); + } else if (os_strcmp(buf, "iapp_interface") == 0) { + bss->ieee802_11f = 1; + os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface)); #endif /* CONFIG_IAPP */ - } else if (os_strcmp(buf, "own_ip_addr") == 0) { - if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { - wpa_printf(MSG_ERROR, "Line %d: invalid IP " - "address '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "nas_identifier") == 0) { - bss->nas_identifier = os_strdup(pos); + } else if (os_strcmp(buf, "own_ip_addr") == 0) { + if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { + wpa_printf(MSG_ERROR, + "Line %d: invalid IP address '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "nas_identifier") == 0) { + os_free(bss->nas_identifier); + bss->nas_identifier = os_strdup(pos); #ifndef CONFIG_NO_RADIUS - } else if (os_strcmp(buf, "auth_server_addr") == 0) { - if (hostapd_config_read_radius_addr( - &bss->radius->auth_servers, - &bss->radius->num_auth_servers, pos, 1812, - &bss->radius->auth_server)) { - wpa_printf(MSG_ERROR, "Line %d: invalid IP " - "address '%s'", line, pos); - errors++; - } - } else if (bss->radius->auth_server && - os_strcmp(buf, "auth_server_port") == 0) { - bss->radius->auth_server->port = atoi(pos); - } else if (bss->radius->auth_server && - os_strcmp(buf, "auth_server_shared_secret") == 0) { - int len = os_strlen(pos); - if (len == 0) { - /* RFC 2865, Ch. 3 */ - wpa_printf(MSG_ERROR, "Line %d: empty shared " - "secret is not allowed.", line); - errors++; - } - bss->radius->auth_server->shared_secret = - (u8 *) os_strdup(pos); - bss->radius->auth_server->shared_secret_len = len; - } else if (os_strcmp(buf, "acct_server_addr") == 0) { - if (hostapd_config_read_radius_addr( - &bss->radius->acct_servers, - &bss->radius->num_acct_servers, pos, 1813, - &bss->radius->acct_server)) { - wpa_printf(MSG_ERROR, "Line %d: invalid IP " - "address '%s'", line, pos); - errors++; - } - } else if (bss->radius->acct_server && - os_strcmp(buf, "acct_server_port") == 0) { - bss->radius->acct_server->port = atoi(pos); - } else if (bss->radius->acct_server && - os_strcmp(buf, "acct_server_shared_secret") == 0) { - int len = os_strlen(pos); - if (len == 0) { - /* RFC 2865, Ch. 3 */ - wpa_printf(MSG_ERROR, "Line %d: empty shared " - "secret is not allowed.", line); - errors++; - } - bss->radius->acct_server->shared_secret = - (u8 *) os_strdup(pos); - bss->radius->acct_server->shared_secret_len = len; - } else if (os_strcmp(buf, "radius_retry_primary_interval") == - 0) { - bss->radius->retry_primary_interval = atoi(pos); - } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) - { - bss->acct_interim_interval = atoi(pos); - } else if (os_strcmp(buf, "radius_request_cui") == 0) { - bss->radius_request_cui = atoi(pos); - } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) { - struct hostapd_radius_attr *attr, *a; - attr = hostapd_parse_radius_attr(pos); - if (attr == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "radius_auth_req_attr", line); - errors++; - } else if (bss->radius_auth_req_attr == NULL) { - bss->radius_auth_req_attr = attr; - } else { - a = bss->radius_auth_req_attr; - while (a->next) - a = a->next; - a->next = attr; - } - } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) { - struct hostapd_radius_attr *attr, *a; - attr = hostapd_parse_radius_attr(pos); - if (attr == NULL) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "radius_acct_req_attr", line); - errors++; - } else if (bss->radius_acct_req_attr == NULL) { - bss->radius_acct_req_attr = attr; - } else { - a = bss->radius_acct_req_attr; - while (a->next) - a = a->next; - a->next = attr; - } - } else if (os_strcmp(buf, "radius_das_port") == 0) { - bss->radius_das_port = atoi(pos); - } else if (os_strcmp(buf, "radius_das_client") == 0) { - if (hostapd_parse_das_client(bss, pos) < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "DAS client", line); - errors++; - } - } else if (os_strcmp(buf, "radius_das_time_window") == 0) { - bss->radius_das_time_window = atoi(pos); - } else if (os_strcmp(buf, "radius_das_require_event_timestamp") - == 0) { - bss->radius_das_require_event_timestamp = atoi(pos); + } else if (os_strcmp(buf, "radius_client_addr") == 0) { + if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) { + wpa_printf(MSG_ERROR, + "Line %d: invalid IP address '%s'", + line, pos); + return 1; + } + bss->radius->force_client_addr = 1; + } else if (os_strcmp(buf, "auth_server_addr") == 0) { + if (hostapd_config_read_radius_addr( + &bss->radius->auth_servers, + &bss->radius->num_auth_servers, pos, 1812, + &bss->radius->auth_server)) { + wpa_printf(MSG_ERROR, + "Line %d: invalid IP address '%s'", + line, pos); + return 1; + } + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_addr_replace") == 0) { + if (hostapd_parse_ip_addr(pos, + &bss->radius->auth_server->addr)) { + wpa_printf(MSG_ERROR, + "Line %d: invalid IP address '%s'", + line, pos); + return 1; + } + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_port") == 0) { + bss->radius->auth_server->port = atoi(pos); + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_shared_secret") == 0) { + int len = os_strlen(pos); + if (len == 0) { + /* RFC 2865, Ch. 3 */ + wpa_printf(MSG_ERROR, "Line %d: empty shared secret is not allowed", + line); + return 1; + } + os_free(bss->radius->auth_server->shared_secret); + bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos); + bss->radius->auth_server->shared_secret_len = len; + } else if (os_strcmp(buf, "acct_server_addr") == 0) { + if (hostapd_config_read_radius_addr( + &bss->radius->acct_servers, + &bss->radius->num_acct_servers, pos, 1813, + &bss->radius->acct_server)) { + wpa_printf(MSG_ERROR, + "Line %d: invalid IP address '%s'", + line, pos); + return 1; + } + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_addr_replace") == 0) { + if (hostapd_parse_ip_addr(pos, + &bss->radius->acct_server->addr)) { + wpa_printf(MSG_ERROR, + "Line %d: invalid IP address '%s'", + line, pos); + return 1; + } + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_port") == 0) { + bss->radius->acct_server->port = atoi(pos); + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_shared_secret") == 0) { + int len = os_strlen(pos); + if (len == 0) { + /* RFC 2865, Ch. 3 */ + wpa_printf(MSG_ERROR, "Line %d: empty shared secret is not allowed", + line); + return 1; + } + os_free(bss->radius->acct_server->shared_secret); + bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos); + bss->radius->acct_server->shared_secret_len = len; + } else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) { + bss->radius->retry_primary_interval = atoi(pos); + } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) { + bss->acct_interim_interval = atoi(pos); + } else if (os_strcmp(buf, "radius_request_cui") == 0) { + bss->radius_request_cui = atoi(pos); + } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) { + struct hostapd_radius_attr *attr, *a; + attr = hostapd_parse_radius_attr(pos); + if (attr == NULL) { + wpa_printf(MSG_ERROR, + "Line %d: invalid radius_auth_req_attr", + line); + return 1; + } else if (bss->radius_auth_req_attr == NULL) { + bss->radius_auth_req_attr = attr; + } else { + a = bss->radius_auth_req_attr; + while (a->next) + a = a->next; + a->next = attr; + } + } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) { + struct hostapd_radius_attr *attr, *a; + attr = hostapd_parse_radius_attr(pos); + if (attr == NULL) { + wpa_printf(MSG_ERROR, + "Line %d: invalid radius_acct_req_attr", + line); + return 1; + } else if (bss->radius_acct_req_attr == NULL) { + bss->radius_acct_req_attr = attr; + } else { + a = bss->radius_acct_req_attr; + while (a->next) + a = a->next; + a->next = attr; + } + } else if (os_strcmp(buf, "radius_das_port") == 0) { + bss->radius_das_port = atoi(pos); + } else if (os_strcmp(buf, "radius_das_client") == 0) { + if (hostapd_parse_das_client(bss, pos) < 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid DAS client", + line); + return 1; + } + } else if (os_strcmp(buf, "radius_das_time_window") == 0) { + bss->radius_das_time_window = atoi(pos); + } else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) { + bss->radius_das_require_event_timestamp = atoi(pos); #endif /* CONFIG_NO_RADIUS */ - } else if (os_strcmp(buf, "auth_algs") == 0) { - bss->auth_algs = atoi(pos); - if (bss->auth_algs == 0) { - wpa_printf(MSG_ERROR, "Line %d: no " - "authentication algorithms allowed", - line); - errors++; - } - } else if (os_strcmp(buf, "max_num_sta") == 0) { - bss->max_num_sta = atoi(pos); - if (bss->max_num_sta < 0 || - bss->max_num_sta > MAX_STA_COUNT) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "max_num_sta=%d; allowed range " - "0..%d", line, bss->max_num_sta, - MAX_STA_COUNT); - errors++; - } - } else if (os_strcmp(buf, "wpa") == 0) { - bss->wpa = atoi(pos); - } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { - bss->wpa_group_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) { - bss->wpa_strict_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { - bss->wpa_gmk_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { - bss->wpa_ptk_rekey = atoi(pos); - } else if (os_strcmp(buf, "wpa_passphrase") == 0) { - int len = os_strlen(pos); - if (len < 8 || len > 63) { - wpa_printf(MSG_ERROR, "Line %d: invalid WPA " - "passphrase length %d (expected " - "8..63)", line, len); - errors++; - } else { - os_free(bss->ssid.wpa_passphrase); - bss->ssid.wpa_passphrase = os_strdup(pos); - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = NULL; - } - } else if (os_strcmp(buf, "wpa_psk") == 0) { - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = - os_zalloc(sizeof(struct hostapd_wpa_psk)); - if (bss->ssid.wpa_psk == NULL) - errors++; - else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, - PMK_LEN) || - pos[PMK_LEN * 2] != '\0') { - wpa_printf(MSG_ERROR, "Line %d: Invalid PSK " - "'%s'.", line, pos); - errors++; - } else { - bss->ssid.wpa_psk->group = 1; - os_free(bss->ssid.wpa_passphrase); - bss->ssid.wpa_passphrase = NULL; - } - } else if (os_strcmp(buf, "wpa_psk_file") == 0) { - os_free(bss->ssid.wpa_psk_file); - bss->ssid.wpa_psk_file = os_strdup(pos); - if (!bss->ssid.wpa_psk_file) { - wpa_printf(MSG_ERROR, "Line %d: allocation " - "failed", line); - errors++; - } - } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) { - bss->wpa_key_mgmt = - hostapd_config_parse_key_mgmt(line, pos); - if (bss->wpa_key_mgmt == -1) - errors++; - } else if (os_strcmp(buf, "wpa_psk_radius") == 0) { - bss->wpa_psk_radius = atoi(pos); - if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED && - bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED && - bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "wpa_psk_radius %d", - line, bss->wpa_psk_radius); - errors++; - } - } else if (os_strcmp(buf, "wpa_pairwise") == 0) { - bss->wpa_pairwise = - hostapd_config_parse_cipher(line, pos); - if (bss->wpa_pairwise == -1 || - bss->wpa_pairwise == 0) - errors++; - else if (bss->wpa_pairwise & - (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | - WPA_CIPHER_WEP104)) { - wpa_printf(MSG_ERROR, "Line %d: unsupported " - "pairwise cipher suite '%s'", - bss->wpa_pairwise, pos); - errors++; - } - } else if (os_strcmp(buf, "rsn_pairwise") == 0) { - bss->rsn_pairwise = - hostapd_config_parse_cipher(line, pos); - if (bss->rsn_pairwise == -1 || - bss->rsn_pairwise == 0) - errors++; - else if (bss->rsn_pairwise & - (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | - WPA_CIPHER_WEP104)) { - wpa_printf(MSG_ERROR, "Line %d: unsupported " - "pairwise cipher suite '%s'", - bss->rsn_pairwise, pos); - errors++; - } + } else if (os_strcmp(buf, "auth_algs") == 0) { + bss->auth_algs = atoi(pos); + if (bss->auth_algs == 0) { + wpa_printf(MSG_ERROR, "Line %d: no authentication algorithms allowed", + line); + return 1; + } + } else if (os_strcmp(buf, "max_num_sta") == 0) { + bss->max_num_sta = atoi(pos); + if (bss->max_num_sta < 0 || + bss->max_num_sta > MAX_STA_COUNT) { + wpa_printf(MSG_ERROR, "Line %d: Invalid max_num_sta=%d; allowed range 0..%d", + line, bss->max_num_sta, MAX_STA_COUNT); + return 1; + } + } else if (os_strcmp(buf, "wpa") == 0) { + bss->wpa = atoi(pos); + } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { + bss->wpa_group_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) { + bss->wpa_strict_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { + bss->wpa_gmk_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { + bss->wpa_ptk_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_passphrase") == 0) { + int len = os_strlen(pos); + if (len < 8 || len > 63) { + wpa_printf(MSG_ERROR, "Line %d: invalid WPA passphrase length %d (expected 8..63)", + line, len); + return 1; + } + os_free(bss->ssid.wpa_passphrase); + bss->ssid.wpa_passphrase = os_strdup(pos); + if (bss->ssid.wpa_passphrase) { + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); + bss->ssid.wpa_passphrase_set = 1; + } + } else if (os_strcmp(buf, "wpa_psk") == 0) { + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); + bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk)); + if (bss->ssid.wpa_psk == NULL) + return 1; + if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, PMK_LEN) || + pos[PMK_LEN * 2] != '\0') { + wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", + line, pos); + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); + return 1; + } + bss->ssid.wpa_psk->group = 1; + os_free(bss->ssid.wpa_passphrase); + bss->ssid.wpa_passphrase = NULL; + bss->ssid.wpa_psk_set = 1; + } else if (os_strcmp(buf, "wpa_psk_file") == 0) { + os_free(bss->ssid.wpa_psk_file); + bss->ssid.wpa_psk_file = os_strdup(pos); + if (!bss->ssid.wpa_psk_file) { + wpa_printf(MSG_ERROR, "Line %d: allocation failed", + line); + return 1; + } + } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) { + bss->wpa_key_mgmt = hostapd_config_parse_key_mgmt(line, pos); + if (bss->wpa_key_mgmt == -1) + return 1; + } else if (os_strcmp(buf, "wpa_psk_radius") == 0) { + bss->wpa_psk_radius = atoi(pos); + if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED && + bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED && + bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) { + wpa_printf(MSG_ERROR, + "Line %d: unknown wpa_psk_radius %d", + line, bss->wpa_psk_radius); + return 1; + } + } else if (os_strcmp(buf, "wpa_pairwise") == 0) { + bss->wpa_pairwise = hostapd_config_parse_cipher(line, pos); + if (bss->wpa_pairwise == -1 || bss->wpa_pairwise == 0) + return 1; + if (bss->wpa_pairwise & + (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) { + wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'", + bss->wpa_pairwise, pos); + return 1; + } + } else if (os_strcmp(buf, "rsn_pairwise") == 0) { + bss->rsn_pairwise = hostapd_config_parse_cipher(line, pos); + if (bss->rsn_pairwise == -1 || bss->rsn_pairwise == 0) + return 1; + if (bss->rsn_pairwise & + (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) { + wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'", + bss->rsn_pairwise, pos); + return 1; + } #ifdef CONFIG_RSN_PREAUTH - } else if (os_strcmp(buf, "rsn_preauth") == 0) { - bss->rsn_preauth = atoi(pos); - } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) { - bss->rsn_preauth_interfaces = os_strdup(pos); + } else if (os_strcmp(buf, "rsn_preauth") == 0) { + bss->rsn_preauth = atoi(pos); + } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) { + os_free(bss->rsn_preauth_interfaces); + bss->rsn_preauth_interfaces = os_strdup(pos); #endif /* CONFIG_RSN_PREAUTH */ #ifdef CONFIG_PEERKEY - } else if (os_strcmp(buf, "peerkey") == 0) { - bss->peerkey = atoi(pos); + } else if (os_strcmp(buf, "peerkey") == 0) { + bss->peerkey = atoi(pos); #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211R - } else if (os_strcmp(buf, "mobility_domain") == 0) { - if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN || - hexstr2bin(pos, bss->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "mobility_domain '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "r1_key_holder") == 0) { - if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN || - hexstr2bin(pos, bss->r1_key_holder, - FT_R1KH_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "r1_key_holder '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "r0_key_lifetime") == 0) { - bss->r0_key_lifetime = atoi(pos); - } else if (os_strcmp(buf, "reassociation_deadline") == 0) { - bss->reassociation_deadline = atoi(pos); - } else if (os_strcmp(buf, "r0kh") == 0) { - if (add_r0kh(bss, pos) < 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "r0kh '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "r1kh") == 0) { - if (add_r1kh(bss, pos) < 0) { - wpa_printf(MSG_DEBUG, "Line %d: Invalid " - "r1kh '%s'", line, pos); - errors++; - return errors; - } - } else if (os_strcmp(buf, "pmk_r1_push") == 0) { - bss->pmk_r1_push = atoi(pos); - } else if (os_strcmp(buf, "ft_over_ds") == 0) { - bss->ft_over_ds = atoi(pos); + } else if (os_strcmp(buf, "mobility_domain") == 0) { + if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN || + hexstr2bin(pos, bss->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid mobility_domain '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "r1_key_holder") == 0) { + if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN || + hexstr2bin(pos, bss->r1_key_holder, FT_R1KH_ID_LEN) != 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid r1_key_holder '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "r0_key_lifetime") == 0) { + bss->r0_key_lifetime = atoi(pos); + } else if (os_strcmp(buf, "reassociation_deadline") == 0) { + bss->reassociation_deadline = atoi(pos); + } else if (os_strcmp(buf, "r0kh") == 0) { + if (add_r0kh(bss, pos) < 0) { + wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "r1kh") == 0) { + if (add_r1kh(bss, pos) < 0) { + wpa_printf(MSG_DEBUG, "Line %d: Invalid r1kh '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "pmk_r1_push") == 0) { + bss->pmk_r1_push = atoi(pos); + } else if (os_strcmp(buf, "ft_over_ds") == 0) { + bss->ft_over_ds = atoi(pos); #endif /* CONFIG_IEEE80211R */ #ifndef CONFIG_NO_CTRL_IFACE - } else if (os_strcmp(buf, "ctrl_interface") == 0) { - os_free(bss->ctrl_interface); - bss->ctrl_interface = os_strdup(pos); - } else if (os_strcmp(buf, "ctrl_interface_group") == 0) { + } else if (os_strcmp(buf, "ctrl_interface") == 0) { + os_free(bss->ctrl_interface); + bss->ctrl_interface = os_strdup(pos); + } else if (os_strcmp(buf, "ctrl_interface_group") == 0) { #ifndef CONFIG_NATIVE_WINDOWS - struct group *grp; - char *endp; - const char *group = pos; - - grp = getgrnam(group); - if (grp) { - bss->ctrl_interface_gid = grp->gr_gid; - bss->ctrl_interface_gid_set = 1; - wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" - " (from group name '%s')", - bss->ctrl_interface_gid, group); - return errors; - } + struct group *grp; + char *endp; + const char *group = pos; - /* Group name not found - try to parse this as gid */ - bss->ctrl_interface_gid = strtol(group, &endp, 10); - if (*group == '\0' || *endp != '\0') { - wpa_printf(MSG_DEBUG, "Line %d: Invalid group " - "'%s'", line, group); - errors++; - return errors; - } + grp = getgrnam(group); + if (grp) { + bss->ctrl_interface_gid = grp->gr_gid; bss->ctrl_interface_gid_set = 1; - wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", - bss->ctrl_interface_gid); + wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d (from group name '%s')", + bss->ctrl_interface_gid, group); + return 0; + } + + /* Group name not found - try to parse this as gid */ + bss->ctrl_interface_gid = strtol(group, &endp, 10); + if (*group == '\0' || *endp != '\0') { + wpa_printf(MSG_DEBUG, "Line %d: Invalid group '%s'", + line, group); + return 1; + } + bss->ctrl_interface_gid_set = 1; + wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", + bss->ctrl_interface_gid); #endif /* CONFIG_NATIVE_WINDOWS */ #endif /* CONFIG_NO_CTRL_IFACE */ #ifdef RADIUS_SERVER - } else if (os_strcmp(buf, "radius_server_clients") == 0) { - os_free(bss->radius_server_clients); - bss->radius_server_clients = os_strdup(pos); - } else if (os_strcmp(buf, "radius_server_auth_port") == 0) { - bss->radius_server_auth_port = atoi(pos); - } else if (os_strcmp(buf, "radius_server_ipv6") == 0) { - bss->radius_server_ipv6 = atoi(pos); + } else if (os_strcmp(buf, "radius_server_clients") == 0) { + os_free(bss->radius_server_clients); + bss->radius_server_clients = os_strdup(pos); + } else if (os_strcmp(buf, "radius_server_auth_port") == 0) { + bss->radius_server_auth_port = atoi(pos); + } else if (os_strcmp(buf, "radius_server_acct_port") == 0) { + bss->radius_server_acct_port = atoi(pos); + } else if (os_strcmp(buf, "radius_server_ipv6") == 0) { + bss->radius_server_ipv6 = atoi(pos); #endif /* RADIUS_SERVER */ - } else if (os_strcmp(buf, "test_socket") == 0) { - os_free(bss->test_socket); - bss->test_socket = os_strdup(pos); - } else if (os_strcmp(buf, "use_pae_group_addr") == 0) { - bss->use_pae_group_addr = atoi(pos); - } else if (os_strcmp(buf, "hw_mode") == 0) { - if (os_strcmp(pos, "a") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211A; - else if (os_strcmp(pos, "b") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211B; - else if (os_strcmp(pos, "g") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211G; - else if (os_strcmp(pos, "ad") == 0) - conf->hw_mode = HOSTAPD_MODE_IEEE80211AD; - else { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "hw_mode '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "wps_rf_bands") == 0) { - if (os_strcmp(pos, "a") == 0) - bss->wps_rf_bands = WPS_RF_50GHZ; - else if (os_strcmp(pos, "g") == 0 || - os_strcmp(pos, "b") == 0) - bss->wps_rf_bands = WPS_RF_24GHZ; - else if (os_strcmp(pos, "ag") == 0 || - os_strcmp(pos, "ga") == 0) - bss->wps_rf_bands = - WPS_RF_24GHZ | WPS_RF_50GHZ; - else { - wpa_printf(MSG_ERROR, "Line %d: unknown " - "wps_rf_band '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "channel") == 0) { + } else if (os_strcmp(buf, "use_pae_group_addr") == 0) { + bss->use_pae_group_addr = atoi(pos); + } else if (os_strcmp(buf, "hw_mode") == 0) { + if (os_strcmp(pos, "a") == 0) + conf->hw_mode = HOSTAPD_MODE_IEEE80211A; + else if (os_strcmp(pos, "b") == 0) + conf->hw_mode = HOSTAPD_MODE_IEEE80211B; + else if (os_strcmp(pos, "g") == 0) + conf->hw_mode = HOSTAPD_MODE_IEEE80211G; + else if (os_strcmp(pos, "ad") == 0) + conf->hw_mode = HOSTAPD_MODE_IEEE80211AD; + else { + wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "wps_rf_bands") == 0) { + if (os_strcmp(pos, "a") == 0) + bss->wps_rf_bands = WPS_RF_50GHZ; + else if (os_strcmp(pos, "g") == 0 || + os_strcmp(pos, "b") == 0) + bss->wps_rf_bands = WPS_RF_24GHZ; + else if (os_strcmp(pos, "ag") == 0 || + os_strcmp(pos, "ga") == 0) + bss->wps_rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; + else { + wpa_printf(MSG_ERROR, + "Line %d: unknown wps_rf_band '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "channel") == 0) { + if (os_strcmp(pos, "acs_survey") == 0) { +#ifndef CONFIG_ACS + wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled", + line); + return 1; +#else /* CONFIG_ACS */ + conf->channel = 0; +#endif /* CONFIG_ACS */ + } else conf->channel = atoi(pos); - } else if (os_strcmp(buf, "beacon_int") == 0) { - int val = atoi(pos); - /* MIB defines range as 1..65535, but very small values - * cause problems with the current implementation. - * Since it is unlikely that this small numbers are - * useful in real life scenarios, do not allow beacon - * period to be set below 15 TU. */ - if (val < 15 || val > 65535) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "beacon_int %d (expected " - "15..65535)", line, val); - errors++; - } else - conf->beacon_int = val; - } else if (os_strcmp(buf, "dtim_period") == 0) { - bss->dtim_period = atoi(pos); - if (bss->dtim_period < 1 || bss->dtim_period > 255) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "dtim_period %d", - line, bss->dtim_period); - errors++; - } - } else if (os_strcmp(buf, "rts_threshold") == 0) { - conf->rts_threshold = atoi(pos); - if (conf->rts_threshold < 0 || - conf->rts_threshold > 2347) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "rts_threshold %d", - line, conf->rts_threshold); - errors++; - } - } else if (os_strcmp(buf, "fragm_threshold") == 0) { - conf->fragm_threshold = atoi(pos); - if (conf->fragm_threshold < 256 || - conf->fragm_threshold > 2346) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "fragm_threshold %d", - line, conf->fragm_threshold); - errors++; - } - } else if (os_strcmp(buf, "send_probe_response") == 0) { - int val = atoi(pos); - if (val != 0 && val != 1) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "send_probe_response %d (expected " - "0 or 1)", line, val); - } else - conf->send_probe_response = val; - } else if (os_strcmp(buf, "supported_rates") == 0) { - if (hostapd_parse_rates(&conf->supported_rates, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid rate " - "list", line); - errors++; - } - } else if (os_strcmp(buf, "basic_rates") == 0) { - if (hostapd_parse_rates(&conf->basic_rates, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid rate " - "list", line); - errors++; - } - } else if (os_strcmp(buf, "preamble") == 0) { - if (atoi(pos)) - conf->preamble = SHORT_PREAMBLE; - else - conf->preamble = LONG_PREAMBLE; - } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) { - bss->ignore_broadcast_ssid = atoi(pos); - } else if (os_strcmp(buf, "wep_default_key") == 0) { - bss->ssid.wep.idx = atoi(pos); - if (bss->ssid.wep.idx > 3) { - wpa_printf(MSG_ERROR, "Invalid " - "wep_default_key index %d", - bss->ssid.wep.idx); - errors++; - } - } else if (os_strcmp(buf, "wep_key0") == 0 || - os_strcmp(buf, "wep_key1") == 0 || - os_strcmp(buf, "wep_key2") == 0 || - os_strcmp(buf, "wep_key3") == 0) { - if (hostapd_config_read_wep(&bss->ssid.wep, - buf[7] - '0', pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid WEP " - "key '%s'", line, buf); - errors++; - } + } else if (os_strcmp(buf, "chanlist") == 0) { + if (hostapd_parse_intlist(&conf->chanlist, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid channel list", + line); + return 1; + } + } else if (os_strcmp(buf, "beacon_int") == 0) { + int val = atoi(pos); + /* MIB defines range as 1..65535, but very small values + * cause problems with the current implementation. + * Since it is unlikely that this small numbers are + * useful in real life scenarios, do not allow beacon + * period to be set below 15 TU. */ + if (val < 15 || val > 65535) { + wpa_printf(MSG_ERROR, "Line %d: invalid beacon_int %d (expected 15..65535)", + line, val); + return 1; + } + conf->beacon_int = val; +#ifdef CONFIG_ACS + } else if (os_strcmp(buf, "acs_num_scans") == 0) { + int val = atoi(pos); + if (val <= 0 || val > 100) { + wpa_printf(MSG_ERROR, "Line %d: invalid acs_num_scans %d (expected 1..100)", + line, val); + return 1; + } + conf->acs_num_scans = val; + } else if (os_strcmp(buf, "acs_chan_bias") == 0) { + if (hostapd_config_parse_acs_chan_bias(conf, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias", + line); + return -1; + } +#endif /* CONFIG_ACS */ + } else if (os_strcmp(buf, "dtim_period") == 0) { + bss->dtim_period = atoi(pos); + if (bss->dtim_period < 1 || bss->dtim_period > 255) { + wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d", + line, bss->dtim_period); + return 1; + } + } else if (os_strcmp(buf, "bss_load_update_period") == 0) { + bss->bss_load_update_period = atoi(pos); + if (bss->bss_load_update_period < 0 || + bss->bss_load_update_period > 100) { + wpa_printf(MSG_ERROR, + "Line %d: invalid bss_load_update_period %d", + line, bss->bss_load_update_period); + return 1; + } + } else if (os_strcmp(buf, "rts_threshold") == 0) { + conf->rts_threshold = atoi(pos); + if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) { + wpa_printf(MSG_ERROR, + "Line %d: invalid rts_threshold %d", + line, conf->rts_threshold); + return 1; + } + } else if (os_strcmp(buf, "fragm_threshold") == 0) { + conf->fragm_threshold = atoi(pos); + if (conf->fragm_threshold < 256 || + conf->fragm_threshold > 2346) { + wpa_printf(MSG_ERROR, + "Line %d: invalid fragm_threshold %d", + line, conf->fragm_threshold); + return 1; + } + } else if (os_strcmp(buf, "send_probe_response") == 0) { + int val = atoi(pos); + if (val != 0 && val != 1) { + wpa_printf(MSG_ERROR, "Line %d: invalid send_probe_response %d (expected 0 or 1)", + line, val); + return 1; + } + conf->send_probe_response = val; + } else if (os_strcmp(buf, "supported_rates") == 0) { + if (hostapd_parse_intlist(&conf->supported_rates, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid rate list", + line); + return 1; + } + } else if (os_strcmp(buf, "basic_rates") == 0) { + if (hostapd_parse_intlist(&conf->basic_rates, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid rate list", + line); + return 1; + } + } else if (os_strcmp(buf, "preamble") == 0) { + if (atoi(pos)) + conf->preamble = SHORT_PREAMBLE; + else + conf->preamble = LONG_PREAMBLE; + } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) { + bss->ignore_broadcast_ssid = atoi(pos); + } else if (os_strcmp(buf, "wep_default_key") == 0) { + bss->ssid.wep.idx = atoi(pos); + if (bss->ssid.wep.idx > 3) { + wpa_printf(MSG_ERROR, + "Invalid wep_default_key index %d", + bss->ssid.wep.idx); + return 1; + } + } else if (os_strcmp(buf, "wep_key0") == 0 || + os_strcmp(buf, "wep_key1") == 0 || + os_strcmp(buf, "wep_key2") == 0 || + os_strcmp(buf, "wep_key3") == 0) { + if (hostapd_config_read_wep(&bss->ssid.wep, + buf[7] - '0', pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid WEP key '%s'", + line, buf); + return 1; + } #ifndef CONFIG_NO_VLAN - } else if (os_strcmp(buf, "dynamic_vlan") == 0) { - bss->ssid.dynamic_vlan = atoi(pos); - } else if (os_strcmp(buf, "vlan_file") == 0) { - if (hostapd_config_read_vlan_file(bss, pos)) { - wpa_printf(MSG_ERROR, "Line %d: failed to " - "read VLAN file '%s'", line, pos); - errors++; - } - } else if (os_strcmp(buf, "vlan_naming") == 0) { - bss->ssid.vlan_naming = atoi(pos); - if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END || - bss->ssid.vlan_naming < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "naming scheme %d", line, - bss->ssid.vlan_naming); - errors++; - } + } else if (os_strcmp(buf, "dynamic_vlan") == 0) { + bss->ssid.dynamic_vlan = atoi(pos); + } else if (os_strcmp(buf, "vlan_file") == 0) { + if (hostapd_config_read_vlan_file(bss, pos)) { + wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "vlan_naming") == 0) { + bss->ssid.vlan_naming = atoi(pos); + if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END || + bss->ssid.vlan_naming < 0) { + wpa_printf(MSG_ERROR, + "Line %d: invalid naming scheme %d", + line, bss->ssid.vlan_naming); + return 1; + } #ifdef CONFIG_FULL_DYNAMIC_VLAN - } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) { - bss->ssid.vlan_tagged_interface = os_strdup(pos); + } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) { + os_free(bss->ssid.vlan_tagged_interface); + bss->ssid.vlan_tagged_interface = os_strdup(pos); #endif /* CONFIG_FULL_DYNAMIC_VLAN */ #endif /* CONFIG_NO_VLAN */ - } else if (os_strcmp(buf, "ap_table_max_size") == 0) { - conf->ap_table_max_size = atoi(pos); - } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) { - conf->ap_table_expiration_time = atoi(pos); - } else if (os_strncmp(buf, "tx_queue_", 9) == 0) { - if (hostapd_config_tx_queue(conf, buf, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid TX " - "queue item", line); - errors++; - } - } else if (os_strcmp(buf, "wme_enabled") == 0 || - os_strcmp(buf, "wmm_enabled") == 0) { - bss->wmm_enabled = atoi(pos); - } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) { - bss->wmm_uapsd = atoi(pos); - } else if (os_strncmp(buf, "wme_ac_", 7) == 0 || - os_strncmp(buf, "wmm_ac_", 7) == 0) { - if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf, - pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid WMM " - "ac item", line); - errors++; - } - } else if (os_strcmp(buf, "bss") == 0) { - if (hostapd_config_bss(conf, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid bss " - "item", line); - errors++; - } - } else if (os_strcmp(buf, "bssid") == 0) { - if (hwaddr_aton(pos, bss->bssid)) { - wpa_printf(MSG_ERROR, "Line %d: invalid bssid " - "item", line); - errors++; - } + } else if (os_strcmp(buf, "ap_table_max_size") == 0) { + conf->ap_table_max_size = atoi(pos); + } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) { + conf->ap_table_expiration_time = atoi(pos); + } else if (os_strncmp(buf, "tx_queue_", 9) == 0) { + if (hostapd_config_tx_queue(conf, buf, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item", + line); + return 1; + } + } else if (os_strcmp(buf, "wme_enabled") == 0 || + os_strcmp(buf, "wmm_enabled") == 0) { + bss->wmm_enabled = atoi(pos); + } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) { + bss->wmm_uapsd = atoi(pos); + } else if (os_strncmp(buf, "wme_ac_", 7) == 0 || + os_strncmp(buf, "wmm_ac_", 7) == 0) { + if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid WMM ac item", + line); + return 1; + } + } else if (os_strcmp(buf, "bss") == 0) { + if (hostapd_config_bss(conf, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid bss item", + line); + return 1; + } + } else if (os_strcmp(buf, "bssid") == 0) { + if (hwaddr_aton(pos, bss->bssid)) { + wpa_printf(MSG_ERROR, "Line %d: invalid bssid item", + line); + return 1; + } #ifdef CONFIG_IEEE80211W - } else if (os_strcmp(buf, "ieee80211w") == 0) { - bss->ieee80211w = atoi(pos); - } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { - bss->assoc_sa_query_max_timeout = atoi(pos); - if (bss->assoc_sa_query_max_timeout == 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "assoc_sa_query_max_timeout", line); - errors++; - } - } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) - { - bss->assoc_sa_query_retry_timeout = atoi(pos); - if (bss->assoc_sa_query_retry_timeout == 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "assoc_sa_query_retry_timeout", - line); - errors++; - } + } else if (os_strcmp(buf, "ieee80211w") == 0) { + bss->ieee80211w = atoi(pos); + } else if (os_strcmp(buf, "group_mgmt_cipher") == 0) { + if (os_strcmp(pos, "AES-128-CMAC") == 0) { + bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC; + } else if (os_strcmp(pos, "BIP-GMAC-128") == 0) { + bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_128; + } else if (os_strcmp(pos, "BIP-GMAC-256") == 0) { + bss->group_mgmt_cipher = WPA_CIPHER_BIP_GMAC_256; + } else if (os_strcmp(pos, "BIP-CMAC-256") == 0) { + bss->group_mgmt_cipher = WPA_CIPHER_BIP_CMAC_256; + } else { + wpa_printf(MSG_ERROR, "Line %d: invalid group_mgmt_cipher: %s", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { + bss->assoc_sa_query_max_timeout = atoi(pos); + if (bss->assoc_sa_query_max_timeout == 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid assoc_sa_query_max_timeout", + line); + return 1; + } + } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) { + bss->assoc_sa_query_retry_timeout = atoi(pos); + if (bss->assoc_sa_query_retry_timeout == 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid assoc_sa_query_retry_timeout", + line); + return 1; + } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211N - } else if (os_strcmp(buf, "ieee80211n") == 0) { - conf->ieee80211n = atoi(pos); - } else if (os_strcmp(buf, "ht_capab") == 0) { - if (hostapd_config_ht_capab(conf, pos) < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "ht_capab", line); - errors++; - } - } else if (os_strcmp(buf, "require_ht") == 0) { - conf->require_ht = atoi(pos); + } else if (os_strcmp(buf, "ieee80211n") == 0) { + conf->ieee80211n = atoi(pos); + } else if (os_strcmp(buf, "ht_capab") == 0) { + if (hostapd_config_ht_capab(conf, pos) < 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid ht_capab", + line); + return 1; + } + } else if (os_strcmp(buf, "require_ht") == 0) { + conf->require_ht = atoi(pos); + } else if (os_strcmp(buf, "obss_interval") == 0) { + conf->obss_interval = atoi(pos); #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC - } else if (os_strcmp(buf, "ieee80211ac") == 0) { - conf->ieee80211ac = atoi(pos); - } else if (os_strcmp(buf, "vht_capab") == 0) { - if (hostapd_config_vht_capab(conf, pos) < 0) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "vht_capab", line); - errors++; - } - } else if (os_strcmp(buf, "require_vht") == 0) { - conf->require_vht = atoi(pos); - } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) { - conf->vht_oper_chwidth = atoi(pos); - } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0) - { - conf->vht_oper_centr_freq_seg0_idx = atoi(pos); - } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) - { - conf->vht_oper_centr_freq_seg1_idx = atoi(pos); + } else if (os_strcmp(buf, "ieee80211ac") == 0) { + conf->ieee80211ac = atoi(pos); + } else if (os_strcmp(buf, "vht_capab") == 0) { + if (hostapd_config_vht_capab(conf, pos) < 0) { + wpa_printf(MSG_ERROR, "Line %d: invalid vht_capab", + line); + return 1; + } + } else if (os_strcmp(buf, "require_vht") == 0) { + conf->require_vht = atoi(pos); + } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) { + conf->vht_oper_chwidth = atoi(pos); + } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0) { + conf->vht_oper_centr_freq_seg0_idx = atoi(pos); + } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) { + conf->vht_oper_centr_freq_seg1_idx = atoi(pos); + } else if (os_strcmp(buf, "vendor_vht") == 0) { + bss->vendor_vht = atoi(pos); #endif /* CONFIG_IEEE80211AC */ - } else if (os_strcmp(buf, "max_listen_interval") == 0) { - bss->max_listen_interval = atoi(pos); - } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) { - bss->disable_pmksa_caching = atoi(pos); - } else if (os_strcmp(buf, "okc") == 0) { - bss->okc = atoi(pos); + } else if (os_strcmp(buf, "max_listen_interval") == 0) { + bss->max_listen_interval = atoi(pos); + } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) { + bss->disable_pmksa_caching = atoi(pos); + } else if (os_strcmp(buf, "okc") == 0) { + bss->okc = atoi(pos); #ifdef CONFIG_WPS - } else if (os_strcmp(buf, "wps_state") == 0) { - bss->wps_state = atoi(pos); - if (bss->wps_state < 0 || bss->wps_state > 2) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "wps_state", line); - errors++; - } - } else if (os_strcmp(buf, "ap_setup_locked") == 0) { - bss->ap_setup_locked = atoi(pos); - } else if (os_strcmp(buf, "uuid") == 0) { - if (uuid_str2bin(pos, bss->uuid)) { - wpa_printf(MSG_ERROR, "Line %d: invalid UUID", - line); - errors++; - } - } else if (os_strcmp(buf, "wps_pin_requests") == 0) { - os_free(bss->wps_pin_requests); - bss->wps_pin_requests = os_strdup(pos); - } else if (os_strcmp(buf, "device_name") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "device_name", line); - errors++; - } - os_free(bss->device_name); - bss->device_name = os_strdup(pos); - } else if (os_strcmp(buf, "manufacturer") == 0) { - if (os_strlen(pos) > 64) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "manufacturer", line); - errors++; - } - os_free(bss->manufacturer); - bss->manufacturer = os_strdup(pos); - } else if (os_strcmp(buf, "model_name") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "model_name", line); - errors++; - } - os_free(bss->model_name); - bss->model_name = os_strdup(pos); - } else if (os_strcmp(buf, "model_number") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "model_number", line); - errors++; - } - os_free(bss->model_number); - bss->model_number = os_strdup(pos); - } else if (os_strcmp(buf, "serial_number") == 0) { - if (os_strlen(pos) > 32) { - wpa_printf(MSG_ERROR, "Line %d: Too long " - "serial_number", line); - errors++; - } - os_free(bss->serial_number); - bss->serial_number = os_strdup(pos); - } else if (os_strcmp(buf, "device_type") == 0) { - if (wps_dev_type_str2bin(pos, bss->device_type)) - errors++; - } else if (os_strcmp(buf, "config_methods") == 0) { - os_free(bss->config_methods); - bss->config_methods = os_strdup(pos); - } else if (os_strcmp(buf, "os_version") == 0) { - if (hexstr2bin(pos, bss->os_version, 4)) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "os_version", line); - errors++; - } - } else if (os_strcmp(buf, "ap_pin") == 0) { - os_free(bss->ap_pin); - bss->ap_pin = os_strdup(pos); - } else if (os_strcmp(buf, "skip_cred_build") == 0) { - bss->skip_cred_build = atoi(pos); - } else if (os_strcmp(buf, "extra_cred") == 0) { - os_free(bss->extra_cred); - bss->extra_cred = - (u8 *) os_readfile(pos, &bss->extra_cred_len); - if (bss->extra_cred == NULL) { - wpa_printf(MSG_ERROR, "Line %d: could not " - "read Credentials from '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "wps_cred_processing") == 0) { - bss->wps_cred_processing = atoi(pos); - } else if (os_strcmp(buf, "ap_settings") == 0) { - os_free(bss->ap_settings); - bss->ap_settings = - (u8 *) os_readfile(pos, &bss->ap_settings_len); - if (bss->ap_settings == NULL) { - wpa_printf(MSG_ERROR, "Line %d: could not " - "read AP Settings from '%s'", - line, pos); - errors++; - } - } else if (os_strcmp(buf, "upnp_iface") == 0) { - bss->upnp_iface = os_strdup(pos); - } else if (os_strcmp(buf, "friendly_name") == 0) { - os_free(bss->friendly_name); - bss->friendly_name = os_strdup(pos); - } else if (os_strcmp(buf, "manufacturer_url") == 0) { - os_free(bss->manufacturer_url); - bss->manufacturer_url = os_strdup(pos); - } else if (os_strcmp(buf, "model_description") == 0) { - os_free(bss->model_description); - bss->model_description = os_strdup(pos); - } else if (os_strcmp(buf, "model_url") == 0) { - os_free(bss->model_url); - bss->model_url = os_strdup(pos); - } else if (os_strcmp(buf, "upc") == 0) { - os_free(bss->upc); - bss->upc = os_strdup(pos); - } else if (os_strcmp(buf, "pbc_in_m1") == 0) { - bss->pbc_in_m1 = atoi(pos); + } else if (os_strcmp(buf, "wps_state") == 0) { + bss->wps_state = atoi(pos); + if (bss->wps_state < 0 || bss->wps_state > 2) { + wpa_printf(MSG_ERROR, "Line %d: invalid wps_state", + line); + return 1; + } + } else if (os_strcmp(buf, "wps_independent") == 0) { + bss->wps_independent = atoi(pos); + } else if (os_strcmp(buf, "ap_setup_locked") == 0) { + bss->ap_setup_locked = atoi(pos); + } else if (os_strcmp(buf, "uuid") == 0) { + if (uuid_str2bin(pos, bss->uuid)) { + wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line); + return 1; + } + } else if (os_strcmp(buf, "wps_pin_requests") == 0) { + os_free(bss->wps_pin_requests); + bss->wps_pin_requests = os_strdup(pos); + } else if (os_strcmp(buf, "device_name") == 0) { + if (os_strlen(pos) > 32) { + wpa_printf(MSG_ERROR, "Line %d: Too long " + "device_name", line); + return 1; + } + os_free(bss->device_name); + bss->device_name = os_strdup(pos); + } else if (os_strcmp(buf, "manufacturer") == 0) { + if (os_strlen(pos) > 64) { + wpa_printf(MSG_ERROR, "Line %d: Too long manufacturer", + line); + return 1; + } + os_free(bss->manufacturer); + bss->manufacturer = os_strdup(pos); + } else if (os_strcmp(buf, "model_name") == 0) { + if (os_strlen(pos) > 32) { + wpa_printf(MSG_ERROR, "Line %d: Too long model_name", + line); + return 1; + } + os_free(bss->model_name); + bss->model_name = os_strdup(pos); + } else if (os_strcmp(buf, "model_number") == 0) { + if (os_strlen(pos) > 32) { + wpa_printf(MSG_ERROR, "Line %d: Too long model_number", + line); + return 1; + } + os_free(bss->model_number); + bss->model_number = os_strdup(pos); + } else if (os_strcmp(buf, "serial_number") == 0) { + if (os_strlen(pos) > 32) { + wpa_printf(MSG_ERROR, "Line %d: Too long serial_number", + line); + return 1; + } + os_free(bss->serial_number); + bss->serial_number = os_strdup(pos); + } else if (os_strcmp(buf, "device_type") == 0) { + if (wps_dev_type_str2bin(pos, bss->device_type)) + return 1; + } else if (os_strcmp(buf, "config_methods") == 0) { + os_free(bss->config_methods); + bss->config_methods = os_strdup(pos); + } else if (os_strcmp(buf, "os_version") == 0) { + if (hexstr2bin(pos, bss->os_version, 4)) { + wpa_printf(MSG_ERROR, "Line %d: invalid os_version", + line); + return 1; + } + } else if (os_strcmp(buf, "ap_pin") == 0) { + os_free(bss->ap_pin); + bss->ap_pin = os_strdup(pos); + } else if (os_strcmp(buf, "skip_cred_build") == 0) { + bss->skip_cred_build = atoi(pos); + } else if (os_strcmp(buf, "extra_cred") == 0) { + os_free(bss->extra_cred); + bss->extra_cred = (u8 *) os_readfile(pos, &bss->extra_cred_len); + if (bss->extra_cred == NULL) { + wpa_printf(MSG_ERROR, "Line %d: could not read Credentials from '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "wps_cred_processing") == 0) { + bss->wps_cred_processing = atoi(pos); + } else if (os_strcmp(buf, "ap_settings") == 0) { + os_free(bss->ap_settings); + bss->ap_settings = + (u8 *) os_readfile(pos, &bss->ap_settings_len); + if (bss->ap_settings == NULL) { + wpa_printf(MSG_ERROR, "Line %d: could not read AP Settings from '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "upnp_iface") == 0) { + os_free(bss->upnp_iface); + bss->upnp_iface = os_strdup(pos); + } else if (os_strcmp(buf, "friendly_name") == 0) { + os_free(bss->friendly_name); + bss->friendly_name = os_strdup(pos); + } else if (os_strcmp(buf, "manufacturer_url") == 0) { + os_free(bss->manufacturer_url); + bss->manufacturer_url = os_strdup(pos); + } else if (os_strcmp(buf, "model_description") == 0) { + os_free(bss->model_description); + bss->model_description = os_strdup(pos); + } else if (os_strcmp(buf, "model_url") == 0) { + os_free(bss->model_url); + bss->model_url = os_strdup(pos); + } else if (os_strcmp(buf, "upc") == 0) { + os_free(bss->upc); + bss->upc = os_strdup(pos); + } else if (os_strcmp(buf, "pbc_in_m1") == 0) { + bss->pbc_in_m1 = atoi(pos); + } else if (os_strcmp(buf, "server_id") == 0) { + os_free(bss->server_id); + bss->server_id = os_strdup(pos); #ifdef CONFIG_WPS_NFC - } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) { - bss->wps_nfc_dev_pw_id = atoi(pos); - if (bss->wps_nfc_dev_pw_id < 0x10 || - bss->wps_nfc_dev_pw_id > 0xffff) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "wps_nfc_dev_pw_id value", line); - errors++; - } - } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) { - wpabuf_free(bss->wps_nfc_dh_pubkey); - bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos); - } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) { - wpabuf_free(bss->wps_nfc_dh_privkey); - bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos); - } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) { - wpabuf_free(bss->wps_nfc_dev_pw); - bss->wps_nfc_dev_pw = hostapd_parse_bin(pos); + } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) { + bss->wps_nfc_dev_pw_id = atoi(pos); + if (bss->wps_nfc_dev_pw_id < 0x10 || + bss->wps_nfc_dev_pw_id > 0xffff) { + wpa_printf(MSG_ERROR, "Line %d: Invalid wps_nfc_dev_pw_id value", + line); + return 1; + } + bss->wps_nfc_pw_from_config = 1; + } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) { + wpabuf_free(bss->wps_nfc_dh_pubkey); + bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos); + bss->wps_nfc_pw_from_config = 1; + } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) { + wpabuf_free(bss->wps_nfc_dh_privkey); + bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos); + bss->wps_nfc_pw_from_config = 1; + } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) { + wpabuf_free(bss->wps_nfc_dev_pw); + bss->wps_nfc_dev_pw = hostapd_parse_bin(pos); + bss->wps_nfc_pw_from_config = 1; #endif /* CONFIG_WPS_NFC */ #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P_MANAGER - } else if (os_strcmp(buf, "manage_p2p") == 0) { - int manage = atoi(pos); - if (manage) - bss->p2p |= P2P_MANAGE; - else - bss->p2p &= ~P2P_MANAGE; - } else if (os_strcmp(buf, "allow_cross_connection") == 0) { - if (atoi(pos)) - bss->p2p |= P2P_ALLOW_CROSS_CONNECTION; - else - bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION; + } else if (os_strcmp(buf, "manage_p2p") == 0) { + if (atoi(pos)) + bss->p2p |= P2P_MANAGE; + else + bss->p2p &= ~P2P_MANAGE; + } else if (os_strcmp(buf, "allow_cross_connection") == 0) { + if (atoi(pos)) + bss->p2p |= P2P_ALLOW_CROSS_CONNECTION; + else + bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION; #endif /* CONFIG_P2P_MANAGER */ - } else if (os_strcmp(buf, "disassoc_low_ack") == 0) { - bss->disassoc_low_ack = atoi(pos); - } else if (os_strcmp(buf, "tdls_prohibit") == 0) { - int val = atoi(pos); - if (val) - bss->tdls |= TDLS_PROHIBIT; - else - bss->tdls &= ~TDLS_PROHIBIT; - } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) { - int val = atoi(pos); - if (val) - bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH; - else - bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH; + } else if (os_strcmp(buf, "disassoc_low_ack") == 0) { + bss->disassoc_low_ack = atoi(pos); + } else if (os_strcmp(buf, "tdls_prohibit") == 0) { + if (atoi(pos)) + bss->tdls |= TDLS_PROHIBIT; + else + bss->tdls &= ~TDLS_PROHIBIT; + } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) { + if (atoi(pos)) + bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH; + else + bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH; #ifdef CONFIG_RSN_TESTING - } else if (os_strcmp(buf, "rsn_testing") == 0) { - extern int rsn_testing; - rsn_testing = atoi(pos); + } else if (os_strcmp(buf, "rsn_testing") == 0) { + extern int rsn_testing; + rsn_testing = atoi(pos); #endif /* CONFIG_RSN_TESTING */ - } else if (os_strcmp(buf, "time_advertisement") == 0) { - bss->time_advertisement = atoi(pos); - } else if (os_strcmp(buf, "time_zone") == 0) { - size_t tz_len = os_strlen(pos); - if (tz_len < 4 || tz_len > 255) { - wpa_printf(MSG_DEBUG, "Line %d: invalid " - "time_zone", line); - errors++; - return errors; - } - os_free(bss->time_zone); - bss->time_zone = os_strdup(pos); - if (bss->time_zone == NULL) - errors++; + } else if (os_strcmp(buf, "time_advertisement") == 0) { + bss->time_advertisement = atoi(pos); + } else if (os_strcmp(buf, "time_zone") == 0) { + size_t tz_len = os_strlen(pos); + if (tz_len < 4 || tz_len > 255) { + wpa_printf(MSG_DEBUG, "Line %d: invalid time_zone", + line); + return 1; + } + os_free(bss->time_zone); + bss->time_zone = os_strdup(pos); + if (bss->time_zone == NULL) + return 1; #ifdef CONFIG_WNM - } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) { - bss->wnm_sleep_mode = atoi(pos); - } else if (os_strcmp(buf, "bss_transition") == 0) { - bss->bss_transition = atoi(pos); + } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) { + bss->wnm_sleep_mode = atoi(pos); + } else if (os_strcmp(buf, "bss_transition") == 0) { + bss->bss_transition = atoi(pos); #endif /* CONFIG_WNM */ #ifdef CONFIG_INTERWORKING - } else if (os_strcmp(buf, "interworking") == 0) { - bss->interworking = atoi(pos); - } else if (os_strcmp(buf, "access_network_type") == 0) { - bss->access_network_type = atoi(pos); - if (bss->access_network_type < 0 || - bss->access_network_type > 15) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "access_network_type", line); - errors++; - } - } else if (os_strcmp(buf, "internet") == 0) { - bss->internet = atoi(pos); - } else if (os_strcmp(buf, "asra") == 0) { - bss->asra = atoi(pos); - } else if (os_strcmp(buf, "esr") == 0) { - bss->esr = atoi(pos); - } else if (os_strcmp(buf, "uesa") == 0) { - bss->uesa = atoi(pos); - } else if (os_strcmp(buf, "venue_group") == 0) { - bss->venue_group = atoi(pos); - bss->venue_info_set = 1; - } else if (os_strcmp(buf, "venue_type") == 0) { - bss->venue_type = atoi(pos); - bss->venue_info_set = 1; - } else if (os_strcmp(buf, "hessid") == 0) { - if (hwaddr_aton(pos, bss->hessid)) { - wpa_printf(MSG_ERROR, "Line %d: invalid " - "hessid", line); - errors++; - } - } else if (os_strcmp(buf, "roaming_consortium") == 0) { - if (parse_roaming_consortium(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "venue_name") == 0) { - if (parse_venue_name(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "network_auth_type") == 0) { - u8 auth_type; - u16 redirect_url_len; - if (hexstr2bin(pos, &auth_type, 1)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "network_auth_type '%s'", - line, pos); - errors++; - return errors; - } - if (auth_type == 0 || auth_type == 2) - redirect_url_len = os_strlen(pos + 2); - else - redirect_url_len = 0; - os_free(bss->network_auth_type); - bss->network_auth_type = - os_malloc(redirect_url_len + 3 + 1); - if (bss->network_auth_type == NULL) { - errors++; - return errors; - } - *bss->network_auth_type = auth_type; - WPA_PUT_LE16(bss->network_auth_type + 1, - redirect_url_len); - if (redirect_url_len) - os_memcpy(bss->network_auth_type + 3, - pos + 2, redirect_url_len); - bss->network_auth_type_len = 3 + redirect_url_len; - } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) { - if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1)) - { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "ipaddr_type_availability '%s'", - line, pos); - bss->ipaddr_type_configured = 0; - errors++; - return errors; - } - bss->ipaddr_type_configured = 1; - } else if (os_strcmp(buf, "domain_name") == 0) { - int j, num_domains, domain_len, domain_list_len = 0; - char *tok_start, *tok_prev; - u8 *domain_list, *domain_ptr; - - domain_list_len = os_strlen(pos) + 1; - domain_list = os_malloc(domain_list_len); - if (domain_list == NULL) { - errors++; - return errors; - } - - domain_ptr = domain_list; - tok_prev = pos; - num_domains = 1; - while ((tok_prev = os_strchr(tok_prev, ','))) { - num_domains++; - tok_prev++; - } - tok_prev = pos; - for (j = 0; j < num_domains; j++) { - tok_start = os_strchr(tok_prev, ','); - if (tok_start) { - domain_len = tok_start - tok_prev; - *domain_ptr = domain_len; - os_memcpy(domain_ptr + 1, tok_prev, - domain_len); - domain_ptr += domain_len + 1; - tok_prev = ++tok_start; - } else { - domain_len = os_strlen(tok_prev); - *domain_ptr = domain_len; - os_memcpy(domain_ptr + 1, tok_prev, - domain_len); - domain_ptr += domain_len + 1; - } + } else if (os_strcmp(buf, "interworking") == 0) { + bss->interworking = atoi(pos); + } else if (os_strcmp(buf, "access_network_type") == 0) { + bss->access_network_type = atoi(pos); + if (bss->access_network_type < 0 || + bss->access_network_type > 15) { + wpa_printf(MSG_ERROR, + "Line %d: invalid access_network_type", + line); + return 1; + } + } else if (os_strcmp(buf, "internet") == 0) { + bss->internet = atoi(pos); + } else if (os_strcmp(buf, "asra") == 0) { + bss->asra = atoi(pos); + } else if (os_strcmp(buf, "esr") == 0) { + bss->esr = atoi(pos); + } else if (os_strcmp(buf, "uesa") == 0) { + bss->uesa = atoi(pos); + } else if (os_strcmp(buf, "venue_group") == 0) { + bss->venue_group = atoi(pos); + bss->venue_info_set = 1; + } else if (os_strcmp(buf, "venue_type") == 0) { + bss->venue_type = atoi(pos); + bss->venue_info_set = 1; + } else if (os_strcmp(buf, "hessid") == 0) { + if (hwaddr_aton(pos, bss->hessid)) { + wpa_printf(MSG_ERROR, "Line %d: invalid hessid", line); + return 1; + } + } else if (os_strcmp(buf, "roaming_consortium") == 0) { + if (parse_roaming_consortium(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "venue_name") == 0) { + if (parse_venue_name(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "network_auth_type") == 0) { + u8 auth_type; + u16 redirect_url_len; + if (hexstr2bin(pos, &auth_type, 1)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid network_auth_type '%s'", + line, pos); + return 1; + } + if (auth_type == 0 || auth_type == 2) + redirect_url_len = os_strlen(pos + 2); + else + redirect_url_len = 0; + os_free(bss->network_auth_type); + bss->network_auth_type = os_malloc(redirect_url_len + 3 + 1); + if (bss->network_auth_type == NULL) + return 1; + *bss->network_auth_type = auth_type; + WPA_PUT_LE16(bss->network_auth_type + 1, redirect_url_len); + if (redirect_url_len) + os_memcpy(bss->network_auth_type + 3, pos + 2, + redirect_url_len); + bss->network_auth_type_len = 3 + redirect_url_len; + } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) { + if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid ipaddr_type_availability '%s'", + line, pos); + bss->ipaddr_type_configured = 0; + return 1; + } + bss->ipaddr_type_configured = 1; + } else if (os_strcmp(buf, "domain_name") == 0) { + int j, num_domains, domain_len, domain_list_len = 0; + char *tok_start, *tok_prev; + u8 *domain_list, *domain_ptr; + + domain_list_len = os_strlen(pos) + 1; + domain_list = os_malloc(domain_list_len); + if (domain_list == NULL) + return 1; + + domain_ptr = domain_list; + tok_prev = pos; + num_domains = 1; + while ((tok_prev = os_strchr(tok_prev, ','))) { + num_domains++; + tok_prev++; + } + tok_prev = pos; + for (j = 0; j < num_domains; j++) { + tok_start = os_strchr(tok_prev, ','); + if (tok_start) { + domain_len = tok_start - tok_prev; + *domain_ptr = domain_len; + os_memcpy(domain_ptr + 1, tok_prev, domain_len); + domain_ptr += domain_len + 1; + tok_prev = ++tok_start; + } else { + domain_len = os_strlen(tok_prev); + *domain_ptr = domain_len; + os_memcpy(domain_ptr + 1, tok_prev, domain_len); + domain_ptr += domain_len + 1; } + } - os_free(bss->domain_name); - bss->domain_name = domain_list; - bss->domain_name_len = domain_list_len; - } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) { - if (parse_3gpp_cell_net(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "nai_realm") == 0) { - if (parse_nai_realm(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "gas_frag_limit") == 0) { - bss->gas_frag_limit = atoi(pos); - } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { - bss->gas_comeback_delay = atoi(pos); + os_free(bss->domain_name); + bss->domain_name = domain_list; + bss->domain_name_len = domain_list_len; + } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) { + if (parse_3gpp_cell_net(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "nai_realm") == 0) { + if (parse_nai_realm(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "gas_frag_limit") == 0) { + bss->gas_frag_limit = atoi(pos); + } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { + bss->gas_comeback_delay = atoi(pos); + } else if (os_strcmp(buf, "qos_map_set") == 0) { + if (parse_qos_map_set(bss, pos, line) < 0) + return 1; #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_RADIUS_TEST - } else if (os_strcmp(buf, "dump_msk_file") == 0) { - os_free(bss->dump_msk_file); - bss->dump_msk_file = os_strdup(pos); + } else if (os_strcmp(buf, "dump_msk_file") == 0) { + os_free(bss->dump_msk_file); + bss->dump_msk_file = os_strdup(pos); #endif /* CONFIG_RADIUS_TEST */ #ifdef CONFIG_HS20 - } else if (os_strcmp(buf, "hs20") == 0) { - bss->hs20 = atoi(pos); - } else if (os_strcmp(buf, "disable_dgaf") == 0) { - bss->disable_dgaf = atoi(pos); - } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) { - if (hs20_parse_oper_friendly_name(bss, pos, line) < 0) - errors++; - } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) { - if (hs20_parse_wan_metrics(bss, pos, line) < 0) { - errors++; - return errors; - } - } else if (os_strcmp(buf, "hs20_conn_capab") == 0) { - if (hs20_parse_conn_capab(bss, pos, line) < 0) { - errors++; - return errors; - } - } else if (os_strcmp(buf, "hs20_operating_class") == 0) { - u8 *oper_class; - size_t oper_class_len; - oper_class_len = os_strlen(pos); - if (oper_class_len < 2 || (oper_class_len & 0x01)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "hs20_operating_class '%s'", - line, pos); - errors++; - return errors; - } - oper_class_len /= 2; - oper_class = os_malloc(oper_class_len); - if (oper_class == NULL) { - errors++; - return errors; - } - if (hexstr2bin(pos, oper_class, oper_class_len)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "hs20_operating_class '%s'", - line, pos); - os_free(oper_class); - errors++; - return errors; - } - os_free(bss->hs20_operating_class); - bss->hs20_operating_class = oper_class; - bss->hs20_operating_class_len = oper_class_len; + } else if (os_strcmp(buf, "hs20") == 0) { + bss->hs20 = atoi(pos); + } else if (os_strcmp(buf, "disable_dgaf") == 0) { + bss->disable_dgaf = atoi(pos); + } else if (os_strcmp(buf, "proxy_arp") == 0) { + bss->proxy_arp = atoi(pos); + } else if (os_strcmp(buf, "osen") == 0) { + bss->osen = atoi(pos); + } else if (os_strcmp(buf, "anqp_domain_id") == 0) { + bss->anqp_domain_id = atoi(pos); + } else if (os_strcmp(buf, "hs20_deauth_req_timeout") == 0) { + bss->hs20_deauth_req_timeout = atoi(pos); + } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) { + if (hs20_parse_oper_friendly_name(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) { + if (hs20_parse_wan_metrics(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "hs20_conn_capab") == 0) { + if (hs20_parse_conn_capab(bss, pos, line) < 0) { + return 1; + } + } else if (os_strcmp(buf, "hs20_operating_class") == 0) { + u8 *oper_class; + size_t oper_class_len; + oper_class_len = os_strlen(pos); + if (oper_class_len < 2 || (oper_class_len & 0x01)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid hs20_operating_class '%s'", + line, pos); + return 1; + } + oper_class_len /= 2; + oper_class = os_malloc(oper_class_len); + if (oper_class == NULL) + return 1; + if (hexstr2bin(pos, oper_class, oper_class_len)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid hs20_operating_class '%s'", + line, pos); + os_free(oper_class); + return 1; + } + os_free(bss->hs20_operating_class); + bss->hs20_operating_class = oper_class; + bss->hs20_operating_class_len = oper_class_len; + } else if (os_strcmp(buf, "hs20_icon") == 0) { + if (hs20_parse_icon(bss, pos) < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_icon '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "osu_ssid") == 0) { + if (hs20_parse_osu_ssid(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "osu_server_uri") == 0) { + if (hs20_parse_osu_server_uri(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "osu_friendly_name") == 0) { + if (hs20_parse_osu_friendly_name(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "osu_nai") == 0) { + if (hs20_parse_osu_nai(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "osu_method_list") == 0) { + if (hs20_parse_osu_method_list(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "osu_icon") == 0) { + if (hs20_parse_osu_icon(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "osu_service_desc") == 0) { + if (hs20_parse_osu_service_desc(bss, pos, line) < 0) + return 1; + } else if (os_strcmp(buf, "subscr_remediation_url") == 0) { + os_free(bss->subscr_remediation_url); + bss->subscr_remediation_url = os_strdup(pos); + } else if (os_strcmp(buf, "subscr_remediation_method") == 0) { + bss->subscr_remediation_method = atoi(pos); #endif /* CONFIG_HS20 */ - } else if (os_strcmp(buf, "vendor_elements") == 0) { - struct wpabuf *elems; - size_t len = os_strlen(pos); - if (len & 0x01) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "vendor_elements '%s'", line, pos); - return 1; - } - len /= 2; - if (len == 0) { - wpabuf_free(bss->vendor_elements); - bss->vendor_elements = NULL; - return 0; - } - - elems = wpabuf_alloc(len); - if (elems == NULL) - return 1; - - if (hexstr2bin(pos, wpabuf_put(elems, len), len)) { - wpabuf_free(elems); - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "vendor_elements '%s'", line, pos); - return 1; - } - +#ifdef CONFIG_TESTING_OPTIONS +#define PARSE_TEST_PROBABILITY(_val) \ + } else if (os_strcmp(buf, #_val) == 0) { \ + char *end; \ + \ + conf->_val = strtod(pos, &end); \ + if (*end || conf->_val < 0.0 || \ + conf->_val > 1.0) { \ + wpa_printf(MSG_ERROR, \ + "Line %d: Invalid value '%s'", \ + line, pos); \ + return 1; \ + } + PARSE_TEST_PROBABILITY(ignore_probe_probability) + PARSE_TEST_PROBABILITY(ignore_auth_probability) + PARSE_TEST_PROBABILITY(ignore_assoc_probability) + PARSE_TEST_PROBABILITY(ignore_reassoc_probability) + PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability) + } else if (os_strcmp(buf, "bss_load_test") == 0) { + WPA_PUT_LE16(bss->bss_load_test, atoi(pos)); + pos = os_strchr(pos, ':'); + if (pos == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Invalid bss_load_test", + line); + return 1; + } + pos++; + bss->bss_load_test[2] = atoi(pos); + pos = os_strchr(pos, ':'); + if (pos == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Invalid bss_load_test", + line); + return 1; + } + pos++; + WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos)); + bss->bss_load_test_set = 1; + } else if (os_strcmp(buf, "radio_measurements") == 0) { + bss->radio_measurements = atoi(pos); +#endif /* CONFIG_TESTING_OPTIONS */ + } else if (os_strcmp(buf, "vendor_elements") == 0) { + struct wpabuf *elems; + size_t len = os_strlen(pos); + if (len & 0x01) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid vendor_elements '%s'", + line, pos); + return 1; + } + len /= 2; + if (len == 0) { wpabuf_free(bss->vendor_elements); - bss->vendor_elements = elems; - } else { - wpa_printf(MSG_ERROR, "Line %d: unknown configuration " - "item '%s'", line, buf); - errors++; + bss->vendor_elements = NULL; + return 0; } - } - return errors; -} + elems = wpabuf_alloc(len); + if (elems == NULL) + return 1; + if (hexstr2bin(pos, wpabuf_put(elems, len), len)) { + wpabuf_free(elems); + wpa_printf(MSG_ERROR, + "Line %d: Invalid vendor_elements '%s'", + line, pos); + return 1; + } -static void hostapd_set_security_params(struct hostapd_bss_config *bss) -{ - int pairwise; - - if (bss->individual_wep_key_len == 0) { - /* individual keys are not use; can use key idx0 for - * broadcast keys */ - bss->broadcast_key_idx_min = 0; - } - - /* Select group cipher based on the enabled pairwise cipher - * suites */ - pairwise = 0; - if (bss->wpa & 1) - pairwise |= bss->wpa_pairwise; - if (bss->wpa & 2) { - if (bss->rsn_pairwise == 0) - bss->rsn_pairwise = bss->wpa_pairwise; - pairwise |= bss->rsn_pairwise; - } - if (pairwise & WPA_CIPHER_TKIP) - bss->wpa_group = WPA_CIPHER_TKIP; - else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == - WPA_CIPHER_GCMP) - bss->wpa_group = WPA_CIPHER_GCMP; - else - bss->wpa_group = WPA_CIPHER_CCMP; - - bss->radius->auth_server = bss->radius->auth_servers; - bss->radius->acct_server = bss->radius->acct_servers; - - if (bss->wpa && bss->ieee802_1x) { - bss->ssid.security_policy = SECURITY_WPA; - } else if (bss->wpa) { - bss->ssid.security_policy = SECURITY_WPA_PSK; - } else if (bss->ieee802_1x) { - int cipher = WPA_CIPHER_NONE; - bss->ssid.security_policy = SECURITY_IEEE_802_1X; - bss->ssid.wep.default_len = bss->default_wep_key_len; - if (bss->default_wep_key_len) - cipher = bss->default_wep_key_len >= 13 ? - WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40; - bss->wpa_group = cipher; - bss->wpa_pairwise = cipher; - bss->rsn_pairwise = cipher; - } else if (bss->ssid.wep.keys_set) { - int cipher = WPA_CIPHER_WEP40; - if (bss->ssid.wep.len[0] >= 13) - cipher = WPA_CIPHER_WEP104; - bss->ssid.security_policy = SECURITY_STATIC_WEP; - bss->wpa_group = cipher; - bss->wpa_pairwise = cipher; - bss->rsn_pairwise = cipher; + wpabuf_free(bss->vendor_elements); + bss->vendor_elements = elems; + } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) { + bss->sae_anti_clogging_threshold = atoi(pos); + } else if (os_strcmp(buf, "sae_groups") == 0) { + if (hostapd_parse_intlist(&bss->sae_groups, pos)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid sae_groups value '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "local_pwr_constraint") == 0) { + int val = atoi(pos); + if (val < 0 || val > 255) { + wpa_printf(MSG_ERROR, "Line %d: Invalid local_pwr_constraint %d (expected 0..255)", + line, val); + return 1; + } + conf->local_pwr_constraint = val; + } else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) { + conf->spectrum_mgmt_required = atoi(pos); + } else if (os_strcmp(buf, "wowlan_triggers") == 0) { + os_free(bss->wowlan_triggers); + bss->wowlan_triggers = os_strdup(pos); } else { - bss->ssid.security_policy = SECURITY_PLAINTEXT; - bss->wpa_group = WPA_CIPHER_NONE; - bss->wpa_pairwise = WPA_CIPHER_NONE; - bss->rsn_pairwise = WPA_CIPHER_NONE; + wpa_printf(MSG_ERROR, + "Line %d: unknown configuration item '%s'", + line, buf); + return 1; } + + return 0; } @@ -3016,7 +3295,6 @@ static void hostapd_set_security_params(struct hostapd_bss_config *bss) struct hostapd_config * hostapd_config_read(const char *fname) { struct hostapd_config *conf; - struct hostapd_bss_config *bss; FILE *f; char buf[512], *pos; int line = 0; @@ -3045,9 +3323,11 @@ struct hostapd_config * hostapd_config_read(const char *fname) return NULL; } - bss = conf->last_bss = conf->bss; + conf->last_bss = conf->bss[0]; while (fgets(buf, sizeof(buf), f)) { + struct hostapd_bss_config *bss; + bss = conf->last_bss; line++; @@ -3079,9 +3359,9 @@ struct hostapd_config * hostapd_config_read(const char *fname) fclose(f); for (i = 0; i < conf->num_bss; i++) - hostapd_set_security_params(&conf->bss[i]); + hostapd_set_security_params(conf->bss[i], 1); - if (hostapd_config_check(conf)) + if (hostapd_config_check(conf, 1)) errors++; #ifndef WPA_IGNORE_CONFIG_ERRORS @@ -3111,9 +3391,9 @@ int hostapd_set_iface(struct hostapd_config *conf, } for (i = 0; i < conf->num_bss; i++) - hostapd_set_security_params(&conf->bss[i]); + hostapd_set_security_params(conf->bss[i], 0); - if (hostapd_config_check(conf)) { + if (hostapd_config_check(conf, 0)) { wpa_printf(MSG_ERROR, "Configuration check failed"); return -1; } diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c index 3c9071c..86f1aa6 100644 --- a/contrib/wpa/hostapd/ctrl_iface.c +++ b/contrib/wpa/hostapd/ctrl_iface.c @@ -1,6 +1,6 @@ /* * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -10,6 +10,11 @@ #ifndef CONFIG_NATIVE_WINDOWS +#ifdef CONFIG_TESTING_OPTIONS +#include <net/ethernet.h> +#include <netinet/ip.h> +#endif /* CONFIG_TESTING_OPTIONS */ + #include <sys/un.h> #include <sys/stat.h> #include <stddef.h> @@ -18,8 +23,11 @@ #include "utils/eloop.h" #include "common/version.h" #include "common/ieee802_11_defs.h" +#include "crypto/tls.h" #include "drivers/driver.h" #include "radius/radius_client.h" +#include "radius/radius_server.h" +#include "l2_packet/l2_packet.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/ieee802_1x.h" @@ -29,6 +37,10 @@ #include "ap/wps_hostapd.h" #include "ap/ctrl_iface_ap.h" #include "ap/ap_drv_ops.h" +#include "ap/hs20.h" +#include "ap/wnm_ap.h" +#include "ap/wpa_auth.h" +#include "ap/beacon.h" #include "wps/wps_defs.h" #include "wps/wps.h" #include "config_file.h" @@ -81,15 +93,15 @@ static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", + (u8 *) from->sun_path, + fromlen - + offsetof(struct sockaddr_un, sun_path)); if (prev == NULL) hapd->ctrl_dst = dst->next; else prev->next = dst->next; os_free(dst); - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); return 0; } prev = dst; @@ -236,14 +248,14 @@ static int hostapd_ctrl_iface_wps_check_pin( if (!wps_pin_valid(pin_val)) { wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); - if (ret < 0 || (size_t) ret >= buflen) + if (os_snprintf_error(buflen, ret)) return -1; return ret; } } ret = os_snprintf(buf, buflen, "%s", pin); - if (ret < 0 || (size_t) ret >= buflen) + if (os_snprintf_error(buflen, ret)) return -1; return ret; @@ -352,6 +364,116 @@ static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd, return -1; } + + +static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd, + char *cmd, char *reply, + size_t max_len) +{ + struct wpabuf *buf; + int res; + char *pos; + int ndef; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (os_strcmp(cmd, "WPS") == 0) + ndef = 0; + else if (os_strcmp(cmd, "NDEF") == 0) + ndef = 1; + else + return -1; + + if (os_strcmp(pos, "WPS-CR") == 0) + buf = hostapd_wps_nfc_hs_cr(hapd, ndef); + else + buf = NULL; + if (buf == NULL) + return -1; + + res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), + wpabuf_len(buf)); + reply[res++] = '\n'; + reply[res] = '\0'; + + wpabuf_free(buf); + + return res; +} + + +static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd, + char *cmd) +{ + size_t len; + struct wpabuf *req, *sel; + int ret; + char *pos, *role, *type, *pos2; + + role = cmd; + pos = os_strchr(role, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + type = pos; + pos = os_strchr(type, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + pos2 = os_strchr(pos, ' '); + if (pos2 == NULL) + return -1; + *pos2++ = '\0'; + + len = os_strlen(pos); + if (len & 0x01) + return -1; + len /= 2; + + req = wpabuf_alloc(len); + if (req == NULL) + return -1; + if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) { + wpabuf_free(req); + return -1; + } + + len = os_strlen(pos2); + if (len & 0x01) { + wpabuf_free(req); + return -1; + } + len /= 2; + + sel = wpabuf_alloc(len); + if (sel == NULL) { + wpabuf_free(req); + return -1; + } + if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) { + wpabuf_free(req); + wpabuf_free(sel); + return -1; + } + + if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) { + ret = hostapd_wps_nfc_report_handover(hapd, req, sel); + } else { + wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover " + "reported: role=%s type=%s", role, type); + ret = -1; + } + wpabuf_free(req); + wpabuf_free(sel); + + return ret; +} + #endif /* CONFIG_WPS_NFC */ @@ -433,8 +555,253 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); } + + +static const char * pbc_status_str(enum pbc_status status) +{ + switch (status) { + case WPS_PBC_STATUS_DISABLE: + return "Disabled"; + case WPS_PBC_STATUS_ACTIVE: + return "Active"; + case WPS_PBC_STATUS_TIMEOUT: + return "Timed-out"; + case WPS_PBC_STATUS_OVERLAP: + return "Overlap"; + default: + return "Unknown"; + } +} + + +static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd, + char *buf, size_t buflen) +{ + int ret; + char *pos, *end; + + pos = buf; + end = buf + buflen; + + ret = os_snprintf(pos, end - pos, "PBC Status: %s\n", + pbc_status_str(hapd->wps_stats.pbc_status)); + + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n", + (hapd->wps_stats.status == WPS_STATUS_SUCCESS ? + "Success": + (hapd->wps_stats.status == WPS_STATUS_FAILURE ? + "Failed" : "None"))); + + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + + /* If status == Failure - Add possible Reasons */ + if(hapd->wps_stats.status == WPS_STATUS_FAILURE && + hapd->wps_stats.failure_reason > 0) { + ret = os_snprintf(pos, end - pos, + "Failure Reason: %s\n", + wps_ei_str(hapd->wps_stats.failure_reason)); + + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + if (hapd->wps_stats.status) { + ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n", + MAC2STR(hapd->wps_stats.peer_addr)); + + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + return pos - buf; +} + #endif /* CONFIG_WPS */ +#ifdef CONFIG_HS20 + +static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + const char *url; + + if (hwaddr_aton(cmd, addr)) + return -1; + url = cmd + 17; + if (*url == '\0') { + url = NULL; + } else { + if (*url != ' ') + return -1; + url++; + if (*url == '\0') + url = NULL; + } + + return hs20_send_wnm_notification(hapd, addr, 1, url); +} + + +static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + int code, reauth_delay, ret; + const char *pos; + size_t url_len; + struct wpabuf *req; + + /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */ + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + pos++; + code = atoi(pos); + + pos = os_strchr(pos, ' '); + if (pos == NULL) + return -1; + pos++; + reauth_delay = atoi(pos); + + url_len = 0; + pos = os_strchr(pos, ' '); + if (pos) { + pos++; + url_len = os_strlen(pos); + } + + req = wpabuf_alloc(4 + url_len); + if (req == NULL) + return -1; + wpabuf_put_u8(req, code); + wpabuf_put_le16(req, reauth_delay); + wpabuf_put_u8(req, url_len); + if (pos) + wpabuf_put_data(req, pos, url_len); + + wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR + " to indicate imminent deauthentication (code=%d " + "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay); + ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req); + wpabuf_free(req); + return ret; +} + +#endif /* CONFIG_HS20 */ + + +#ifdef CONFIG_INTERWORKING + +static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd, + const char *cmd) +{ + u8 qos_map_set[16 + 2 * 21], count = 0; + const char *pos = cmd; + int val, ret; + + for (;;) { + if (count == sizeof(qos_map_set)) { + wpa_printf(MSG_ERROR, "Too many qos_map_set parameters"); + return -1; + } + + val = atoi(pos); + if (val < 0 || val > 255) { + wpa_printf(MSG_INFO, "Invalid QoS Map Set"); + return -1; + } + + qos_map_set[count++] = val; + pos = os_strchr(pos, ','); + if (!pos) + break; + pos++; + } + + if (count < 16 || count & 1) { + wpa_printf(MSG_INFO, "Invalid QoS Map Set"); + return -1; + } + + ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count); + if (ret) { + wpa_printf(MSG_INFO, "Failed to set QoS Map Set"); + return -1; + } + + os_memcpy(hapd->conf->qos_map_set, qos_map_set, count); + hapd->conf->qos_map_set_len = count; + + return 0; +} + + +static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + struct sta_info *sta; + struct wpabuf *buf; + u8 *qos_map_set = hapd->conf->qos_map_set; + u8 qos_map_set_len = hapd->conf->qos_map_set_len; + int ret; + + if (!qos_map_set_len) { + wpa_printf(MSG_INFO, "QoS Map Set is not set"); + return -1; + } + + if (hwaddr_aton(cmd, addr)) + return -1; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " + "for QoS Map Configuration message", + MAC2STR(addr)); + return -1; + } + + if (!sta->qos_map_enabled) { + wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate " + "support for QoS Map", MAC2STR(addr)); + return -1; + } + + buf = wpabuf_alloc(2 + 2 + qos_map_set_len); + if (buf == NULL) + return -1; + + wpabuf_put_u8(buf, WLAN_ACTION_QOS); + wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG); + + /* QoS Map Set Element */ + wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET); + wpabuf_put_u8(buf, qos_map_set_len); + wpabuf_put_data(buf, qos_map_set, qos_map_set_len); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + + return ret; +} + +#endif /* CONFIG_INTERWORKING */ + #ifdef CONFIG_WNM @@ -442,9 +809,8 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, const char *cmd) { u8 addr[ETH_ALEN]; - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; int disassoc_timer; + struct sta_info *sta; if (hwaddr_aton(cmd, addr)) return -1; @@ -452,31 +818,15 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, return -1; disassoc_timer = atoi(cmd + 17); - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for disassociation imminent message", + MAC2STR(addr)); return -1; } - return 0; + return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); } @@ -484,50 +834,222 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, const char *cmd) { u8 addr[ETH_ALEN]; - const char *url; - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - size_t url_len; + const char *url, *timerstr; + int disassoc_timer; + struct sta_info *sta; if (hwaddr_aton(cmd, addr)) return -1; - url = cmd + 17; - if (*url != ' ') + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for ESS disassociation imminent message", + MAC2STR(addr)); return -1; - url++; - url_len = os_strlen(url); - if (url_len > 255) + } + + timerstr = cmd + 17; + if (*timerstr != ' ') + return -1; + timerstr++; + disassoc_timer = atoi(timerstr); + if (disassoc_timer < 0 || disassoc_timer > 65535) return -1; - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); - mgmt->u.action.u.bss_tm_req.validity_interval = 0; + url = os_strchr(timerstr, ' '); + if (url == NULL) + return -1; + url++; - pos = mgmt->u.action.u.bss_tm_req.variable; + return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); +} - /* Session Information URL */ - *pos++ = url_len; - os_memcpy(pos, url, url_len); - pos += url_len; - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); +static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + const char *pos, *end; + int disassoc_timer = 0; + struct sta_info *sta; + u8 req_mode = 0, valid_int = 0x01; + u8 bss_term_dur[12]; + char *url = NULL; + int ret; + u8 nei_rep[1000]; + u8 *nei_pos = nei_rep; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); return -1; } - return 0; + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for BSS TM Request message", + MAC2STR(addr)); + return -1; + } + + pos = os_strstr(cmd, " disassoc_timer="); + if (pos) { + pos += 16; + disassoc_timer = atoi(pos); + if (disassoc_timer < 0 || disassoc_timer > 65535) { + wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); + return -1; + } + } + + pos = os_strstr(cmd, " valid_int="); + if (pos) { + pos += 11; + valid_int = atoi(pos); + } + + pos = os_strstr(cmd, " bss_term="); + if (pos) { + pos += 10; + req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; + /* TODO: TSF configurable/learnable */ + bss_term_dur[0] = 4; /* Subelement ID */ + bss_term_dur[1] = 10; /* Length */ + os_memset(bss_term_dur, 2, 8); + end = os_strchr(pos, ','); + if (end == NULL) { + wpa_printf(MSG_DEBUG, "Invalid bss_term data"); + return -1; + } + end++; + WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); + } + + + /* + * BSS Transition Candidate List Entries - Neighbor Report elements + * neighbor=<BSSID>,<BSSID Information>,<Operating Class>, + * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>] + */ + pos = cmd; + while (pos) { + u8 *nei_start; + long int val; + char *endptr, *tmp; + + pos = os_strstr(pos, " neighbor="); + if (!pos) + break; + if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) { + wpa_printf(MSG_DEBUG, + "Not enough room for additional neighbor"); + return -1; + } + pos += 10; + + nei_start = nei_pos; + *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT; + nei_pos++; /* length to be filled in */ + + if (hwaddr_aton(pos, nei_pos)) { + wpa_printf(MSG_DEBUG, "Invalid BSSID"); + return -1; + } + nei_pos += ETH_ALEN; + pos += 17; + if (*pos != ',') { + wpa_printf(MSG_DEBUG, "Missing BSSID Information"); + return -1; + } + pos++; + + val = strtol(pos, &endptr, 0); + WPA_PUT_LE32(nei_pos, val); + nei_pos += 4; + if (*endptr != ',') { + wpa_printf(MSG_DEBUG, "Missing Operating Class"); + return -1; + } + pos = endptr + 1; + + *nei_pos++ = atoi(pos); /* Operating Class */ + pos = os_strchr(pos, ','); + if (pos == NULL) { + wpa_printf(MSG_DEBUG, "Missing Channel Number"); + return -1; + } + pos++; + + *nei_pos++ = atoi(pos); /* Channel Number */ + pos = os_strchr(pos, ','); + if (pos == NULL) { + wpa_printf(MSG_DEBUG, "Missing PHY Type"); + return -1; + } + pos++; + + *nei_pos++ = atoi(pos); /* PHY Type */ + end = os_strchr(pos, ' '); + tmp = os_strchr(pos, ','); + if (tmp && (!end || tmp < end)) { + /* Optional Subelements (hexdump) */ + size_t len; + + pos = tmp + 1; + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) { + wpa_printf(MSG_DEBUG, + "Not enough room for neighbor subelements"); + return -1; + } + if (len & 0x01 || + hexstr2bin(pos, nei_pos, len / 2) < 0) { + wpa_printf(MSG_DEBUG, + "Invalid neighbor subelement info"); + return -1; + } + nei_pos += len / 2; + pos = end; + } + + nei_start[1] = nei_pos - nei_start - 2; + } + + pos = os_strstr(cmd, " url="); + if (pos) { + size_t len; + pos += 5; + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + url = os_malloc(len + 1); + if (url == NULL) + return -1; + os_memcpy(url, pos, len); + url[len] = '\0'; + req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; + } + + if (os_strstr(cmd, " pref=1")) + req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; + if (os_strstr(cmd, " abridged=1")) + req_mode |= WNM_BSS_TM_REQ_ABRIDGED; + if (os_strstr(cmd, " disassoc_imminent=1")) + req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; + + ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, + valid_int, bss_term_dur, url, + nei_pos > nei_rep ? nei_rep : NULL, + nei_pos - nei_rep); + os_free(url); + return ret; } #endif /* CONFIG_WNM */ @@ -547,7 +1069,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, MAC2STR(hapd->own_addr), wpa_ssid_txt(hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len)); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; @@ -556,7 +1078,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, hapd->conf->wps_state == 0 ? "disabled" : (hapd->conf->wps_state == 1 ? "not configured" : "configured")); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; @@ -564,7 +1086,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, hapd->conf->ssid.wpa_passphrase) { ret = os_snprintf(pos, end - pos, "passphrase=%s\n", hapd->conf->ssid.wpa_passphrase); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } @@ -576,7 +1098,7 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, wpa_snprintf_hex(hex, sizeof(hex), hapd->conf->ssid.wpa_psk->psk, PMK_LEN); ret = os_snprintf(pos, end - pos, "psk=%s\n", hex); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } @@ -584,134 +1106,127 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) { ret = os_snprintf(pos, end - pos, "key_mgmt="); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { ret = os_snprintf(pos, end - pos, "WPA-PSK "); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { ret = os_snprintf(pos, end - pos, "WPA-EAP "); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } #ifdef CONFIG_IEEE80211R if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { ret = os_snprintf(pos, end - pos, "FT-PSK "); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { ret = os_snprintf(pos, end - pos, "FT-EAP "); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } +#ifdef CONFIG_SAE + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { + ret = os_snprintf(pos, end - pos, "FT-SAE "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SAE */ #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 "); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_SAE + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { + ret = os_snprintf(pos, end - pos, "SAE "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SAE */ + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { + ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + if (hapd->conf->wpa_key_mgmt & + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { + ret = os_snprintf(pos, end - pos, + "WPA-EAP-SUITE-B-192 "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } ret = os_snprintf(pos, end - pos, "\n"); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } - if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) { - ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n"); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } else if (hapd->conf->wpa && - hapd->conf->wpa_group == WPA_CIPHER_GCMP) { - ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n"); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } else if (hapd->conf->wpa && - hapd->conf->wpa_group == WPA_CIPHER_TKIP) { - ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n"); - if (ret < 0 || ret >= end - pos) + if (hapd->conf->wpa) { + ret = os_snprintf(pos, end - pos, "group_cipher=%s\n", + wpa_cipher_txt(hapd->conf->wpa_group)); + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) { ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher="); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; - if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) { - ret = os_snprintf(pos, end - pos, "CCMP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) { - ret = os_snprintf(pos, end - pos, "GCMP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) { - ret = os_snprintf(pos, end - pos, "TKIP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } + ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise, + " "); + if (ret < 0) + return pos - buf; + pos += ret; ret = os_snprintf(pos, end - pos, "\n"); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) { ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher="); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; - if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) { - ret = os_snprintf(pos, end - pos, "CCMP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) { - ret = os_snprintf(pos, end - pos, "GCMP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } - if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) { - ret = os_snprintf(pos, end - pos, "TKIP "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - } + ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise, + " "); + if (ret < 0) + return pos - buf; + pos += ret; ret = os_snprintf(pos, end - pos, "\n"); - if (ret < 0 || ret >= end - pos) + if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; } @@ -752,6 +1267,10 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) wps_testing_dummy_cred = atoi(value); wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", wps_testing_dummy_cred); + } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) { + wps_corrupt_pkhash = atoi(value); + wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", + wps_corrupt_pkhash); #endif /* CONFIG_WPS_TESTING */ #ifdef CONFIG_INTERWORKING } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) { @@ -761,8 +1280,44 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) else hapd->gas_frag_limit = val; #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { + hapd->ext_mgmt_frame_handling = atoi(value); + } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { + hapd->ext_eapol_frame_io = atoi(value); +#endif /* CONFIG_TESTING_OPTIONS */ } else { + struct sta_info *sta; + int vlan_id; + ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); + if (ret) + return ret; + + if (os_strcasecmp(cmd, "deny_mac_file") == 0) { + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (hostapd_maclist_found( + hapd->conf->deny_mac, + hapd->conf->num_deny_mac, sta->addr, + &vlan_id) && + (!vlan_id || vlan_id == sta->vlan_id)) + ap_sta_disconnect( + hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } + } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED && + os_strcasecmp(cmd, "accept_mac_file") == 0) { + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (!hostapd_maclist_found( + hapd->conf->accept_mac, + hapd->conf->num_accept_mac, + sta->addr, &vlan_id) || + (vlan_id && vlan_id != sta->vlan_id)) + ap_sta_disconnect( + hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } + } } return ret; @@ -778,7 +1333,12 @@ static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd, if (os_strcmp(cmd, "version") == 0) { res = os_snprintf(buf, buflen, "%s", VERSION_STR); - if (res < 0 || (unsigned int) res >= buflen) + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } else if (os_strcmp(cmd, "tls_library") == 0) { + res = tls_get_library_version(buf, buflen); + if (os_snprintf_error(buflen, res)) return -1; return res; } @@ -817,11 +1377,481 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) } +#ifdef CONFIG_TESTING_OPTIONS + +static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) +{ + union wpa_event_data data; + char *pos, *param; + enum wpa_event_type event; + + wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd); + + os_memset(&data, 0, sizeof(data)); + + param = os_strchr(cmd, ' '); + if (param == NULL) + return -1; + *param++ = '\0'; + + if (os_strcmp(cmd, "DETECTED") == 0) + event = EVENT_DFS_RADAR_DETECTED; + else if (os_strcmp(cmd, "CAC-FINISHED") == 0) + event = EVENT_DFS_CAC_FINISHED; + else if (os_strcmp(cmd, "CAC-ABORTED") == 0) + event = EVENT_DFS_CAC_ABORTED; + else if (os_strcmp(cmd, "NOP-FINISHED") == 0) + event = EVENT_DFS_NOP_FINISHED; + else { + wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s", + cmd); + return -1; + } + + pos = os_strstr(param, "freq="); + if (pos) + data.dfs_event.freq = atoi(pos + 5); + + pos = os_strstr(param, "ht_enabled=1"); + if (pos) + data.dfs_event.ht_enabled = 1; + + pos = os_strstr(param, "chan_offset="); + if (pos) + data.dfs_event.chan_offset = atoi(pos + 12); + + pos = os_strstr(param, "chan_width="); + if (pos) + data.dfs_event.chan_width = atoi(pos + 11); + + pos = os_strstr(param, "cf1="); + if (pos) + data.dfs_event.cf1 = atoi(pos + 4); + + pos = os_strstr(param, "cf2="); + if (pos) + data.dfs_event.cf2 = atoi(pos + 4); + + wpa_supplicant_event(hapd, event, &data); + + return 0; +} + + +static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) +{ + size_t len; + u8 *buf; + int res; + + wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(cmd, buf, len) < 0) { + os_free(buf); + return -1; + } + + res = hostapd_drv_send_mlme(hapd, buf, len, 0); + os_free(buf); + return res; +} + + +static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd) +{ + char *pos; + u8 src[ETH_ALEN], *buf; + int used; + size_t len; + + wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, src); + if (used < 0) + return -1; + pos += used; + while (*pos == ' ') + pos++; + + len = os_strlen(pos); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + ieee802_1x_receive(hapd, src, buf, len); + os_free(buf); + + return 0; +} + + +static u16 ipv4_hdr_checksum(const void *buf, size_t len) +{ + size_t i; + u32 sum = 0; + const u16 *pos = buf; + + for (i = 0; i < len / 2; i++) + sum += *pos++; + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return sum ^ 0xffff; +} + + +#define HWSIM_PACKETLEN 1500 +#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header)) + +void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) +{ + struct hostapd_data *hapd = ctx; + const struct ether_header *eth; + const struct iphdr *ip; + const u8 *pos; + unsigned int i; + + if (len != HWSIM_PACKETLEN) + return; + + eth = (const struct ether_header *) buf; + ip = (const struct iphdr *) (eth + 1); + pos = (const u8 *) (ip + 1); + + if (ip->ihl != 5 || ip->version != 4 || + ntohs(ip->tot_len) != HWSIM_IP_LEN) + return; + + for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) { + if (*pos != (u8) i) + return; + pos++; + } + + wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR, + MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost)); +} + + +static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd, + char *cmd) +{ + int enabled = atoi(cmd); + char *pos; + const char *ifname; + + if (!enabled) { + if (hapd->l2_test) { + l2_packet_deinit(hapd->l2_test); + hapd->l2_test = NULL; + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, + "test data: Disabled"); + } + return 0; + } + + if (hapd->l2_test) + return 0; + + pos = os_strstr(cmd, " ifname="); + if (pos) + ifname = pos + 8; + else + ifname = hapd->conf->iface; + + hapd->l2_test = l2_packet_init(ifname, hapd->own_addr, + ETHERTYPE_IP, hostapd_data_test_rx, + hapd, 1); + if (hapd->l2_test == NULL) + return -1; + + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled"); + + return 0; +} + + +static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd) +{ + u8 dst[ETH_ALEN], src[ETH_ALEN]; + char *pos; + int used; + long int val; + u8 tos; + u8 buf[HWSIM_PACKETLEN]; + struct ether_header *eth; + struct iphdr *ip; + u8 *dpos; + unsigned int i; + + if (hapd->l2_test == NULL) + return -1; + + /* format: <dst> <src> <tos> */ + + pos = cmd; + used = hwaddr_aton2(pos, dst); + if (used < 0) + return -1; + pos += used; + while (*pos == ' ') + pos++; + used = hwaddr_aton2(pos, src); + if (used < 0) + return -1; + pos += used; + + val = strtol(pos, NULL, 0); + if (val < 0 || val > 0xff) + return -1; + tos = val; + + eth = (struct ether_header *) buf; + os_memcpy(eth->ether_dhost, dst, ETH_ALEN); + os_memcpy(eth->ether_shost, src, ETH_ALEN); + eth->ether_type = htons(ETHERTYPE_IP); + ip = (struct iphdr *) (eth + 1); + os_memset(ip, 0, sizeof(*ip)); + ip->ihl = 5; + ip->version = 4; + ip->ttl = 64; + ip->tos = tos; + ip->tot_len = htons(HWSIM_IP_LEN); + ip->protocol = 1; + ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1); + ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2); + ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); + dpos = (u8 *) (ip + 1); + for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) + *dpos++ = i; + + if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf, + HWSIM_PACKETLEN) < 0) + return -1; + + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR + " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos); + + return 0; +} + + +static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd, + char *cmd) +{ + u8 *buf; + struct ether_header *eth; + struct l2_packet_data *l2 = NULL; + size_t len; + u16 ethertype; + int res = -1; + const char *ifname = hapd->conf->iface; + + if (os_strncmp(cmd, "ifname=", 7) == 0) { + cmd += 7; + ifname = cmd; + cmd = os_strchr(cmd, ' '); + if (cmd == NULL) + return -1; + *cmd++ = '\0'; + } + + len = os_strlen(cmd); + if (len & 1 || len < ETH_HLEN * 2) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(cmd, buf, len) < 0) + goto done; + + eth = (struct ether_header *) buf; + ethertype = ntohs(eth->ether_type); + + l2 = l2_packet_init(ifname, hapd->own_addr, ethertype, + hostapd_data_test_rx, hapd, 1); + if (l2 == NULL) + goto done; + + res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res); +done: + if (l2) + l2_packet_deinit(l2); + os_free(buf); + + return res < 0 ? -1 : 0; +} + + +static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd) +{ +#ifdef WPA_TRACE_BFD + extern char wpa_trace_fail_func[256]; + extern unsigned int wpa_trace_fail_after; + char *pos; + + wpa_trace_fail_after = atoi(cmd); + pos = os_strchr(cmd, ':'); + if (pos) { + pos++; + os_strlcpy(wpa_trace_fail_func, pos, + sizeof(wpa_trace_fail_func)); + } else { + wpa_trace_fail_after = 0; + } + + return 0; +#else /* WPA_TRACE_BFD */ + return -1; +#endif /* WPA_TRACE_BFD */ +} + + +static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd, + char *buf, size_t buflen) +{ +#ifdef WPA_TRACE_BFD + extern char wpa_trace_fail_func[256]; + extern unsigned int wpa_trace_fail_after; + + return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, + wpa_trace_fail_func); +#else /* WPA_TRACE_BFD */ + return -1; +#endif /* WPA_TRACE_BFD */ +} + +#endif /* CONFIG_TESTING_OPTIONS */ + + +static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, + char *pos) +{ +#ifdef NEED_AP_MLME + struct csa_settings settings; + int ret; + unsigned int i; + + ret = hostapd_parse_csa_settings(pos, &settings); + if (ret) + return ret; + + for (i = 0; i < iface->num_bss; i++) { + ret = hostapd_switch_channel(iface->bss[i], &settings); + if (ret) { + /* FIX: What do we do if CSA fails in the middle of + * submitting multi-BSS CSA requests? */ + return ret; + } + } + + return 0; +#else /* NEED_AP_MLME */ + return -1; +#endif /* NEED_AP_MLME */ +} + + +static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, + int reply_size, const char *param) +{ +#ifdef RADIUS_SERVER + if (os_strcmp(param, "radius_server") == 0) { + return radius_server_get_mib(hapd->radius_srv, reply, + reply_size); + } +#endif /* RADIUS_SERVER */ + return -1; +} + + +static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, + char *buf, size_t buflen) +{ + int ret; + char *pos; + u8 *data = NULL; + unsigned int vendor_id, subcmd; + struct wpabuf *reply; + size_t data_len = 0; + + /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ + vendor_id = strtoul(cmd, &pos, 16); + if (!isblank(*pos)) + return -EINVAL; + + subcmd = strtoul(pos, &pos, 10); + + if (*pos != '\0') { + if (!isblank(*pos++)) + return -EINVAL; + data_len = os_strlen(pos); + } + + if (data_len) { + data_len /= 2; + data = os_malloc(data_len); + if (!data) + return -ENOBUFS; + + if (hexstr2bin(pos, data, data_len)) { + wpa_printf(MSG_DEBUG, + "Vendor command: wrong parameter format"); + os_free(data); + return -EINVAL; + } + } + + reply = wpabuf_alloc((buflen - 1) / 2); + if (!reply) { + os_free(data); + return -ENOBUFS; + } + + ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len, + reply); + + if (ret == 0) + ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), + wpabuf_len(reply)); + + wpabuf_free(reply); + os_free(data); + + return ret; +} + + static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct hostapd_data *hapd = eloop_ctx; - char buf[256]; + char buf[4096]; int res; struct sockaddr_un from; socklen_t fromlen = sizeof(from); @@ -833,7 +1863,8 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, res = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { - perror("recvfrom(ctrl_iface)"); + wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", + strerror(errno)); return; } buf[res] = '\0'; @@ -843,8 +1874,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, reply = os_malloc(reply_size); if (reply == NULL) { - sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, - fromlen); + if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", + strerror(errno)); + } return; } @@ -857,6 +1891,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "RELOG", 5) == 0) { if (wpa_debug_reopen_file() < 0) reply_len = -1; + } else if (os_strcmp(buf, "STATUS") == 0) { + reply_len = hostapd_ctrl_iface_status(hapd, reply, + reply_size); + } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) { + reply_len = hostapd_drv_status(hapd, reply, reply_size); } else if (os_strcmp(buf, "MIB") == 0) { reply_len = ieee802_11_get_mib(hapd, reply, reply_size); if (reply_len >= 0) { @@ -886,6 +1925,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len += res; } #endif /* CONFIG_NO_RADIUS */ + } else if (os_strncmp(buf, "MIB ", 4) == 0) { + reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size, + buf + 4); } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, reply_size); @@ -914,6 +1956,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) reply_len = -1; + } else if (os_strcmp(buf, "STOP_AP") == 0) { + if (hostapd_ctrl_iface_stop_ap(hapd)) + reply_len = -1; #ifdef CONFIG_IEEE80211W #ifdef NEED_AP_MLME } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { @@ -940,6 +1985,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) reply_len = -1; + } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) { + reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply, + reply_size); #ifdef CONFIG_WPS_NFC } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17)) @@ -950,8 +1998,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { reply_len = hostapd_ctrl_iface_wps_nfc_token( hapd, buf + 14, reply, reply_size); + } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { + reply_len = hostapd_ctrl_iface_nfc_get_handover_sel( + hapd, buf + 21, reply, reply_size); + } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { + if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20)) + reply_len = -1; #endif /* CONFIG_WPS_NFC */ #endif /* CONFIG_WPS */ +#ifdef CONFIG_INTERWORKING + } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) { + if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16)) + reply_len = -1; + } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) { + if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18)) + reply_len = -1; +#endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_HS20 + } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) { + if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) { + if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16)) + reply_len = -1; +#endif /* CONFIG_HS20 */ #ifdef CONFIG_WNM } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18)) @@ -959,6 +2029,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13)) reply_len = -1; + } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { + if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11)) + reply_len = -1; #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "GET_CONFIG") == 0) { reply_len = hostapd_ctrl_iface_get_config(hapd, reply, @@ -978,6 +2051,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "DISABLE", 7) == 0) { if (hostapd_ctrl_iface_disable(hapd->iface)) reply_len = -1; + } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { + if (ieee802_11_set_beacon(hapd)) + reply_len = -1; +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strncmp(buf, "RADAR ", 6) == 0) { + if (hostapd_ctrl_iface_radar(hapd, buf + 6)) + reply_len = -1; + } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { + if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8)) + reply_len = -1; + } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { + if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { + if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) { + if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) { + if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) { + if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) { + reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply, + reply_size); +#endif /* CONFIG_TESTING_OPTIONS */ + } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { + if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) + reply_len = -1; + } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { + reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply, + reply_size); + } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { + ieee802_1x_erp_flush(hapd); +#ifdef RADIUS_SERVER + radius_server_erp_flush(hapd->radius_srv); +#endif /* RADIUS_SERVER */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -987,7 +2100,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, os_memcpy(reply, "FAIL\n", 5); reply_len = 5; } - sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); + if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", + strerror(errno)); + } os_free(reply); } @@ -1013,7 +2130,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) } -static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, +static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global, const char *txt, size_t len) { struct hostapd_data *hapd = ctx; @@ -1042,7 +2159,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) wpa_printf(MSG_DEBUG, "Using existing control " "interface directory."); } else { - perror("mkdir[ctrl_interface]"); + wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", + strerror(errno)); goto fail; } } @@ -1050,7 +2168,17 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) if (hapd->conf->ctrl_interface_gid_set && chown(hapd->conf->ctrl_interface, -1, hapd->conf->ctrl_interface_gid) < 0) { - perror("chown[ctrl_interface]"); + wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", + strerror(errno)); + return -1; + } + + if (!hapd->conf->ctrl_interface_gid_set && + hapd->iface->interfaces->ctrl_iface_group && + chown(hapd->conf->ctrl_interface, -1, + hapd->iface->interfaces->ctrl_iface_group) < 0) { + wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", + strerror(errno)); return -1; } @@ -1075,7 +2203,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) s = socket(PF_UNIX, SOCK_DGRAM, 0); if (s < 0) { - perror("socket(PF_UNIX)"); + wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); goto fail; } @@ -1096,15 +2224,16 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) " allow connections - assuming it was left" "over from forced program termination"); if (unlink(fname) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - fname); + wpa_printf(MSG_ERROR, + "Could not unlink existing ctrl_iface socket '%s': %s", + fname, strerror(errno)); goto fail; } if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("hostapd-ctrl-iface: bind(PF_UNIX)"); + wpa_printf(MSG_ERROR, + "hostapd-ctrl-iface: bind(PF_UNIX): %s", + strerror(errno)); goto fail; } wpa_printf(MSG_DEBUG, "Successfully replaced leftover " @@ -1122,19 +2251,32 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) if (hapd->conf->ctrl_interface_gid_set && chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) { - perror("chown[ctrl_interface/ifname]"); + wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s", + strerror(errno)); + goto fail; + } + + if (!hapd->conf->ctrl_interface_gid_set && + hapd->iface->interfaces->ctrl_iface_group && + chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) { + wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s", + strerror(errno)); goto fail; } if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { - perror("chmod[ctrl_interface/ifname]"); + wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", + strerror(errno)); goto fail; } os_free(fname); hapd->ctrl_sock = s; - eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, - NULL); + if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, + NULL) < 0) { + hostapd_ctrl_iface_deinit(hapd); + return -1; + } hapd->msg_ctx = hapd; wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); @@ -1172,17 +2314,26 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) "directory not empty - leaving it " "behind"); } else { - perror("rmdir[ctrl_interface]"); + wpa_printf(MSG_ERROR, + "rmdir[ctrl_interface=%s]: %s", + hapd->conf->ctrl_interface, + strerror(errno)); } } } dst = hapd->ctrl_dst; + hapd->ctrl_dst = NULL; while (dst) { prev = dst; dst = dst->next; os_free(prev); } + +#ifdef CONFIG_TESTING_OPTIONS + l2_packet_deinit(hapd->l2_test); + hapd->l2_test = NULL; +#endif /* CONFIG_TESTING_OPTIONS */ } @@ -1208,6 +2359,16 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, } +static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) +{ +#ifdef CONFIG_WPS_TESTING + wps_version_number = 0x20; + wps_testing_dummy_cred = 0; + wps_corrupt_pkhash = 0; +#endif /* CONFIG_WPS_TESTING */ +} + + static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { @@ -1222,10 +2383,12 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, res = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { - perror("recvfrom(ctrl_iface)"); + wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", + strerror(errno)); return; } buf[res] = '\0'; + wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf); os_memcpy(reply, "OK\n", 3); reply_len = 3; @@ -1233,12 +2396,23 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, if (os_strcmp(buf, "PING") == 0) { os_memcpy(reply, "PONG\n", 5); reply_len = 5; + } else if (os_strncmp(buf, "RELOG", 5) == 0) { + if (wpa_debug_reopen_file() < 0) + reply_len = -1; + } else if (os_strcmp(buf, "FLUSH") == 0) { + hostapd_ctrl_iface_flush(interfaces); } else if (os_strncmp(buf, "ADD ", 4) == 0) { if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0) reply_len = -1; } else if (os_strncmp(buf, "REMOVE ", 7) == 0) { if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0) reply_len = -1; +#ifdef CONFIG_MODULE_TESTS + } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { + int hapd_module_tests(void); + if (hapd_module_tests() < 0) + reply_len = -1; +#endif /* CONFIG_MODULE_TESTS */ } else { wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " "ignored"); @@ -1250,7 +2424,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len = 5; } - sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); + if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", + strerror(errno)); + } } @@ -1291,9 +2469,16 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) wpa_printf(MSG_DEBUG, "Using existing control " "interface directory."); } else { - perror("mkdir[ctrl_interface]"); + wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", + strerror(errno)); goto fail; } + } else if (interface->ctrl_iface_group && + chown(interface->global_iface_path, -1, + interface->ctrl_iface_group) < 0) { + wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", + strerror(errno)); + goto fail; } if (os_strlen(interface->global_iface_path) + 1 + @@ -1302,7 +2487,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) s = socket(PF_UNIX, SOCK_DGRAM, 0); if (s < 0) { - perror("socket(PF_UNIX)"); + wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); goto fail; } @@ -1323,15 +2508,15 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) " allow connections - assuming it was left" "over from forced program termination"); if (unlink(fname) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - fname); + wpa_printf(MSG_ERROR, + "Could not unlink existing ctrl_iface socket '%s': %s", + fname, strerror(errno)); goto fail; } if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(PF_UNIX)"); + wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s", + strerror(errno)); goto fail; } wpa_printf(MSG_DEBUG, "Successfully replaced leftover " @@ -1347,8 +2532,16 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) } } + if (interface->ctrl_iface_group && + chown(fname, -1, interface->ctrl_iface_group) < 0) { + wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", + strerror(errno)); + goto fail; + } + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { - perror("chmod[ctrl_interface/ifname]"); + wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", + strerror(errno)); goto fail; } os_free(fname); @@ -1391,7 +2584,10 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) "directory not empty - leaving it " "behind"); } else { - perror("rmdir[ctrl_interface]"); + wpa_printf(MSG_ERROR, + "rmdir[ctrl_interface=%s]: %s", + interfaces->global_iface_path, + strerror(errno)); } } os_free(interfaces->global_iface_path); diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig index b5ddca3..4cde2b5 100644 --- a/contrib/wpa/hostapd/defconfig +++ b/contrib/wpa/hostapd/defconfig @@ -15,13 +15,22 @@ CONFIG_DRIVER_HOSTAP=y # Driver interface for wired authenticator #CONFIG_DRIVER_WIRED=y -# Driver interface for madwifi driver -#CONFIG_DRIVER_MADWIFI=y -#CFLAGS += -I../../madwifi # change to the madwifi source directory - # Driver interface for drivers using the nl80211 kernel interface CONFIG_DRIVER_NL80211=y +# driver_nl80211.c requires libnl. If you are compiling it yourself +# you may need to point hostapd to your version of libnl. +# +#CFLAGS += -I$<path to libnl include files> +#LIBS += -L$<path to libnl library files> + +# Use libnl v2.0 (or 3.0) libraries. +#CONFIG_LIBNL20=y + +# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) +#CONFIG_LIBNL32=y + + # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) #CONFIG_DRIVER_BSD=y #CFLAGS += -I/usr/local/include @@ -42,14 +51,14 @@ CONFIG_RSN_PREAUTH=y CONFIG_PEERKEY=y # IEEE 802.11w (management frame protection) -# This version is an experimental implementation based on IEEE 802.11w/D1.0 -# draft and is subject to change since the standard has not yet been finalized. -# Driver support is also needed for IEEE 802.11w. -#CONFIG_IEEE80211W=y +CONFIG_IEEE80211W=y # Integrated EAP server CONFIG_EAP=y +# EAP Re-authentication Protocol (ERP) in integrated EAP server +CONFIG_ERP=y + # EAP-MD5 for the integrated EAP server CONFIG_EAP_MD5=y @@ -96,16 +105,13 @@ CONFIG_EAP_TTLS=y #CONFIG_EAP_GPSK_SHA256=y # EAP-FAST for the integrated EAP server -# Note: Default OpenSSL package does not include support for all the -# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch) -# to add the needed functions. +# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed +# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., +# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. #CONFIG_EAP_FAST=y # Wi-Fi Protected Setup (WPS) #CONFIG_WPS=y -# Enable WSC 2.0 support -#CONFIG_WPS2=y # Enable UPnP support for external WPS Registrars #CONFIG_WPS_UPNP=y # Enable WPS support with NFC config method @@ -117,6 +123,9 @@ CONFIG_EAP_TTLS=y # Trusted Network Connect (EAP-TNC) #CONFIG_EAP_TNC=y +# EAP-EKE for the integrated EAP server +#CONFIG_EAP_EKE=y + # PKCS#12 (PFX) support (used to read private key and certificate file from # a file that usually has extension .p12 or .pfx) CONFIG_PKCS12=y @@ -132,7 +141,7 @@ CONFIG_IPV6=y #CONFIG_IEEE80211R=y # Use the hostapd's IEEE 802.11 authentication (ACL), but without -# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211) +# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211) #CONFIG_DRIVER_RADIUS_ACL=y # IEEE 802.11n (High Throughput) support @@ -154,6 +163,12 @@ CONFIG_IPV6=y # Disabled by default. #CONFIG_DEBUG_FILE=y +# Add support for sending all debug messages (regardless of debug verbosity) +# to the Linux kernel tracing facility. This helps debug the entire stack by +# making it easy to record everything happening from the driver up into the +# same file, e.g., using trace-cmd. +#CONFIG_DEBUG_LINUX_TRACING=y + # Remove support for RADIUS accounting #CONFIG_NO_ACCOUNTING=y @@ -171,7 +186,7 @@ CONFIG_IPV6=y # Note: This requires libnl 3.1 or newer. #CONFIG_VLAN_NETLINK=y -# Remove support for dumping state into a file on SIGUSR1 signal +# Remove support for dumping internal state through control interface commands # This can be used to reduce binary size at the cost of disabling a debugging # option. #CONFIG_NO_DUMP_STATE=y @@ -267,3 +282,35 @@ CONFIG_IPV6=y # Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file #CONFIG_SQLITE=y + +# Testing options +# This can be used to enable some testing options (see also the example +# configuration file) that are really useful only for testing clients that +# connect to this hostapd. These options allow, for example, to drop a +# certain percentage of probe requests or auth/(re)assoc frames. +# +#CONFIG_TESTING_OPTIONS=y + +# Automatic Channel Selection +# This will allow hostapd to pick the channel automatically when channel is set +# to "acs_survey" or "0". Eventually, other ACS algorithms can be added in +# similar way. +# +# Automatic selection is currently only done through initialization, later on +# we hope to do background checks to keep us moving to more ideal channels as +# time goes by. ACS is currently only supported through the nl80211 driver and +# your driver must have survey dump capability that is filled by the driver +# during scanning. +# +# You can customize the ACS survey algorithm with the hostapd.conf variable +# acs_num_scans. +# +# Supported ACS drivers: +# * ath9k +# * ath5k +# * ath10k +# +# For more details refer to: +# http://wireless.kernel.org/en/users/Documentation/acs +# +#CONFIG_ACS=y diff --git a/contrib/wpa/hostapd/dump_state.c b/contrib/wpa/hostapd/dump_state.c deleted file mode 100644 index d33e05f..0000000 --- a/contrib/wpa/hostapd/dump_state.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * hostapd / State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include <time.h> - -#include "utils/common.h" -#include "radius/radius_client.h" -#include "radius/radius_server.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "eap_server/eap.h" -#include "ap/hostapd.h" -#include "ap/ap_config.h" -#include "ap/sta_info.h" -#include "dump_state.h" - - -static void fprint_char(FILE *f, char c) -{ - if (c >= 32 && c < 127) - fprintf(f, "%c", c); - else - fprintf(f, "<%02x>", c); -} - - -static void ieee802_1x_dump_state(FILE *f, const char *prefix, - struct sta_info *sta) -{ - struct eapol_state_machine *sm = sta->eapol_sm; - if (sm == NULL) - return; - - fprintf(f, "%sIEEE 802.1X:\n", prefix); - - if (sm->identity) { - size_t i; - fprintf(f, "%sidentity=", prefix); - for (i = 0; i < sm->identity_len; i++) - fprint_char(f, sm->identity[i]); - fprintf(f, "\n"); - } - - fprintf(f, "%slast EAP type: Authentication Server: %d (%s) " - "Supplicant: %d (%s)\n", prefix, - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv), - sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp)); - - fprintf(f, "%scached_packets=%s\n", prefix, - sm->last_recv_radius ? "[RX RADIUS]" : ""); - - eapol_auth_dump_state(f, prefix, sm); -} - - -/** - * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file - */ -static void hostapd_dump_state(struct hostapd_data *hapd) -{ - FILE *f; - time_t now; - struct sta_info *sta; - int i; -#ifndef CONFIG_NO_RADIUS - char *buf; -#endif /* CONFIG_NO_RADIUS */ - - if (!hapd->conf->dump_log_name) { - wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump " - "request"); - return; - } - - wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'", - hapd->conf->dump_log_name); - f = fopen(hapd->conf->dump_log_name, "w"); - if (f == NULL) { - wpa_printf(MSG_WARNING, "Could not open dump file '%s' for " - "writing.", hapd->conf->dump_log_name); - return; - } - - time(&now); - fprintf(f, "hostapd state dump - %s", ctime(&now)); - fprintf(f, "num_sta=%d num_sta_non_erp=%d " - "num_sta_no_short_slot_time=%d\n" - "num_sta_no_short_preamble=%d\n", - hapd->num_sta, hapd->iface->num_sta_non_erp, - hapd->iface->num_sta_no_short_slot_time, - hapd->iface->num_sta_no_short_preamble); - - for (sta = hapd->sta_list; sta != NULL; sta = sta->next) { - fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr)); - - fprintf(f, - " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "\n" - " capability=0x%x listen_interval=%d\n", - sta->aid, - sta->flags, - (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""), - (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), - (sta->flags & WLAN_STA_PS ? "[PS]" : ""), - (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""), - (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""), - (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""), - (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : - ""), - (sta->flags & WLAN_STA_SHORT_PREAMBLE ? - "[SHORT_PREAMBLE]" : ""), - (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), - (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""), - (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""), - (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""), - (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), - (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""), - (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""), - (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), - sta->capability, - sta->listen_interval); - - fprintf(f, " supported_rates="); - for (i = 0; i < sta->supported_rates_len; i++) - fprintf(f, "%02x ", sta->supported_rates[i]); - fprintf(f, "\n"); - - fprintf(f, - " timeout_next=%s\n", - (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" : - (sta->timeout_next == STA_DISASSOC ? "DISASSOC" : - "DEAUTH"))); - - ieee802_1x_dump_state(f, " ", sta); - } - -#ifndef CONFIG_NO_RADIUS - buf = os_malloc(4096); - if (buf) { - int count = radius_client_get_mib(hapd->radius, buf, 4096); - if (count < 0) - count = 0; - else if (count > 4095) - count = 4095; - buf[count] = '\0'; - fprintf(f, "%s", buf); - -#ifdef RADIUS_SERVER - count = radius_server_get_mib(hapd->radius_srv, buf, 4096); - if (count < 0) - count = 0; - else if (count > 4095) - count = 4095; - buf[count] = '\0'; - fprintf(f, "%s", buf); -#endif /* RADIUS_SERVER */ - - os_free(buf); - } -#endif /* CONFIG_NO_RADIUS */ - fclose(f); -} - - -int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx) -{ - size_t i; - - for (i = 0; i < iface->num_bss; i++) - hostapd_dump_state(iface->bss[i]); - - return 0; -} diff --git a/contrib/wpa/hostapd/dump_state.h b/contrib/wpa/hostapd/dump_state.h deleted file mode 100644 index a209d65..0000000 --- a/contrib/wpa/hostapd/dump_state.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * hostapd / State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DUMP_STATE_H -#define DUMP_STATE_H - -int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx); - -#endif /* DUMP_STATE_H */ diff --git a/contrib/wpa/hostapd/eap_register.c b/contrib/wpa/hostapd/eap_register.c index 0a7ff91..8477c21 100644 --- a/contrib/wpa/hostapd/eap_register.c +++ b/contrib/wpa/hostapd/eap_register.c @@ -44,6 +44,13 @@ int eap_server_register_methods(void) ret = eap_server_unauth_tls_register(); #endif /* EAP_SERVER_TLS */ +#ifdef EAP_SERVER_TLS +#ifdef CONFIG_HS20 + if (ret == 0) + ret = eap_server_wfa_unauth_tls_register(); +#endif /* CONFIG_HS20 */ +#endif /* EAP_SERVER_TLS */ + #ifdef EAP_SERVER_MSCHAPV2 if (ret == 0) ret = eap_server_mschapv2_register(); @@ -134,5 +141,10 @@ int eap_server_register_methods(void) ret = eap_server_pwd_register(); #endif /* EAP_SERVER_PWD */ +#ifdef EAP_SERVER_EKE + if (ret == 0) + ret = eap_server_eke_register(); +#endif /* EAP_SERVER_EKE */ + return ret; } diff --git a/contrib/wpa/hostapd/hapd_module_tests.c b/contrib/wpa/hostapd/hapd_module_tests.c new file mode 100644 index 0000000..f7887eb --- /dev/null +++ b/contrib/wpa/hostapd/hapd_module_tests.c @@ -0,0 +1,17 @@ +/* + * hostapd module tests + * Copyright (c) 2014, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" + +int hapd_module_tests(void) +{ + wpa_printf(MSG_INFO, "hostapd module tests"); + return 0; +} diff --git a/contrib/wpa/hostapd/hlr_auc_gw.c b/contrib/wpa/hostapd/hlr_auc_gw.c index e04e2e9..42d59db 100644 --- a/contrib/wpa/hostapd/hlr_auc_gw.c +++ b/contrib/wpa/hostapd/hlr_auc_gw.c @@ -1,6 +1,6 @@ /* * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator - * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,6 +18,9 @@ * SIM-REQ-AUTH <IMSI> <max_chal> * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3] * SIM-RESP-AUTH <IMSI> FAILURE + * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3] + * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3] + * GSM-AUTH-RESP <IMSI> FAILURE * * EAP-AKA / UMTS query/response: * AKA-REQ-AUTH <IMSI> @@ -30,12 +33,16 @@ * IMSI and max_chal are sent as an ASCII string, * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings. * - * The example implementation here reads GSM authentication triplets from a + * An example implementation here reads GSM authentication triplets from a * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex * strings. This is used to simulate an HLR/AuC. As such, it is not very useful * for real life authentication, but it is useful both as an example * implementation and for EAP-SIM/AKA/AKA' testing. * + * For a stronger example design, Milenage and GSM-Milenage algorithms can be + * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and + * EAP-SIM, respectively, if Ki is known. + * * SQN generation follows the not time-based Profile 2 described in * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this * can be changed with a command line options if needed. @@ -58,6 +65,7 @@ static char *milenage_file = NULL; static int update_milenage = 0; static int sqn_changes = 0; static int ind_len = 5; +static int stdout_debug = 1; /* GSM triplets */ struct gsm_triplet { @@ -214,6 +222,9 @@ static int db_update_milenage_sqn(struct milenage_parameters *m) { char cmd[128], val[13], *pos; + if (sqlite_db == NULL) + return 0; + pos = val; pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6); *pos = '\0'; @@ -611,31 +622,30 @@ static struct milenage_parameters * get_milenage(const char *imsi) } -static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, - char *imsi) +static int sim_req_auth(char *imsi, char *resp, size_t resp_len) { int count, max_chal, ret; char *pos; - char reply[1000], *rpos, *rend; + char *rpos, *rend; struct milenage_parameters *m; struct gsm_triplet *g; - reply[0] = '\0'; + resp[0] = '\0'; pos = strchr(imsi, ' '); if (pos) { *pos++ = '\0'; max_chal = atoi(pos); - if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL) + if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL) max_chal = EAP_SIM_MAX_CHAL; } else max_chal = EAP_SIM_MAX_CHAL; - rend = &reply[sizeof(reply)]; - rpos = reply; + rend = resp + resp_len; + rpos = resp; ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi); if (ret < 0 || ret >= rend - rpos) - return; + return -1; rpos += ret; m = get_milenage(imsi); @@ -643,7 +653,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, u8 _rand[16], sres[4], kc[8]; for (count = 0; count < max_chal; count++) { if (random_get_bytes(_rand, 16) < 0) - return; + return -1; gsm_milenage(m->opc, m->ki, _rand, sres, kc); *rpos++ = ' '; rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8); @@ -653,7 +663,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16); } *rpos = '\0'; - goto send; + return 0; } count = 0; @@ -677,15 +687,61 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, printf("No GSM triplets found for %s\n", imsi); ret = snprintf(rpos, rend - rpos, " FAILURE"); if (ret < 0 || ret >= rend - rpos) - return; + return -1; rpos += ret; } -send: - printf("Send: %s\n", reply); - if (sendto(s, reply, rpos - reply, 0, - (struct sockaddr *) from, fromlen) < 0) - perror("send"); + return 0; +} + + +static int gsm_auth_req(char *imsi, char *resp, size_t resp_len) +{ + int count, ret; + char *pos, *rpos, *rend; + struct milenage_parameters *m; + + resp[0] = '\0'; + + pos = os_strchr(imsi, ' '); + if (!pos) + return -1; + *pos++ = '\0'; + + rend = resp + resp_len; + rpos = resp; + ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi); + if (os_snprintf_error(rend - rpos, ret)) + return -1; + rpos += ret; + + m = get_milenage(imsi); + if (m) { + u8 _rand[16], sres[4], kc[8]; + for (count = 0; count < EAP_SIM_MAX_CHAL; count++) { + if (hexstr2bin(pos, _rand, 16) != 0) + return -1; + gsm_milenage(m->opc, m->ki, _rand, sres, kc); + *rpos++ = count == 0 ? ' ' : ':'; + rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8); + *rpos++ = ':'; + rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4); + pos += 16 * 2; + if (*pos != ':') + break; + pos++; + } + *rpos = '\0'; + return 0; + } + + printf("No GSM triplets found for %s\n", imsi); + ret = os_snprintf(rpos, rend - rpos, " FAILURE"); + if (os_snprintf_error(rend - rpos, ret)) + return -1; + rpos += ret; + + return 0; } @@ -711,11 +767,10 @@ static void inc_sqn(u8 *sqn) } -static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, - char *imsi) +static int aka_req_auth(char *imsi, char *resp, size_t resp_len) { /* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */ - char reply[1000], *pos, *end; + char *pos, *end; u8 _rand[EAP_AKA_RAND_LEN]; u8 autn[EAP_AKA_AUTN_LEN]; u8 ik[EAP_AKA_IK_LEN]; @@ -729,16 +784,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, m = get_milenage(imsi); if (m) { if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0) - return; + return -1; res_len = EAP_AKA_RES_MAX_LEN; inc_sqn(m->sqn); #ifdef CONFIG_SQLITE db_update_milenage_sqn(m); #endif /* CONFIG_SQLITE */ sqn_changes = 1; - printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n", - m->sqn[0], m->sqn[1], m->sqn[2], - m->sqn[3], m->sqn[4], m->sqn[5]); + if (stdout_debug) { + printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n", + m->sqn[0], m->sqn[1], m->sqn[2], + m->sqn[3], m->sqn[4], m->sqn[5]); + } milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand, autn, ik, ck, res, &res_len); } else { @@ -756,18 +813,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, #endif /* AKA_USE_FIXED_TEST_VALUES */ } - pos = reply; - end = &reply[sizeof(reply)]; + pos = resp; + end = resp + resp_len; ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi); if (ret < 0 || ret >= end - pos) - return; + return -1; pos += ret; if (failed) { ret = snprintf(pos, end - pos, "FAILURE"); if (ret < 0 || ret >= end - pos) - return; + return -1; pos += ret; - goto done; + return 0; } pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN); *pos++ = ' '; @@ -779,65 +836,87 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, *pos++ = ' '; pos += wpa_snprintf_hex(pos, end - pos, res, res_len); -done: - printf("Send: %s\n", reply); - - if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from, - fromlen) < 0) - perror("send"); + return 0; } -static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen, - char *imsi) +static int aka_auts(char *imsi, char *resp, size_t resp_len) { char *auts, *__rand; u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6]; struct milenage_parameters *m; + resp[0] = '\0'; + /* AKA-AUTS <IMSI> <AUTS> <RAND> */ auts = strchr(imsi, ' '); if (auts == NULL) - return; + return -1; *auts++ = '\0'; __rand = strchr(auts, ' '); if (__rand == NULL) - return; + return -1; *__rand++ = '\0'; - printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand); + if (stdout_debug) { + printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", + imsi, auts, __rand); + } if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) || hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) { printf("Could not parse AUTS/RAND\n"); - return; + return -1; } m = get_milenage(imsi); if (m == NULL) { printf("Unknown IMSI: %s\n", imsi); - return; + return -1; } if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) { printf("AKA-AUTS: Incorrect MAC-S\n"); } else { memcpy(m->sqn, sqn, 6); - printf("AKA-AUTS: Re-synchronized: " - "SQN=%02x%02x%02x%02x%02x%02x\n", - sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]); + if (stdout_debug) { + printf("AKA-AUTS: Re-synchronized: " + "SQN=%02x%02x%02x%02x%02x%02x\n", + sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]); + } #ifdef CONFIG_SQLITE db_update_milenage_sqn(m); #endif /* CONFIG_SQLITE */ sqn_changes = 1; } + + return 0; +} + + +static int process_cmd(char *cmd, char *resp, size_t resp_len) +{ + if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0) + return sim_req_auth(cmd + 13, resp, resp_len); + + if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0) + return gsm_auth_req(cmd + 13, resp, resp_len); + + if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0) + return aka_req_auth(cmd + 13, resp, resp_len); + + if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0) + return aka_auts(cmd + 9, resp, resp_len); + + printf("Unknown request: %s\n", cmd); + return -1; } static int process(int s) { - char buf[1000]; + char buf[1000], resp[1000]; struct sockaddr_un from; socklen_t fromlen; ssize_t res; @@ -859,14 +938,21 @@ static int process(int s) printf("Received: %s\n", buf); - if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0) - sim_req_auth(s, &from, fromlen, buf + 13); - else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0) - aka_req_auth(s, &from, fromlen, buf + 13); - else if (strncmp(buf, "AKA-AUTS ", 9) == 0) - aka_auts(s, &from, fromlen, buf + 9); - else - printf("Unknown request: %s\n", buf); + if (process_cmd(buf, resp, sizeof(resp)) < 0) { + printf("Failed to process request\n"); + return -1; + } + + if (resp[0] == '\0') { + printf("No response\n"); + return 0; + } + + printf("Send: %s\n", resp); + + if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from, + fromlen) < 0) + perror("send"); return 0; } @@ -894,8 +980,10 @@ static void cleanup(void) os_free(prev); } - close(serv_sock); - unlink(socket_path); + if (serv_sock >= 0) + close(serv_sock); + if (socket_path) + unlink(socket_path); #ifdef CONFIG_SQLITE if (sqlite_db) { @@ -917,12 +1005,12 @@ static void usage(void) { printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA " "database/authenticator\n" - "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n" + "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n" "\n" "usage:\n" "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] " "[-m<milenage file>] \\\n" - " [-D<DB file>] [-i<IND len in bits>]\n" + " [-D<DB file>] [-i<IND len in bits>] [command]\n" "\n" "options:\n" " -h = show this usage help\n" @@ -932,7 +1020,15 @@ static void usage(void) " -g<triplet file> = path for GSM authentication triplets\n" " -m<milenage file> = path for Milenage keys\n" " -D<DB file> = path to SQLite database\n" - " -i<IND len in bits> = IND length for SQN (default: 5)\n", + " -i<IND len in bits> = IND length for SQN (default: 5)\n" + "\n" + "If the optional command argument, like " + "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n" + "command is processed with response sent to stdout. Otherwise, " + "hlr_auc_gw opens\n" + "a control interface and processes commands sent through it " + "(e.g., by EAP server\n" + "in hostapd).\n", default_socket_path); } @@ -942,6 +1038,7 @@ int main(int argc, char *argv[]) int c; char *gsm_triplet_file = NULL; char *sqlite_db_file = NULL; + int ret = 0; if (os_program_init()) return -1; @@ -1005,18 +1102,31 @@ int main(int argc, char *argv[]) if (milenage_file && read_milenage(milenage_file) < 0) return -1; - serv_sock = open_socket(socket_path); - if (serv_sock < 0) - return -1; + if (optind == argc) { + serv_sock = open_socket(socket_path); + if (serv_sock < 0) + return -1; - printf("Listening for requests on %s\n", socket_path); + printf("Listening for requests on %s\n", socket_path); - atexit(cleanup); - signal(SIGTERM, handle_term); - signal(SIGINT, handle_term); + atexit(cleanup); + signal(SIGTERM, handle_term); + signal(SIGINT, handle_term); - for (;;) - process(serv_sock); + for (;;) + process(serv_sock); + } else { + char buf[1000]; + socket_path = NULL; + stdout_debug = 0; + if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) { + printf("FAIL\n"); + ret = -1; + } else { + printf("%s\n", buf); + } + cleanup(); + } #ifdef CONFIG_SQLITE if (sqlite_db) { @@ -1027,5 +1137,5 @@ int main(int argc, char *argv[]) os_program_deinit(); - return 0; + return ret; } diff --git a/contrib/wpa/hostapd/hostapd.8 b/contrib/wpa/hostapd/hostapd.8 index b4456bb..d19d862 100644 --- a/contrib/wpa/hostapd/hostapd.8 +++ b/contrib/wpa/hostapd/hostapd.8 @@ -12,7 +12,7 @@ daemon. .B hostapd is a user space daemon for access point and authentication servers. It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server. -The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211). +The current version supports Linux (Host AP, mac80211-based drivers) and FreeBSD (net80211). .B hostapd is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication. diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf index 75b1941..9e81e9e 100644 --- a/contrib/wpa/hostapd/hostapd.conf +++ b/contrib/wpa/hostapd/hostapd.conf @@ -2,10 +2,10 @@ # Empty lines and lines starting with # are ignored # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for -# management frames); ath0 for madwifi +# management frames with the Host AP driver); wlan0 with many nl80211 drivers interface=wlan0 -# In case of madwifi, atheros, and nl80211 driver interfaces, an additional +# In case of atheros and nl80211 driver interfaces, an additional # configuration parameter, bridge, may be used to notify hostapd if the # interface is included in a bridge. This parameter is not used with Host AP # driver. If the bridge parameter is not set, the drivers will automatically @@ -18,12 +18,15 @@ interface=wlan0 # interface is also created. #bridge=br0 -# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd); +# Driver interface type (hostap/wired/none/nl80211/bsd); # default: hostap). nl80211 is used with all Linux mac80211 drivers. # Use driver=none if building hostapd as a standalone RADIUS server that does # not control any wireless/wired driver. # driver=hostap +# Driver interface parameters (mainly for development testing use) +# driver_params=<params> + # hostapd event logger configuration # # Two output method: syslog and stdout (only usable if not forking to @@ -51,9 +54,6 @@ logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 -# Dump file for state information (on SIGUSR1) -dump_file=/tmp/hostapd.dump - # Interface for separate control program. If this is specified, hostapd # will create this directory and a UNIX domain socket for listening to requests # from external programs (CLI/GUI, etc.) for status information and @@ -105,6 +105,26 @@ ssid=test # (default: 0 = disabled) #ieee80211d=1 +# Enable IEEE 802.11h. This enables radar detection and DFS support if +# available. DFS support is required on outdoor 5 GHz channels in most countries +# of the world. This can be used only with ieee80211d=1. +# (default: 0 = disabled) +#ieee80211h=1 + +# Add Power Constraint element to Beacon and Probe Response frames +# This config option adds Power Constraint element when applicable and Country +# element is added. Power Constraint element is required by Transmit Power +# Control. This can be used only with ieee80211d=1. +# Valid values are 0..255. +#local_pwr_constraint=3 + +# Set Spectrum Management subfield in the Capability Information field. +# This config option forces the Spectrum Management bit to be set. When this +# option is not set, the value of the Spectrum Management bit depends on whether +# DFS or TPC is required by regulatory authorities. This can be used only with +# ieee80211d=1 and local_pwr_constraint configured. +#spectrum_mgmt_required=1 + # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, # ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to # specify band) @@ -115,8 +135,44 @@ hw_mode=g # (default: 0, i.e., not set) # Please note that some drivers do not use this value from hostapd and the # channel will need to be configured separately with iwconfig. +# +# If CONFIG_ACS build option is enabled, the channel can be selected +# automatically at run time by setting channel=acs_survey or channel=0, both of +# which will enable the ACS survey based algorithm. channel=1 +# ACS tuning - Automatic Channel Selection +# See: http://wireless.kernel.org/en/users/Documentation/acs +# +# You can customize the ACS survey algorithm with following variables: +# +# acs_num_scans requirement is 1..100 - number of scans to be performed that +# are used to trigger survey data gathering of an underlying device driver. +# Scans are passive and typically take a little over 100ms (depending on the +# driver) on each available channel for given hw_mode. Increasing this value +# means sacrificing startup time and gathering more data wrt channel +# interference that may help choosing a better channel. This can also help fine +# tune the ACS scan time in case a driver has different scan dwell times. +# +# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be +# used to increase (or decrease) the likelihood of a specific channel to be +# selected by the ACS algorithm. The total interference factor for each channel +# gets multiplied by the specified bias value before finding the channel with +# the lowest value. In other words, values between 0.0 and 1.0 can be used to +# make a channel more likely to be picked while values larger than 1.0 make the +# specified channel less likely to be picked. This can be used, e.g., to prefer +# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default +# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified). +# +# Defaults: +#acs_num_scans=5 +#acs_chan_bias=1:0.8 6:0.8 11:0.8 + +# Channel list restriction. This option allows hostapd to select one of the +# provided channels when a channel should be automatically selected. +# Default: not set (allow any enabled channel to be selected) +#chanlist=100 104 108 112 116 + # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 @@ -176,7 +232,7 @@ fragm_threshold=2346 # Station MAC address -based authentication # Please note that this kind of access control requires a driver that uses # hostapd to take care of management frame processing and as such, this can be -# used with driver=hostap or driver=nl80211, but not with driver=madwifi. +# used with driver=hostap or driver=nl80211, but not with driver=atheros. # 0 = accept unless in deny list # 1 = deny unless in accept list # 2 = use external RADIUS server (accept/deny lists are searched first) @@ -383,10 +439,24 @@ wmm_ac_vo_acm=0 # use a separate bridge. #wds_bridge=wds-br0 +# Start the AP with beaconing disabled by default. +#start_disabled=0 + # Client isolation can be used to prevent low-level bridging of frames between # associated stations in the BSS. By default, this bridging is allowed. #ap_isolate=1 +# BSS Load update period (in BUs) +# This field is used to enable and configure adding a BSS Load element into +# Beacon and Probe Response frames. +#bss_load_update_period=50 + +# Fixed BSS Load value for testing purposes +# This field can be used to configure hostapd to add a fixed BSS Load element +# into Beacon and Probe Response frames for testing purposes. The format is +# <station count>:<channel utilization>:<available admission capacity> +#bss_load_test=12:80:20000 + ##### IEEE 802.11n related configuration ###################################### # ieee80211n: Whether IEEE 802.11n (HT) is enabled @@ -399,7 +469,7 @@ wmm_ac_vo_acm=0 # LDPC coding capability: [LDPC] = supported # Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary # channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz -# with secondary channel below the primary channel +# with secondary channel above the primary channel # (20 MHz only if neither is set) # Note: There are limits on which channels can be used with HT40- and # HT40+. Following table shows the channels that may be available for @@ -426,13 +496,20 @@ wmm_ac_vo_acm=0 # Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not # set) # DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) -# PSMP support: [PSMP] (disabled if not set) +# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set) # L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) #ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] # Require stations to support HT PHY (reject association if they do not) #require_ht=1 +# If set non-zero, require stations to perform scans of overlapping +# channels to test for stations which would be affected by 40 MHz traffic. +# This parameter sets the interval in seconds between these scans. Setting this +# to non-zero allows 2.4 GHz band AP to move dynamically to a 40 MHz channel if +# no co-existence issues with neighboring devices are found. +#obss_interval=0 + ##### IEEE 802.11ac related configuration ##################################### # ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled @@ -627,6 +704,17 @@ eapol_key_index_workaround=0 # is only used by one station. #use_pae_group_addr=1 +# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696) +# +# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before +# EAP-Identity/Request +#erp_send_reauth_start=1 +# +# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not +# set (no local ER server). This is also used by the integrated EAP server if +# ERP is enabled (eap_server_erp=1). +#erp_domain=example.com + ##### Integrated EAP server ################################################### # Optionally, hostapd can be configured to use an integrated EAP server @@ -660,6 +748,11 @@ eap_server=0 # Passphrase for private key #private_key_passwd=secret passphrase +# Server identity +# EAP methods that provide mechanism for authenticated server identity delivery +# use this value. If not set, "hostapd" is used as a default. +#server_id=server.example.com + # Enable CRL verification. # Note: hostapd does not yet support CRL downloading based on CDP. Thus, a # valid CRL signed by the CA is required to be included in the ca_cert file. @@ -671,6 +764,20 @@ eap_server=0 # 2 = check all CRLs in the certificate path #check_crl=1 +# Cached OCSP stapling response (DER encoded) +# If set, this file is sent as a certificate status response by the EAP server +# if the EAP peer requests certificate status in the ClientHello message. +# This cache file can be updated, e.g., by running following command +# periodically to get an update from the OCSP responder: +# openssl ocsp \ +# -no_nonce \ +# -CAfile /etc/hostapd.ca.pem \ +# -issuer /etc/hostapd.ca.pem \ +# -cert /etc/hostapd.server.pem \ +# -url http://ocsp.example.com:8888/ \ +# -respout /tmp/ocsp-cache.der +#ocsp_stapling_response=/tmp/ocsp-cache.der + # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an # ephemeral DH key exchange. In most cases, the default RSA authentication does @@ -683,6 +790,15 @@ eap_server=0 # "openssl dhparam -out /etc/hostapd.dh.pem 1024" #dh_file=/etc/hostapd.dh.pem +# OpenSSL cipher string +# +# This is an OpenSSL specific configuration option for configuring the default +# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default. +# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation +# on cipher suite configuration. This is applicable only if hostapd is built to +# use OpenSSL. +#openssl_ciphers=DEFAULT:!EXP:!LOW + # Fragment size for EAP methods #fragment_size=1400 @@ -744,6 +860,10 @@ eap_server=0 # EAP method is enabled, the peer will be allowed to connect without TNC. #tnc=1 +# EAP Re-authentication Protocol (ERP) - RFC 6696 +# +# Whether to enable ERP on the EAP server. +#eap_server_erp=1 ##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) ####################### @@ -765,6 +885,12 @@ own_ip_addr=127.0.0.1 # 48 octets long. #nas_identifier=ap.example.com +# RADIUS client forced local IP address for the access point +# Normally the local IP address is determined automatically based on configured +# IP addresses, but this field can be used to force a specific address to be +# used, e.g., when the device has multiple IP addresses. +#radius_client_addr=127.0.0.1 + # RADIUS authentication server #auth_server_addr=127.0.0.1 #auth_server_port=1812 @@ -814,9 +940,8 @@ own_ip_addr=127.0.0.1 # is used for the stations. This information is parsed from following RADIUS # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value -# VLANID as a string). vlan_file option below must be configured if dynamic -# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be -# used to set static client MAC address to VLAN ID mapping. +# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can +# be used to set static client MAC address to VLAN ID mapping. # 0 = disabled (default) # 1 = option; use default interface if RADIUS server does not include VLAN ID # 2 = required; reject authentication if RADIUS server does not include VLAN ID @@ -828,6 +953,8 @@ own_ip_addr=127.0.0.1 # multiple BSSIDs or SSIDs. Each line in this text file is defining a new # interface and the line must include VLAN ID and interface name separated by # white space (space or tab). +# If no entries are provided by this file, the station is statically mapped +# to <bss-iface>.<vlan-id> interfaces. #vlan_file=/etc/hostapd.vlan # Interface where 802.1q tagged packets should appear when a RADIUS server is @@ -837,6 +964,12 @@ own_ip_addr=127.0.0.1 # to the bridge. #vlan_tagged_interface=eth0 +# Bridge (prefix) to add the wifi and the tagged interface to. This gets the +# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given +# and br%s.%d if a tagged interface is given, provided %s = tagged interface +# and %d = VLAN ID. +#vlan_bridge=brvlan + # When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs # to know how to name it. # 0 = vlan<XXX>, e.g., vlan1 @@ -906,6 +1039,11 @@ own_ip_addr=127.0.0.1 # The UDP port number for the RADIUS authentication server #radius_server_auth_port=1812 +# The UDP port number for the RADIUS accounting server +# Commenting this out or setting this to 0 can be used to disable RADIUS +# accounting while still enabling RADIUS authentication. +#radius_server_acct_port=1813 + # Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API) #radius_server_ipv6=1 @@ -1012,6 +1150,17 @@ own_ip_addr=127.0.0.1 # 2 = required #ieee80211w=0 +# Group management cipher suite +# Default: AES-128-CMAC (BIP) +# Other options (depending on driver support): +# BIP-GMAC-128 +# BIP-GMAC-256 +# BIP-CMAC-256 +# Note: All the stations connecting to the BSS will also need to support the +# selected cipher. The default AES-128-CMAC is the only option that is commonly +# available in deployed devices. +#group_mgmt_cipher=AES-128-CMAC + # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) # (maximum time to wait for a SA Query response) # dot11AssociationSAQueryMaximumTimeout, 1...4294967295 @@ -1037,6 +1186,19 @@ own_ip_addr=127.0.0.1 # 1 = enabled #okc=1 +# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold) +# This parameter defines how many open SAE instances can be in progress at the +# same time before the anti-clogging mechanism is taken into use. +#sae_anti_clogging_threshold=5 + +# Enabled SAE finite cyclic groups +# SAE implementation are required to support group 19 (ECC group defined over a +# 256-bit prime order field). All groups that are supported by the +# implementation are enabled by default. This configuration parameter can be +# used to specify a limited set of allowed groups. The group values are listed +# in the IANA registry: +# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9 +#sae_groups=19 20 21 25 26 ##### IEEE 802.11r configuration ############################################## @@ -1111,6 +1273,14 @@ own_ip_addr=127.0.0.1 # 2 = WPS enabled, configured #wps_state=2 +# Whether to manage this interface independently from other WPS interfaces +# By default, a single hostapd process applies WPS operations to all configured +# interfaces. This parameter can be used to disable that behavior for a subset +# of interfaces. If this is set to non-zero for an interface, WPS commands +# issued on that interface do not apply to other interfaces and WPS operations +# performed on other interfaces do not affect this interface. +#wps_independent=0 + # AP can be configured into a locked state where new WPS Registrar are not # accepted, but previously authorized Registrars (including the internal one) # can continue to add new Enrollees. @@ -1315,6 +1485,11 @@ own_ip_addr=127.0.0.1 # 1 = enabled #bss_transition=1 +# Proxy ARP +# 0 = disabled (default) +# 1 = enabled +#proxy_arp=1 + ##### IEEE 802.11u-2011 ####################################################### # Enable Interworking service @@ -1381,6 +1556,9 @@ own_ip_addr=127.0.0.1 # information to be complete. #venue_name=eng:Example venue #venue_name=fin:Esimerkkipaikka +# Alternative format for language:value strings: +# (double quoted string, printf-escaped string) +#venue_name=P"eng:Example\nvenue" # Network Authentication Type # This parameter indicates what type of network authentication is used in the @@ -1432,6 +1610,8 @@ own_ip_addr=127.0.0.1 # accordance with IETF RFC 4282 # NAI Realm(s): Semi-colon delimited NAI Realm(s) # EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...] +# EAP Method types, see: +# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4 # AuthParam (Table 8-188 in IEEE Std 802.11-2012): # ID 2 = Non-EAP Inner Authentication Type # 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2 @@ -1445,6 +1625,23 @@ own_ip_addr=127.0.0.1 # username/password #nai_realm=0,example.org,13[5:6],21[2:4][5:7] +# QoS Map Set configuration +# +# Comma delimited QoS Map Set in decimal values +# (see IEEE Std 802.11-2012, 8.4.2.97) +# +# format: +# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]> +# +# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value +# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range +# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for +# each UP starting from 0. If both low and high value are set to 255, the +# corresponding UP is not used. +# +# default: not set +#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255 + ##### Hotspot 2.0 ############################################################# # Enable Hotspot 2.0 support @@ -1457,6 +1654,21 @@ own_ip_addr=127.0.0.1 # forging such frames to other stations in the BSS. #disable_dgaf=1 +# OSU Server-Only Authenticated L2 Encryption Network +#osen=1 + +# ANQP Domain ID (0..65535) +# An identifier for a set of APs in an ESS that share the same common ANQP +# information. 0 = Some of the ANQP information is unique to this AP (default). +#anqp_domain_id=1234 + +# Deauthentication request timeout +# If the RADIUS server indicates that the station is not allowed to connect to +# the BSS/ESS, the AP can allow the station some time to download a +# notification page (URL included in the message). This parameter sets that +# timeout in seconds. +#hs20_deauth_req_timeout=60 + # Operator Friendly Name # This parameter can be used to configure one or more Operator Friendly Name # Duples. Each entry has a two or three character language code (ISO-639) @@ -1500,6 +1712,54 @@ own_ip_addr=127.0.0.1 # channels 36-48): #hs20_operating_class=5173 +# OSU icons +# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path> +#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png +#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png + +# OSU SSID (see ssid2 for format description) +# This is the SSID used for all OSU connections to all the listed OSU Providers. +#osu_ssid="example" + +# OSU Providers +# One or more sets of following parameter. Each OSU provider is started by the +# mandatory osu_server_uri item. The other parameters add information for the +# last added OSU provider. +# +#osu_server_uri=https://example.com/osu/ +#osu_friendly_name=eng:Example operator +#osu_friendly_name=fin:Esimerkkipalveluntarjoaja +#osu_nai=anonymous@example.com +#osu_method_list=1 0 +#osu_icon=icon32 +#osu_icon=icon64 +#osu_service_desc=eng:Example services +#osu_service_desc=fin:Esimerkkipalveluja +# +#osu_server_uri=... + +##### TESTING OPTIONS ######################################################### +# +# The options in this section are only available when the build configuration +# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow +# testing some scenarios that are otherwise difficult to reproduce. +# +# Ignore probe requests sent to hostapd with the given probability, must be a +# floating point number in the range [0, 1). +#ignore_probe_probability=0.0 +# +# Ignore authentication frames with the given probability +#ignore_auth_probability=0.0 +# +# Ignore association requests with the given probability +#ignore_assoc_probability=0.0 +# +# Ignore reassociation requests with the given probability +#ignore_reassoc_probability=0.0 +# +# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability +#corrupt_gtk_rekey_mic_probability=0.0 + ##### Multiple BSSID support ################################################## # # Above configuration is using the default interface (wlan#, or multi-SSID VLAN @@ -1521,6 +1781,11 @@ own_ip_addr=127.0.0.1 # - is not the same as the MAC address of the radio # - is not the same as any other explicitly specified BSSID # +# Not all drivers support multiple BSSes. The exact mechanism for determining +# the driver capabilities is driver specific. With the current (i.e., a recent +# kernel) drivers using nl80211, this information can be checked with "iw list" +# (search for "valid interface combinations"). +# # Please note that hostapd uses some of the values configured for the first BSS # as the defaults for the following BSSes. However, it is recommended that all # BSSes include explicit configuration of all relevant configuration items. diff --git a/contrib/wpa/hostapd/hostapd.eap_user b/contrib/wpa/hostapd/hostapd.eap_user index 12a2c61..00edc95 100644 --- a/contrib/wpa/hostapd/hostapd.eap_user +++ b/contrib/wpa/hostapd/hostapd.eap_user @@ -48,6 +48,12 @@ # TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a # plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password # hash. +# +# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly +# to the way radius_auth_req_attr is used for Access-Request packet in +# hostapd.conf. For EAP server, this is configured separately for each user +# entry with radius_accept_attr=<value> line(s) following the main user entry +# line. # Phase 1 users "user" MD5 "password" diff --git a/contrib/wpa/hostapd/hostapd.eap_user_sqlite b/contrib/wpa/hostapd/hostapd.eap_user_sqlite index f688327..826db34 100644 --- a/contrib/wpa/hostapd/hostapd.eap_user_sqlite +++ b/contrib/wpa/hostapd/hostapd.eap_user_sqlite @@ -2,6 +2,7 @@ CREATE TABLE users( identity TEXT PRIMARY KEY, methods TEXT, password TEXT, + remediation TEXT, phase2 INTEGER ); @@ -15,3 +16,11 @@ INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 use INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS'); INSERT INTO wildcards(identity,methods) VALUES ('0','AKA'); + +CREATE TABLE authlog( + timestamp TEXT, + session TEXT, + nas_ip TEXT, + username TEXT, + note TEXT +); diff --git a/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c index e8e1bb2..3f00cbb 100644 --- a/contrib/wpa/hostapd/hostapd_cli.c +++ b/contrib/wpa/hostapd/hostapd_cli.c @@ -1,6 +1,6 @@ /* * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,7 +18,7 @@ static const char *hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors"; static const char *hostapd_cli_license = @@ -79,6 +79,7 @@ static const char *commands_help = #endif /* CONFIG_WPS_NFC */ " wps_ap_pin <cmd> [params..] enable/disable AP PIN\n" " wps_config <SSID> <auth> <encr> <key> configure AP\n" +" wps_get_status show current WPS status\n" #endif /* CONFIG_WPS */ " get_config show current configuration\n" " help show this usage help\n" @@ -90,7 +91,12 @@ static const char *commands_help = static struct wpa_ctrl *ctrl_conn; static int hostapd_cli_quit = 0; static int hostapd_cli_attached = 0; -static const char *ctrl_iface_dir = "/var/run/hostapd"; + +#ifndef CONFIG_CTRL_IFACE_DIR +#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd" +#endif /* CONFIG_CTRL_IFACE_DIR */ +static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; + static char *ctrl_ifname = NULL; static const char *pid_file = NULL; static const char *action_file = NULL; @@ -210,8 +216,21 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc > 0 && os_strcmp(argv[0], "driver") == 0) + return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); + return wpa_ctrl_command(ctrl, "STATUS"); +} + + static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) { + if (argc > 0) { + char buf[100]; + os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]); + return wpa_ctrl_command(ctrl, buf); + } return wpa_ctrl_command(ctrl, "MIB"); } @@ -219,28 +238,19 @@ static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int hostapd_cli_exec(const char *program, const char *arg1, const char *arg2) { - char *cmd; + char *arg; size_t len; int res; - int ret = 0; - len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; - cmd = os_malloc(len); - if (cmd == NULL) - return -1; - res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); - if (res < 0 || (size_t) res >= len) { - os_free(cmd); + len = os_strlen(arg1) + os_strlen(arg2) + 2; + arg = os_malloc(len); + if (arg == NULL) return -1; - } - cmd[len - 1] = '\0'; -#ifndef _WIN32_WCE - if (system(cmd) < 0) - ret = -1; -#endif /* _WIN32_WCE */ - os_free(cmd); + os_snprintf(arg, len, "%s %s", arg1, arg2); + res = os_exec(program, arg, 1); + os_free(arg); - return ret; + return res; } @@ -264,12 +274,15 @@ static void hostapd_cli_action_process(char *msg, size_t len) static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char buf[64]; - if (argc != 1) { - printf("Invalid 'sta' command - exactly one argument, STA " + if (argc < 1) { + printf("Invalid 'sta' command - at least one argument, STA " "address, is required.\n"); return -1; } - snprintf(buf, sizeof(buf), "STA %s", argv[0]); + if (argc > 1) + snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]); + else + snprintf(buf, sizeof(buf), "STA %s", argv[0]); return wpa_ctrl_command(ctrl, buf); } @@ -380,7 +393,7 @@ static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, else res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + if (os_snprintf_error(sizeof(cmd), res)) { printf("Too long WPS_CHECK_PIN command.\n"); return -1; } @@ -443,7 +456,7 @@ static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + if (os_snprintf_error(sizeof(cmd), res)) { printf("Too long WPS_NFC_CONFIG_TOKEN command.\n"); return -1; } @@ -464,12 +477,35 @@ static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, } res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + if (os_snprintf_error(sizeof(cmd), res)) { printf("Too long WPS_NFC_TOKEN command.\n"); return -1; } return wpa_ctrl_command(ctrl, cmd); } + + +static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + char cmd[64]; + int res; + + if (argc != 2) { + printf("Invalid 'nfc_get_handover_sel' command - two arguments " + "are required.\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s", + argv[0], argv[1]); + if (os_snprintf_error(sizeof(cmd), res)) { + printf("Too long NFC_GET_HANDOVER_SEL command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + #endif /* CONFIG_WPS_NFC */ @@ -494,6 +530,13 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "WPS_GET_STATUS"); +} + + static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -553,7 +596,7 @@ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s", argv[0], argv[1]); - if (res < 0 || res >= (int) sizeof(buf)) + if (os_snprintf_error(sizeof(buf), res)) return -1; return wpa_ctrl_command(ctrl, buf); } @@ -565,16 +608,43 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, char buf[300]; int res; - if (argc < 2) { - printf("Invalid 'ess_disassoc' command - two arguments (STA " - "addr and URL) are needed\n"); + if (argc < 3) { + printf("Invalid 'ess_disassoc' command - three arguments (STA " + "addr, disassoc timer, and URL) are needed\n"); return -1; } - res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s", - argv[0], argv[1]); - if (res < 0 || res >= (int) sizeof(buf)) + res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s", + argv[0], argv[1], argv[2]); + if (os_snprintf_error(sizeof(buf), res)) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + +static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[2000], *tmp; + int res, i, total; + + if (argc < 1) { + printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n"); + return -1; + } + + res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]); + if (os_snprintf_error(sizeof(buf), res)) return -1; + + total = res; + for (i = 1; i < argc; i++) { + tmp = &buf[total]; + res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]); + if (os_snprintf_error(sizeof(buf) - total, res)) + return -1; + total += res; + } return wpa_ctrl_command(ctrl, buf); } @@ -652,6 +722,90 @@ static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + char buf[200]; + int res; + + if (argc != 1) { + printf("Invalid 'set_qos_map_set' command - " + "one argument (comma delimited QoS map set) " + "is needed\n"); + return -1; + } + + res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]); + if (os_snprintf_error(sizeof(buf), res)) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + +static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + char buf[50]; + int res; + + if (argc != 1) { + printf("Invalid 'send_qos_map_conf' command - " + "one argument (STA addr) is needed\n"); + return -1; + } + + res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]); + if (os_snprintf_error(sizeof(buf), res)) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + +static int hostapd_cli_cmd_hs20_wnm_notif(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[300]; + int res; + + if (argc < 2) { + printf("Invalid 'hs20_wnm_notif' command - two arguments (STA " + "addr and URL) are needed\n"); + return -1; + } + + res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s", + argv[0], argv[1]); + if (os_snprintf_error(sizeof(buf), res)) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + +static int hostapd_cli_cmd_hs20_deauth_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[300]; + int res; + + if (argc < 3) { + printf("Invalid 'hs20_deauth_req' command - at least three arguments (STA addr, Code, Re-auth Delay) are needed\n"); + return -1; + } + + if (argc > 3) + res = os_snprintf(buf, sizeof(buf), + "HS20_DEAUTH_REQ %s %s %s %s", + argv[0], argv[1], argv[2], argv[3]); + else + res = os_snprintf(buf, sizeof(buf), + "HS20_DEAUTH_REQ %s %s %s", + argv[0], argv[1], argv[2]); + if (os_snprintf_error(sizeof(buf), res)) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) { hostapd_cli_quit = 1; @@ -706,8 +860,10 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, } hostapd_cli_close_connection(); - free(ctrl_ifname); - ctrl_ifname = strdup(argv[0]); + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(argv[0]); + if (ctrl_ifname == NULL) + return -1; if (hostapd_cli_open_connection(ctrl_ifname)) { printf("Connected to interface '%s.\n", ctrl_ifname); @@ -737,7 +893,7 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) } res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + if (os_snprintf_error(sizeof(cmd), res)) { printf("Too long SET command.\n"); return -1; } @@ -757,7 +913,7 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) } res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); - if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + if (os_snprintf_error(sizeof(cmd), res)) { printf("Too long GET command.\n"); return -1; } @@ -765,6 +921,94 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + char cmd[256]; + int res; + int i; + char *tmp; + int total; + + if (argc < 2) { + printf("Invalid chan_switch command: needs at least two " + "arguments (count and freq)\n" + "usage: <cs_count> <freq> [sec_channel_offset=] " + "[center_freq1=] [center_freq2=] [bandwidth=] " + "[blocktx] [ht|vht]\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s", + argv[0], argv[1]); + if (os_snprintf_error(sizeof(cmd), res)) { + printf("Too long CHAN_SWITCH command.\n"); + return -1; + } + + total = res; + for (i = 2; i < argc; i++) { + tmp = cmd + total; + res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]); + if (os_snprintf_error(sizeof(cmd) - total, res)) { + printf("Too long CHAN_SWITCH command.\n"); + return -1; + } + total += res; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ENABLE"); +} + + +static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOAD"); +} + + +static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DISABLE"); +} + + +static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc < 2 || argc > 3) { + printf("Invalid vendor command\n" + "usage: <vendor id> <command id> [<hex formatted command argument>]\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1], + argc == 3 ? argv[2] : ""); + if (os_snprintf_error(sizeof(cmd), res)) { + printf("Too long VENDOR command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ERP_FLUSH"); +} + + struct hostapd_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); @@ -774,6 +1018,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = { { "ping", hostapd_cli_cmd_ping }, { "mib", hostapd_cli_cmd_mib }, { "relog", hostapd_cli_cmd_relog }, + { "status", hostapd_cli_cmd_status }, { "sta", hostapd_cli_cmd_sta }, { "all_sta", hostapd_cli_cmd_all_sta }, { "new_sta", hostapd_cli_cmd_new_sta }, @@ -791,12 +1036,15 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = { { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read }, { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token }, { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token }, + { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel }, #endif /* CONFIG_WPS_NFC */ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, { "wps_config", hostapd_cli_cmd_wps_config }, + { "wps_get_status", hostapd_cli_cmd_wps_get_status }, #endif /* CONFIG_WPS */ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent }, { "ess_disassoc", hostapd_cli_cmd_ess_disassoc }, + { "bss_tm_req", hostapd_cli_cmd_bss_tm_req }, { "get_config", hostapd_cli_cmd_get_config }, { "help", hostapd_cli_cmd_help }, { "interface", hostapd_cli_cmd_interface }, @@ -805,6 +1053,16 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = { { "quit", hostapd_cli_cmd_quit }, { "set", hostapd_cli_cmd_set }, { "get", hostapd_cli_cmd_get }, + { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set }, + { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf }, + { "chan_switch", hostapd_cli_cmd_chan_switch }, + { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif }, + { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req }, + { "vendor", hostapd_cli_cmd_vendor }, + { "enable", hostapd_cli_cmd_enable }, + { "reload", hostapd_cli_cmd_reload }, + { "disable", hostapd_cli_cmd_disable }, + { "erp_flush", hostapd_cli_cmd_erp_flush }, { NULL, NULL } }; diff --git a/contrib/wpa/hostapd/main.c b/contrib/wpa/hostapd/main.c index 56f0002..dd389a8 100644 --- a/contrib/wpa/hostapd/main.c +++ b/contrib/wpa/hostapd/main.c @@ -1,6 +1,6 @@ /* * hostapd / main() - * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,10 +9,12 @@ #include "utils/includes.h" #ifndef CONFIG_NATIVE_WINDOWS #include <syslog.h> +#include <grp.h> #endif /* CONFIG_NATIVE_WINDOWS */ #include "utils/common.h" #include "utils/eloop.h" +#include "utils/uuid.h" #include "crypto/random.h" #include "crypto/tls.h" #include "common/version.h" @@ -24,17 +26,9 @@ #include "ap/ap_drv_ops.h" #include "config_file.h" #include "eap_register.h" -#include "dump_state.h" #include "ctrl_iface.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -extern struct wpa_driver_ops *wpa_drivers[]; - - struct hapd_global { void **drv_priv; size_t drv_count; @@ -98,22 +92,24 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, if (hapd && hapd->conf && addr) os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", hapd->conf->iface, MAC2STR(addr), - module_str ? " " : "", module_str, txt); + module_str ? " " : "", module_str ? module_str : "", + txt); else if (hapd && hapd->conf) os_snprintf(format, maxlen, "%s:%s%s %s", hapd->conf->iface, module_str ? " " : "", - module_str, txt); + module_str ? module_str : "", txt); else if (addr) os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", MAC2STR(addr), module_str ? " " : "", - module_str, txt); + module_str ? module_str : "", txt); else os_snprintf(format, maxlen, "%s%s%s", - module_str, module_str ? ": " : "", txt); + module_str ? module_str : "", + module_str ? ": " : "", txt); if ((conf_stdout & module) && level >= conf_stdout_level) { wpa_debug_print_timestamp(); - printf("%s\n", format); + wpa_printf(MSG_INFO, "%s", format); } #ifndef CONFIG_NATIVE_WINDOWS @@ -147,63 +143,8 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, /** - * hostapd_init - Allocate and initialize per-interface data - * @config_file: Path to the configuration file - * Returns: Pointer to the allocated interface data or %NULL on failure - * - * This function is used to allocate main data structures for per-interface - * data. The allocated data buffer will be freed by calling - * hostapd_cleanup_iface(). + * hostapd_driver_init - Preparate driver interface */ -static struct hostapd_iface * hostapd_init(const char *config_file) -{ - struct hostapd_iface *hapd_iface = NULL; - struct hostapd_config *conf = NULL; - struct hostapd_data *hapd; - size_t i; - - hapd_iface = os_zalloc(sizeof(*hapd_iface)); - if (hapd_iface == NULL) - goto fail; - - hapd_iface->config_fname = os_strdup(config_file); - if (hapd_iface->config_fname == NULL) - goto fail; - - conf = hostapd_config_read(hapd_iface->config_fname); - if (conf == NULL) - goto fail; - hapd_iface->conf = conf; - - hapd_iface->num_bss = conf->num_bss; - hapd_iface->bss = os_calloc(conf->num_bss, - sizeof(struct hostapd_data *)); - if (hapd_iface->bss == NULL) - goto fail; - - for (i = 0; i < conf->num_bss; i++) { - hapd = hapd_iface->bss[i] = - hostapd_alloc_bss_data(hapd_iface, conf, - &conf->bss[i]); - if (hapd == NULL) - goto fail; - hapd->msg_ctx = hapd; - } - - return hapd_iface; - -fail: - if (conf) - hostapd_config_free(conf); - if (hapd_iface) { - os_free(hapd_iface->config_fname); - os_free(hapd_iface->bss); - os_free(hapd_iface); - } - return NULL; -} - - static int hostapd_driver_init(struct hostapd_iface *iface) { struct wpa_init_params params; @@ -243,9 +184,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface) } params.bssid = b; params.ifname = hapd->conf->iface; - params.ssid = hapd->conf->ssid.ssid; - params.ssid_len = hapd->conf->ssid.ssid_len; - params.test_socket = hapd->conf->test_socket; + params.driver_params = hapd->iconf->driver_params; params.use_pae_group_addr = hapd->conf->use_pae_group_addr; params.num_bridge = hapd->iface->num_bss; @@ -271,14 +210,35 @@ static int hostapd_driver_init(struct hostapd_iface *iface) if (hapd->driver->get_capa && hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { + struct wowlan_triggers *triggs; + iface->drv_flags = capa.flags; + iface->smps_modes = capa.smps_modes; iface->probe_resp_offloads = capa.probe_resp_offloads; + iface->extended_capa = capa.extended_capa; + iface->extended_capa_mask = capa.extended_capa_mask; + iface->extended_capa_len = capa.extended_capa_len; + iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; + + triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); + if (triggs && hapd->driver->set_wowlan) { + if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) + wpa_printf(MSG_ERROR, "set_wowlan failed"); + } + os_free(triggs); } return 0; } +/** + * hostapd_interface_init - Read configuration file and init BSS data + * + * This function is used to parse configuration file for a full interface (one + * or more BSSes sharing the same radio) and allocate memory for the BSS + * interfaces. No actiual driver operations are started. + */ static struct hostapd_iface * hostapd_interface_init(struct hapd_interfaces *interfaces, const char *config_fname, int debug) @@ -287,7 +247,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, int k; wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); - iface = hostapd_init(config_fname); + iface = hostapd_init(interfaces, config_fname); if (!iface) return NULL; iface->interfaces = interfaces; @@ -297,13 +257,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, iface->bss[0]->conf->logger_stdout_level--; } - if (iface->conf->bss[0].iface[0] != 0 || - hostapd_drv_none(iface->bss[0])) { - if (hostapd_driver_init(iface) || - hostapd_setup_interface(iface)) { - hostapd_interface_deinit_free(iface); - return NULL; - } + if (iface->conf->bss[0]->iface[0] == '\0' && + !hostapd_drv_none(iface->bss[0])) { + wpa_printf(MSG_ERROR, "Interface name not specified in %s", + config_fname); + hostapd_interface_deinit_free(iface); + return NULL; } return iface; @@ -346,10 +305,7 @@ static void handle_reload(int sig, void *signal_ctx) static void handle_dump_state(int sig, void *signal_ctx) { -#ifdef HOSTAPD_DUMP_STATE - struct hapd_interfaces *interfaces = signal_ctx; - hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); -#endif /* HOSTAPD_DUMP_STATE */ + /* Not used anymore - ignore signal */ } #endif /* CONFIG_NATIVE_WINDOWS */ @@ -452,7 +408,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, #endif /* EAP_SERVER_TNC */ if (daemonize && os_daemonize(pid_file)) { - perror("daemon"); + wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); return -1; } @@ -468,7 +424,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> " "and contributors\n"); } @@ -480,7 +436,8 @@ static void usage(void) "\n" "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] " "\\\n" - " [-g <global ctrl_iface>] <configuration file(s)>\n" + " [-g <global ctrl_iface>] [-G <group>] \\\n" + " <configuration file(s)>\n" "\n" "options:\n" " -h show this usage\n" @@ -488,11 +445,16 @@ static void usage(void) " -B run daemon in the background\n" " -e entropy file\n" " -g global control interface path\n" + " -G group for control interfaces\n" " -P PID file\n" " -K include key data in debug messages\n" #ifdef CONFIG_DEBUG_FILE " -f log output to debug file instead of stdout\n" #endif /* CONFIG_DEBUG_FILE */ +#ifdef CONFIG_DEBUG_LINUX_TRACING + " -T = record to Linux tracing in addition to logging\n" + " (records all messages regardless of debug verbosity)\n" +#endif /* CONFIG_DEBUG_LINUX_TRACING */ " -t include timestamps in some debug messages\n" " -v show hostapd version\n"); @@ -503,8 +465,9 @@ static void usage(void) static const char * hostapd_msg_ifname_cb(void *ctx) { struct hostapd_data *hapd = ctx; - if (hapd && hapd->iconf && hapd->iconf->bss) - return hapd->iconf->bss->iface; + if (hapd && hapd->iconf && hapd->iconf->bss && + hapd->iconf->num_bss > 0 && hapd->iconf->bss[0]) + return hapd->iconf->bss[0]->iface; return NULL; } @@ -519,6 +482,8 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, return -1; pos = os_strrchr(interfaces->global_iface_path, '/'); if (pos == NULL) { + wpa_printf(MSG_ERROR, "No '/' in the global control interface " + "file"); os_free(interfaces->global_iface_path); interfaces->global_iface_path = NULL; return -1; @@ -531,15 +496,57 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, } +static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, + const char *group) +{ +#ifndef CONFIG_NATIVE_WINDOWS + struct group *grp; + grp = getgrnam(group); + if (grp == NULL) { + wpa_printf(MSG_ERROR, "Unknown group '%s'", group); + return -1; + } + interfaces->ctrl_iface_group = grp->gr_gid; +#endif /* CONFIG_NATIVE_WINDOWS */ + return 0; +} + + +#ifdef CONFIG_WPS +static int gen_uuid(const char *txt_addr) +{ + u8 addr[ETH_ALEN]; + u8 uuid[UUID_LEN]; + char buf[100]; + + if (hwaddr_aton(txt_addr, addr) < 0) + return -1; + + uuid_gen_mac_addr(addr, uuid); + if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0) + return -1; + + printf("%s\n", buf); + + return 0; +} +#endif /* CONFIG_WPS */ + + int main(int argc, char *argv[]) { struct hapd_interfaces interfaces; int ret = 1; - size_t i; + size_t i, j; int c, debug = 0, daemonize = 0; char *pid_file = NULL; const char *log_file = NULL; const char *entropy_file = NULL; + char **bss_config = NULL, **tmp_bss; + size_t num_bss_configs = 0; +#ifdef CONFIG_DEBUG_LINUX_TRACING + int enable_trace_dbg = 0; +#endif /* CONFIG_DEBUG_LINUX_TRACING */ if (os_program_init()) return -1; @@ -556,7 +563,7 @@ int main(int argc, char *argv[]) interfaces.global_ctrl_sock = -1; for (;;) { - c = getopt(argc, argv, "Bde:f:hKP:tvg:"); + c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:"); if (c < 0) break; switch (c) { @@ -587,31 +594,65 @@ int main(int argc, char *argv[]) case 't': wpa_debug_timestamp++; break; +#ifdef CONFIG_DEBUG_LINUX_TRACING + case 'T': + enable_trace_dbg = 1; + break; +#endif /* CONFIG_DEBUG_LINUX_TRACING */ case 'v': show_version(); exit(1); break; case 'g': - hostapd_get_global_ctrl_iface(&interfaces, optarg); + if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) + return -1; break; - + case 'G': + if (hostapd_get_ctrl_iface_group(&interfaces, optarg)) + return -1; + break; + case 'b': + tmp_bss = os_realloc_array(bss_config, + num_bss_configs + 1, + sizeof(char *)); + if (tmp_bss == NULL) + goto out; + bss_config = tmp_bss; + bss_config[num_bss_configs++] = optarg; + break; +#ifdef CONFIG_WPS + case 'u': + return gen_uuid(optarg); +#endif /* CONFIG_WPS */ default: usage(); break; } } - if (optind == argc && interfaces.global_iface_path == NULL) + if (optind == argc && interfaces.global_iface_path == NULL && + num_bss_configs == 0) usage(); wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); if (log_file) wpa_debug_open_file(log_file); + else + wpa_debug_setup_stdout(); +#ifdef CONFIG_DEBUG_LINUX_TRACING + if (enable_trace_dbg) { + int tret = wpa_debug_open_linux_tracing(); + if (tret) { + wpa_printf(MSG_ERROR, "Failed to enable trace logging"); + return -1; + } + } +#endif /* CONFIG_DEBUG_LINUX_TRACING */ interfaces.count = argc - optind; - if (interfaces.count) { - interfaces.iface = os_calloc(interfaces.count, + if (interfaces.count || num_bss_configs) { + interfaces.iface = os_calloc(interfaces.count + num_bss_configs, sizeof(struct hostapd_iface *)); if (interfaces.iface == NULL) { wpa_printf(MSG_ERROR, "malloc failed"); @@ -619,30 +660,93 @@ int main(int argc, char *argv[]) } } - if (hostapd_global_init(&interfaces, entropy_file)) + if (hostapd_global_init(&interfaces, entropy_file)) { + wpa_printf(MSG_ERROR, "Failed to initilize global context"); return -1; + } - /* Initialize interfaces */ + /* Allocate and parse configuration for full interface files */ for (i = 0; i < interfaces.count; i++) { interfaces.iface[i] = hostapd_interface_init(&interfaces, argv[optind + i], debug); - if (!interfaces.iface[i]) + if (!interfaces.iface[i]) { + wpa_printf(MSG_ERROR, "Failed to initialize interface"); + goto out; + } + } + + /* Allocate and parse configuration for per-BSS files */ + for (i = 0; i < num_bss_configs; i++) { + struct hostapd_iface *iface; + char *fname; + + wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]); + fname = os_strchr(bss_config[i], ':'); + if (fname == NULL) { + wpa_printf(MSG_ERROR, + "Invalid BSS config identifier '%s'", + bss_config[i]); + goto out; + } + *fname++ = '\0'; + iface = hostapd_interface_init_bss(&interfaces, bss_config[i], + fname, debug); + if (iface == NULL) + goto out; + for (j = 0; j < interfaces.count; j++) { + if (interfaces.iface[j] == iface) + break; + } + if (j == interfaces.count) { + struct hostapd_iface **tmp; + tmp = os_realloc_array(interfaces.iface, + interfaces.count + 1, + sizeof(struct hostapd_iface *)); + if (tmp == NULL) { + hostapd_interface_deinit_free(iface); + goto out; + } + interfaces.iface = tmp; + interfaces.iface[interfaces.count++] = iface; + } + } + + /* + * Enable configured interfaces. Depending on channel configuration, + * this may complete full initialization before returning or use a + * callback mechanism to complete setup in case of operations like HT + * co-ex scans, ACS, or DFS are needed to determine channel parameters. + * In such case, the interface will be enabled from eloop context within + * hostapd_global_run(). + */ + interfaces.terminate_on_error = interfaces.count; + for (i = 0; i < interfaces.count; i++) { + if (hostapd_driver_init(interfaces.iface[i]) || + hostapd_setup_interface(interfaces.iface[i])) goto out; } hostapd_global_ctrl_iface_init(&interfaces); - if (hostapd_global_run(&interfaces, daemonize, pid_file)) + if (hostapd_global_run(&interfaces, daemonize, pid_file)) { + wpa_printf(MSG_ERROR, "Failed to start eloop"); goto out; + } ret = 0; out: hostapd_global_ctrl_iface_deinit(&interfaces); /* Deinitialize all interfaces */ - for (i = 0; i < interfaces.count; i++) + for (i = 0; i < interfaces.count; i++) { + if (!interfaces.iface[i]) + continue; + interfaces.iface[i]->driver_ap_teardown = + !!(interfaces.iface[i]->drv_flags & + WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); hostapd_interface_deinit_free(interfaces.iface[i]); + } os_free(interfaces.iface); hostapd_global_deinit(pid_file); @@ -650,6 +754,9 @@ int main(int argc, char *argv[]) if (log_file) wpa_debug_close_file(); + wpa_debug_close_linux_tracing(); + + os_free(bss_config); os_program_deinit(); diff --git a/contrib/wpa/hostapd/wps-ap-nfc.py b/contrib/wpa/hostapd/wps-ap-nfc.py new file mode 100755 index 0000000..2fc3012 --- /dev/null +++ b/contrib/wpa/hostapd/wps-ap-nfc.py @@ -0,0 +1,342 @@ +#!/usr/bin/python +# +# Example nfcpy to hostapd wrapper for WPS NFC operations +# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi> +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import sys +import time +import argparse + +import nfc +import nfc.ndef +import nfc.llcp +import nfc.handover + +import logging + +import wpaspy + +wpas_ctrl = '/var/run/hostapd' +continue_loop = True +summary_file = None +success_file = None + +def summary(txt): + print txt + if summary_file: + with open(summary_file, 'a') as f: + f.write(txt + "\n") + +def success_report(txt): + summary(txt) + if success_file: + with open(success_file, 'a') as f: + f.write(txt + "\n") + +def wpas_connect(): + ifaces = [] + if os.path.isdir(wpas_ctrl): + try: + ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] + except OSError, error: + print "Could not find hostapd: ", error + return None + + if len(ifaces) < 1: + print "No hostapd control interface found" + return None + + for ctrl in ifaces: + try: + wpas = wpaspy.Ctrl(ctrl) + return wpas + except Exception, e: + pass + return None + + +def wpas_tag_read(message): + wpas = wpas_connect() + if (wpas == None): + return False + if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")): + return False + return True + + +def wpas_get_config_token(): + wpas = wpas_connect() + if (wpas == None): + return None + ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF") + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + + +def wpas_get_password_token(): + wpas = wpas_connect() + if (wpas == None): + return None + ret = wpas.request("WPS_NFC_TOKEN NDEF") + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + + +def wpas_get_handover_sel(): + wpas = wpas_connect() + if (wpas == None): + return None + ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR") + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + + +def wpas_report_handover(req, sel): + wpas = wpas_connect() + if (wpas == None): + return None + return wpas.request("NFC_REPORT_HANDOVER RESP WPS " + + str(req).encode("hex") + " " + + str(sel).encode("hex")) + + +class HandoverServer(nfc.handover.HandoverServer): + def __init__(self, llc): + super(HandoverServer, self).__init__(llc) + self.ho_server_processing = False + self.success = False + + # override to avoid parser error in request/response.pretty() in nfcpy + # due to new WSC handover format + def _process_request(self, request): + summary("received handover request {}".format(request.type)) + response = nfc.ndef.Message("\xd1\x02\x01Hs\x12") + if not request.type == 'urn:nfc:wkt:Hr': + summary("not a handover request") + else: + try: + request = nfc.ndef.HandoverRequestMessage(request) + except nfc.ndef.DecodeError as e: + summary("error decoding 'Hr' message: {}".format(e)) + else: + response = self.process_request(request) + summary("send handover response {}".format(response.type)) + return response + + def process_request(self, request): + summary("HandoverServer - request received") + try: + print "Parsed handover request: " + request.pretty() + except Exception, e: + print e + print str(request).encode("hex") + + sel = nfc.ndef.HandoverSelectMessage(version="1.2") + + for carrier in request.carriers: + print "Remote carrier type: " + carrier.type + if carrier.type == "application/vnd.wfa.wsc": + summary("WPS carrier type match - add WPS carrier record") + data = wpas_get_handover_sel() + if data is None: + summary("Could not get handover select carrier record from hostapd") + continue + print "Handover select carrier record from hostapd:" + print data.encode("hex") + if "OK" in wpas_report_handover(carrier.record, data): + success_report("Handover reported successfully") + else: + summary("Handover report rejected") + + message = nfc.ndef.Message(data); + sel.add_carrier(message[0], "active", message[1:]) + + print "Handover select:" + try: + print sel.pretty() + except Exception, e: + print e + print str(sel).encode("hex") + + summary("Sending handover select") + self.success = True + return sel + + +def wps_tag_read(tag): + success = False + if len(tag.ndef.message): + for record in tag.ndef.message: + print "record type " + record.type + if record.type == "application/vnd.wfa.wsc": + summary("WPS tag - send to hostapd") + success = wpas_tag_read(tag.ndef.message) + break + else: + summary("Empty tag") + + if success: + success_report("Tag read succeeded") + + return success + + +def rdwr_connected_write(tag): + summary("Tag found - writing - " + str(tag)) + global write_data + tag.ndef.message = str(write_data) + success_report("Tag write succeeded") + print "Done - remove tag" + global only_one + if only_one: + global continue_loop + continue_loop = False + global write_wait_remove + while write_wait_remove and tag.is_present: + time.sleep(0.1) + +def wps_write_config_tag(clf, wait_remove=True): + summary("Write WPS config token") + global write_data, write_wait_remove + write_wait_remove = wait_remove + write_data = wpas_get_config_token() + if write_data == None: + summary("Could not get WPS config token from hostapd") + return + + print "Touch an NFC tag" + clf.connect(rdwr={'on-connect': rdwr_connected_write}) + + +def wps_write_password_tag(clf, wait_remove=True): + summary("Write WPS password token") + global write_data, write_wait_remove + write_wait_remove = wait_remove + write_data = wpas_get_password_token() + if write_data == None: + summary("Could not get WPS password token from hostapd") + return + + print "Touch an NFC tag" + clf.connect(rdwr={'on-connect': rdwr_connected_write}) + + +def rdwr_connected(tag): + global only_one, no_wait + summary("Tag connected: " + str(tag)) + + if tag.ndef: + print "NDEF tag: " + tag.type + try: + print tag.ndef.message.pretty() + except Exception, e: + print e + success = wps_tag_read(tag) + if only_one and success: + global continue_loop + continue_loop = False + else: + summary("Not an NDEF tag - remove tag") + return True + + return not no_wait + + +def llcp_startup(clf, llc): + print "Start LLCP server" + global srv + srv = HandoverServer(llc) + return llc + +def llcp_connected(llc): + print "P2P LLCP connected" + global wait_connection + wait_connection = False + global srv + srv.start() + return True + + +def main(): + clf = nfc.ContactlessFrontend() + + parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations') + parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, + action='store_const', dest='loglevel', + help='verbose debug output') + parser.add_argument('-q', const=logging.WARNING, action='store_const', + dest='loglevel', help='be quiet') + parser.add_argument('--only-one', '-1', action='store_true', + help='run only one operation and exit') + parser.add_argument('--no-wait', action='store_true', + help='do not wait for tag to be removed before exiting') + parser.add_argument('--summary', + help='summary file for writing status updates') + parser.add_argument('--success', + help='success file for writing success update') + parser.add_argument('command', choices=['write-config', + 'write-password'], + nargs='?') + args = parser.parse_args() + + global only_one + only_one = args.only_one + + global no_wait + no_wait = args.no_wait + + if args.summary: + global summary_file + summary_file = args.summary + + if args.success: + global success_file + success_file = args.success + + logging.basicConfig(level=args.loglevel) + + try: + if not clf.open("usb"): + print "Could not open connection with an NFC device" + raise SystemExit + + if args.command == "write-config": + wps_write_config_tag(clf, wait_remove=not args.no_wait) + raise SystemExit + + if args.command == "write-password": + wps_write_password_tag(clf, wait_remove=not args.no_wait) + raise SystemExit + + global continue_loop + while continue_loop: + print "Waiting for a tag or peer to be touched" + wait_connection = True + try: + if not clf.connect(rdwr={'on-connect': rdwr_connected}, + llcp={'on-startup': llcp_startup, + 'on-connect': llcp_connected}): + break + except Exception, e: + print "clf.connect failed" + + global srv + if only_one and srv and srv.success: + raise SystemExit + + except KeyboardInterrupt: + raise SystemExit + finally: + clf.close() + + raise SystemExit + +if __name__ == '__main__': + main() |