diff options
author | Andrew Shadura <andrewsh@debian.org> | 2016-10-20 18:23:40 +0200 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2016-10-20 18:23:40 +0200 |
commit | 1e2b7568b4f69a9da79de660a1a04ef077479628 (patch) | |
tree | 252210229f2c2d4387457403887894a73eff4cf6 /hostapd | |
parent | aa5e2237f3bbd73853b3ffbb4bf693298c409792 (diff) |
Imported Upstream version 2.6
Diffstat (limited to 'hostapd')
-rw-r--r-- | hostapd/Android.mk | 45 | ||||
-rw-r--r-- | hostapd/ChangeLog | 73 | ||||
-rw-r--r-- | hostapd/Makefile | 106 | ||||
-rw-r--r-- | hostapd/README | 2 | ||||
-rw-r--r-- | hostapd/android.config | 8 | ||||
-rw-r--r-- | hostapd/config_file.c | 216 | ||||
-rw-r--r-- | hostapd/ctrl_iface.c | 860 | ||||
-rw-r--r-- | hostapd/defconfig | 17 | ||||
-rw-r--r-- | hostapd/hapd_module_tests.c | 1 | ||||
-rw-r--r-- | hostapd/hlr_auc_gw.c | 136 | ||||
-rw-r--r-- | hostapd/hostapd.android.rc | 20 | ||||
-rw-r--r-- | hostapd/hostapd.conf | 143 | ||||
-rw-r--r-- | hostapd/hostapd_cli.c | 650 | ||||
-rw-r--r-- | hostapd/main.c | 131 |
14 files changed, 1874 insertions, 534 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 5885f2b..ea3a39a 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -46,7 +46,6 @@ endif INCLUDES = $(LOCAL_PATH) INCLUDES += $(LOCAL_PATH)/src INCLUDES += $(LOCAL_PATH)/src/utils -INCLUDES += external/openssl/include INCLUDES += system/security/keystore/include ifdef CONFIG_DRIVER_NL80211 ifneq ($(wildcard external/libnl),) @@ -97,6 +96,8 @@ OBJS += src/ap/pmksa_cache_auth.c OBJS += src/ap/ieee802_11_shared.c OBJS += src/ap/beacon.c OBJS += src/ap/bss_load.c +OBJS += src/ap/neighbor_db.c +OBJS += src/ap/rrm.c OBJS_d = OBJS_p = LIBS = @@ -176,17 +177,25 @@ ifdef CONFIG_NO_VLAN L_CFLAGS += -DCONFIG_NO_VLAN else OBJS += src/ap/vlan_init.c -ifdef CONFIG_VLAN_NETLINK +OBJS += src/ap/vlan_ifconfig.c +OBJS += src/ap/vlan.c ifdef CONFIG_FULL_DYNAMIC_VLAN +# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges +# and VLAN interfaces for the VLAN feature. +L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN +OBJS += src/ap/vlan_full.c +ifdef CONFIG_VLAN_NETLINK OBJS += src/ap/vlan_util.c +else +OBJS += src/ap/vlan_ioctl.c endif -L_CFLAGS += -DCONFIG_VLAN_NETLINK endif endif ifdef CONFIG_NO_CTRL_IFACE L_CFLAGS += -DCONFIG_NO_CTRL_IFACE else +OBJS += src/common/ctrl_iface_common.c OBJS += ctrl_iface.c OBJS += src/ap/ctrl_iface_ap.c endif @@ -262,6 +271,11 @@ ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_MBO +L_CFLAGS += -DCONFIG_MBO +OBJS += src/ap/mbo_ap.c +endif + ifdef CONFIG_FST L_CFLAGS += -DCONFIG_FST OBJS += src/fst/fst.c @@ -555,6 +569,7 @@ endif ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS OBJS += src/crypto/tls_openssl.c +OBJS += src/crypto/tls_openssl_ocsp.c LIBS += -lssl endif OBJS += src/crypto/crypto_openssl.c @@ -651,6 +666,8 @@ CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif @@ -809,6 +826,16 @@ L_CFLAGS += -DCONFIG_SHA384 OBJS += src/crypto/sha384-prf.c endif +ifdef CONFIG_INTERNAL_SHA384 +L_CFLAGS += -DCONFIG_INTERNAL_SHA384 +OBJS += src/crypto/sha384-internal.c +endif + +ifdef CONFIG_INTERNAL_SHA512 +L_CFLAGS += -DCONFIG_INTERNAL_SHA512 +OBJS += src/crypto/sha512-internal.c +endif + ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c endif @@ -850,12 +877,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL endif -ifdef CONFIG_FULL_DYNAMIC_VLAN -# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges -# and vlan interfaces for the vlan feature. -L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN -endif - ifdef NEED_BASE64 OBJS += src/utils/base64.c endif @@ -926,7 +947,10 @@ ifdef CONFIG_ANDROID_LOG L_CFLAGS += -DCONFIG_ANDROID_LOG endif -OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c +OBJS_c = hostapd_cli.c +OBJS_c += src/common/wpa_ctrl.c +OBJS_c += src/utils/os_$(CONFIG_OS).c +OBJS_c += src/common/cli.c OBJS_c += src/utils/eloop.c OBJS_c += src/utils/common.c ifdef CONFIG_WPA_TRACE @@ -971,6 +995,7 @@ endif LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(OBJS) LOCAL_C_INCLUDES := $(INCLUDES) +LOCAL_INIT_RC := hostapd.android.rc include $(BUILD_EXECUTABLE) endif # ifeq ($(WPA_BUILD_HOSTAPD),true) diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index af54e1e..d2b669b 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -1,5 +1,78 @@ ChangeLog for hostapd +2016-10-02 - v2.6 + * fixed EAP-pwd last fragment validation + [http://w1.fi/security/2015-7/] (CVE-2015-5314) + * fixed WPS configuration update vulnerability with malformed passphrase + [http://w1.fi/security/2016-1/] (CVE-2016-4476) + * extended channel switch support for VHT bandwidth changes + * added support for configuring new ANQP-elements with + anqp_elem=<InfoID>:<hexdump of payload> + * fixed Suite B 192-bit AKM to use proper PMK length + (note: this makes old releases incompatible with the fixed behavior) + * added no_probe_resp_if_max_sta=1 parameter to disable Probe Response + frame sending for not-associated STAs if max_num_sta limit has been + reached + * added option (-S as command line argument) to request all interfaces + to be started at the same time + * modified rts_threshold and fragm_threshold configuration parameters + to allow -1 to be used to disable RTS/fragmentation + * EAP-pwd: added support for Brainpool Elliptic Curves + (with OpenSSL 1.0.2 and newer) + * fixed EAPOL reauthentication after FT protocol run + * fixed FTIE generation for 4-way handshake after FT protocol run + * fixed and improved various FST operations + * TLS server + - support SHA384 and SHA512 hashes + - support TLS v1.2 signature algorithm with SHA384 and SHA512 + - support PKCS #5 v2.0 PBES2 + - support PKCS #5 with PKCS #12 style key decryption + - minimal support for PKCS #12 + - support OCSP stapling (including ocsp_multi) + * added support for OpenSSL 1.1 API changes + - drop support for OpenSSL 0.9.8 + - drop support for OpenSSL 1.0.0 + * EAP-PEAP: support fast-connect crypto binding + * RADIUS + - fix Called-Station-Id to not escape SSID + - add Event-Timestamp to all Accounting-Request packets + - add Acct-Session-Id to Accounting-On/Off + - add Acct-Multi-Session-Id ton Access-Request packets + - add Service-Type (= Frames) + - allow server to provide PSK instead of passphrase for WPA-PSK + Tunnel_password case + - update full message for interim accounting updates + - add Acct-Delay-Time into Accounting messages + - add require_message_authenticator configuration option to require + CoA/Disconnect-Request packets to be authenticated + * started to postpone WNM-Notification frame sending by 100 ms so that + the STA has some more time to configure the key before this frame is + received after the 4-way handshake + * VHT: added interoperability workaround for 80+80 and 160 MHz channels + * extended VLAN support (per-STA vif, etc.) + * fixed PMKID derivation with SAE + * nl80211 + - added support for full station state operations + - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use + unencrypted EAPOL frames + * added initial MBO support; number of extensions to WNM BSS Transition + Management + * added initial functionality for location related operations + * added assocresp_elements parameter to allow vendor specific elements + to be added into (Re)Association Response frames + * improved Public Action frame addressing + - use Address 3 = wildcard BSSID in GAS response if a query from an + unassociated STA used that address + - fix TX status processing for Address 3 = wildcard BSSID + - add gas_address3 configuration parameter to control Address 3 + behavior + * added command line parameter -i to override interface parameter in + hostapd.conf + * added command completion support to hostapd_cli + * added passive client taxonomy determination (CONFIG_TAXONOMY=y + compile option and "SIGNATURE <addr>" control interface command) + * number of small fixes + 2015-09-27 - v2.5 * fixed WPS UPnP vulnerability with HTTP chunked transfer encoding [http://w1.fi/security/2015-2/] (CVE-2015-4141) diff --git a/hostapd/Makefile b/hostapd/Makefile index a812b9d..46dffe5 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -6,18 +6,39 @@ ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif +ifdef LIBS +# If LIBS is set with some global build system defaults, clone those for +# LIBS_c, LIBS_h, and LIBS_n to cover hostapd_cli, hlr_auc_gw, and +# nt_password_hash as well. +ifndef LIBS_c +LIBS_c := $(LIBS) +endif +ifndef LIBS_h +LIBS_h := $(LIBS) +endif +ifndef LIBS_n +LIBS_n := $(LIBS) +endif +endif + CFLAGS += $(EXTRA_CFLAGS) CFLAGS += -I$(abspath ../src) CFLAGS += -I$(abspath ../src/utils) export BINDIR ?= /usr/local/bin/ -# Uncomment following line and set the path to your kernel tree include -# directory if your C library does not include all header files. -# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include - -include .config +ifndef CONFIG_NO_GITVER +# Add VERSION_STR postfix for builds from a git repository +ifeq ($(wildcard ../.git),../.git) +GITVER := $(shell git describe --dirty=+) +ifneq ($(GITVER),) +CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\" +endif +endif +endif + ifdef CONFIG_TESTING_OPTIONS CFLAGS += -DCONFIG_TESTING_OPTIONS CONFIG_WPS_TESTING=y @@ -63,8 +84,13 @@ OBJS += ../src/ap/pmksa_cache_auth.o OBJS += ../src/ap/ieee802_11_shared.o OBJS += ../src/ap/beacon.o OBJS += ../src/ap/bss_load.o +OBJS += ../src/ap/neighbor_db.o +OBJS += ../src/ap/rrm.o -OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o +OBJS_c = hostapd_cli.o +OBJS_c += ../src/common/wpa_ctrl.o +OBJS_c += ../src/utils/os_$(CONFIG_OS).o +OBJS_c += ../src/common/cli.o NEED_RC4=y NEED_AES=y @@ -74,6 +100,11 @@ NEED_SHA1=y OBJS += ../src/drivers/drivers.o CFLAGS += -DHOSTAPD +ifdef CONFIG_TAXONOMY +CFLAGS += -DCONFIG_TAXONOMY +OBJS += ../src/ap/taxonomy.o +endif + ifdef CONFIG_MODULE_TESTS CFLAGS += -DCONFIG_MODULE_TESTS OBJS += hapd_module_tests.o @@ -115,6 +146,10 @@ ifdef CONFIG_ELOOP_EPOLL CFLAGS += -DCONFIG_ELOOP_EPOLL endif +ifdef CONFIG_ELOOP_KQUEUE +CFLAGS += -DCONFIG_ELOOP_KQUEUE +endif + OBJS += ../src/utils/common.o OBJS_c += ../src/utils/common.o OBJS += ../src/utils/wpa_debug.o @@ -165,22 +200,53 @@ ifdef CONFIG_NO_VLAN CFLAGS += -DCONFIG_NO_VLAN else OBJS += ../src/ap/vlan_init.o -ifdef CONFIG_VLAN_NETLINK +OBJS += ../src/ap/vlan_ifconfig.o +OBJS += ../src/ap/vlan.o ifdef CONFIG_FULL_DYNAMIC_VLAN +# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges +# and VLAN interfaces for the VLAN feature. +CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN +OBJS += ../src/ap/vlan_full.o +ifdef CONFIG_VLAN_NETLINK OBJS += ../src/ap/vlan_util.o +else +OBJS += ../src/ap/vlan_ioctl.o endif -CFLAGS += -DCONFIG_VLAN_NETLINK endif endif ifdef CONFIG_NO_CTRL_IFACE CFLAGS += -DCONFIG_NO_CTRL_IFACE else +ifeq ($(CONFIG_CTRL_IFACE), udp) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +else +ifeq ($(CONFIG_CTRL_IFACE), udp6) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +else +ifeq ($(CONFIG_CTRL_IFACE), udp-remote) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +else +ifeq ($(CONFIG_CTRL_IFACE), udp6-remote) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +else +CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +endif +endif +endif +endif +OBJS += ../src/common/ctrl_iface_common.o OBJS += ctrl_iface.o OBJS += ../src/ap/ctrl_iface_ap.o endif -CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX +ifndef CONFIG_NO_CTRL_IFACE +CFLAGS += -DCONFIG_CTRL_IFACE +endif ifdef CONFIG_IAPP CFLAGS += -DCONFIG_IAPP @@ -252,6 +318,11 @@ ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_MBO +CFLAGS += -DCONFIG_MBO +OBJS += ../src/ap/mbo_ap.o +endif + include ../src/drivers/drivers.mak OBJS += $(DRV_AP_OBJS) CFLAGS += $(DRV_AP_CFLAGS) @@ -534,6 +605,7 @@ endif ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS OBJS += ../src/crypto/tls_openssl.o +OBJS += ../src/crypto/tls_openssl_ocsp.o LIBS += -lssl endif OBJS += ../src/crypto/crypto_openssl.o @@ -634,6 +706,8 @@ CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif @@ -794,6 +868,16 @@ CFLAGS += -DCONFIG_SHA384 OBJS += ../src/crypto/sha384-prf.o endif +ifdef CONFIG_INTERNAL_SHA384 +CFLAGS += -DCONFIG_INTERNAL_SHA384 +OBJS += ../src/crypto/sha384-internal.o +endif + +ifdef CONFIG_INTERNAL_SHA512 +CFLAGS += -DCONFIG_INTERNAL_SHA512 +OBJS += ../src/crypto/sha512-internal.o +endif + ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_groups.o endif @@ -835,12 +919,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL endif -ifdef CONFIG_FULL_DYNAMIC_VLAN -# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges -# and vlan interfaces for the vlan feature. -CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN -endif - ifdef NEED_BASE64 OBJS += ../src/utils/base64.o endif diff --git a/hostapd/README b/hostapd/README index 366b199..5d5fd36 100644 --- a/hostapd/README +++ b/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-2015, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/hostapd/android.config b/hostapd/android.config index 0b1d7c7..e382c40 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -25,6 +25,9 @@ #LIBS += -L$(LIBNL)/lib CONFIG_LIBNL20=y +# QCA vendor extensions to nl80211 +CONFIG_DRIVER_NL80211_QCA=y + # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) #CONFIG_DRIVER_BSD=y #CFLAGS += -I/usr/local/include @@ -191,3 +194,8 @@ CONFIG_AP=y # Enable Fast Session Transfer (FST) #CONFIG_FST=y + +# Multiband Operation support +# These extentions facilitate efficient use of multiple frequency bands +# available to the AP and the devices that may associate with it. +#CONFIG_MBO=y diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 82ac61d..5079f69 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -97,6 +97,8 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, } vlan->vlan_id = vlan_id; + vlan->vlan_desc.untagged = vlan_id; + vlan->vlan_desc.notempty = !!vlan_id; os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname)); vlan->next = bss->vlan; bss->vlan = vlan; @@ -197,7 +199,10 @@ static int hostapd_config_read_maclist(const char *fname, *acl = newacl; os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); - (*acl)[*num].vlan_id = vlan_id; + os_memset(&(*acl)[*num].vlan_id, 0, + sizeof((*acl)[*num].vlan_id)); + (*acl)[*num].vlan_id.untagged = vlan_id; + (*acl)[*num].vlan_id.notempty = !!vlan_id; (*num)++; } @@ -631,8 +636,7 @@ hostapd_parse_radius_attr(const char *value) } -static int hostapd_parse_das_client(struct hostapd_bss_config *bss, - const char *val) +static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val) { char *secret; @@ -640,7 +644,7 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss, if (secret == NULL) return -1; - secret++; + *secret++ = '\0'; if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr)) return -1; @@ -1519,6 +1523,54 @@ fail: } +static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line) +{ + char *delim; + u16 infoid; + size_t len; + struct wpabuf *payload; + struct anqp_element *elem; + + delim = os_strchr(buf, ':'); + if (!delim) + return -1; + delim++; + infoid = atoi(buf); + len = os_strlen(delim); + if (len & 1) + return -1; + len /= 2; + payload = wpabuf_alloc(len); + if (!payload) + return -1; + if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) { + wpabuf_free(payload); + return -1; + } + + dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) { + if (elem->infoid == infoid) { + /* Update existing entry */ + wpabuf_free(elem->payload); + elem->payload = payload; + return 0; + } + } + + /* Add a new entry */ + elem = os_zalloc(sizeof(*elem)); + if (!elem) { + wpabuf_free(payload); + return -1; + } + elem->infoid = infoid; + elem->payload = payload; + dl_list_add(&bss->anqp_elem, &elem->list); + + return 0; +} + + static int parse_qos_map_set(struct hostapd_bss_config *bss, char *buf, int line) { @@ -1867,31 +1919,6 @@ static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss, #endif /* CONFIG_HS20 */ -#ifdef CONFIG_WPS_NFC -static struct wpabuf * hostapd_parse_bin(const char *buf) -{ - size_t len; - struct wpabuf *ret; - - len = os_strlen(buf); - if (len & 0x01) - return NULL; - len /= 2; - - ret = wpabuf_alloc(len); - if (ret == NULL) - return NULL; - - if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { - wpabuf_free(ret); - return NULL; - } - - return ret; -} -#endif /* CONFIG_WPS_NFC */ - - #ifdef CONFIG_ACS static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf, char *pos) @@ -1934,6 +1961,31 @@ fail: #endif /* CONFIG_ACS */ +static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf, + const char *val) +{ + struct wpabuf *elems; + + if (val[0] == '\0') { + wpabuf_free(*buf); + *buf = NULL; + return 0; + } + + elems = wpabuf_parse_bin(val); + if (!elems) { + wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'", + line, name, val); + return -1; + } + + wpabuf_free(*buf); + *buf = elems; + + return 0; +} + + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *buf, char *pos, int line) @@ -2084,6 +2136,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, } 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, "ocsp_stapling_response_multi") == 0) { + os_free(bss->ocsp_stapling_response_multi); + bss->ocsp_stapling_response_multi = os_strdup(pos); } else if (os_strcmp(buf, "dh_file") == 0) { os_free(bss->dh_file); bss->dh_file = os_strdup(pos); @@ -2139,6 +2194,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } 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_db_timeout") == 0) { + bss->eap_sim_db_timeout = atoi(pos); } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) { bss->eap_sim_aka_result_ind = atoi(pos); #endif /* EAP_SERVER_SIM */ @@ -2353,6 +2410,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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_das_require_message_authenticator") == + 0) { + bss->radius_das_require_message_authenticator = atoi(pos); #endif /* CONFIG_NO_RADIUS */ } else if (os_strcmp(buf, "auth_algs") == 0) { bss->auth_algs = atoi(pos); @@ -2644,7 +2704,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "rts_threshold") == 0) { conf->rts_threshold = atoi(pos); - if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) { + if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) { wpa_printf(MSG_ERROR, "Line %d: invalid rts_threshold %d", line, conf->rts_threshold); @@ -2652,8 +2712,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "fragm_threshold") == 0) { conf->fragm_threshold = atoi(pos); - if (conf->fragm_threshold < 256 || - conf->fragm_threshold > 2346) { + if (conf->fragm_threshold == -1) { + /* allow a value of -1 */ + } else if (conf->fragm_threshold < 256 || + conf->fragm_threshold > 2346) { wpa_printf(MSG_ERROR, "Line %d: invalid fragm_threshold %d", line, conf->fragm_threshold); @@ -2686,6 +2748,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->preamble = LONG_PREAMBLE; } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) { bss->ignore_broadcast_ssid = atoi(pos); + } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) { + bss->no_probe_resp_if_max_sta = atoi(pos); } else if (os_strcmp(buf, "wep_default_key") == 0) { bss->ssid.wep.idx = atoi(pos); if (bss->ssid.wep.idx > 3) { @@ -2707,6 +2771,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, #ifndef CONFIG_NO_VLAN } else if (os_strcmp(buf, "dynamic_vlan") == 0) { bss->ssid.dynamic_vlan = atoi(pos); + } else if (os_strcmp(buf, "per_sta_vif") == 0) { + bss->ssid.per_sta_vif = 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'", @@ -2762,6 +2828,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line); return 1; } + } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) { + conf->use_driver_iface_addr = atoi(pos); #ifdef CONFIG_IEEE80211W } else if (os_strcmp(buf, "ieee80211w") == 0) { bss->ieee80211w = atoi(pos); @@ -2827,6 +2895,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->vht_oper_centr_freq_seg1_idx = atoi(pos); } else if (os_strcmp(buf, "vendor_vht") == 0) { bss->vendor_vht = atoi(pos); + } else if (os_strcmp(buf, "use_sta_nsts") == 0) { + bss->use_sta_nsts = atoi(pos); #endif /* CONFIG_IEEE80211AC */ } else if (os_strcmp(buf, "max_listen_interval") == 0) { bss->max_listen_interval = atoi(pos); @@ -2965,15 +3035,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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_dh_pubkey = wpabuf_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_dh_privkey = wpabuf_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_dev_pw = wpabuf_parse_bin(pos); bss->wps_nfc_pw_from_config = 1; #endif /* CONFIG_WPS_NFC */ #endif /* CONFIG_WPS */ @@ -3136,6 +3206,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "nai_realm") == 0) { if (parse_nai_realm(bss, pos, line) < 0) return 1; + } else if (os_strcmp(buf, "anqp_elem") == 0) { + if (parse_anqp_elem(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) { @@ -3149,13 +3222,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_free(bss->dump_msk_file); bss->dump_msk_file = os_strdup(pos); #endif /* CONFIG_RADIUS_TEST */ +#ifdef CONFIG_PROXYARP + } else if (os_strcmp(buf, "proxy_arp") == 0) { + bss->proxy_arp = atoi(pos); +#endif /* CONFIG_PROXYARP */ #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, "proxy_arp") == 0) { - bss->proxy_arp = atoi(pos); } else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) { bss->na_mcast_to_ucast = atoi(pos); } else if (os_strcmp(buf, "osen") == 0) { @@ -3231,6 +3306,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "subscr_remediation_method") == 0) { bss->subscr_remediation_method = atoi(pos); #endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + } else if (os_strcmp(buf, "mbo") == 0) { + bss->mbo_enabled = atoi(pos); +#endif /* CONFIG_MBO */ #ifdef CONFIG_TESTING_OPTIONS #define PARSE_TEST_PROBABILITY(_val) \ } else if (os_strcmp(buf, #_val) == 0) { \ @@ -3249,6 +3328,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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, "ecsa_ie_only") == 0) { + conf->ecsa_ie_only = atoi(pos); } else if (os_strcmp(buf, "bss_load_test") == 0) { WPA_PUT_LE16(bss->bss_load_test, atoi(pos)); pos = os_strchr(pos, ':'); @@ -3269,7 +3350,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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); + /* + * DEPRECATED: This parameter will be removed in the future. + * Use rrm_neighbor_report instead. + */ + int val = atoi(pos); + + if (val & BIT(0)) + bss->radio_measurements[0] |= + WLAN_RRM_CAPS_NEIGHBOR_REPORT; } else if (os_strcmp(buf, "own_ie_override") == 0) { struct wpabuf *tmp; size_t len = os_strlen(pos) / 2; @@ -3290,35 +3379,11 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->own_ie_override = tmp; #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 = NULL; - return 0; - } - - elems = wpabuf_alloc(len); - if (elems == NULL) + if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos)) 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); + } else if (os_strcmp(buf, "assocresp_elements") == 0) { + if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos)) return 1; - } - - 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) { @@ -3391,7 +3456,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, return -1; } val = strtol(pos, &endp, 0); - if (*endp || val < 1 || val > FST_MAX_LLT_MS) { + if (*endp || val < 1 || + (unsigned long int) val > FST_MAX_LLT_MS) { wpa_printf(MSG_ERROR, "Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)", line, val, pos, FST_MAX_LLT_MS); @@ -3409,6 +3475,22 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) { os_free(bss->no_auth_if_seen_on); bss->no_auth_if_seen_on = os_strdup(pos); + } else if (os_strcmp(buf, "lci") == 0) { + wpabuf_free(conf->lci); + conf->lci = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "civic") == 0) { + wpabuf_free(conf->civic); + conf->civic = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) { + if (atoi(pos)) + bss->radio_measurements[0] |= + WLAN_RRM_CAPS_NEIGHBOR_REPORT; + } else if (os_strcmp(buf, "gas_address3") == 0) { + bss->gas_address3 = atoi(pos); + } else if (os_strcmp(buf, "ftm_responder") == 0) { + bss->ftm_responder = atoi(pos); + } else if (os_strcmp(buf, "ftm_initiator") == 0) { + bss->ftm_initiator = atoi(pos); } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", @@ -3429,7 +3511,7 @@ struct hostapd_config * hostapd_config_read(const char *fname) { struct hostapd_config *conf; FILE *f; - char buf[512], *pos; + char buf[4096], *pos; int line = 0; int errors = 0; size_t i; diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index cb6fb17..d7db4a7 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -19,10 +19,16 @@ #include <sys/stat.h> #include <stddef.h> +#ifdef CONFIG_CTRL_IFACE_UDP +#include <netdb.h> +#endif /* CONFIG_CTRL_IFACE_UDP */ + #include "utils/common.h" #include "utils/eloop.h" +#include "utils/module_tests.h" #include "common/version.h" #include "common/ieee802_11_defs.h" +#include "common/ctrl_iface_common.h" #include "crypto/tls.h" #include "drivers/driver.h" #include "eapol_auth/eapol_auth_sm.h" @@ -42,6 +48,8 @@ #include "ap/wnm_ap.h" #include "ap/wpa_auth.h" #include "ap/beacon.h" +#include "ap/neighbor_db.h" +#include "ap/rrm.h" #include "wps/wps_defs.h" #include "wps/wps.h" #include "fst/fst_ctrl_iface.h" @@ -51,14 +59,15 @@ #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256 -struct wpa_ctrl_dst { - struct wpa_ctrl_dst *next; - struct sockaddr_un addr; - socklen_t addrlen; - int debug_level; - int errors; -}; - +#ifdef CONFIG_CTRL_IFACE_UDP +#define COOKIE_LEN 8 +static unsigned char cookie[COOKIE_LEN]; +static unsigned char gcookie[COOKIE_LEN]; +#define HOSTAPD_CTRL_IFACE_PORT 8877 +#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50 +#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878 +#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50 +#endif /* CONFIG_CTRL_IFACE_UDP */ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, enum wpa_msg_type type, @@ -66,81 +75,27 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dst->next = hapd->ctrl_dst; - hapd->ctrl_dst = dst; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - return 0; + return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen); } static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst, *prev = NULL; - - dst = hapd->ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - 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); - return 0; - } - prev = dst; - dst = dst->next; - } - return -1; + return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen); } static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, char *level) { - struct wpa_ctrl_dst *dst; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - - dst = hapd->ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - dst->debug_level = atoi(level); - return 0; - } - dst = dst->next; - } - - return -1; + return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level); } @@ -884,6 +839,8 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, int ret; u8 nei_rep[1000]; u8 *nei_pos = nei_rep; + u8 mbo[10]; + size_t mbo_len = 0; if (hwaddr_aton(cmd, addr)) { wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); @@ -1049,10 +1006,66 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, if (os_strstr(cmd, " disassoc_imminent=1")) req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; +#ifdef CONFIG_MBO + pos = os_strstr(cmd, "mbo="); + if (pos) { + unsigned int mbo_reason, cell_pref, reassoc_delay; + u8 *mbo_pos = mbo; + + ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason, + &reassoc_delay, &cell_pref); + if (ret != 3) { + wpa_printf(MSG_DEBUG, + "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>"); + return -1; + } + + if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) { + wpa_printf(MSG_DEBUG, + "Invalid MBO transition reason code %u", + mbo_reason); + return -1; + } + + /* Valid values for Cellular preference are: 0, 1, 255 */ + if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) { + wpa_printf(MSG_DEBUG, + "Invalid MBO cellular capability %u", + cell_pref); + return -1; + } + + if (reassoc_delay > 65535 || + (reassoc_delay && + !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) { + wpa_printf(MSG_DEBUG, + "MBO: Assoc retry delay is only valid in disassoc imminent mode"); + return -1; + } + + *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON; + *mbo_pos++ = 1; + *mbo_pos++ = mbo_reason; + *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF; + *mbo_pos++ = 1; + *mbo_pos++ = cell_pref; + + if (reassoc_delay) { + *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY; + *mbo_pos++ = 2; + WPA_PUT_LE16(mbo_pos, reassoc_delay); + mbo_pos += 2; + } + + mbo_len = mbo_pos - mbo; + } +#endif /* CONFIG_MBO */ + 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); + nei_pos - nei_rep, mbo_len ? mbo : NULL, + mbo_len); os_free(url); return ret; } @@ -1320,9 +1333,28 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { hapd->ext_eapol_frame_io = atoi(value); #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_MBO + } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) { + int val; + + if (!hapd->conf->mbo_enabled) + return -1; + + val = atoi(value); + if (val < 0 || val > 1) + return -1; + + hapd->mbo_assoc_disallow = val; + ieee802_11_update_beacons(hapd->iface); + + /* + * TODO: Need to configure drivers that do AP MLME offload with + * disallowing station logic. + */ +#endif /* CONFIG_MBO */ } else { struct sta_info *sta; - int vlan_id; + struct vlan_description vlan_id; ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); if (ret) @@ -1334,7 +1366,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hapd->conf->deny_mac, hapd->conf->num_deny_mac, sta->addr, &vlan_id) && - (!vlan_id || vlan_id == sta->vlan_id)) + (!vlan_id.notempty || + !vlan_compare(&vlan_id, sta->vlan_desc))) ap_sta_disconnect( hapd, sta, sta->addr, WLAN_REASON_UNSPECIFIED); @@ -1346,7 +1379,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hapd->conf->accept_mac, hapd->conf->num_accept_mac, sta->addr, &vlan_id) || - (vlan_id && vlan_id != sta->vlan_id)) + (vlan_id.notempty && + vlan_compare(&vlan_id, sta->vlan_desc))) ap_sta_disconnect( hapd, sta, sta->addr, WLAN_REASON_UNSPECIFIED); @@ -1557,8 +1591,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len) #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) +static 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; @@ -1745,8 +1779,6 @@ done: 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); @@ -1770,9 +1802,6 @@ 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 */ @@ -1784,8 +1813,6 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd, static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_test_fail_func[256]; - extern unsigned int wpa_trace_test_fail_after; char *pos; wpa_trace_test_fail_after = atoi(cmd); @@ -1809,9 +1836,6 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd, char *buf, size_t buflen) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_test_fail_func[256]; - extern unsigned int wpa_trace_test_fail_after; - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, wpa_trace_test_fail_func); #else /* WPA_TRACE_BFD */ @@ -1875,13 +1899,13 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ vendor_id = strtoul(cmd, &pos, 16); - if (!isblank(*pos)) + if (!isblank((unsigned char) *pos)) return -EINVAL; subcmd = strtoul(pos, &pos, 10); if (*pos != '\0') { - if (!isblank(*pos++)) + if (!isblank((unsigned char) *pos++)) return -EINVAL; data_len = os_strlen(pos); } @@ -2016,6 +2040,9 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd, struct hostapd_sta_info *info; struct os_reltime now; + if (!iface->num_sta_seen) + return 0; + sta_track_expire(iface, 0); pos = buf; @@ -2040,10 +2067,228 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd, #endif /* NEED_AP_MLME */ +static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address"); + return -1; + } + + return hostapd_send_lci_req(hapd, addr); +} + + +static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd) +{ + u8 addr[ETH_ALEN]; + char *token, *context = NULL; + int random_interval, min_ap; + u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS]; + unsigned int n_responders; + + token = str_token(cmd, " ", &context); + if (!token || hwaddr_aton(token, addr)) { + wpa_printf(MSG_INFO, + "CTRL: REQ_RANGE - Bad destination address"); + return -1; + } + + token = str_token(cmd, " ", &context); + if (!token) + return -1; + + random_interval = atoi(token); + if (random_interval < 0 || random_interval > 0xffff) + return -1; + + token = str_token(cmd, " ", &context); + if (!token) + return -1; + + min_ap = atoi(token); + if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP) + return -1; + + n_responders = 0; + while ((token = str_token(cmd, " ", &context))) { + if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) { + wpa_printf(MSG_INFO, + "CTRL: REQ_RANGE: Too many responders"); + return -1; + } + + if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) { + wpa_printf(MSG_INFO, + "CTRL: REQ_RANGE: Bad responder address"); + return -1; + } + + n_responders++; + } + + if (!n_responders) { + wpa_printf(MSG_INFO, + "CTRL: REQ_RANGE - No FTM responder address"); + return -1; + } + + return hostapd_send_range_req(hapd, addr, random_interval, min_ap, + responders, n_responders); +} + + +static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf) +{ + struct wpa_ssid_value ssid; + u8 bssid[ETH_ALEN]; + struct wpabuf *nr, *lci = NULL, *civic = NULL; + char *tmp; + int ret; + + if (!(hapd->conf->radio_measurements[0] & + WLAN_RRM_CAPS_NEIGHBOR_REPORT)) { + wpa_printf(MSG_ERROR, + "CTRL: SET_NEIGHBOR: Neighbor report is not enabled"); + return -1; + } + + if (hwaddr_aton(buf, bssid)) { + wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID"); + return -1; + } + + tmp = os_strstr(buf, "ssid="); + if (!tmp || ssid_parse(tmp + 5, &ssid)) { + wpa_printf(MSG_ERROR, + "CTRL: SET_NEIGHBOR: Bad or missing SSID"); + return -1; + } + buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' '); + if (!buf) + return -1; + + tmp = os_strstr(buf, "nr="); + if (!tmp) { + wpa_printf(MSG_ERROR, + "CTRL: SET_NEIGHBOR: Missing Neighbor Report element"); + return -1; + } + + buf = os_strchr(tmp, ' '); + if (buf) + *buf++ = '\0'; + + nr = wpabuf_parse_bin(tmp + 3); + if (!nr) { + wpa_printf(MSG_ERROR, + "CTRL: SET_NEIGHBOR: Bad Neighbor Report element"); + return -1; + } + + if (!buf) + goto set; + + tmp = os_strstr(buf, "lci="); + if (tmp) { + buf = os_strchr(tmp, ' '); + if (buf) + *buf++ = '\0'; + lci = wpabuf_parse_bin(tmp + 4); + if (!lci) { + wpa_printf(MSG_ERROR, + "CTRL: SET_NEIGHBOR: Bad LCI subelement"); + wpabuf_free(nr); + return -1; + } + } + + if (!buf) + goto set; + + tmp = os_strstr(buf, "civic="); + if (tmp) { + buf = os_strchr(tmp, ' '); + if (buf) + *buf++ = '\0'; + civic = wpabuf_parse_bin(tmp + 6); + if (!civic) { + wpa_printf(MSG_ERROR, + "CTRL: SET_NEIGHBOR: Bad civic subelement"); + wpabuf_free(nr); + wpabuf_free(lci); + return -1; + } + } + +set: + ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic); + + wpabuf_free(nr); + wpabuf_free(lci); + wpabuf_free(civic); + + return ret; +} + + +static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd, + char *buf) +{ + struct wpa_ssid_value ssid; + u8 bssid[ETH_ALEN]; + char *tmp; + + if (hwaddr_aton(buf, bssid)) { + wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID"); + return -1; + } + + tmp = os_strstr(buf, "ssid="); + if (!tmp || ssid_parse(tmp + 5, &ssid)) { + wpa_printf(MSG_ERROR, + "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID"); + return -1; + } + + return hostapd_neighbor_remove(hapd, bssid, &ssid); +} + + +static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf, + size_t buflen) +{ + int ret, i; + char *pos, *end; + + ret = os_snprintf(buf, buflen, "%016llX:\n", + (long long unsigned) iface->drv_flags); + if (os_snprintf_error(buflen, ret)) + return -1; + + pos = buf + ret; + end = buf + buflen; + + for (i = 0; i < 64; i++) { + if (iface->drv_flags & (1LLU << i)) { + ret = os_snprintf(pos, end - pos, "%s\n", + driver_flag_to_string(1LLU << i)); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + } + + return pos - buf; +} + + static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, char *buf, char *reply, int reply_size, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { int reply_len, res; @@ -2122,6 +2367,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) reply_len = -1; +#ifdef CONFIG_TAXONOMY + } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) { + reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10, + reply, reply_size); +#endif /* CONFIG_TAXONOMY */ + } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) { + if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9)) + reply_len = -1; } else if (os_strcmp(buf, "STOP_AP") == 0) { if (hostapd_ctrl_iface_stop_ap(hapd)) reply_len = -1; @@ -2276,6 +2529,26 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, reply_len = hostapd_ctrl_iface_track_sta_list( hapd, reply, reply_size); #endif /* NEED_AP_MLME */ + } else if (os_strcmp(buf, "PMKSA") == 0) { + reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply, + reply_size); + } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { + hostapd_ctrl_iface_pmksa_flush(hapd); + } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) { + if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13)) + reply_len = -1; + } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) { + if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16)) + reply_len = -1; + } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) { + if (hostapd_ctrl_iface_req_lci(hapd, buf + 8)) + reply_len = -1; + } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) { + if (hostapd_ctrl_iface_req_range(hapd, buf + 10)) + reply_len = -1; + } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { + reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply, + reply_size); } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -2296,12 +2569,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, struct hostapd_data *hapd = eloop_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); - char *reply; + char *reply, *pos = buf; const int reply_size = 4096; int reply_len; int level = MSG_DEBUG; +#ifdef CONFIG_CTRL_IFACE_UDP + unsigned char lcookie[COOKIE_LEN]; +#endif /* CONFIG_CTRL_IFACE_UDP */ res = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &fromlen); @@ -2311,9 +2587,6 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, return; } buf[res] = '\0'; - if (os_strcmp(buf, "PING") == 0) - level = MSG_EXCESSIVE; - wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res); reply = os_malloc(reply_size); if (reply == NULL) { @@ -2325,10 +2598,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, return; } - reply_len = hostapd_ctrl_iface_receive_process(hapd, buf, +#ifdef CONFIG_CTRL_IFACE_UDP + if (os_strcmp(buf, "GET_COOKIE") == 0) { + os_memcpy(reply, "COOKIE=", 7); + wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, + cookie, COOKIE_LEN); + reply_len = 7 + 2 * COOKIE_LEN; + goto done; + } + + if (os_strncmp(buf, "COOKIE=", 7) != 0 || + hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) { + wpa_printf(MSG_DEBUG, + "CTRL: No cookie in the request - drop request"); + os_free(reply); + return; + } + + if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid cookie in the request - drop request"); + os_free(reply); + return; + } + + pos = buf + 7 + 2 * COOKIE_LEN; + while (*pos == ' ') + pos++; +#endif /* CONFIG_CTRL_IFACE_UDP */ + + if (os_strcmp(pos, "PING") == 0) + level = MSG_EXCESSIVE; + wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res); + + reply_len = hostapd_ctrl_iface_receive_process(hapd, pos, reply, reply_size, &from, fromlen); +#ifdef CONFIG_CTRL_IFACE_UDP +done: +#endif /* CONFIG_CTRL_IFACE_UDP */ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen) < 0) { wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", @@ -2338,6 +2647,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } +#ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { char *buf; @@ -2357,6 +2667,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) buf[len - 1] = '\0'; return buf; } +#endif /* CONFIG_CTRL_IFACE_UDP */ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, @@ -2372,6 +2683,99 @@ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int hostapd_ctrl_iface_init(struct hostapd_data *hapd) { +#ifdef CONFIG_CTRL_IFACE_UDP + int port = HOSTAPD_CTRL_IFACE_PORT; + char p[32] = { 0 }; + char port_str[40], *tmp; + char *pos; + struct addrinfo hints = { 0 }, *res, *saveres; + int n; + + if (hapd->ctrl_sock > -1) { + wpa_printf(MSG_DEBUG, "ctrl_iface already exists!"); + return 0; + } + + if (hapd->conf->ctrl_interface == NULL) + return 0; + + pos = os_strstr(hapd->conf->ctrl_interface, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port"); + goto fail; + } + } + + dl_list_init(&hapd->ctrl_dst); + hapd->ctrl_sock = -1; + os_get_random(cookie, COOKIE_LEN); + +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + hints.ai_flags = AI_PASSIVE; +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ + +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + hints.ai_family = AF_INET6; +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + hints.ai_family = AF_INET; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + hints.ai_socktype = SOCK_DGRAM; + +try_again: + os_snprintf(p, sizeof(p), "%d", port); + n = getaddrinfo(NULL, p, &hints, &res); + if (n) { + wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n)); + goto fail; + } + + saveres = res; + hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (hapd->ctrl_sock < 0) { + wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); + goto fail; + } + + if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) { + port--; + if ((HOSTAPD_CTRL_IFACE_PORT - port) < + HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos) + goto try_again; + wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno)); + goto fail; + } + + freeaddrinfo(saveres); + + os_snprintf(port_str, sizeof(port_str), "udp:%d", port); + tmp = os_strdup(port_str); + if (tmp) { + os_free(hapd->conf->ctrl_interface); + hapd->conf->ctrl_interface = tmp; + } + wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port); + + if (eloop_register_read_sock(hapd->ctrl_sock, + 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); + + return 0; + +fail: + if (hapd->ctrl_sock >= 0) + close(hapd->ctrl_sock); + return -1; +#else /* CONFIG_CTRL_IFACE_UDP */ struct sockaddr_un addr; int s = -1; char *fname = NULL; @@ -2381,6 +2785,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) return 0; } + dl_list_init(&hapd->ctrl_dst); + if (hapd->conf->ctrl_interface == NULL) return 0; @@ -2520,6 +2926,7 @@ fail: os_free(fname); } return -1; +#endif /* CONFIG_CTRL_IFACE_UDP */ } @@ -2528,10 +2935,14 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) struct wpa_ctrl_dst *dst, *prev; if (hapd->ctrl_sock > -1) { +#ifndef CONFIG_CTRL_IFACE_UDP char *fname; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + eloop_unregister_read_sock(hapd->ctrl_sock); close(hapd->ctrl_sock); hapd->ctrl_sock = -1; +#ifndef CONFIG_CTRL_IFACE_UDP fname = hostapd_ctrl_iface_path(hapd); if (fname) unlink(fname); @@ -2550,15 +2961,12 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) strerror(errno)); } } +#endif /* !CONFIG_CTRL_IFACE_UDP */ } - dst = hapd->ctrl_dst; - hapd->ctrl_dst = NULL; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } + dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst, + list) + os_free(dst); #ifdef CONFIG_TESTING_OPTIONS l2_packet_deinit(hapd->l2_test); @@ -2590,54 +2998,18 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dst->next = interfaces->global_ctrl_dst; - interfaces->global_ctrl_dst = dst; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)", - from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - return 0; + return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen); } static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst, *prev = NULL; - - dst = interfaces->global_ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - 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 (global)", - from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - if (prev == NULL) - interfaces->global_ctrl_dst = dst->next; - else - prev->next = dst->next; - os_free(dst); - return 0; - } - prev = dst; - dst = dst->next; - } - return -1; + return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen); } @@ -2791,6 +3163,51 @@ error_return: static int +hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces, + const char *input, + char *reply, int reply_size) +{ + size_t i, j; + int res; + char *pos, *end; + struct hostapd_iface *iface; + int show_ctrl = 0; + + if (input) + show_ctrl = !!os_strstr(input, "ctrl"); + + pos = reply; + end = reply + reply_size; + + for (i = 0; i < interfaces->count; i++) { + iface = interfaces->iface[i]; + + for (j = 0; j < iface->num_bss; j++) { + struct hostapd_bss_config *conf; + + conf = iface->conf->bss[j]; + if (show_ctrl) + res = os_snprintf(pos, end - pos, + "%s ctrl_iface=%s\n", + conf->iface, + conf->ctrl_interface ? + conf->ctrl_interface : "N/A"); + else + res = os_snprintf(pos, end - pos, "%s\n", + conf->iface); + if (os_snprintf_error(end - pos, res)) { + *pos = '\0'; + return pos - reply; + } + pos += res; + } + } + + return pos - reply; +} + + +static int hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces, char *cmd) { @@ -2839,7 +3256,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces, const char *ifname, char *buf, char *reply, int reply_size, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { struct hostapd_data *hapd; @@ -2863,15 +3280,18 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { void *interfaces = eloop_ctx; - char buf[256]; + char buffer[256], *buf = buffer; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply; int reply_len; const int reply_size = 4096; +#ifdef CONFIG_CTRL_IFACE_UDP + unsigned char lcookie[COOKIE_LEN]; +#endif /* CONFIG_CTRL_IFACE_UDP */ - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", @@ -2894,6 +3314,35 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, os_memcpy(reply, "OK\n", 3); reply_len = 3; +#ifdef CONFIG_CTRL_IFACE_UDP + if (os_strcmp(buf, "GET_COOKIE") == 0) { + os_memcpy(reply, "COOKIE=", 7); + wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, + gcookie, COOKIE_LEN); + reply_len = 7 + 2 * COOKIE_LEN; + goto send_reply; + } + + if (os_strncmp(buf, "COOKIE=", 7) != 0 || + hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) { + wpa_printf(MSG_DEBUG, + "CTRL: No cookie in the request - drop request"); + os_free(reply); + return; + } + + if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid cookie in the request - drop request"); + os_free(reply); + return; + } + + buf += 7 + 2 * COOKIE_LEN; + while (*buf == ' ') + buf++; +#endif /* CONFIG_CTRL_IFACE_UDP */ + if (os_strncmp(buf, "IFNAME=", 7) == 0) { char *pos = os_strchr(buf + 7, ' '); @@ -2930,7 +3379,6 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, 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 */ @@ -2954,6 +3402,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len = os_snprintf(reply, reply_size, "OK\n"); else reply_len = -1; + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { + reply_len = hostapd_global_ctrl_iface_interfaces( + interfaces, buf + 10, reply, sizeof(buffer)); + } else if (os_strcmp(buf, "TERMINATE") == 0) { + eloop_terminate(); } else { wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " "ignored"); @@ -2975,6 +3428,7 @@ send_reply: } +#ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) { char *buf; @@ -2994,10 +3448,95 @@ static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) buf[len - 1] = '\0'; return buf; } +#endif /* CONFIG_CTRL_IFACE_UDP */ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) { +#ifdef CONFIG_CTRL_IFACE_UDP + int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT; + char p[32] = { 0 }; + char *pos; + struct addrinfo hints = { 0 }, *res, *saveres; + int n; + + if (interface->global_ctrl_sock > -1) { + wpa_printf(MSG_DEBUG, "ctrl_iface already exists!"); + return 0; + } + + if (interface->global_iface_path == NULL) + return 0; + + pos = os_strstr(interface->global_iface_path, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port"); + goto fail; + } + } + + dl_list_init(&interface->global_ctrl_dst); + interface->global_ctrl_sock = -1; + os_get_random(gcookie, COOKIE_LEN); + +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + hints.ai_flags = AI_PASSIVE; +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ + +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + hints.ai_family = AF_INET6; +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + hints.ai_family = AF_INET; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + hints.ai_socktype = SOCK_DGRAM; + +try_again: + os_snprintf(p, sizeof(p), "%d", port); + n = getaddrinfo(NULL, p, &hints, &res); + if (n) { + wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n)); + goto fail; + } + + saveres = res; + interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (interface->global_ctrl_sock < 0) { + wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); + goto fail; + } + + if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) < + 0) { + port++; + if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) < + HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos) + goto try_again; + wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno)); + goto fail; + } + + freeaddrinfo(saveres); + + wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port); + + if (eloop_register_read_sock(interface->global_ctrl_sock, + hostapd_global_ctrl_iface_receive, + interface, NULL) < 0) { + hostapd_global_ctrl_iface_deinit(interface); + return -1; + } + + return 0; + +fail: + if (interface->global_ctrl_sock >= 0) + close(interface->global_ctrl_sock); + return -1; +#else /* CONFIG_CTRL_IFACE_UDP */ struct sockaddr_un addr; int s = -1; char *fname = NULL; @@ -3103,18 +3642,22 @@ fail: os_free(fname); } return -1; +#endif /* CONFIG_CTRL_IFACE_UDP */ } void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) { +#ifndef CONFIG_CTRL_IFACE_UDP char *fname = NULL; +#endif /* CONFIG_CTRL_IFACE_UDP */ struct wpa_ctrl_dst *dst, *prev; if (interfaces->global_ctrl_sock > -1) { eloop_unregister_read_sock(interfaces->global_ctrl_sock); close(interfaces->global_ctrl_sock); interfaces->global_ctrl_sock = -1; +#ifndef CONFIG_CTRL_IFACE_UDP fname = hostapd_global_ctrl_iface_path(interfaces); if (fname) { unlink(fname); @@ -3134,18 +3677,15 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) strerror(errno)); } } +#endif /* CONFIG_CTRL_IFACE_UDP */ } os_free(interfaces->global_iface_path); interfaces->global_iface_path = NULL; - dst = interfaces->global_ctrl_dst; - interfaces->global_ctrl_dst = NULL; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } + dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst, + struct wpa_ctrl_dst, list) + os_free(dst); } @@ -3154,6 +3694,7 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, const char *buf, size_t len) { struct wpa_ctrl_dst *dst, *next; + struct dl_list *ctrl_dst; struct msghdr msg; int idx; struct iovec io[2]; @@ -3162,13 +3703,13 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, if (type != WPA_MSG_ONLY_GLOBAL) { s = hapd->ctrl_sock; - dst = hapd->ctrl_dst; + ctrl_dst = &hapd->ctrl_dst; } else { s = hapd->iface->interfaces->global_ctrl_sock; - dst = hapd->iface->interfaces->global_ctrl_dst; + ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst; } - if (s < 0 || dst == NULL) + if (s < 0 || dl_list_empty(ctrl_dst)) return; os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); @@ -3181,12 +3722,10 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, msg.msg_iovlen = 2; idx = 0; - while (dst) { - next = dst->next; + dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { if (level >= dst->debug_level) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); + sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send", + &dst->addr, dst->addrlen); msg.msg_name = &dst->addr; msg.msg_namelen = dst->addrlen; if (sendmsg(s, &msg, 0) < 0) { @@ -3210,7 +3749,6 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, dst->errors = 0; } idx++; - dst = next; } } diff --git a/hostapd/defconfig b/hostapd/defconfig index 430f758..4659dd1 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -18,6 +18,9 @@ CONFIG_DRIVER_HOSTAP=y # Driver interface for drivers using the nl80211 kernel interface CONFIG_DRIVER_NL80211=y +# QCA vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_QCA=y + # driver_nl80211.c requires libnl. If you are compiling it yourself # you may need to point hostapd to your version of libnl. # @@ -246,6 +249,9 @@ CONFIG_IPV6=y # Should we use epoll instead of select? Select is used by default. #CONFIG_ELOOP_EPOLL=y +# Should we use kqueue instead of select? Select is used by default. +#CONFIG_ELOOP_KQUEUE=y + # Select TLS implementation # openssl = OpenSSL (default) # gnutls = GnuTLS @@ -326,3 +332,14 @@ CONFIG_IPV6=y # http://wireless.kernel.org/en/users/Documentation/acs # #CONFIG_ACS=y + +# Multiband Operation support +# These extentions facilitate efficient use of multiple frequency bands +# available to the AP and the devices that may associate with it. +#CONFIG_MBO=y + +# Client Taxonomy +# Has the AP retain the Probe Request and (Re)Association Request frames from +# a client, from which a signature can be produced which can identify the model +# of client device like "Nexus 6P" or "iPhone 5s". +#CONFIG_TAXONOMY=y diff --git a/hostapd/hapd_module_tests.c b/hostapd/hapd_module_tests.c index f7887eb..a5016f2 100644 --- a/hostapd/hapd_module_tests.c +++ b/hostapd/hapd_module_tests.c @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/module_tests.h" int hapd_module_tests(void) { diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c index 84d0308..2117d34 100644 --- a/hostapd/hlr_auc_gw.c +++ b/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-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -284,7 +284,7 @@ static int read_gsm_triplets(const char *fname) f = fopen(fname, "r"); if (f == NULL) { - printf("Could not open GSM tripler data file '%s'\n", fname); + printf("Could not open GSM triplet data file '%s'\n", fname); return -1; } @@ -312,66 +312,40 @@ static int read_gsm_triplets(const char *fname) } /* IMSI */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) >= sizeof(g->imsi)) { - printf("%s:%d - Too long IMSI (%s)\n", - fname, line, pos); + pos2 = NULL; + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) >= sizeof(g->imsi)) { + printf("%s:%d - Invalid IMSI\n", fname, line); ret = -1; break; } os_strlcpy(g->imsi, pos, sizeof(g->imsi)); - pos = pos2 + 1; /* Kc */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { - printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { + printf("%s:%d - Invalid Kc\n", fname, line); ret = -1; break; } - pos = pos2 + 1; /* SRES */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid SRES (%s)\n", fname, line, - pos); + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) != 8 || + hexstr2bin(pos, g->sres, 4)) { + printf("%s:%d - Invalid SRES\n", fname, line); ret = -1; break; } - *pos2 = '\0'; - if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) { - printf("%s:%d - Invalid SRES (%s)\n", fname, line, - pos); - ret = -1; - break; - } - pos = pos2 + 1; /* RAND */ - pos2 = strchr(pos, ':'); - if (pos2) - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) { - printf("%s:%d - Invalid RAND (%s)\n", fname, line, - pos); + pos = str_token(buf, ":", &pos2); + if (!pos || os_strlen(pos) != 32 || + hexstr2bin(pos, g->_rand, 16)) { + printf("%s:%d - Invalid RAND\n", fname, line); ret = -1; break; } - pos = pos2 + 1; g->next = gsm_db; gsm_db = g; @@ -450,86 +424,58 @@ static int read_milenage(const char *fname) } /* IMSI */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) >= sizeof(m->imsi)) { - printf("%s:%d - Too long IMSI (%s)\n", - fname, line, pos); + pos2 = NULL; + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) >= sizeof(m->imsi)) { + printf("%s:%d - Invalid IMSI\n", fname, line); ret = -1; break; } os_strlcpy(m->imsi, pos, sizeof(m->imsi)); - pos = pos2 + 1; /* Ki */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 32 || + hexstr2bin(pos, m->ki, 16)) { + printf("%s:%d - Invalid Ki\n", fname, line); ret = -1; break; } - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) { - printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; /* OPc */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) { - printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 32 || + hexstr2bin(pos, m->opc, 16)) { + printf("%s:%d - Invalid OPc\n", fname, line); ret = -1; break; } - pos = pos2 + 1; /* AMF */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { - printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { + printf("%s:%d - Invalid AMF\n", fname, line); ret = -1; break; } - pos = pos2 + 1; /* SQN */ - pos2 = strchr(pos, ' '); - if (pos2) - *pos2 = '\0'; - if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) { - printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos); + pos = str_token(buf, " ", &pos2); + if (!pos || os_strlen(pos) != 12 || + hexstr2bin(pos, m->sqn, 6)) { + printf("%s:%d - Invalid SEQ\n", fname, line); ret = -1; break; } - if (pos2) { - pos = pos2 + 1; + pos = str_token(buf, " ", &pos2); + if (pos) { m->res_len = atoi(pos); if (m->res_len && (m->res_len < EAP_AKA_RES_MIN_LEN || m->res_len > EAP_AKA_RES_MAX_LEN)) { - printf("%s:%d - Invalid RES_len (%s)\n", - fname, line, pos); + printf("%s:%d - Invalid RES_len\n", + fname, line); ret = -1; break; } @@ -1027,7 +973,7 @@ static void usage(void) { printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA " "database/authenticator\n" - "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n" + "Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n" "\n" "usage:\n" "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] " diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc new file mode 100644 index 0000000..83e8d87 --- /dev/null +++ b/hostapd/hostapd.android.rc @@ -0,0 +1,20 @@ +# +# init.rc fragment for hostapd on Android +# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. +# + +on post-fs-data + mkdir /data/misc/wifi/hostapd 0770 wifi wifi + +service hostapd /system/bin/hostapd \ + -e /data/misc/wifi/entropy.bin \ + /data/misc/wifi/hostapd.conf + class main + user wifi + writepid /data/misc/wifi/hostapd.pid + group wifi + disabled + oneshot diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index a0071f7..fa9a855 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -3,6 +3,8 @@ # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for # management frames with the Host AP driver); wlan0 with many nl80211 drivers +# Note: This attribute can be overridden by the values supplied with the '-i' +# command line parameter. interface=wlan0 # In case of atheros and nl80211 driver interfaces, an additional @@ -125,11 +127,13 @@ ssid=test # 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). When using ACS (see channel parameter), a special value "any" -# can be used to indicate that any support band can be used. This special case -# is currently supported only with drivers with which offloaded ACS is used. +# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz), +# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used +# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this +# needs to be set to hw_mode=a. When using ACS (see channel parameter), a +# special value "any" can be used to indicate that any support band can be used. +# This special case is currently supported only with drivers with which +# offloaded ACS is used. # Default: IEEE 802.11b hw_mode=g @@ -173,7 +177,7 @@ channel=1 # Channel list restriction. This option allows hostapd to select one of the # provided channels when a channel should be automatically selected. # Channel list can be provided as range using hyphen ('-') or individual -# channels can be specified by space (' ') seperated values +# channels can be specified by space (' ') separated values # Default: all channels allowed in selected hw_mode #chanlist=100 104 108 112 116 #chanlist=1 6 11-13 @@ -192,16 +196,16 @@ dtim_period=2 # (default: 2007) max_num_sta=255 -# RTS/CTS threshold; 2347 = disabled (default); range 0..2347 +# RTS/CTS threshold; -1 = disabled (default); range -1..65535 # If this field is not included in hostapd.conf, hostapd will not control # RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it. -rts_threshold=2347 +rts_threshold=-1 -# Fragmentation threshold; 2346 = disabled (default); range 256..2346 +# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346 # If this field is not included in hostapd.conf, hostapd will not control # fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set # it. -fragm_threshold=2346 +fragm_threshold=-1 # Rate configuration # Default is to enable all rates supported by the hardware. This configuration @@ -267,13 +271,27 @@ auth_algs=3 # requests for broadcast SSID ignore_broadcast_ssid=0 -# Additional vendor specfic elements for Beacon and Probe Response frames +# Do not reply to broadcast Probe Request frames from unassociated STA if there +# is no room for additional stations (max_num_sta). This can be used to +# discourage a STA from trying to associate with this AP if the association +# would be rejected due to maximum STA limit. +# Default: 0 (disabled) +#no_probe_resp_if_max_sta=0 + +# Additional vendor specific elements for Beacon and Probe Response frames # This parameter can be used to add additional vendor specific element(s) into # the end of the Beacon and Probe Response frames. The format for these # element(s) is a hexdump of the raw information elements (id+len+payload for # one or more elements) #vendor_elements=dd0411223301 +# Additional vendor specific elements for (Re)Association Response frames +# This parameter can be used to add additional vendor specific element(s) into +# the end of the (Re)Association Response frames. The format for these +# element(s) is a hexdump of the raw information elements (id+len+payload for +# one or more elements) +#assocresp_elements=dd0411223301 + # TX queue parameters (EDCF / bursting) # tx_queue_<queue name>_<param> # queues: data0, data1, data2, data3, after_beacon, beacon @@ -470,6 +488,7 @@ wmm_ac_vo_acm=0 # 0 = disabled (default) # 1 = enabled # Note: You will also need to enable WMM for full HT functionality. +# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band. #ieee80211n=1 # ht_capab: HT capabilities (list of flags) @@ -523,6 +542,7 @@ wmm_ac_vo_acm=0 # 0 = disabled (default) # 1 = enabled # Note: You will also need to enable WMM for full VHT functionality. +# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT. #ieee80211ac=1 # vht_capab: VHT capabilities (list of flags) @@ -605,9 +625,9 @@ wmm_ac_vo_acm=0 # VHT TXOP PS: [VHT-TXOP-PS] # Indicates whether or not the AP supports VHT TXOP Power Save Mode # or whether or not the STA is in VHT TXOP Power Save mode -# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS +# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS # mode -# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save +# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save # mode # # +HTC-VHT Capable: [HTC-VHT] @@ -665,6 +685,13 @@ wmm_ac_vo_acm=0 # #vht_oper_centr_freq_seg1_idx=159 +# Workaround to use station's nsts capability in (Re)Association Response frame +# This may be needed with some deployed devices as an interoperability +# workaround for beamforming if the AP's capability is greater than the +# station's capability. This is disabled by default and can be enabled by +# setting use_sta_nsts=1. +#use_sta_nsts=0 + ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization @@ -788,6 +815,11 @@ eap_server=0 # -respout /tmp/ocsp-cache.der #ocsp_stapling_response=/tmp/ocsp-cache.der +# Cached OCSP stapling response list (DER encoded OCSPResponseList) +# This is similar to ocsp_stapling_response, but the extended version defined in +# RFC 6961 to allow multiple OCSP responses to be provided. +#ocsp_stapling_response_multi=/tmp/ocsp-multi-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 @@ -825,6 +857,11 @@ eap_server=0 #eap_sim_db=unix:/tmp/hlr_auc_gw.sock #eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db +# EAP-SIM DB request timeout +# This parameter sets the maximum time to wait for a database request response. +# The parameter value is in seconds. +#eap_sim_db_timeout=1 + # Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, # random value. It is configured as a 16-octet value in hex format. It can be # generated, e.g., with the following command: @@ -888,11 +925,23 @@ eap_server=0 # The own IP address of the access point (used as NAS-IP-Address) own_ip_addr=127.0.0.1 -# Optional NAS-Identifier string for RADIUS messages. When used, this should be -# a unique to the NAS within the scope of the RADIUS server. For example, a -# fully qualified domain name can be used here. +# NAS-Identifier string for RADIUS messages. When used, this should be unique +# to the NAS within the scope of the RADIUS server. Please note that hostapd +# uses a separate RADIUS client for each BSS and as such, a unique +# nas_identifier value should be configured separately for each BSS. This is +# particularly important for cases where RADIUS accounting is used +# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions +# and that may get interpreted as applying to all BSSes if the same +# NAS-Identifier value is used.) For example, a fully qualified domain name +# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here. +# # When using IEEE 802.11r, nas_identifier must be set and must be between 1 and # 48 octets long. +# +# It is mandatory to configure either own_ip_addr or nas_identifier to be +# compliant with the RADIUS protocol. When using RADIUS accounting, it is +# strongly recommended that nas_identifier is set to a unique value for each +# BSS. #nas_identifier=ap.example.com # RADIUS client forced local IP address for the access point @@ -957,6 +1006,17 @@ own_ip_addr=127.0.0.1 # 2 = required; reject authentication if RADIUS server does not include VLAN ID #dynamic_vlan=0 +# Per-Station AP_VLAN interface mode +# If enabled, each station is assigned its own AP_VLAN interface. +# This implies per-station group keying and ebtables filtering of inter-STA +# traffic (when passed through the AP). +# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be +# added to the bridge given by the "bridge" configuration option (see above). +# Otherwise, it will be added to the per-VLAN bridge. +# 0 = disabled (default) +# 1 = enabled +#per_sta_vif=0 + # VLAN interface list for dynamic VLAN mode is read from a separate text file. # This list is used to map VLAN ID from the RADIUS server to a network # interface. Each station is bound to one interface in the same way as with @@ -1035,6 +1095,9 @@ own_ip_addr=127.0.0.1 # # DAS require Event-Timestamp #radius_das_require_event_timestamp=1 +# +# DAS require Message-Authenticator +#radius_das_require_message_authenticator=1 ##### RADIUS authentication server configuration ############################## @@ -1228,6 +1291,7 @@ own_ip_addr=127.0.0.1 # PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID) # 6-octet identifier as a hex string. +# Defaults to BSSID. #r1_key_holder=000102030405 # Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535) @@ -1684,6 +1748,24 @@ own_ip_addr=127.0.0.1 # username/password #nai_realm=0,example.org,13[5:6],21[2:4][5:7] +# Arbitrary ANQP-element configuration +# Additional ANQP-elements with arbitrary values can be defined by specifying +# their contents in raw format as a hexdump of the payload. Note that these +# values will override ANQP-element contents that may have been specified in the +# more higher layer configuration parameters listed above. +# format: anqp_elem=<InfoID>:<hexdump of payload> +# For example, AP Geospatial Location ANQP-element with unknown location: +#anqp_elem=265:0000 +# For example, AP Civic Location ANQP-element with unknown location: +#anqp_elem=266:000000 + +# GAS Address 3 behavior +# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default +# based on GAS request Address3 +# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3 +# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases) +#gas_address3=0 + # QoS Map Set configuration # # Comma delimited QoS Map Set in decimal values @@ -1823,6 +1905,27 @@ own_ip_addr=127.0.0.1 # Transitioning between states). #fst_llt=100 +##### Radio measurements / location ########################################### + +# The content of a LCI measurement subelement +#lci=<Hexdump of binary data of the LCI report> + +# The content of a location civic measurement subelement +#civic=<Hexdump of binary data of the location civic report> + +# Enable neighbor report via radio measurements +#rrm_neighbor_report=1 + +# Publish fine timing measurement (FTM) responder functionality +# This parameter only controls publishing via Extended Capabilities element. +# Actual functionality is managed outside hostapd. +#ftm_responder=0 + +# Publish fine timing measurement (FTM) initiator functionality +# This parameter only controls publishing via Extended Capabilities element. +# Actual functionality is managed outside hostapd. +#ftm_initiator=0 + ##### TESTING OPTIONS ######################################################### # # The options in this section are only available when the build configuration @@ -1844,6 +1947,10 @@ own_ip_addr=127.0.0.1 # # Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability #corrupt_gtk_rekey_mic_probability=0.0 +# +# Include only ECSA IE without CSA IE where possible +# (channel switch operating class is needed) +#ecsa_ie_only=0 ##### Multiple BSSID support ################################################## # @@ -1866,6 +1973,10 @@ 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 # +# Alternatively, the 'use_driver_iface_addr' parameter can be used to request +# hostapd to use the driver auto-generated interface address (e.g., to use the +# exact MAC addresses allocated to the device). +# # 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" diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 46c2f37..5e62542 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1,6 +1,6 @@ /* * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -15,79 +15,13 @@ #include "utils/eloop.h" #include "utils/edit.h" #include "common/version.h" +#include "common/cli.h" +#ifndef CONFIG_NO_CTRL_IFACE static const char *const hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors"; - - -static const char *const hostapd_cli_license = -"This software may be distributed under the terms of the BSD license.\n" -"See README for more details.\n"; - -static const char *const hostapd_cli_full_license = -"This software may be distributed under the terms of the BSD license.\n" -"\n" -"Redistribution and use in source and binary forms, with or without\n" -"modification, are permitted provided that the following conditions are\n" -"met:\n" -"\n" -"1. Redistributions of source code must retain the above copyright\n" -" notice, this list of conditions and the following disclaimer.\n" -"\n" -"2. Redistributions in binary form must reproduce the above copyright\n" -" notice, this list of conditions and the following disclaimer in the\n" -" documentation and/or other materials provided with the distribution.\n" -"\n" -"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" -" names of its contributors may be used to endorse or promote products\n" -" derived from this software without specific prior written permission.\n" -"\n" -"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" -"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" -"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" -"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" -"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" -"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" -"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" -"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" -"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" -"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" -"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" -"\n"; - -static const char *const commands_help = -"Commands:\n" -" mib get MIB variables (dot1x, dot11, radius)\n" -" sta <addr> get MIB variables for one station\n" -" all_sta get MIB variables for all stations\n" -" new_sta <addr> add a new station\n" -" deauthenticate <addr> deauthenticate a station\n" -" disassociate <addr> disassociate a station\n" -#ifdef CONFIG_IEEE80211W -" sa_query <addr> send SA Query to a station\n" -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS -" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n" -" wps_check_pin <PIN> verify PIN checksum\n" -" wps_pbc indicate button pushed to initiate PBC\n" -" wps_cancel cancel the pending WPS operation\n" -#ifdef CONFIG_WPS_NFC -" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n" -" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n" -" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n" -#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" -" interface [ifname] show interfaces/select interface\n" -" level <debug level> change debug level\n" -" license show full hostapd_cli license\n" -" quit exit hostapd_cli\n"; +"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors"; static struct wpa_ctrl *ctrl_conn; static int hostapd_cli_quit = 0; @@ -104,6 +38,13 @@ static const char *pid_file = NULL; static const char *action_file = NULL; static int ping_interval = 5; static int interactive = 0; +static int event_handler_registered = 0; + +static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */ + +static void print_help(FILE *stream, const char *cmd); +static char ** list_cmd_list(void); +static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx); static void usage(void) @@ -128,20 +69,49 @@ static void usage(void) " -B run a daemon in the background\n" " -i<ifname> Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n" - "%s", - commands_help); + " socket path)\n\n"); + print_help(stderr, NULL); +} + + +static void register_event_handler(struct wpa_ctrl *ctrl) +{ + if (!ctrl_conn) + return; + if (interactive) { + event_handler_registered = + !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl), + hostapd_cli_receive, + NULL, NULL); + } +} + + +static void unregister_event_handler(struct wpa_ctrl *ctrl) +{ + if (!ctrl_conn) + return; + if (interactive && event_handler_registered) { + eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl)); + event_handler_registered = 0; + } } static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) { +#ifndef CONFIG_CTRL_IFACE_UDP char *cfile; int flen; +#endif /* !CONFIG_CTRL_IFACE_UDP */ if (ifname == NULL) return NULL; +#ifdef CONFIG_CTRL_IFACE_UDP + ctrl_conn = wpa_ctrl_open(ifname); + return ctrl_conn; +#else /* CONFIG_CTRL_IFACE_UDP */ flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; cfile = malloc(flen); if (cfile == NULL) @@ -158,6 +128,7 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir); free(cfile); return ctrl_conn; +#endif /* CONFIG_CTRL_IFACE_UDP */ } @@ -166,6 +137,7 @@ static void hostapd_cli_close_connection(void) if (ctrl_conn == NULL) return; + unregister_event_handler(ctrl_conn); if (hostapd_cli_attached) { wpa_ctrl_detach(ctrl_conn); hostapd_cli_attached = 0; @@ -215,6 +187,22 @@ static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) } +static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, + int min_args, int argc, char *argv[]) +{ + char buf[4096]; + + if (argc < min_args) { + printf("Invalid %s command - at least %d argument%s required.\n", + cmd, min_args, min_args > 1 ? "s are" : " is"); + return -1; + } + if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0) + return -1; + return wpa_ctrl_command(ctrl, buf); +} + + static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "PING"); @@ -330,6 +318,21 @@ static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, } +static char ** hostapd_complete_deauthenticate(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -348,6 +351,37 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, } +static char ** hostapd_complete_disassociate(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + +#ifdef CONFIG_TAXONOMY +static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[64]; + + if (argc != 1) { + printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n"); + return -1; + } + os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]); + return wpa_ctrl_command(ctrl, buf); +} +#endif /* CONFIG_TAXONOMY */ + + #ifdef CONFIG_IEEE80211W static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) @@ -720,15 +754,30 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - printf("%s", commands_help); + print_help(stdout, argc > 0 ? argv[0] : NULL); return 0; } +static char ** hostapd_cli_complete_help(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = list_cmd_list(); + break; + } + + return res; +} + + static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license); + printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license); return 0; } @@ -839,6 +888,28 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl, + struct dl_list *interfaces) +{ + struct dirent *dent; + DIR *dir; + + if (!ctrl || !interfaces) + return; + dir = opendir(ctrl_iface_dir); + if (dir == NULL) + return; + + while ((dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + cli_txt_list_add(interfaces, dent->d_name); + } + closedir(dir); +} + + static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) { struct dirent *dent; @@ -880,6 +951,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, printf("Connected to interface '%s.\n", ctrl_ifname); if (wpa_ctrl_attach(ctrl_conn) == 0) { hostapd_cli_attached = 1; + register_event_handler(ctrl_conn); } else { printf("Warning: Failed to attach to " "hostapd.\n"); @@ -892,6 +964,24 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, } +static char ** hostapd_complete_interface(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + DEFINE_DL_LIST(interfaces); + + switch (arg) { + case 1: + hostapd_cli_get_interfaces(ctrl_conn, &interfaces); + res = cli_txt_list_array(&interfaces); + cli_txt_list_flush(&interfaces); + break; + } + + return res; +} + + static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; @@ -1068,68 +1158,245 @@ static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc == 0) + return -1; + return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); +} + + +static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PMKSA"); +} + + +static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PMKSA_FLUSH"); +} + + +static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[2048]; + int res; + + if (argc < 3 || argc > 5) { + printf("Invalid set_neighbor command: needs 3-5 arguments\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s", + argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "", + argc == 5 ? argv[4] : ""); + if (os_snprintf_error(sizeof(cmd), res)) { + printf("Too long SET_NEIGHBOR command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[400]; + int res; + + if (argc != 2) { + printf("Invalid remove_neighbor command: needs 2 arguments\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s", + argv[0], argv[1]); + if (os_snprintf_error(sizeof(cmd), res)) { + printf("Too long REMOVE_NEIGHBOR command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid req_lci command - requires destination address\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]); + if (os_snprintf_error(sizeof(cmd), res)) { + printf("Too long REQ_LCI command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc < 4) { + printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n"); + return -1; + } + + return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv); +} + + +static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); +} + + struct hostapd_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); + char ** (*completion)(const char *str, int pos); + const char *usage; }; static const 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 }, - { "deauthenticate", hostapd_cli_cmd_deauthenticate }, - { "disassociate", hostapd_cli_cmd_disassociate }, + { "ping", hostapd_cli_cmd_ping, NULL, + "= pings hostapd" }, + { "mib", hostapd_cli_cmd_mib, NULL, + "= get MIB variables (dot1x, dot11, radius)" }, + { "relog", hostapd_cli_cmd_relog, NULL, NULL }, + { "status", hostapd_cli_cmd_status, NULL, NULL }, + { "sta", hostapd_cli_cmd_sta, NULL, + "<addr> = get MIB variables for one station" }, + { "all_sta", hostapd_cli_cmd_all_sta, NULL, + "= get MIB variables for all stations" }, + { "new_sta", hostapd_cli_cmd_new_sta, NULL, + "<addr> = add a new station" }, + { "deauthenticate", hostapd_cli_cmd_deauthenticate, + hostapd_complete_deauthenticate, + "<addr> = deauthenticate a station" }, + { "disassociate", hostapd_cli_cmd_disassociate, + hostapd_complete_disassociate, + "<addr> = disassociate a station" }, +#ifdef CONFIG_TAXONOMY + { "signature", hostapd_cli_cmd_signature, NULL, + "<addr> = get taxonomy signature for a station" }, +#endif /* CONFIG_TAXONOMY */ #ifdef CONFIG_IEEE80211W - { "sa_query", hostapd_cli_cmd_sa_query }, + { "sa_query", hostapd_cli_cmd_sa_query, NULL, + "<addr> = send SA Query to a station" }, #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS - { "wps_pin", hostapd_cli_cmd_wps_pin }, - { "wps_check_pin", hostapd_cli_cmd_wps_check_pin }, - { "wps_pbc", hostapd_cli_cmd_wps_pbc }, - { "wps_cancel", hostapd_cli_cmd_wps_cancel }, + { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, + "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, + { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL, + "<PIN> = verify PIN checksum" }, + { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL, + "= indicate button pushed to initiate PBC" }, + { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL, + "= cancel the pending WPS operation" }, #ifdef CONFIG_WPS_NFC - { "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 }, + { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL, + "<hexdump> = report read NFC tag with WPS data" }, + { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL, + "<WPS/NDEF> = build NFC configuration token" }, + { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL, + "<WPS/NDEF/enable/disable> = manager NFC password token" }, + { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL, + NULL }, #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 }, + { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL, + "<cmd> [params..] = enable/disable AP PIN" }, + { "wps_config", hostapd_cli_cmd_wps_config, NULL, + "<SSID> <auth> <encr> <key> = configure AP" }, + { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL, + "= show current WPS 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 }, + { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL }, + { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL }, + { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL }, + { "get_config", hostapd_cli_cmd_get_config, NULL, + "= show current configuration" }, + { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help, + "= show this usage help" }, + { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface, + "[ifname] = show interfaces/select interface" }, #ifdef CONFIG_FST - { "fst", hostapd_cli_cmd_fst }, + { "fst", hostapd_cli_cmd_fst, NULL, NULL }, #endif /* CONFIG_FST */ - { "level", hostapd_cli_cmd_level }, - { "license", hostapd_cli_cmd_license }, - { "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 }, - { "log_level", hostapd_cli_cmd_log_level }, - { NULL, NULL } + { "raw", hostapd_cli_cmd_raw, NULL, NULL }, + { "level", hostapd_cli_cmd_level, NULL, + "<debug level> = change debug level" }, + { "license", hostapd_cli_cmd_license, NULL, + "= show full hostapd_cli license" }, + { "quit", hostapd_cli_cmd_quit, NULL, + "= exit hostapd_cli" }, + { "set", hostapd_cli_cmd_set, NULL, NULL }, + { "get", hostapd_cli_cmd_get, NULL, NULL }, + { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL }, + { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL }, + { "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL }, + { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL }, + { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL }, + { "vendor", hostapd_cli_cmd_vendor, NULL, NULL }, + { "enable", hostapd_cli_cmd_enable, NULL, NULL }, + { "reload", hostapd_cli_cmd_reload, NULL, NULL }, + { "disable", hostapd_cli_cmd_disable, NULL, NULL }, + { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL }, + { "log_level", hostapd_cli_cmd_log_level, NULL, NULL }, + { "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL }, + { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL }, + { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL }, + { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL }, + { "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL }, + { "req_range", hostapd_cli_cmd_req_range, NULL, NULL }, + { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL }, + { NULL, NULL, NULL, NULL } }; +/* + * Prints command usage, lines are padded with the specified string. + */ +static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd, + const char *pad) +{ + char c; + size_t n; + + if (cmd->usage == NULL) + return; + fprintf(stream, "%s%s ", pad, cmd->cmd); + for (n = 0; (c = cmd->usage[n]); n++) { + fprintf(stream, "%c", c); + if (c == '\n') + fprintf(stream, "%s", pad); + } + fprintf(stream, "\n"); +} + + +static void print_help(FILE *stream, const char *cmd) +{ + int n; + + fprintf(stream, "commands:\n"); + for (n = 0; hostapd_cli_commands[n].cmd; n++) { + if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd)) + print_cmd_help(stream, &hostapd_cli_commands[n], " "); + } +} + + static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) { const struct hostapd_cli_cmd *cmd, *match = NULL; @@ -1169,6 +1436,34 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static void cli_event(const char *str) +{ + const char *start, *s; + + start = os_strchr(str, '>'); + if (start == NULL) + return; + + start++; + + if (str_starts(start, AP_STA_CONNECTED)) { + s = os_strchr(start, ' '); + if (s == NULL) + return; + cli_txt_list_add(&stations, s + 1); + return; + } + + if (str_starts(start, AP_STA_DISCONNECTED)) { + s = os_strchr(start, ' '); + if (s == NULL) + return; + cli_txt_list_del_addr(&stations, s + 1); + return; + } +} + + static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, int action_monitor) { @@ -1183,6 +1478,7 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, if (action_monitor) hostapd_cli_action_process(buf, len); else { + cli_event(buf); if (in_read && first) printf("\n"); first = 0; @@ -1196,35 +1492,9 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, } -#define max_args 10 - -static int tokenize_cmd(char *cmd, char *argv[]) +static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx) { - char *pos; - int argc = 0; - - pos = cmd; - for (;;) { - while (*pos == ' ') - pos++; - if (*pos == '\0') - break; - argv[argc] = pos; - argc++; - if (argc == max_args) - break; - if (*pos == '"') { - char *pos2 = os_strrchr(pos, '"'); - if (pos2) - pos = pos2 + 1; - } - while (*pos != '\0' && *pos != ' ') - pos++; - if (*pos == ' ') - *pos++ = '\0'; - } - - return argc; + hostapd_cli_recv_pending(ctrl_conn, 0, 0); } @@ -1240,6 +1510,7 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx) printf("Connection to hostapd re-established\n"); if (wpa_ctrl_attach(ctrl_conn) == 0) { hostapd_cli_attached = 1; + register_event_handler(ctrl_conn); } else { printf("Warning: Failed to attach to " "hostapd.\n"); @@ -1274,17 +1545,82 @@ static void hostapd_cli_edit_eof_cb(void *ctx) } +static char ** list_cmd_list(void) +{ + char **res; + int i, count; + + count = ARRAY_SIZE(hostapd_cli_commands); + res = os_calloc(count + 1, sizeof(char *)); + if (res == NULL) + return NULL; + + for (i = 0; hostapd_cli_commands[i].cmd; i++) { + res[i] = os_strdup(hostapd_cli_commands[i].cmd); + if (res[i] == NULL) + break; + } + + return res; +} + + +static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str, + int pos) +{ + int i; + + for (i = 0; hostapd_cli_commands[i].cmd; i++) { + if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0) + continue; + if (hostapd_cli_commands[i].completion) + return hostapd_cli_commands[i].completion(str, pos); + if (!hostapd_cli_commands[i].usage) + return NULL; + edit_clear_line(); + printf("\r%s\n", hostapd_cli_commands[i].usage); + edit_redraw(); + break; + } + + return NULL; +} + + +static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str, + int pos) +{ + char **res; + const char *end; + char *cmd; + + end = os_strchr(str, ' '); + if (end == NULL || str + pos < end) + return list_cmd_list(); + + cmd = os_malloc(pos + 1); + if (cmd == NULL) + return NULL; + os_memcpy(cmd, str, pos); + cmd[end - str] = '\0'; + res = hostapd_cli_cmd_completion(cmd, str, pos); + os_free(cmd); + return res; +} + + static void hostapd_cli_interactive(void) { printf("\nInteractive mode\n\n"); eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, - NULL, NULL, NULL, NULL); + hostapd_cli_edit_completion_cb, NULL, NULL, NULL); eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); eloop_run(); + cli_txt_list_flush(&stations); edit_deinit(NULL, NULL); eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL); } @@ -1388,8 +1724,7 @@ int main(int argc, char *argv[]) interactive = (argc == optind) && (action_file == NULL); if (interactive) { - printf("%s\n\n%s\n\n", hostapd_cli_version, - hostapd_cli_license); + printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license); } if (eloop_init()) @@ -1437,6 +1772,7 @@ int main(int argc, char *argv[]) if (interactive || action_file) { if (wpa_ctrl_attach(ctrl_conn) == 0) { hostapd_cli_attached = 1; + register_event_handler(ctrl_conn); } else { printf("Warning: Failed to attach to hostapd.\n"); if (action_file) @@ -1444,7 +1780,7 @@ int main(int argc, char *argv[]) } } - if (daemonize && os_daemonize(pid_file)) + if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) return -1; if (interactive) @@ -1454,8 +1790,18 @@ int main(int argc, char *argv[]) else wpa_request(ctrl_conn, argc - optind, &argv[optind]); + unregister_event_handler(ctrl_conn); os_free(ctrl_ifname); eloop_destroy(); hostapd_cli_cleanup(); return 0; } + +#else /* CONFIG_NO_CTRL_IFACE */ + +int main(int argc, char *argv[]) +{ + return -1; +} + +#endif /* CONFIG_NO_CTRL_IFACE */ diff --git a/hostapd/main.c b/hostapd/main.c index 6c7406a..2c8dbd3 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -1,6 +1,6 @@ /* * hostapd / main() - * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -171,7 +171,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface) if (global.drv_priv[i] == NULL && wpa_drivers[i]->global_init) { - global.drv_priv[i] = wpa_drivers[i]->global_init(); + global.drv_priv[i] = + wpa_drivers[i]->global_init(iface->interfaces); if (global.drv_priv[i] == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize " "driver '%s'", @@ -216,11 +217,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface) iface->drv_flags = capa.flags; iface->smps_modes = capa.smps_modes; iface->probe_resp_offloads = capa.probe_resp_offloads; + /* + * Use default extended capa values from per-radio information + */ 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; + /* + * Override extended capa with per-interface type (AP), if + * available from the driver. + */ + hostapd_get_ext_capa(iface); + triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); if (triggs && hapd->driver->set_wowlan) { if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) @@ -241,7 +251,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface) * interfaces. No actiual driver operations are started. */ static struct hostapd_iface * -hostapd_interface_init(struct hapd_interfaces *interfaces, +hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name, const char *config_fname, int debug) { struct hostapd_iface *iface; @@ -251,6 +261,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, iface = hostapd_init(interfaces, config_fname); if (!iface) return NULL; + + if (if_name) { + os_strlcpy(iface->conf->bss[0]->iface, if_name, + sizeof(iface->conf->bss[0]->iface)); + } + iface->interfaces = interfaces; for (k = 0; k < debug; k++) { @@ -260,7 +276,8 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, if (iface->conf->bss[0]->iface[0] == '\0' && !hostapd_drv_none(iface->bss[0])) { - wpa_printf(MSG_ERROR, "Interface name not specified in %s", + wpa_printf(MSG_ERROR, + "Interface name not specified in %s, nor by '-i' parameter", config_fname); hostapd_interface_deinit_free(iface); return NULL; @@ -329,6 +346,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces, wpa_printf(MSG_ERROR, "Failed to initialize event loop"); return -1; } + interfaces->eloop_initialized = 1; random_init(entropy_file); @@ -356,7 +374,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces, } -static void hostapd_global_deinit(const char *pid_file) +static void hostapd_global_deinit(const char *pid_file, int eloop_initialized) { int i; @@ -374,7 +392,8 @@ static void hostapd_global_deinit(const char *pid_file) random_deinit(); - eloop_destroy(); + if (eloop_initialized) + eloop_destroy(); #ifndef CONFIG_NATIVE_WINDOWS closelog(); @@ -408,9 +427,16 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, } #endif /* EAP_SERVER_TNC */ - if (daemonize && os_daemonize(pid_file)) { - wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); - return -1; + if (daemonize) { + if (os_daemonize(pid_file)) { + wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); + return -1; + } + if (eloop_sock_requeue()) { + wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s", + strerror(errno)); + return -1; + } } eloop_run(); @@ -425,7 +451,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-2015, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> " "and contributors\n"); } @@ -437,7 +463,8 @@ static void usage(void) "\n" "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] " "\\\n" - " [-g <global ctrl_iface>] [-G <group>] \\\n" + " [-g <global ctrl_iface>] [-G <group>]\\\n" + " [-i <comma-separated list of interface names>]\\\n" " <configuration file(s)>\n" "\n" "options:\n" @@ -456,6 +483,8 @@ static void usage(void) " -T = record to Linux tracing in addition to logging\n" " (records all messages regardless of debug verbosity)\n" #endif /* CONFIG_DEBUG_LINUX_TRACING */ + " -i list of interface names to use\n" + " -S start all the interfaces synchronously\n" " -t include timestamps in some debug messages\n" " -v show hostapd version\n"); @@ -466,9 +495,8 @@ 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 && - hapd->iconf->num_bss > 0 && hapd->iconf->bss[0]) - return hapd->iconf->bss[0]->iface; + if (hapd && hapd->conf) + return hapd->conf->iface; return NULL; } @@ -476,11 +504,16 @@ static const char * hostapd_msg_ifname_cb(void *ctx) static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, const char *path) { +#ifndef CONFIG_CTRL_IFACE_UDP char *pos; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + os_free(interfaces->global_iface_path); interfaces->global_iface_path = os_strdup(path); if (interfaces->global_iface_path == NULL) return -1; + +#ifndef CONFIG_CTRL_IFACE_UDP pos = os_strrchr(interfaces->global_iface_path, '/'); if (pos == NULL) { wpa_printf(MSG_ERROR, "No '/' in the global control interface " @@ -492,6 +525,7 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, *pos = '\0'; interfaces->global_iface_name = pos + 1; +#endif /* !CONFIG_CTRL_IFACE_UDP */ return 0; } @@ -513,6 +547,43 @@ static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, } +static int hostapd_get_interface_names(char ***if_names, + size_t *if_names_size, + char *optarg) +{ + char *if_name, *tmp, **nnames; + size_t i; + + if (!optarg) + return -1; + if_name = strtok_r(optarg, ",", &tmp); + + while (if_name) { + nnames = os_realloc_array(*if_names, 1 + *if_names_size, + sizeof(char *)); + if (!nnames) + goto fail; + *if_names = nnames; + + (*if_names)[*if_names_size] = os_strdup(if_name); + if (!(*if_names)[*if_names_size]) + goto fail; + (*if_names_size)++; + if_name = strtok_r(NULL, ",", &tmp); + } + + return 0; + +fail: + for (i = 0; i < *if_names_size; i++) + os_free((*if_names)[i]); + os_free(*if_names); + *if_names = NULL; + *if_names_size = 0; + return -1; +} + + #ifdef CONFIG_WPS static int gen_uuid(const char *txt_addr) { @@ -570,6 +641,9 @@ int main(int argc, char *argv[]) #ifdef CONFIG_DEBUG_LINUX_TRACING int enable_trace_dbg = 0; #endif /* CONFIG_DEBUG_LINUX_TRACING */ + int start_ifaces_in_sync = 0; + char **if_names = NULL; + size_t if_names_size = 0; if (os_program_init()) return -1; @@ -584,10 +658,10 @@ int main(int argc, char *argv[]) interfaces.global_iface_path = NULL; interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; - interfaces.global_ctrl_dst = NULL; + dl_list_init(&interfaces.global_ctrl_dst); for (;;) { - c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:"); + c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:"); if (c < 0) break; switch (c) { @@ -644,10 +718,18 @@ int main(int argc, char *argv[]) bss_config = tmp_bss; bss_config[num_bss_configs++] = optarg; break; + case 'S': + start_ifaces_in_sync = 1; + break; #ifdef CONFIG_WPS case 'u': return gen_uuid(optarg); #endif /* CONFIG_WPS */ + case 'i': + if (hostapd_get_interface_names(&if_names, + &if_names_size, optarg)) + goto out; + break; default: usage(); break; @@ -705,13 +787,21 @@ int main(int argc, char *argv[]) /* Allocate and parse configuration for full interface files */ for (i = 0; i < interfaces.count; i++) { + char *if_name = NULL; + + if (i < if_names_size) + if_name = if_names[i]; + interfaces.iface[i] = hostapd_interface_init(&interfaces, + if_name, argv[optind + i], debug); if (!interfaces.iface[i]) { wpa_printf(MSG_ERROR, "Failed to initialize interface"); goto out; } + if (start_ifaces_in_sync) + interfaces.iface[i]->need_to_start_in_sync = 1; } /* Allocate and parse configuration for per-BSS files */ @@ -787,8 +877,9 @@ int main(int argc, char *argv[]) } os_free(interfaces.iface); - eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL); - hostapd_global_deinit(pid_file); + if (interfaces.eloop_initialized) + eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL); + hostapd_global_deinit(pid_file, interfaces.eloop_initialized); os_free(pid_file); if (log_file) @@ -797,6 +888,10 @@ int main(int argc, char *argv[]) os_free(bss_config); + for (i = 0; i < if_names_size; i++) + os_free(if_names[i]); + os_free(if_names); + fst_global_deinit(); os_program_deinit(); |