summaryrefslogtreecommitdiff
path: root/hostapd
diff options
context:
space:
mode:
authorStefan Lippers-Hollmann <s.l-h@gmx.de>2014-06-29 23:18:53 +0000
committerAndrew Shadura <andrewsh@debian.org>2016-07-20 21:37:01 +0200
commit3a03694454bbec18114240b108a0af232133766b (patch)
treeade1c03a378de7430ac902dab71fb96576508eb6 /hostapd
parentc2af19e367fc0d1abca6a52d00b239618e8c6186 (diff)
Imported Upstream version 2.1
Diffstat (limited to 'hostapd')
-rw-r--r--hostapd/Android.mk172
-rw-r--r--hostapd/ChangeLog157
-rw-r--r--hostapd/Makefile154
-rw-r--r--hostapd/README31
-rw-r--r--hostapd/README-WPS63
-rw-r--r--hostapd/android.config190
-rw-r--r--hostapd/config_file.c1521
-rw-r--r--hostapd/config_file.h13
-rw-r--r--hostapd/ctrl_iface.c1241
-rw-r--r--hostapd/ctrl_iface.h23
-rw-r--r--hostapd/defconfig86
-rw-r--r--hostapd/dump_state.c186
-rw-r--r--hostapd/dump_state.h20
-rw-r--r--hostapd/eap_register.c20
-rw-r--r--hostapd/eap_register.h10
-rw-r--r--hostapd/hlr_auc_gw.c558
-rw-r--r--hostapd/hlr_auc_gw.txt104
-rw-r--r--hostapd/hostapd.conf552
-rw-r--r--hostapd/hostapd.eap_user_sqlite17
-rw-r--r--hostapd/hostapd_cli.c318
-rw-r--r--hostapd/main.c351
-rw-r--r--hostapd/nt_password_hash.c10
-rw-r--r--hostapd/wps-ap-nfc.py282
23 files changed, 4784 insertions, 1295 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 04fd771..6e37beb 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -1,37 +1,55 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
LOCAL_PATH := $(call my-dir)
WPA_BUILD_HOSTAPD := false
-ifneq ($(TARGET_SIMULATOR),true)
- ifneq ($(BOARD_HOSTAPD_DRIVER),)
- WPA_BUILD_HOSTAPD := true
- CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y
- endif
+ifneq ($(BOARD_HOSTAPD_DRIVER),)
+ WPA_BUILD_HOSTAPD := true
+ CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y
endif
-include $(LOCAL_PATH)/.config
+ifeq ($(WPA_BUILD_HOSTAPD),true)
+
+include $(LOCAL_PATH)/android.config
# To ignore possible wrong network configurations
L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
# Set Android log name
L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
+ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
+L_CFLAGS += -DANDROID_P2P
+endif
+
+ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
+L_CFLAGS += -DANDROID_P2P
+endif
+
+ifeq ($(BOARD_WLAN_DEVICE), mrvl)
+L_CFLAGS += -DANDROID_P2P
+endif
+
+# Use Android specific directory for control interface sockets
+L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\"
+
# To force sizeof(enum) = 4
ifeq ($(TARGET_ARCH),arm)
L_CFLAGS += -mabi=aapcs-linux
endif
-# To allow non-ASCII characters in SSID
-L_CFLAGS += -DWPA_UNICODE_SSID
-
-# OpenSSL is configured without engines on Android
-L_CFLAGS += -DOPENSSL_NO_ENGINE
-
INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/src
INCLUDES += $(LOCAL_PATH)/src/utils
INCLUDES += external/openssl/include
-INCLUDES += frameworks/base/cmds/keystore
+INCLUDES += system/security/keystore/include
ifdef CONFIG_DRIVER_NL80211
INCLUDES += external/libnl-headers
endif
@@ -65,6 +83,7 @@ OBJS += src/ap/utils.c
OBJS += src/ap/authsrv.c
OBJS += src/ap/ieee802_1x.c
OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
OBJS += src/ap/ieee802_11_auth.c
OBJS += src/ap/sta_info.c
OBJS += src/ap/wpa_auth.c
@@ -118,10 +137,10 @@ OBJS += src/eapol_auth/eapol_auth_sm.c
ifndef CONFIG_NO_DUMP_STATE
-# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
-# a file (undefine it, if you want to save in binary size)
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
L_CFLAGS += -DHOSTAPD_DUMP_STATE
-OBJS += dump_state.c
OBJS += src/eapol_auth/eapol_auth_dump.c
endif
@@ -131,6 +150,7 @@ CONFIG_NO_ACCOUNTING=y
else
OBJS += src/radius/radius.c
OBJS += src/radius/radius_client.c
+OBJS += src/radius/radius_das.c
endif
ifdef CONFIG_NO_ACCOUNTING
@@ -143,6 +163,12 @@ ifdef CONFIG_NO_VLAN
L_CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += src/ap/vlan_init.c
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_util.c
+endif
+L_CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@@ -185,10 +211,26 @@ NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+OBJS += src/ap/wnm_ap.c
+endif
+
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
OBJS += $(DRV_AP_OBJS)
@@ -225,6 +267,14 @@ OBJS += src/eap_server/eap_server_tls.c
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+endif
+
ifdef CONFIG_EAP_PEAP
L_CFLAGS += -DEAP_SERVER_PEAP
OBJS += src/eap_server/eap_server_peap.c
@@ -301,7 +351,7 @@ ifdef CONFIG_EAP_GPSK
L_CFLAGS += -DEAP_SERVER_GPSK
OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c
ifdef CONFIG_EAP_GPSK_SHA256
-L_CFLAGS += -DEAP_SERVER_GPSK_SHA256
+L_CFLAGS += -DEAP_GPSK_SHA256
endif
NEED_SHA256=y
NEED_AES_OMAC1=y
@@ -313,6 +363,13 @@ OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
NEED_SHA256=y
endif
+ifdef CONFIG_EAP_EKE
+L_CFLAGS += -DEAP_SERVER_EKE
+OBJS += src/eap_server/eap_server_eke.c src/eap_common/eap_eke_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
ifdef CONFIG_EAP_VENDOR_TEST
L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
OBJS += src/eap_server/eap_server_vendor_test.c
@@ -351,25 +408,10 @@ NEED_AES_CBC=y
NEED_MODEXP=y
CONFIG_EAP=y
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
L_CFLAGS += -DCONFIG_WPS_NFC
OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -458,6 +500,15 @@ ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
OBJS += src/crypto/tls_openssl.c
@@ -476,10 +527,6 @@ ifeq ($(CONFIG_TLS), gnutls)
ifdef TLS_FUNCS
OBJS += src/crypto/tls_gnutls.c
LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
endif
OBJS += src/crypto/crypto_gnutls.c
HOBJS += src/crypto/crypto_gnutls.c
@@ -541,6 +588,9 @@ OBJS += src/tls/pkcs8.c
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
L_CFLAGS += -DCONFIG_TLS_INTERNAL
@@ -655,14 +705,19 @@ endif
SHA1OBJS =
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
ifdef NEED_FIPS186_2_PRF
SHA1OBJS += src/crypto/fips_prf_internal.c
endif
endif
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
ifdef NEED_T_PRF
SHA1OBJS += src/crypto/sha1-tprf.c
endif
@@ -701,10 +756,17 @@ endif
endif
ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
OBJS += src/crypto/sha256.c
+endif
+OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
OBJS += src/crypto/sha256-internal.c
endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += src/crypto/sha256-tlsprf.c
+endif
endif
ifdef NEED_DH_GROUPS
@@ -719,11 +781,16 @@ OBJS += src/crypto/dh_group5.c
endif
endif
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
OBJS += src/crypto/random.c
HOBJS += src/crypto/random.c
+HOBJS += src/utils/eloop.c
HOBJS += $(SHA1OBJS)
HOBJS += src/crypto/md5.c
endif
@@ -756,23 +823,50 @@ OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
OBJS += src/ap/ieee802_11.c
OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
endif
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+
ifdef CONFIG_P2P_MANAGER
L_CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += src/ap/p2p_hostapd.c
endif
+ifdef CONFIG_HS20
+L_CFLAGS += -DCONFIG_HS20
+OBJS += src/ap/hs20.c
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+L_CFLAGS += -DCONFIG_INTERWORKING
+OBJS += src/common/gas.c
+OBJS += src/ap/gas_serv.c
+endif
+
OBJS += src/drivers/driver_common.c
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
ifdef CONFIG_NO_STDOUT_DEBUG
L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
L_CFLAGS += -DCONFIG_DEBUG_FILE
endif
@@ -793,14 +887,12 @@ else
OBJS_c += src/utils/edit_simple.c
endif
-ifeq ($(WPA_BUILD_HOSTAPD),true)
-
########################
include $(CLEAR_VARS)
LOCAL_MODULE := hostapd_cli
LOCAL_MODULE_TAGS := debug
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS_c)
LOCAL_C_INCLUDES := $(INCLUDES)
@@ -816,7 +908,7 @@ endif
ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB)
endif
-LOCAL_SHARED_LIBRARIES := libc libcutils libcrypto libssl
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog libcrypto libssl
ifdef CONFIG_DRIVER_NL80211
LOCAL_STATIC_LIBRARIES += libnl_2
endif
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 496f839..5ef9676 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,30 +1,137 @@
ChangeLog for hostapd
-2012-11-06 - v1.1
- * Fix EAPOL processing when STA switches between multi-BSSes.
- * EAP-TLS server: Fix a bug with TLS Message Length validation that
- could result in the process terminating.
- * Fix memory allocation failure handling in EAP-TTLS/MSCHAPv2 server.
- * Fix EAP-FAST with OpenSSL 1.0.1.
- * Fix WPA GTK rekeying with multiple VLANs.
- * EAP-pwd: Increase maximum number of hunting-and-pecking iterations,
- which results in less authentication attempts failing.
- * hlr_auc_gw: Use 5 bit IND for SQN updates. The length of IND can be
- configured on the command line with the new -i<IND len> parameter.
- -i0 would make hlr_auc_gw behave the same as the prev implementation.
- * EAP-AKA'
- - Update to RFC 5448 in the leading characters used in the username.
- This will make EAP-AKA' not interoperate between the earlier draft
- version and the new version.
- - server: Fix identity for MK derivation, when the EAP client is using
- pseudonym.
- * WPS:
- - Fix nonce comparisons to compare all bytes, not just the first byte.
- - Fix NFC password token building with WPS 2.0 to avoid wpabuf
- overflow and application abort if NFC out-of-band mechanism is used
- with WPS 2.0 enabled.
-
-2012-04-18 - v1.0
+2014-02-04 - v2.1
+ * added support for simultaneous authentication of equals (SAE) for
+ stronger password-based authentication with WPA2-Personal
+ * added nl80211 functionality
+ - VHT configuration for nl80211
+ - support split wiphy dump
+ - driver-based MAC ACL
+ - QoS Mapping configuration
+ * added fully automated regression testing with mac80211_hwsim
+ * allow ctrl_iface group to be specified on command line (-G<group>)
+ * allow single hostapd process to control independent WPS interfaces
+ (wps_independent=1) instead of synchronized operations through all
+ configured interfaces within a process
+ * avoid processing received management frames multiple times when using
+ nl80211 with multiple BSSes
+ * added support for DFS (processing radar detection events, CAC, channel
+ re-selection)
+ * added EAP-EKE server
+ * added automatic channel selection (ACS)
+ * added option for using per-BSS (vif) configuration files with
+ -b<phyname>:<config file name>
+ * extended global control interface ADD/REMOVE commands to allow BSSes
+ of a radio to be removed individually without having to add/remove all
+ other BSSes of the radio at the same time
+ * added support for sending debug info to Linux tracing (-T on command
+ line)
+ * replace dump_file functionality with same information being available
+ through the hostapd control interface
+ * added support for using Protected Dual of Public Action frames for
+ GAS/ANQP exchanges when PMF is enabled
+ * added support for WPS+NFC updates
+ - improved protocol
+ - option to fetch and report alternative carrier records for external
+ NFC operations
+ * various bug fixes
+
+2013-01-12 - v2.0
+ * added AP-STA-DISCONNECTED ctrl_iface event
+ * improved debug logging (human readable event names, interface name
+ included in more entries)
+ * added number of small changes to make it easier for static analyzers
+ to understand the implementation
+ * added a workaround for Windows 7 Michael MIC failure reporting and
+ use of the Secure bit in EAPOL-Key msg 3/4
+ * fixed number of small bugs (see git logs for more details)
+ * changed OpenSSL to read full certificate chain from server_cert file
+ * nl80211: number of updates to use new cfg80211/nl80211 functionality
+ - replace monitor interface with nl80211 commands
+ - additional information for driver-based AP SME
+ * EAP-pwd:
+ - fix KDF for group 21 and zero-padding
+ - added support for fragmentation
+ - increased maximum number of hunting-and-pecking iterations
+ * avoid excessive Probe Response retries for broadcast Probe Request
+ frames (only with drivers using hostapd SME/MLME)
+ * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+ * fixed WPS operation stopping on dual concurrent AP
+ * added wps_rf_bands configuration parameter for overriding RF Bands
+ value for WPS
+ * added support for getting per-device PSK from RADIUS Tunnel-Password
+ * added support for libnl 3.2 and newer
+ * increased initial group key handshake retransmit timeout to 500 ms
+ * added a workaround for 4-way handshake to update SNonce even after
+ having sent EAPOL-Key 3/4 to avoid issues with some supplicant
+ implementations that can change SNonce for each EAP-Key 2/4
+ * added a workaround for EAPOL-Key 4/4 using incorrect type value in
+ WPA2 mode (some deployed stations use WPA type in that message)
+ * added a WPS workaround for mixed mode AP Settings with Windows 7
+ * changed WPS AP PIN disabling mechanism to disable the PIN after 10
+ consecutive failures in addition to using the exponential lockout
+ period
+ * added support for WFA Hotspot 2.0
+ - GAS/ANQP advertisement of network information
+ - disable_dgaf parameter to disable downstream group-addressed
+ forwarding
+ * simplified licensing terms by selecting the BSD license as the only
+ alternative
+ * EAP-SIM: fixed re-authentication not to update pseudonym
+ * EAP-SIM: use Notification round before EAP-Failure
+ * EAP-AKA: added support for AT_COUNTER_TOO_SMALL
+ * EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized
+ * EAP-AKA': fixed identity for MK derivation
+ * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+ breaks interoperability with older versions
+ * EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id
+ * changed ANonce to be a random number instead of Counter-based
+ * added support for canceling WPS operations with hostapd_cli wps_cancel
+ * fixed EAP/WPS to PSK transition on reassociation in cases where
+ deauthentication is missed
+ * hlr_auc_gw enhancements:
+ - a new command line parameter -u can be used to enable updating of
+ SQN in Milenage file
+ - use 5 bit IND for SQN updates
+ - SQLite database can now be used to store Milenage information
+ * EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms
+ and reauth data
+ * added support for Chargeable-User-Identity (RFC 4372)
+ * added radius_auth_req_attr and radius_acct_req_attr configuration
+ parameters to allow adding/overriding of RADIUS attributes in
+ Access-Request and Accounting-Request packets
+ * added support for RADIUS dynamic authorization server (RFC 5176)
+ * added initial support for WNM operations
+ - BSS max idle period
+ - WNM-Sleep Mode
+ * added new WPS NFC ctrl_iface mechanism
+ - removed obsoleted WPS_OOB command (including support for deprecated
+ UFD config_method)
+ * added FT support for drivers that implement MLME internally
+ * added SA Query support for drivers that implement MLME internally
+ * removed default ACM=1 from AC_VO and AC_VI
+ * changed VENDOR-TEST EAP method to use proper private enterprise number
+ (this will not interoperate with older versions)
+ * added hostapd.conf parameter vendor_elements to allow arbitrary vendor
+ specific elements to be added to the Beacon and Probe Response frames
+ * added support for configuring GCMP cipher for IEEE 802.11ad
+ * added support for 256-bit AES with internal TLS implementation
+ * changed EAPOL transmission to use AC_VO if WMM is active
+ * fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length
+ correctly; invalid messages could have caused the hostapd process to
+ terminate before this fix [CVE-2012-4445]
+ * limit number of active wildcard PINs for WPS Registrar to one to avoid
+ confusing behavior with multiple wildcard PINs
+ * added a workaround for WPS PBC session overlap detection to avoid
+ interop issues with deployed station implementations that do not
+ remove active PBC indication from Probe Request frames properly
+ * added support for using SQLite for the eap_user database
+ * added Acct-Session-Id attribute into Access-Request messages
+ * fixed EAPOL frame transmission to non-QoS STAs with nl80211
+ (do not send QoS frames if the STA did not negotiate use of QoS for
+ this association)
+
+2012-05-10 - v1.0
* Add channel selection support in hostapd. See hostapd.conf.
* Add support for IEEE 802.11v Time Advertisement mechanism with UTC
TSF offset. See hostapd.conf for config info.
diff --git a/hostapd/Makefile b/hostapd/Makefile
index e46561e..5fd6481 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -6,8 +6,8 @@ ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
-CFLAGS += -I../src
-CFLAGS += -I../src/utils
+CFLAGS += -I$(abspath ../src)
+CFLAGS += -I$(abspath ../src/utils)
# Uncomment following line and set the path to your kernel tree include
# directory if your C library does not include all header files.
@@ -15,6 +15,11 @@ CFLAGS += -I../src/utils
-include .config
+ifdef CONFIG_TESTING_OPTIONS
+CFLAGS += -DCONFIG_TESTING_OPTIONS
+CONFIG_WPS_TESTING=y
+endif
+
ifndef CONFIG_OS
ifdef CONFIG_NATIVE_WINDOWS
CONFIG_OS=win32
@@ -43,6 +48,7 @@ OBJS += ../src/ap/utils.o
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ieee802_1x.o
OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
OBJS += ../src/ap/ieee802_11_auth.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/wpa_auth.o
@@ -83,6 +89,14 @@ CONFIG_ELOOP=eloop
endif
OBJS += ../src/utils/$(CONFIG_ELOOP).o
OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifeq ($(CONFIG_ELOOP), eloop)
+# Using glibc < 2.17 requires -lrt for clock_gettime()
+LIBS += -lrt
+LIBS_c += -lrt
+LIBS_h += -lrt
+endif
+
OBJS += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
OBJS_c += ../src/utils/wpa_debug.o
@@ -96,11 +110,19 @@ OBJS += ../src/common/wpa_common.o
OBJS += ../src/eapol_auth/eapol_auth_sm.o
+ifdef CONFIG_CODE_COVERAGE
+CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+LIBS += -lgcov
+LIBS_c += -lgcov
+LIBS_h += -lgcov
+LIBS_n += -lgcov
+endif
+
ifndef CONFIG_NO_DUMP_STATE
-# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
-# a file (undefine it, if you want to save in binary size)
+# define HOSTAPD_DUMP_STATE to include support for dumping internal state
+# through control interface commands (undefine it, if you want to save in
+# binary size)
CFLAGS += -DHOSTAPD_DUMP_STATE
-OBJS += dump_state.o
OBJS += ../src/eapol_auth/eapol_auth_dump.o
endif
@@ -110,6 +132,7 @@ CONFIG_NO_ACCOUNTING=y
else
OBJS += ../src/radius/radius.o
OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
endif
ifdef CONFIG_NO_ACCOUNTING
@@ -122,6 +145,12 @@ ifdef CONFIG_NO_VLAN
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_util.o
+endif
+CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@@ -164,10 +193,26 @@ NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
+endif
+
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
include ../src/drivers/drivers.mak
OBJS += $(DRV_AP_OBJS)
CFLAGS += $(DRV_AP_CFLAGS)
@@ -203,6 +248,14 @@ OBJS += ../src/eap_server/eap_server_tls.o
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+endif
+
ifdef CONFIG_EAP_PEAP
CFLAGS += -DEAP_SERVER_PEAP
OBJS += ../src/eap_server/eap_server_peap.o
@@ -279,7 +332,7 @@ ifdef CONFIG_EAP_GPSK
CFLAGS += -DEAP_SERVER_GPSK
OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
ifdef CONFIG_EAP_GPSK_SHA256
-CFLAGS += -DEAP_SERVER_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
endif
NEED_SHA256=y
NEED_AES_OMAC1=y
@@ -291,6 +344,13 @@ OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
NEED_SHA256=y
endif
+ifdef CONFIG_EAP_EKE
+CFLAGS += -DEAP_SERVER_EKE
+OBJS += ../src/eap_server/eap_server_eke.o ../src/eap_common/eap_eke_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
ifdef CONFIG_EAP_VENDOR_TEST
CFLAGS += -DEAP_SERVER_VENDOR_TEST
OBJS += ../src/eap_server/eap_server_vendor_test.o
@@ -329,25 +389,10 @@ NEED_AES_CBC=y
NEED_MODEXP=y
CONFIG_EAP=y
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
CFLAGS += -DCONFIG_WPS_NFC
OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -440,6 +485,11 @@ ifdef CONFIG_TLSV11
CFLAGS += -DCONFIG_TLSV11
endif
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o
@@ -519,6 +569,9 @@ OBJS += ../src/tls/pkcs8.o
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
CFLAGS += -DCONFIG_TLS_INTERNAL
@@ -632,14 +685,19 @@ OBJS += $(AESOBJS)
endif
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
SHA1OBJS += ../src/crypto/fips_prf_internal.o
endif
endif
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -678,10 +736,17 @@ endif
endif
ifdef NEED_SHA256
+CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
OBJS += ../src/crypto/sha256.o
+endif
+OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
OBJS += ../src/crypto/sha256-internal.o
endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.o
+endif
endif
ifdef NEED_DH_GROUPS
@@ -696,6 +761,10 @@ OBJS += ../src/crypto/dh_group5.o
endif
endif
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -734,19 +803,32 @@ OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
OBJS += ../src/ap/ieee802_11.o
OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
endif
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+
ifdef CONFIG_P2P_MANAGER
CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += ../src/ap/p2p_hostapd.o
endif
+ifdef CONFIG_HS20
+CFLAGS += -DCONFIG_HS20
+OBJS += ../src/ap/hs20.o
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
CFLAGS += -DCONFIG_INTERWORKING
+OBJS += ../src/common/gas.o
+OBJS += ../src/ap/gas_serv.o
endif
OBJS += ../src/drivers/driver_common.o
@@ -757,14 +839,30 @@ else
OBJS_c += ../src/utils/edit_simple.o
endif
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
+endif
+
ifdef CONFIG_NO_STDOUT_DEBUG
CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
CFLAGS += -DCONFIG_DEBUG_FILE
endif
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@@ -776,9 +874,15 @@ Q=
E=true
endif
+ifdef CONFIG_CODE_COVERAGE
+%.o: %.c
+ @$(E) " CC " $<
+ $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
+else
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
+endif
verify_config:
@if [ ! -r .config ]; then \
@@ -847,9 +951,15 @@ hlr_auc_gw: $(HOBJS)
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
@$(E) " LD " $@
+lcov-html:
+ lcov -c -d .. > lcov.info
+ genhtml lcov.info --output-directory lcov-html
+
clean:
$(MAKE) -C ../src clean
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
- rm -f *.d
+ rm -f *.d *.gcno *.gcda *.gcov
+ rm -f lcov.info
+ rm -rf lcov-html
-include $(OBJS:%.o=%.d)
diff --git a/hostapd/README b/hostapd/README
index 189983e..50868ee 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,37 +2,22 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
License
-------
-GPL v2:
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-(this copy of the license is in COPYING file)
-
-
-Alternatively, this software may be distributed, used, and modified
-under the terms of BSD license:
+This software may be distributed, used, and modified under the terms of
+BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index 17988d4..654b5bc 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -66,6 +66,10 @@ CONFIG_WPS=y
CONFIG_WPS2=y
CONFIG_WPS_UPNP=y
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
@@ -289,3 +293,62 @@ For example:
This can be used to update the externally stored AP configuration and
then update hostapd configuration (followed by restarting of hostapd).
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the AP acts as an Enrollee, a local NFC tag with a password token
+can be used by touching the NFC interface of an external Registrar. The
+wps_nfc_token command is used to manage use of the NFC password token
+from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
+password token (in place of AP PIN) and "wps_nfc_token disable" disables
+the NFC password token.
+
+The NFC password token that is either pre-configured in the
+configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The nfc_pw_token tool from
+wpa_supplicant can be used to generate NFC password tokens during
+manufacturing (each AP needs to have its own random keys).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token. The output value from this command is a hexdump
+of the current AP configuration (WPS parameter requests this to include
+only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+When the NFC device on the AP reads an NFC tag with a MIME media type
+"application/vnd.wfa.wsc", the NDEF message payload (with or without
+NDEF encapsulation) can be delivered to hostapd using the
+following hostapd_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a password token, the token is added to the
+internal Registrar. This allows station Enrollee from which the password
+token was received to run through WPS protocol to provision the
+credential.
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" is used to report completed NFC
+connection handover. The first parameter indicates whether the local
+device initiated or responded to the connection handover and the carrier
+records are the selected carrier from the handover request and select
+messages as a hexdump.
diff --git a/hostapd/android.config b/hostapd/android.config
new file mode 100644
index 0000000..81a2e2c
--- /dev/null
+++ b/hostapd/android.config
@@ -0,0 +1,190 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+CONFIG_LIBNL20=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+#CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+#CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+#CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+#CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+#CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+#CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+#CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+#CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+#CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+#CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable WSC 2.0 support
+CONFIG_WPS2=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Add support for writing debug log to Android logcat instead of standard output
+CONFIG_ANDROID_LOG=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Remove support for dumping internal state through control interface commands
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# Enable AP
+CONFIG_AP=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 1bfd456..54e4af9 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,15 +1,9 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -28,9 +22,6 @@
#include "config_file.h"
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
#ifndef CONFIG_NO_VLAN
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
@@ -89,7 +80,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
return -1;
}
- vlan = os_malloc(sizeof(*vlan));
+ vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while reading "
"VLAN interfaces from '%s'", fname);
@@ -97,14 +88,10 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
return -1;
}
- os_memset(vlan, 0, sizeof(*vlan));
vlan->vlan_id = vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
- if (bss->vlan_tail)
- bss->vlan_tail->next = vlan;
- else
- bss->vlan = vlan;
- bss->vlan_tail = vlan;
+ vlan->next = bss->vlan;
+ bss->vlan = vlan;
}
fclose(f);
@@ -173,7 +160,7 @@ static int hostapd_config_read_maclist(const char *fname,
if (*pos != '\0')
vlan_id = atoi(pos);
- newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
if (newacl == NULL) {
wpa_printf(MSG_ERROR, "MAC list reallocation failed");
fclose(f);
@@ -206,6 +193,12 @@ static int hostapd_config_read_eap_user(const char *fname,
if (!fname)
return 0;
+ if (os_strncmp(fname, "sqlite:", 7) == 0) {
+ os_free(conf->eap_user_sqlite);
+ conf->eap_user_sqlite = os_strdup(fname + 7);
+ return 0;
+ }
+
f = fopen(fname, "r");
if (!f) {
wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
@@ -330,7 +323,7 @@ static int hostapd_config_read_eap_user(const char *fname,
}
num_methods++;
- if (num_methods >= EAP_USER_MAX_METHODS)
+ if (num_methods >= EAP_MAX_METHODS)
break;
skip_eap:
if (pos3 == NULL)
@@ -481,7 +474,7 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
int ret;
static int server_index = 1;
- nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+ nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
if (nserv == NULL)
return -1;
@@ -497,6 +490,100 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
return ret;
}
+
+
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value)
+{
+ const char *pos;
+ char syntax;
+ struct hostapd_radius_attr *attr;
+ size_t len;
+
+ attr = os_zalloc(sizeof(*attr));
+ if (attr == NULL)
+ return NULL;
+
+ attr->type = atoi(value);
+
+ pos = os_strchr(value, ':');
+ if (pos == NULL) {
+ attr->val = wpabuf_alloc(1);
+ if (attr->val == NULL) {
+ os_free(attr);
+ return NULL;
+ }
+ wpabuf_put_u8(attr->val, 0);
+ return attr;
+ }
+
+ pos++;
+ if (pos[0] == '\0' || pos[1] != ':') {
+ os_free(attr);
+ return NULL;
+ }
+ syntax = *pos++;
+ pos++;
+
+ switch (syntax) {
+ case 's':
+ attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+ break;
+ case 'x':
+ len = os_strlen(pos);
+ if (len & 1)
+ break;
+ len /= 2;
+ attr->val = wpabuf_alloc(len);
+ if (attr->val == NULL)
+ break;
+ if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+ wpabuf_free(attr->val);
+ os_free(attr);
+ return NULL;
+ }
+ break;
+ case 'd':
+ attr->val = wpabuf_alloc(4);
+ if (attr->val)
+ wpabuf_put_be32(attr->val, atoi(pos));
+ break;
+ default:
+ os_free(attr);
+ return NULL;
+ }
+
+ if (attr->val == NULL) {
+ os_free(attr);
+ return NULL;
+ }
+
+ return attr;
+}
+
+
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
+ const char *val)
+{
+ char *secret;
+
+ secret = os_strchr(val, ' ');
+ if (secret == NULL)
+ return -1;
+
+ secret++;
+
+ if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
+ return -1;
+
+ os_free(bss->radius_das_shared_secret);
+ bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
+ if (bss->radius_das_shared_secret == NULL)
+ return -1;
+ bss->radius_das_shared_secret_len = os_strlen(secret);
+
+ return 0;
+}
#endif /* CONFIG_NO_RADIUS */
@@ -536,6 +623,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ else if (os_strcmp(start, "SAE") == 0)
+ val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "FT-SAE") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -561,47 +654,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
static int hostapd_config_parse_cipher(int line, const char *value)
{
- int val = 0, last;
- char *start, *end, *buf;
-
- buf = os_strdup(value);
- if (buf == NULL)
+ int val = wpa_parse_cipher(value);
+ if (val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, value);
return -1;
- start = buf;
-
- while (*start != '\0') {
- while (*start == ' ' || *start == '\t')
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (*end != ' ' && *end != '\t' && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
- if (os_strcmp(start, "CCMP") == 0)
- val |= WPA_CIPHER_CCMP;
- else if (os_strcmp(start, "TKIP") == 0)
- val |= WPA_CIPHER_TKIP;
- else if (os_strcmp(start, "WEP104") == 0)
- val |= WPA_CIPHER_WEP104;
- else if (os_strcmp(start, "WEP40") == 0)
- val |= WPA_CIPHER_WEP40;
- else if (os_strcmp(start, "NONE") == 0)
- val |= WPA_CIPHER_NONE;
- else {
- wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
- line, start);
- os_free(buf);
- return -1;
- }
-
- if (last)
- break;
- start = end + 1;
}
- os_free(buf);
-
if (val == 0) {
wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
line);
@@ -646,14 +704,14 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
}
-static int hostapd_parse_rates(int **rate_list, char *val)
+static int hostapd_parse_intlist(int **int_list, char *val)
{
int *list;
int count;
char *pos, *end;
- os_free(*rate_list);
- *rate_list = NULL;
+ os_free(*int_list);
+ *int_list = NULL;
pos = val;
count = 0;
@@ -680,37 +738,39 @@ static int hostapd_parse_rates(int **rate_list, char *val)
}
list[count] = -1;
- *rate_list = list;
+ *int_list = list;
return 0;
}
static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
{
- struct hostapd_bss_config *bss;
+ struct hostapd_bss_config **all, *bss;
if (*ifname == '\0')
return -1;
- bss = os_realloc(conf->bss, (conf->num_bss + 1) *
- sizeof(struct hostapd_bss_config));
- if (bss == NULL) {
+ all = os_realloc_array(conf->bss, conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config *));
+ if (all == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"multi-BSS entry");
return -1;
}
- conf->bss = bss;
+ conf->bss = all;
- bss = &(conf->bss[conf->num_bss]);
- os_memset(bss, 0, sizeof(*bss));
+ bss = os_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return -1;
bss->radius = os_zalloc(sizeof(*bss->radius));
if (bss->radius == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"multi-BSS RADIUS data");
+ os_free(bss);
return -1;
}
- conf->num_bss++;
+ conf->bss[conf->num_bss++] = bss;
conf->last_bss = bss;
hostapd_config_defaults_bss(bss);
@@ -817,78 +877,6 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
}
-static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
- char *val)
-{
- int num, v;
- char *pos;
- struct hostapd_wmm_ac_params *ac;
-
- /* skip 'wme_ac_' or 'wmm_ac_' prefix */
- pos = name + 7;
- if (os_strncmp(pos, "be_", 3) == 0) {
- num = 0;
- pos += 3;
- } else if (os_strncmp(pos, "bk_", 3) == 0) {
- num = 1;
- pos += 3;
- } else if (os_strncmp(pos, "vi_", 3) == 0) {
- num = 2;
- pos += 3;
- } else if (os_strncmp(pos, "vo_", 3) == 0) {
- num = 3;
- pos += 3;
- } else {
- wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
- return -1;
- }
-
- ac = &conf->wmm_ac_params[num];
-
- if (os_strcmp(pos, "aifs") == 0) {
- v = atoi(val);
- if (v < 1 || v > 255) {
- wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
- return -1;
- }
- ac->aifs = v;
- } else if (os_strcmp(pos, "cwmin") == 0) {
- v = atoi(val);
- if (v < 0 || v > 12) {
- wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
- return -1;
- }
- ac->cwmin = v;
- } else if (os_strcmp(pos, "cwmax") == 0) {
- v = atoi(val);
- if (v < 0 || v > 12) {
- wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
- return -1;
- }
- ac->cwmax = v;
- } else if (os_strcmp(pos, "txop_limit") == 0) {
- v = atoi(val);
- if (v < 0 || v > 0xffff) {
- wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
- return -1;
- }
- ac->txop_limit = v;
- } else if (os_strcmp(pos, "acm") == 0) {
- v = atoi(val);
- if (v < 0 || v > 1) {
- wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
- return -1;
- }
- ac->admission_control_mandatory = v;
- } else {
- wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211R
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
@@ -1040,214 +1028,577 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
#endif /* CONFIG_IEEE80211N */
-static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
- struct hostapd_config *conf)
+#ifdef CONFIG_IEEE80211AC
+static int hostapd_config_vht_capab(struct hostapd_config *conf,
+ const char *capab)
+{
+ if (os_strstr(capab, "[MAX-MPDU-7991]"))
+ conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
+ if (os_strstr(capab, "[MAX-MPDU-11454]"))
+ conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
+ if (os_strstr(capab, "[VHT160]"))
+ conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ if (os_strstr(capab, "[VHT160-80PLUS80]"))
+ conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ if (os_strstr(capab, "[VHT160-80PLUS80]"))
+ conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ if (os_strstr(capab, "[RXLDPC]"))
+ conf->vht_capab |= VHT_CAP_RXLDPC;
+ if (os_strstr(capab, "[SHORT-GI-80]"))
+ conf->vht_capab |= VHT_CAP_SHORT_GI_80;
+ if (os_strstr(capab, "[SHORT-GI-160]"))
+ conf->vht_capab |= VHT_CAP_SHORT_GI_160;
+ if (os_strstr(capab, "[TX-STBC-2BY1]"))
+ conf->vht_capab |= VHT_CAP_TXSTBC;
+ if (os_strstr(capab, "[RX-STBC-1]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_1;
+ if (os_strstr(capab, "[RX-STBC-12]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_2;
+ if (os_strstr(capab, "[RX-STBC-123]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_3;
+ if (os_strstr(capab, "[RX-STBC-1234]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_4;
+ if (os_strstr(capab, "[SU-BEAMFORMER]"))
+ conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
+ if (os_strstr(capab, "[SU-BEAMFORMEE]"))
+ conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+ if (os_strstr(capab, "[BF-ANTENNA-2]") &&
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
+ if (os_strstr(capab, "[MU-BEAMFORMER]"))
+ conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+ if (os_strstr(capab, "[MU-BEAMFORMEE]"))
+ conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+ if (os_strstr(capab, "[VHT-TXOP-PS]"))
+ conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
+ if (os_strstr(capab, "[HTC-VHT]"))
+ conf->vht_capab |= VHT_CAP_HTC_VHT;
+ if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+ if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
+ (conf->vht_capab & VHT_CAP_HTC_VHT))
+ conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
+ if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
+ (conf->vht_capab & VHT_CAP_HTC_VHT))
+ conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+ if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
+ conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
+ if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
+ conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
+ return 0;
+}
+#endif /* CONFIG_IEEE80211AC */
+
+
+#ifdef CONFIG_INTERWORKING
+static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
+ int line)
{
- if (bss->ieee802_1x && !bss->eap_server &&
- !bss->radius->auth_servers) {
- wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
- "EAP authenticator configured).");
+ size_t len = os_strlen(pos);
+ u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+
+ struct hostapd_roaming_consortium *rc;
+
+ if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
+ hexstr2bin(pos, oi, len / 2)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
+ "'%s'", line, pos);
return -1;
}
+ len /= 2;
- if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
- bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
- bss->ssid.wpa_psk_file == NULL) {
- wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
- "is not configured.");
+ rc = os_realloc_array(bss->roaming_consortium,
+ bss->roaming_consortium_count + 1,
+ sizeof(struct hostapd_roaming_consortium));
+ if (rc == NULL)
return -1;
+
+ os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
+ rc[bss->roaming_consortium_count].len = len;
+
+ bss->roaming_consortium = rc;
+ bss->roaming_consortium_count++;
+
+ return 0;
+}
+
+
+static int parse_lang_string(struct hostapd_lang_string **array,
+ unsigned int *count, char *pos)
+{
+ char *sep, *str = NULL;
+ size_t clen, nlen, slen;
+ struct hostapd_lang_string *ls;
+ int ret = -1;
+
+ if (*pos == '"' || (*pos == 'P' && pos[1] == '"')) {
+ str = wpa_config_parse_string(pos, &slen);
+ if (!str)
+ return -1;
+ pos = str;
}
- if (hostapd_mac_comp_empty(bss->bssid) != 0) {
- size_t i;
-
- for (i = 0; i < conf->num_bss; i++) {
- if ((&conf->bss[i] != bss) &&
- (hostapd_mac_comp(conf->bss[i].bssid,
- bss->bssid) == 0)) {
- wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
- " on interface '%s' and '%s'.",
- MAC2STR(bss->bssid),
- conf->bss[i].iface, bss->iface);
- return -1;
- }
+ sep = os_strchr(pos, ':');
+ if (sep == NULL)
+ goto fail;
+ *sep++ = '\0';
+
+ clen = os_strlen(pos);
+ if (clen < 2 || clen > sizeof(ls->lang))
+ goto fail;
+ nlen = os_strlen(sep);
+ if (nlen > 252)
+ goto fail;
+
+ ls = os_realloc_array(*array, *count + 1,
+ sizeof(struct hostapd_lang_string));
+ if (ls == NULL)
+ goto fail;
+
+ *array = ls;
+ ls = &(*array)[*count];
+ (*count)++;
+
+ os_memset(ls->lang, 0, sizeof(ls->lang));
+ os_memcpy(ls->lang, pos, clen);
+ ls->name_len = nlen;
+ os_memcpy(ls->name, sep, nlen);
+
+ ret = 0;
+fail:
+ os_free(str);
+ return ret;
+}
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+ line, pos);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ size_t count;
+ char *pos;
+ u8 *info = NULL, *ipos;
+
+ /* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
+
+ count = 1;
+ for (pos = buf; *pos; pos++) {
+ if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
+ goto fail;
+ if (*pos == ';')
+ count++;
+ }
+ if (1 + count * 3 > 0x7f)
+ goto fail;
+
+ info = os_zalloc(2 + 3 + count * 3);
+ if (info == NULL)
+ return -1;
+
+ ipos = info;
+ *ipos++ = 0; /* GUD - Version 1 */
+ *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
+ *ipos++ = 0; /* PLMN List IEI */
+ /* ext(b8) | Length of PLMN List value contents(b7..1) */
+ *ipos++ = 1 + count * 3;
+ *ipos++ = count; /* Number of PLMNs */
+
+ pos = buf;
+ while (pos && *pos) {
+ char *mcc, *mnc;
+ size_t mnc_len;
+
+ mcc = pos;
+ mnc = os_strchr(pos, ',');
+ if (mnc == NULL)
+ goto fail;
+ *mnc++ = '\0';
+ pos = os_strchr(mnc, ';');
+ if (pos)
+ *pos++ = '\0';
+
+ mnc_len = os_strlen(mnc);
+ if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
+ goto fail;
+
+ /* BC coded MCC,MNC */
+ /* MCC digit 2 | MCC digit 1 */
+ *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
+ /* MNC digit 3 | MCC digit 3 */
+ *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
+ (mcc[2] - '0');
+ /* MNC digit 2 | MNC digit 1 */
+ *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
+ }
+
+ os_free(bss->anqp_3gpp_cell_net);
+ bss->anqp_3gpp_cell_net = info;
+ bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
+ wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
+ bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
+ line, buf);
+ os_free(info);
+ return -1;
+}
+
+
+static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
+{
+ struct hostapd_nai_realm_data *realm;
+ size_t i, j, len;
+ int *offsets;
+ char *pos, *end, *rpos;
+
+ offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
+ sizeof(int));
+ if (offsets == NULL)
+ return -1;
+
+ for (i = 0; i < bss->nai_realm_count; i++) {
+ realm = &bss->nai_realm_data[i];
+ for (j = 0; j < MAX_NAI_REALMS; j++) {
+ offsets[i * MAX_NAI_REALMS + j] =
+ realm->realm[j] ?
+ realm->realm[j] - realm->realm_buf : -1;
}
}
-#ifdef CONFIG_IEEE80211R
- if ((bss->wpa_key_mgmt &
- (WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X)) &&
- (bss->nas_identifier == NULL ||
- os_strlen(bss->nas_identifier) < 1 ||
- os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
- wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
- "nas_identifier to be configured as a 1..48 octet "
- "string");
+ realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
+ sizeof(struct hostapd_nai_realm_data));
+ if (realm == NULL) {
+ os_free(offsets);
return -1;
}
-#endif /* CONFIG_IEEE80211R */
+ bss->nai_realm_data = realm;
+
+ /* patch the pointers after realloc */
+ for (i = 0; i < bss->nai_realm_count; i++) {
+ realm = &bss->nai_realm_data[i];
+ for (j = 0; j < MAX_NAI_REALMS; j++) {
+ int offs = offsets[i * MAX_NAI_REALMS + j];
+ if (offs >= 0)
+ realm->realm[j] = realm->realm_buf + offs;
+ else
+ realm->realm[j] = NULL;
+ }
+ }
+ os_free(offsets);
-#ifdef CONFIG_IEEE80211N
- if (conf->ieee80211n &&
- bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11n = 1;
- wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
- "allowed, disabling HT capabilities");
+ realm = &bss->nai_realm_data[bss->nai_realm_count];
+ os_memset(realm, 0, sizeof(*realm));
+
+ pos = buf;
+ realm->encoding = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ end = os_strchr(pos, ',');
+ if (end) {
+ len = end - pos;
+ *end = '\0';
+ } else {
+ len = os_strlen(pos);
}
- if (conf->ieee80211n && bss->wpa &&
- !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
- !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
- bss->disable_11n = 1;
- wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
- "requires CCMP to be enabled, disabling HT "
- "capabilities");
+ if (len > MAX_NAI_REALMLEN) {
+ wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
+ "characters)", (int) len, MAX_NAI_REALMLEN);
+ goto fail;
}
-#endif /* CONFIG_IEEE80211N */
+ os_memcpy(realm->realm_buf, pos, len);
+
+ if (end)
+ pos = end + 1;
+ else
+ pos = NULL;
+
+ while (pos && *pos) {
+ struct hostapd_nai_realm_eap *eap;
+
+ if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
+ wpa_printf(MSG_ERROR, "Too many EAP methods");
+ goto fail;
+ }
+
+ eap = &realm->eap_method[realm->eap_method_count];
+ realm->eap_method_count++;
+
+ end = os_strchr(pos, ',');
+ if (end == NULL)
+ end = pos + os_strlen(pos);
+
+ eap->eap_method = atoi(pos);
+ for (;;) {
+ pos = os_strchr(pos, '[');
+ if (pos == NULL || pos > end)
+ break;
+ pos++;
+ if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
+ wpa_printf(MSG_ERROR, "Too many auth params");
+ goto fail;
+ }
+ eap->auth_id[eap->num_auths] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL || pos > end)
+ goto fail;
+ pos++;
+ eap->auth_val[eap->num_auths] = atoi(pos);
+ pos = os_strchr(pos, ']');
+ if (pos == NULL || pos > end)
+ goto fail;
+ pos++;
+ eap->num_auths++;
+ }
+
+ if (*end != ',')
+ break;
-#ifdef CONFIG_WPS2
- if (bss->wps_state && bss->ignore_broadcast_ssid) {
- wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
- "configuration forced WPS to be disabled");
- bss->wps_state = 0;
+ pos = end + 1;
}
- if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
- wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
- "disabled");
- bss->wps_state = 0;
+ /* Split realm list into null terminated realms */
+ rpos = realm->realm_buf;
+ i = 0;
+ while (*rpos) {
+ if (i >= MAX_NAI_REALMS) {
+ wpa_printf(MSG_ERROR, "Too many realms");
+ goto fail;
+ }
+ realm->realm[i++] = rpos;
+ rpos = os_strchr(rpos, ';');
+ if (rpos == NULL)
+ break;
+ *rpos++ = '\0';
}
-#endif /* CONFIG_WPS2 */
+
+ bss->nai_realm_count++;
return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
+ return -1;
}
-static int hostapd_config_check(struct hostapd_config *conf)
+static int parse_qos_map_set(struct hostapd_bss_config *bss,
+ char *buf, int line)
{
- size_t i;
+ u8 qos_map_set[16 + 2 * 21], count = 0;
+ char *pos = buf;
+ int val;
+
+ for (;;) {
+ if (count == sizeof(qos_map_set)) {
+ wpa_printf(MSG_ERROR, "Line %d: Too many qos_map_set "
+ "parameters '%s'", line, buf);
+ return -1;
+ }
- if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
- wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
- "setting the country_code");
- return -1;
+ val = atoi(pos);
+ if (val > 255 || val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set "
+ "'%s'", line, buf);
+ return -1;
+ }
+
+ qos_map_set[count++] = val;
+ pos = os_strchr(pos, ',');
+ if (!pos)
+ break;
+ pos++;
}
- for (i = 0; i < conf->num_bss; i++) {
- if (hostapd_config_check_bss(&conf->bss[i], conf))
- return -1;
+ if (count < 16 || count & 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid qos_map_set '%s'",
+ line, buf);
+ return -1;
}
+ os_memcpy(bss->qos_map_set, qos_map_set, count);
+ bss->qos_map_set_len = count;
+
return 0;
}
+#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_INTERWORKING
-static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
- int line)
+
+#ifdef CONFIG_HS20
+static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
+ int line)
{
- size_t len = os_strlen(pos);
- u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+ u8 *conn_cap;
+ char *pos;
- struct hostapd_roaming_consortium *rc;
+ if (bss->hs20_connection_capability_len >= 0xfff0)
+ return -1;
- if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
- hexstr2bin(pos, oi, len / 2)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
- "'%s'", line, pos);
+ conn_cap = os_realloc(bss->hs20_connection_capability,
+ bss->hs20_connection_capability_len + 4);
+ if (conn_cap == NULL)
return -1;
- }
- len /= 2;
- rc = os_realloc(bss->roaming_consortium,
- sizeof(struct hostapd_roaming_consortium) *
- (bss->roaming_consortium_count + 1));
- if (rc == NULL)
+ bss->hs20_connection_capability = conn_cap;
+ conn_cap += bss->hs20_connection_capability_len;
+ pos = buf;
+ conn_cap[0] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ WPA_PUT_LE16(conn_cap + 1, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
return -1;
+ pos++;
+ conn_cap[3] = atoi(pos);
+ bss->hs20_connection_capability_len += 4;
- os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
- rc[bss->roaming_consortium_count].len = len;
+ return 0;
+}
- bss->roaming_consortium = rc;
- bss->roaming_consortium_count++;
+
+static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ u8 *wan_metrics;
+ char *pos;
+
+ /* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
+
+ wan_metrics = os_zalloc(13);
+ if (wan_metrics == NULL)
+ return -1;
+
+ pos = buf;
+ /* WAN Info */
+ if (hexstr2bin(pos, wan_metrics, 1) < 0)
+ goto fail;
+ pos += 2;
+ if (*pos != ':')
+ goto fail;
+ pos++;
+
+ /* Downlink Speed */
+ WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Uplink Speed */
+ WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Downlink Load */
+ wan_metrics[9] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Uplink Load */
+ wan_metrics[10] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* LMD */
+ WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
+
+ os_free(bss->hs20_wan_metrics);
+ bss->hs20_wan_metrics = wan_metrics;
return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
+ line, pos);
+ os_free(wan_metrics);
+ return -1;
}
-#endif /* CONFIG_INTERWORKING */
-/**
- * hostapd_config_read - Read and parse a configuration file
- * @fname: Configuration file name (including path, if needed)
- * Returns: Allocated configuration data structure
- */
-struct hostapd_config * hostapd_config_read(const char *fname)
+static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
+ char *pos, int line)
{
- struct hostapd_config *conf;
- struct hostapd_bss_config *bss;
- FILE *f;
- char buf[256], *pos;
- int line = 0;
- int errors = 0;
- int pairwise;
- size_t i;
+ if (parse_lang_string(&bss->hs20_oper_friendly_name,
+ &bss->hs20_oper_friendly_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_oper_friendly_name '%s'", line, pos);
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_HS20 */
- f = fopen(fname, "r");
- if (f == NULL) {
- wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
- "for reading.", fname);
+
+#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;
- conf = hostapd_config_defaults();
- if (conf == NULL) {
- fclose(f);
+ ret = wpabuf_alloc(len);
+ if (ret == NULL)
return NULL;
- }
- /* set default driver based on configuration */
- conf->driver = wpa_drivers[0];
- if (conf->driver == NULL) {
- wpa_printf(MSG_ERROR, "No driver wrappers registered!");
- hostapd_config_free(conf);
- fclose(f);
+ if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+ wpabuf_free(ret);
return NULL;
}
- bss = conf->last_bss = conf->bss;
-
- while (fgets(buf, sizeof(buf), f)) {
- bss = conf->last_bss;
- line++;
+ return ret;
+}
+#endif /* CONFIG_WPS_NFC */
- if (buf[0] == '#')
- continue;
- pos = buf;
- while (*pos != '\0') {
- if (*pos == '\n') {
- *pos = '\0';
- break;
- }
- pos++;
- }
- if (buf[0] == '\0')
- continue;
- pos = os_strchr(buf, '=');
- if (pos == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
- line, buf);
- errors++;
- continue;
- }
- *pos = '\0';
- pos++;
+static int hostapd_config_fill(struct hostapd_config *conf,
+ struct hostapd_bss_config *bss,
+ char *buf, char *pos, int line)
+{
+ int errors = 0;
+ {
if (os_strcmp(buf, "interface") == 0) {
- os_strlcpy(conf->bss[0].iface, pos,
- sizeof(conf->bss[0].iface));
+ os_strlcpy(conf->bss[0]->iface, pos,
+ sizeof(conf->bss[0]->iface));
} else if (os_strcmp(buf, "bridge") == 0) {
os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+ } else if (os_strcmp(buf, "vlan_bridge") == 0) {
+ os_strlcpy(bss->vlan_bridge, pos,
+ sizeof(bss->vlan_bridge));
} else if (os_strcmp(buf, "wds_bridge") == 0) {
os_strlcpy(bss->wds_bridge, pos,
sizeof(bss->wds_bridge));
@@ -1280,7 +1631,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else if (os_strcmp(buf, "logger_stdout") == 0) {
bss->logger_stdout = atoi(pos);
} else if (os_strcmp(buf, "dump_file") == 0) {
- bss->dump_log_name = os_strdup(pos);
+ wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
+ line);
} else if (os_strcmp(buf, "ssid") == 0) {
bss->ssid.ssid_len = os_strlen(pos);
if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
@@ -1291,9 +1643,24 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else {
os_memcpy(bss->ssid.ssid, pos,
bss->ssid.ssid_len);
- bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
bss->ssid.ssid_set = 1;
}
+ } else if (os_strcmp(buf, "ssid2") == 0) {
+ size_t slen;
+ char *str = wpa_config_parse_string(pos, &slen);
+ if (str == NULL || slen < 1 ||
+ slen > HOSTAPD_MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+ "'%s'", line, pos);
+ errors++;
+ } else {
+ os_memcpy(bss->ssid.ssid, str, slen);
+ bss->ssid.ssid_len = slen;
+ bss->ssid.ssid_set = 1;
+ }
+ os_free(str);
+ } else if (os_strcmp(buf, "utf8_ssid") == 0) {
+ bss->ssid.utf8_ssid = atoi(pos) > 0;
} else if (os_strcmp(buf, "macaddr_acl") == 0) {
bss->macaddr_acl = atoi(pos);
if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
@@ -1322,16 +1689,22 @@ struct hostapd_config * hostapd_config_read(const char *fname)
}
} else if (os_strcmp(buf, "wds_sta") == 0) {
bss->wds_sta = atoi(pos);
+ } else if (os_strcmp(buf, "start_disabled") == 0) {
+ bss->start_disabled = atoi(pos);
} else if (os_strcmp(buf, "ap_isolate") == 0) {
bss->isolate = atoi(pos);
} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
bss->ap_max_inactivity = atoi(pos);
+ } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
+ bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) {
os_memcpy(conf->country, pos, 2);
/* FIX: make this configurable */
conf->country[2] = ' ';
} else if (os_strcmp(buf, "ieee80211d") == 0) {
conf->ieee80211d = atoi(pos);
+ } else if (os_strcmp(buf, "ieee80211h") == 0) {
+ conf->ieee80211h = atoi(pos);
} else if (os_strcmp(buf, "ieee8021x") == 0) {
bss->ieee802_1x = atoi(pos);
} else if (os_strcmp(buf, "eapol_version") == 0) {
@@ -1370,6 +1743,9 @@ struct hostapd_config * hostapd_config_read(const char *fname)
bss->private_key_passwd = os_strdup(pos);
} else if (os_strcmp(buf, "check_crl") == 0) {
bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
+ os_free(bss->ocsp_stapling_response);
+ bss->ocsp_stapling_response = os_strdup(pos);
} else if (os_strcmp(buf, "dh_file") == 0) {
os_free(bss->dh_file);
bss->dh_file = os_strdup(pos);
@@ -1442,7 +1818,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
"allocate memory for "
"eap_req_id_text", line);
errors++;
- continue;
+ return errors;
}
bss->eap_req_id_text_len =
os_strlen(bss->eap_req_id_text);
@@ -1562,6 +1938,51 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
{
bss->acct_interim_interval = atoi(pos);
+ } else if (os_strcmp(buf, "radius_request_cui") == 0) {
+ bss->radius_request_cui = atoi(pos);
+ } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(pos);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "radius_auth_req_attr", line);
+ errors++;
+ } else if (bss->radius_auth_req_attr == NULL) {
+ bss->radius_auth_req_attr = attr;
+ } else {
+ a = bss->radius_auth_req_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(pos);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "radius_acct_req_attr", line);
+ errors++;
+ } else if (bss->radius_acct_req_attr == NULL) {
+ bss->radius_acct_req_attr = attr;
+ } else {
+ a = bss->radius_acct_req_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ } else if (os_strcmp(buf, "radius_das_port") == 0) {
+ bss->radius_das_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_client") == 0) {
+ if (hostapd_parse_das_client(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "DAS client", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "radius_das_time_window") == 0) {
+ bss->radius_das_time_window = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_require_event_timestamp")
+ == 0) {
+ bss->radius_das_require_event_timestamp = atoi(pos);
#endif /* CONFIG_NO_RADIUS */
} else if (os_strcmp(buf, "auth_algs") == 0) {
bss->auth_algs = atoi(pos);
@@ -1601,6 +2022,11 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else {
os_free(bss->ssid.wpa_passphrase);
bss->ssid.wpa_passphrase = os_strdup(pos);
+ if (bss->ssid.wpa_passphrase) {
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk = NULL;
+ bss->ssid.wpa_passphrase_set = 1;
+ }
}
} else if (os_strcmp(buf, "wpa_psk") == 0) {
os_free(bss->ssid.wpa_psk);
@@ -1616,6 +2042,9 @@ struct hostapd_config * hostapd_config_read(const char *fname)
errors++;
} else {
bss->ssid.wpa_psk->group = 1;
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = NULL;
+ bss->ssid.wpa_psk_set = 1;
}
} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
os_free(bss->ssid.wpa_psk_file);
@@ -1630,6 +2059,16 @@ struct hostapd_config * hostapd_config_read(const char *fname)
hostapd_config_parse_key_mgmt(line, pos);
if (bss->wpa_key_mgmt == -1)
errors++;
+ } else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+ bss->wpa_psk_radius = atoi(pos);
+ if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+ bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
+ bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown "
+ "wpa_psk_radius %d",
+ line, bss->wpa_psk_radius);
+ errors++;
+ }
} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
bss->wpa_pairwise =
hostapd_config_parse_cipher(line, pos);
@@ -1676,7 +2115,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"mobility_domain '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "r1_key_holder") == 0) {
if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
@@ -1685,7 +2124,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"r1_key_holder '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
bss->r0_key_lifetime = atoi(pos);
@@ -1696,14 +2135,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"r0kh '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "r1kh") == 0) {
if (add_r1kh(bss, pos) < 0) {
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"r1kh '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
bss->pmk_r1_push = atoi(pos);
@@ -1727,7 +2166,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
" (from group name '%s')",
bss->ctrl_interface_gid, group);
- continue;
+ return errors;
}
/* Group name not found - try to parse this as gid */
@@ -1736,7 +2175,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
"'%s'", line, group);
errors++;
- continue;
+ return errors;
}
bss->ctrl_interface_gid_set = 1;
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
@@ -1764,13 +2203,38 @@ struct hostapd_config * hostapd_config_read(const char *fname)
conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
else if (os_strcmp(pos, "g") == 0)
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (os_strcmp(pos, "ad") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
else {
wpa_printf(MSG_ERROR, "Line %d: unknown "
"hw_mode '%s'", line, pos);
errors++;
}
+ } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
+ if (os_strcmp(pos, "a") == 0)
+ bss->wps_rf_bands = WPS_RF_50GHZ;
+ else if (os_strcmp(pos, "g") == 0 ||
+ os_strcmp(pos, "b") == 0)
+ bss->wps_rf_bands = WPS_RF_24GHZ;
+ else if (os_strcmp(pos, "ag") == 0 ||
+ os_strcmp(pos, "ga") == 0)
+ bss->wps_rf_bands =
+ WPS_RF_24GHZ | WPS_RF_50GHZ;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: unknown "
+ "wps_rf_band '%s'", line, pos);
+ errors++;
+ }
} else if (os_strcmp(buf, "channel") == 0) {
- conf->channel = atoi(pos);
+ if (os_strcmp(pos, "acs_survey") == 0) {
+#ifndef CONFIG_ACS
+ wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled",
+ line);
+ errors++;
+#endif /* CONFIG_ACS */
+ conf->channel = 0;
+ } else
+ conf->channel = atoi(pos);
} else if (os_strcmp(buf, "beacon_int") == 0) {
int val = atoi(pos);
/* MIB defines range as 1..65535, but very small values
@@ -1785,6 +2249,16 @@ struct hostapd_config * hostapd_config_read(const char *fname)
errors++;
} else
conf->beacon_int = val;
+#ifdef CONFIG_ACS
+ } else if (os_strcmp(buf, "acs_num_scans") == 0) {
+ int val = atoi(pos);
+ if (val <= 0 || val > 100) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid acs_num_scans %d (expected 1..100)",
+ line, val);
+ errors++;
+ } else
+ conf->acs_num_scans = val;
+#endif /* CONFIG_ACS */
} else if (os_strcmp(buf, "dtim_period") == 0) {
bss->dtim_period = atoi(pos);
if (bss->dtim_period < 1 || bss->dtim_period > 255) {
@@ -1820,13 +2294,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else
conf->send_probe_response = val;
} else if (os_strcmp(buf, "supported_rates") == 0) {
- if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+ if (hostapd_parse_intlist(&conf->supported_rates, pos))
+ {
wpa_printf(MSG_ERROR, "Line %d: invalid rate "
"list", line);
errors++;
}
} else if (os_strcmp(buf, "basic_rates") == 0) {
- if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+ if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate "
"list", line);
errors++;
@@ -1865,6 +2340,15 @@ struct hostapd_config * hostapd_config_read(const char *fname)
"read VLAN file '%s'", line, pos);
errors++;
}
+ } else if (os_strcmp(buf, "vlan_naming") == 0) {
+ bss->ssid.vlan_naming = atoi(pos);
+ if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
+ bss->ssid.vlan_naming < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "naming scheme %d", line,
+ bss->ssid.vlan_naming);
+ errors++;
+ }
#ifdef CONFIG_FULL_DYNAMIC_VLAN
} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
bss->ssid.vlan_tagged_interface = os_strdup(pos);
@@ -1887,7 +2371,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
bss->wmm_uapsd = atoi(pos);
} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
os_strncmp(buf, "wmm_ac_", 7) == 0) {
- if (hostapd_config_wmm_ac(conf, buf, pos)) {
+ if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
+ pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
"ac item", line);
errors++;
@@ -1935,7 +2420,29 @@ struct hostapd_config * hostapd_config_read(const char *fname)
}
} else if (os_strcmp(buf, "require_ht") == 0) {
conf->require_ht = atoi(pos);
+ } else if (os_strcmp(buf, "obss_interval") == 0) {
+ conf->obss_interval = atoi(pos);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ } else if (os_strcmp(buf, "ieee80211ac") == 0) {
+ conf->ieee80211ac = atoi(pos);
+ } else if (os_strcmp(buf, "vht_capab") == 0) {
+ if (hostapd_config_vht_capab(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "vht_capab", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "require_vht") == 0) {
+ conf->require_vht = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
+ conf->vht_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
+ {
+ conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
+ {
+ conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
@@ -1950,6 +2457,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
"wps_state", line);
errors++;
}
+ } else if (os_strcmp(buf, "wps_independent") == 0) {
+ bss->wps_independent = atoi(pos);
} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
bss->ap_setup_locked = atoi(pos);
} else if (os_strcmp(buf, "uuid") == 0) {
@@ -2059,6 +2568,32 @@ struct hostapd_config * hostapd_config_read(const char *fname)
bss->upc = os_strdup(pos);
} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
bss->pbc_in_m1 = atoi(pos);
+ } else if (os_strcmp(buf, "server_id") == 0) {
+ os_free(bss->server_id);
+ bss->server_id = os_strdup(pos);
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+ bss->wps_nfc_dev_pw_id = atoi(pos);
+ if (bss->wps_nfc_dev_pw_id < 0x10 ||
+ bss->wps_nfc_dev_pw_id > 0xffff) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "wps_nfc_dev_pw_id value", line);
+ errors++;
+ }
+ bss->wps_nfc_pw_from_config = 1;
+ } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+ wpabuf_free(bss->wps_nfc_dh_pubkey);
+ bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
+ } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+ wpabuf_free(bss->wps_nfc_dh_privkey);
+ bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
+ } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+ wpabuf_free(bss->wps_nfc_dev_pw);
+ bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
} else if (os_strcmp(buf, "manage_p2p") == 0) {
@@ -2100,12 +2635,18 @@ struct hostapd_config * hostapd_config_read(const char *fname)
wpa_printf(MSG_DEBUG, "Line %d: invalid "
"time_zone", line);
errors++;
- continue;
+ return errors;
}
os_free(bss->time_zone);
bss->time_zone = os_strdup(pos);
if (bss->time_zone == NULL)
errors++;
+#ifdef CONFIG_WNM
+ } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
+ bss->wnm_sleep_mode = atoi(pos);
+ } else if (os_strcmp(buf, "bss_transition") == 0) {
+ bss->bss_transition = atoi(pos);
+#endif /* CONFIG_WNM */
#ifdef CONFIG_INTERWORKING
} else if (os_strcmp(buf, "interworking") == 0) {
bss->interworking = atoi(pos);
@@ -2140,7 +2681,230 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else if (os_strcmp(buf, "roaming_consortium") == 0) {
if (parse_roaming_consortium(bss, pos, line) < 0)
errors++;
+ } else if (os_strcmp(buf, "venue_name") == 0) {
+ if (parse_venue_name(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "network_auth_type") == 0) {
+ u8 auth_type;
+ u16 redirect_url_len;
+ if (hexstr2bin(pos, &auth_type, 1)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "network_auth_type '%s'",
+ line, pos);
+ errors++;
+ return errors;
+ }
+ if (auth_type == 0 || auth_type == 2)
+ redirect_url_len = os_strlen(pos + 2);
+ else
+ redirect_url_len = 0;
+ os_free(bss->network_auth_type);
+ bss->network_auth_type =
+ os_malloc(redirect_url_len + 3 + 1);
+ if (bss->network_auth_type == NULL) {
+ errors++;
+ return errors;
+ }
+ *bss->network_auth_type = auth_type;
+ WPA_PUT_LE16(bss->network_auth_type + 1,
+ redirect_url_len);
+ if (redirect_url_len)
+ os_memcpy(bss->network_auth_type + 3,
+ pos + 2, redirect_url_len);
+ bss->network_auth_type_len = 3 + redirect_url_len;
+ } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
+ if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "ipaddr_type_availability '%s'",
+ line, pos);
+ bss->ipaddr_type_configured = 0;
+ errors++;
+ return errors;
+ }
+ bss->ipaddr_type_configured = 1;
+ } else if (os_strcmp(buf, "domain_name") == 0) {
+ int j, num_domains, domain_len, domain_list_len = 0;
+ char *tok_start, *tok_prev;
+ u8 *domain_list, *domain_ptr;
+
+ domain_list_len = os_strlen(pos) + 1;
+ domain_list = os_malloc(domain_list_len);
+ if (domain_list == NULL) {
+ errors++;
+ return errors;
+ }
+
+ domain_ptr = domain_list;
+ tok_prev = pos;
+ num_domains = 1;
+ while ((tok_prev = os_strchr(tok_prev, ','))) {
+ num_domains++;
+ tok_prev++;
+ }
+ tok_prev = pos;
+ for (j = 0; j < num_domains; j++) {
+ tok_start = os_strchr(tok_prev, ',');
+ if (tok_start) {
+ domain_len = tok_start - tok_prev;
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev,
+ domain_len);
+ domain_ptr += domain_len + 1;
+ tok_prev = ++tok_start;
+ } else {
+ domain_len = os_strlen(tok_prev);
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev,
+ domain_len);
+ domain_ptr += domain_len + 1;
+ }
+ }
+
+ os_free(bss->domain_name);
+ bss->domain_name = domain_list;
+ bss->domain_name_len = domain_list_len;
+ } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
+ if (parse_3gpp_cell_net(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "nai_realm") == 0) {
+ if (parse_nai_realm(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
+ bss->gas_frag_limit = atoi(pos);
+ } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+ bss->gas_comeback_delay = atoi(pos);
+ } else if (os_strcmp(buf, "qos_map_set") == 0) {
+ if (parse_qos_map_set(bss, pos, line) < 0)
+ errors++;
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_RADIUS_TEST
+ } else if (os_strcmp(buf, "dump_msk_file") == 0) {
+ os_free(bss->dump_msk_file);
+ bss->dump_msk_file = os_strdup(pos);
+#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_HS20
+ } else if (os_strcmp(buf, "hs20") == 0) {
+ bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "disable_dgaf") == 0) {
+ bss->disable_dgaf = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
+ if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
+ if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
+ errors++;
+ return errors;
+ }
+ } else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
+ if (hs20_parse_conn_capab(bss, pos, line) < 0) {
+ errors++;
+ return errors;
+ }
+ } else if (os_strcmp(buf, "hs20_operating_class") == 0) {
+ u8 *oper_class;
+ size_t oper_class_len;
+ oper_class_len = os_strlen(pos);
+ if (oper_class_len < 2 || (oper_class_len & 0x01)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_operating_class '%s'",
+ line, pos);
+ errors++;
+ return errors;
+ }
+ oper_class_len /= 2;
+ oper_class = os_malloc(oper_class_len);
+ if (oper_class == NULL) {
+ errors++;
+ return errors;
+ }
+ if (hexstr2bin(pos, oper_class, oper_class_len)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_operating_class '%s'",
+ line, pos);
+ os_free(oper_class);
+ errors++;
+ return errors;
+ }
+ os_free(bss->hs20_operating_class);
+ bss->hs20_operating_class = oper_class;
+ bss->hs20_operating_class_len = oper_class_len;
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_TESTING_OPTIONS
+#define PARSE_TEST_PROBABILITY(_val) \
+ } else if (os_strcmp(buf, #_val) == 0) { \
+ char *end; \
+ \
+ conf->_val = strtod(pos, &end); \
+ if (*end || conf->_val < 0.0d || \
+ conf->_val > 1.0d) { \
+ wpa_printf(MSG_ERROR, \
+ "Line %d: Invalid value '%s'", \
+ line, pos); \
+ errors++; \
+ return errors; \
+ }
+ PARSE_TEST_PROBABILITY(ignore_probe_probability)
+ PARSE_TEST_PROBABILITY(ignore_auth_probability)
+ PARSE_TEST_PROBABILITY(ignore_assoc_probability)
+ PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
+ PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+ } else if (os_strcmp(buf, "bss_load_test") == 0) {
+ WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "bss_load_test", line);
+ return 1;
+ }
+ pos++;
+ bss->bss_load_test[2] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "bss_load_test", line);
+ return 1;
+ }
+ pos++;
+ WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
+ bss->bss_load_test_set = 1;
+#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)
+ return 1;
+
+ if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+ wpabuf_free(elems);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "vendor_elements '%s'", line, pos);
+ return 1;
+ }
+
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = elems;
+ } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
+ bss->sae_anti_clogging_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "sae_groups") == 0) {
+ if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "sae_groups value '%s'", line, pos);
+ return 1;
+ }
} else {
wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
"item '%s'", line, buf);
@@ -2148,66 +2912,84 @@ struct hostapd_config * hostapd_config_read(const char *fname)
}
}
- fclose(f);
+ return errors;
+}
- for (i = 0; i < conf->num_bss; i++) {
- bss = &conf->bss[i];
- if (bss->individual_wep_key_len == 0) {
- /* individual keys are not use; can use key idx0 for
- * broadcast keys */
- bss->broadcast_key_idx_min = 0;
- }
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+ struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
+ FILE *f;
+ char buf[512], *pos;
+ int line = 0;
+ int errors = 0;
+ size_t i;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ "for reading.", fname);
+ return NULL;
+ }
- /* Select group cipher based on the enabled pairwise cipher
- * suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ /* set default driver based on configuration */
+ conf->driver = wpa_drivers[0];
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+ hostapd_config_free(conf);
+ fclose(f);
+ return NULL;
+ }
+
+ bss = conf->last_bss = conf->bss[0];
+
+ while (fgets(buf, sizeof(buf), f)) {
+ bss = conf->last_bss;
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
}
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
-
- bss->radius->auth_server = bss->radius->auth_servers;
- bss->radius->acct_server = bss->radius->acct_servers;
-
- if (bss->wpa && bss->ieee802_1x) {
- bss->ssid.security_policy = SECURITY_WPA;
- } else if (bss->wpa) {
- bss->ssid.security_policy = SECURITY_WPA_PSK;
- } else if (bss->ieee802_1x) {
- int cipher = WPA_CIPHER_NONE;
- bss->ssid.security_policy = SECURITY_IEEE_802_1X;
- bss->ssid.wep.default_len = bss->default_wep_key_len;
- if (bss->default_wep_key_len)
- cipher = bss->default_wep_key_len >= 13 ?
- WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
- bss->wpa_group = cipher;
- bss->wpa_pairwise = cipher;
- bss->rsn_pairwise = cipher;
- } else if (bss->ssid.wep.keys_set) {
- int cipher = WPA_CIPHER_WEP40;
- if (bss->ssid.wep.len[0] >= 13)
- cipher = WPA_CIPHER_WEP104;
- bss->ssid.security_policy = SECURITY_STATIC_WEP;
- bss->wpa_group = cipher;
- bss->wpa_pairwise = cipher;
- bss->rsn_pairwise = cipher;
- } else {
- bss->ssid.security_policy = SECURITY_PLAINTEXT;
- bss->wpa_group = WPA_CIPHER_NONE;
- bss->wpa_pairwise = WPA_CIPHER_NONE;
- bss->rsn_pairwise = WPA_CIPHER_NONE;
+ if (buf[0] == '\0')
+ continue;
+
+ pos = os_strchr(buf, '=');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+ line, buf);
+ errors++;
+ continue;
}
+ *pos = '\0';
+ pos++;
+ errors += hostapd_config_fill(conf, bss, buf, pos, line);
}
- if (hostapd_config_check(conf))
+ fclose(f);
+
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_set_security_params(conf->bss[i]);
+
+ if (hostapd_config_check(conf, 1))
errors++;
#ifndef WPA_IGNORE_CONFIG_ERRORS
@@ -2221,3 +3003,28 @@ struct hostapd_config * hostapd_config_read(const char *fname)
return conf;
}
+
+
+int hostapd_set_iface(struct hostapd_config *conf,
+ struct hostapd_bss_config *bss, char *field, char *value)
+{
+ int errors;
+ size_t i;
+
+ errors = hostapd_config_fill(conf, bss, field, value, 0);
+ if (errors) {
+ wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
+ "to value '%s'", field, value);
+ return -1;
+ }
+
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_set_security_params(conf->bss[i]);
+
+ if (hostapd_config_check(conf, 0)) {
+ wpa_printf(MSG_ERROR, "Configuration check failed");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index 7111a9a..fba57b8 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -2,19 +2,16 @@
* hostapd / Configuration file parser
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
struct hostapd_config * hostapd_config_read(const char *fname);
+int hostapd_set_iface(struct hostapd_config *conf,
+ struct hostapd_bss_config *bss, char *field,
+ char *value);
#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 4a6e011..4a9da5f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,15 +1,9 @@
/*
* hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -26,18 +20,21 @@
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
#include "radius/radius_client.h"
+#include "radius/radius_server.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ieee802_1x.h"
#include "ap/wpa_auth.h"
#include "ap/ieee802_11.h"
#include "ap/sta_info.h"
-#include "ap/accounting.h"
#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
#include "ap/ap_drv_ops.h"
+#include "ap/wnm_ap.h"
+#include "ap/wpa_auth.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
+#include "config_file.h"
#include "ctrl_iface.h"
@@ -87,15 +84,15 @@ static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
os_memcmp(from->sun_path, dst->addr.sun_path,
fromlen - offsetof(struct sockaddr_un, sun_path))
== 0) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ (u8 *) from->sun_path,
+ fromlen -
+ offsetof(struct sockaddr_un, sun_path));
if (prev == NULL)
hapd->ctrl_dst = dst->next;
else
prev->next = dst->next;
os_free(dst);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path,
- fromlen -
- offsetof(struct sockaddr_un, sun_path));
return 0;
}
prev = dst;
@@ -159,171 +156,6 @@ static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
}
-#ifdef CONFIG_P2P_MANAGER
-static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
- u8 minor_reason_code, const u8 *addr)
-{
- struct ieee80211_mgmt *mgmt;
- int ret;
- u8 *pos;
-
- if (hapd->driver->send_frame == NULL)
- return -1;
-
- mgmt = os_zalloc(sizeof(*mgmt) + 100);
- if (mgmt == NULL)
- return -1;
-
- wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor "
- "reason code %u (stype=%u)",
- MAC2STR(addr), minor_reason_code, stype);
-
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
- os_memcpy(mgmt->da, addr, ETH_ALEN);
- os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
- if (stype == WLAN_FC_STYPE_DEAUTH) {
- mgmt->u.deauth.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
- } else {
- mgmt->u.disassoc.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
- }
-
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4 + 3 + 1;
- WPA_PUT_BE24(pos, OUI_WFA);
- pos += 3;
- *pos++ = P2P_OUI_TYPE;
-
- *pos++ = P2P_ATTR_MINOR_REASON_CODE;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- *pos++ = minor_reason_code;
-
- ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
- pos - (u8 *) mgmt, 1);
- os_free(mgmt);
-
- return ret < 0 ? -1 : 0;
-}
-#endif /* CONFIG_P2P_MANAGER */
-
-
-static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
- const char *txtaddr)
-{
- u8 addr[ETH_ALEN];
- struct sta_info *sta;
- const char *pos;
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
-
- if (hwaddr_aton(txtaddr, addr))
- return -1;
-
- pos = os_strstr(txtaddr, " test=");
- if (pos) {
- struct ieee80211_mgmt mgmt;
- int encrypt;
- if (hapd->driver->send_frame == NULL)
- return -1;
- pos += 6;
- encrypt = atoi(pos);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_DEAUTH);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.deauth.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
- return -1;
- return 0;
- }
-
-#ifdef CONFIG_P2P_MANAGER
- pos = os_strstr(txtaddr, " p2p=");
- if (pos) {
- return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
- atoi(pos + 5), addr);
- }
-#endif /* CONFIG_P2P_MANAGER */
-
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
- sta = ap_get_sta(hapd, addr);
- if (sta)
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- else if (addr[0] == 0xff)
- hostapd_free_stas(hapd);
-
- return 0;
-}
-
-
-static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
- const char *txtaddr)
-{
- u8 addr[ETH_ALEN];
- struct sta_info *sta;
- const char *pos;
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
-
- if (hwaddr_aton(txtaddr, addr))
- return -1;
-
- pos = os_strstr(txtaddr, " test=");
- if (pos) {
- struct ieee80211_mgmt mgmt;
- int encrypt;
- if (hapd->driver->send_frame == NULL)
- return -1;
- pos += 6;
- encrypt = atoi(pos);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_DISASSOC);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.disassoc.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
- return -1;
- return 0;
- }
-
-#ifdef CONFIG_P2P_MANAGER
- pos = os_strstr(txtaddr, " p2p=");
- if (pos) {
- return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
- atoi(pos + 5), addr);
- }
-#endif /* CONFIG_P2P_MANAGER */
-
- hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
- sta = ap_get_sta(hapd, addr);
- if (sta)
- ap_sta_disassociate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- else if (addr[0] == 0xff)
- hostapd_free_stas(hapd);
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
@@ -421,28 +253,219 @@ static int hostapd_ctrl_iface_wps_check_pin(
}
-#ifdef CONFIG_WPS_OOB
-static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
+#ifdef CONFIG_WPS_NFC
+static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
+ char *pos)
{
- char *path, *method, *name;
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = hostapd_wps_nfc_tag_read(hapd, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = hostapd_wps_nfc_config_token(hapd, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
+ char *reply, size_t max_len,
+ int ndef)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = hostapd_wps_nfc_token_gen(hapd, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ if (os_strcmp(cmd, "WPS") == 0)
+ return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+ max_len, 0);
+
+ if (os_strcmp(cmd, "NDEF") == 0)
+ return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+ max_len, 1);
+
+ if (os_strcmp(cmd, "enable") == 0)
+ return hostapd_wps_nfc_token_enable(hapd);
+
+ if (os_strcmp(cmd, "disable") == 0) {
+ hostapd_wps_nfc_token_disable(hapd);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ if (os_strcmp(pos, "WPS-CR") == 0)
+ buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
+ else
+ buf = NULL;
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *req, *sel;
+ int ret;
+ char *pos, *role, *type, *pos2;
+
+ role = cmd;
+ pos = os_strchr(role, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ type = pos;
+ pos = os_strchr(type, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ return -1;
+ *pos2++ = '\0';
- path = os_strchr(txt, ' ');
- if (path == NULL)
+ len = os_strlen(pos);
+ if (len & 0x01)
return -1;
- *path++ = '\0';
+ len /= 2;
- method = os_strchr(path, ' ');
- if (method == NULL)
+ req = wpabuf_alloc(len);
+ if (req == NULL)
return -1;
- *method++ = '\0';
+ if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpabuf_free(req);
+ return -1;
+ }
- name = os_strchr(method, ' ');
- if (name != NULL)
- *name++ = '\0';
+ len = os_strlen(pos2);
+ if (len & 0x01) {
+ wpabuf_free(req);
+ return -1;
+ }
+ len /= 2;
- return hostapd_wps_start_oob(hapd, txt, path, method, name);
+ sel = wpabuf_alloc(len);
+ if (sel == NULL) {
+ wpabuf_free(req);
+ return -1;
+ }
+ if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpabuf_free(req);
+ wpabuf_free(sel);
+ return -1;
+ }
+
+ if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
+ ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
+ } else {
+ wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+ "reported: role=%s type=%s", role, type);
+ ret = -1;
+ }
+ wpabuf_free(req);
+ wpabuf_free(sel);
+
+ return ret;
}
-#endif /* CONFIG_WPS_OOB */
+
+#endif /* CONFIG_WPS_NFC */
static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
@@ -523,59 +546,242 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
}
+
+
+static const char * pbc_status_str(enum pbc_status status)
+{
+ switch (status) {
+ case WPS_PBC_STATUS_DISABLE:
+ return "Disabled";
+ case WPS_PBC_STATUS_ACTIVE:
+ return "Active";
+ case WPS_PBC_STATUS_TIMEOUT:
+ return "Timed-out";
+ case WPS_PBC_STATUS_OVERLAP:
+ return "Overlap";
+ default:
+ return "Unknown";
+ }
+}
+
+
+static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
+ pbc_status_str(hapd->wps_stats.pbc_status));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
+ (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
+ "Success":
+ (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
+ "Failed" : "None")));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ /* If status == Failure - Add possible Reasons */
+ if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
+ hapd->wps_stats.failure_reason > 0) {
+ ret = os_snprintf(pos, end - pos,
+ "Failure Reason: %s\n",
+ wps_ei_str(hapd->wps_stats.failure_reason));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->wps_stats.status) {
+ ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
+ MAC2STR(hapd->wps_stats.peer_addr));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
#endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+
+static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 qos_map_set[16 + 2 * 21], count = 0;
+ const char *pos = cmd;
+ int val, ret;
+
+ for (;;) {
+ if (count == sizeof(qos_map_set)) {
+ wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
+ return -1;
+ }
+
+ val = atoi(pos);
+ if (val < 0 || val > 255) {
+ wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+ return -1;
+ }
+
+ qos_map_set[count++] = val;
+ pos = os_strchr(pos, ',');
+ if (!pos)
+ break;
+ pos++;
+ }
+
+ if (count < 16 || count & 1) {
+ wpa_printf(MSG_INFO, "Invalid QoS Map Set");
+ return -1;
+ }
+
+ ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
+ if (ret) {
+ wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
+ return -1;
+ }
+
+ os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
+ hapd->conf->qos_map_set_len = count;
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ struct wpabuf *buf;
+ u8 *qos_map_set = hapd->conf->qos_map_set;
+ u8 qos_map_set_len = hapd->conf->qos_map_set_len;
+ int ret;
+
+ if (!qos_map_set_len) {
+ wpa_printf(MSG_INFO, "QoS Map Set is not set");
+ return -1;
+ }
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
+ "for QoS Map Configuration message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ if (!sta->qos_map_enabled) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
+ "support for QoS Map", MAC2STR(addr));
+ return -1;
+ }
+
+ buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
+ if (buf == NULL)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_QOS);
+ wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
+
+ /* QoS Map Set Element */
+ wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
+ wpabuf_put_u8(buf, qos_map_set_len);
+ wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_WNM
+
+static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int disassoc_timer;
+ struct sta_info *sta;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ if (cmd[17] != ' ')
+ return -1;
+ disassoc_timer = atoi(cmd + 17);
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for disassociation imminent message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
+}
+
+
static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
- const char *url;
- u8 buf[1000], *pos;
- struct ieee80211_mgmt *mgmt;
- size_t url_len;
+ const char *url, *timerstr;
+ int disassoc_timer;
+ struct sta_info *sta;
if (hwaddr_aton(cmd, addr))
return -1;
- url = cmd + 17;
- if (*url != ' ')
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for ESS disassociation imminent message",
+ MAC2STR(addr));
return -1;
- url++;
- url_len = os_strlen(url);
- if (url_len > 255)
+ }
+
+ timerstr = cmd + 17;
+ if (*timerstr != ' ')
+ return -1;
+ timerstr++;
+ disassoc_timer = atoi(timerstr);
+ if (disassoc_timer < 0 || disassoc_timer > 65535)
return -1;
- os_memset(buf, 0, sizeof(buf));
- mgmt = (struct ieee80211_mgmt *) buf;
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(mgmt->da, addr, ETH_ALEN);
- os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
- mgmt->u.action.category = WLAN_ACTION_WNM;
- mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
- mgmt->u.action.u.bss_tm_req.dialog_token = 1;
- mgmt->u.action.u.bss_tm_req.req_mode =
- WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
- mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
- mgmt->u.action.u.bss_tm_req.validity_interval = 0;
-
- pos = mgmt->u.action.u.bss_tm_req.variable;
-
- /* Session Information URL */
- *pos++ = url_len;
- os_memcpy(pos, url, url_len);
- pos += url_len;
-
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
- "Management Request frame");
+ url = os_strchr(timerstr, ' ');
+ if (url == NULL)
return -1;
- }
+ url++;
- return 0;
+ return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
}
+#endif /* CONFIG_WNM */
+
static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
char *buf, size_t buflen)
@@ -589,7 +795,8 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
"ssid=%s\n",
MAC2STR(hapd->own_addr),
- hapd->conf->ssid.ssid);
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
@@ -678,14 +885,9 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
pos += ret;
}
- if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- } else if (hapd->conf->wpa &&
- hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
+ if (hapd->conf->wpa) {
+ ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
+ wpa_cipher_txt(hapd->conf->wpa_group));
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
@@ -697,18 +899,11 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "CCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "TKIP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
+ ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+ " ");
+ if (ret < 0)
+ return pos - buf;
+ pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
@@ -722,18 +917,11 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "CCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "TKIP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
+ ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+ " ");
+ if (ret < 0)
+ return pos - buf;
+ pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
@@ -777,9 +965,25 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
wps_testing_dummy_cred = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+ wps_corrupt_pkhash = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+ wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+ } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
+ int val = atoi(value);
+ if (val <= 0)
+ ret = -1;
+ else
+ hapd->gas_frag_limit = val;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
+ hapd->ext_mgmt_frame_handling = atoi(value);
+#endif /* CONFIG_TESTING_OPTIONS */
} else {
- ret = -1;
+ ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
}
return ret;
@@ -804,11 +1008,161 @@ static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
}
+static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
+{
+ if (hostapd_enable_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Enabling of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
+{
+ if (hostapd_reload_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Reloading of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
+{
+ if (hostapd_disable_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Disabling of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
+{
+ union wpa_event_data data;
+ char *pos, *param;
+ enum wpa_event_type event;
+
+ wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
+
+ os_memset(&data, 0, sizeof(data));
+
+ param = os_strchr(cmd, ' ');
+ if (param == NULL)
+ return -1;
+ *param++ = '\0';
+
+ if (os_strcmp(cmd, "DETECTED") == 0)
+ event = EVENT_DFS_RADAR_DETECTED;
+ else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
+ event = EVENT_DFS_CAC_FINISHED;
+ else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
+ event = EVENT_DFS_CAC_ABORTED;
+ else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
+ event = EVENT_DFS_NOP_FINISHED;
+ else {
+ wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
+ cmd);
+ return -1;
+ }
+
+ pos = os_strstr(param, "freq=");
+ if (pos)
+ data.dfs_event.freq = atoi(pos + 5);
+
+ pos = os_strstr(param, "ht_enabled=1");
+ if (pos)
+ data.dfs_event.ht_enabled = 1;
+
+ pos = os_strstr(param, "chan_offset=");
+ if (pos)
+ data.dfs_event.chan_offset = atoi(pos + 12);
+
+ pos = os_strstr(param, "chan_width=");
+ if (pos)
+ data.dfs_event.chan_width = atoi(pos + 11);
+
+ pos = os_strstr(param, "cf1=");
+ if (pos)
+ data.dfs_event.cf1 = atoi(pos + 4);
+
+ pos = os_strstr(param, "cf2=");
+ if (pos)
+ data.dfs_event.cf2 = atoi(pos + 4);
+
+ wpa_supplicant_event(hapd, event, &data);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
+{
+ size_t len;
+ u8 *buf;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
+
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+ os_free(buf);
+ return res;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
+{
+#ifdef NEED_AP_MLME
+ struct csa_settings settings;
+ int ret = hostapd_parse_csa_settings(pos, &settings);
+
+ if (ret)
+ return ret;
+
+ return hostapd_switch_channel(hapd, &settings);
+#else /* NEED_AP_MLME */
+ return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
+static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
+ int reply_size, const char *param)
+{
+#ifdef RADIUS_SERVER
+ if (os_strcmp(param, "radius_server") == 0) {
+ return radius_server_get_mib(hapd->radius_srv, reply,
+ reply_size);
+ }
+#endif /* RADIUS_SERVER */
+ return -1;
+}
+
+
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
- char buf[256];
+ char buf[4096];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
@@ -844,6 +1198,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
+ } else if (os_strcmp(buf, "STATUS") == 0) {
+ reply_len = hostapd_ctrl_iface_status(hapd, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
+ reply_len = hostapd_drv_status(hapd, reply, reply_size);
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
if (reply_len >= 0) {
@@ -873,6 +1232,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len += res;
}
#endif /* CONFIG_NO_RADIUS */
+ } else if (os_strncmp(buf, "MIB ", 4) == 0) {
+ reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
+ buf + 4);
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
reply_size);
@@ -918,21 +1280,52 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
if (hostapd_wps_button_pushed(hapd, NULL))
reply_len = -1;
-#ifdef CONFIG_WPS_OOB
- } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
- if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
+ } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+ if (hostapd_wps_cancel(hapd))
reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
reply, reply_size);
} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
+ reply_size);
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+ if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
+ hapd, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_nfc_token(
+ hapd, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
+ hapd, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
+ reply_len = -1;
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
+#ifdef CONFIG_INTERWORKING
+ } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
+ if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
+ if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
+ reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_WNM
+ } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+ if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
+ reply_len = -1;
} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
reply_len = -1;
+#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
reply_size);
@@ -942,6 +1335,26 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "GET ", 4) == 0) {
reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
reply_size);
+ } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
+ if (hostapd_ctrl_iface_enable(hapd->iface))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
+ if (hostapd_ctrl_iface_reload(hapd->iface))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
+ if (hostapd_ctrl_iface_disable(hapd->iface))
+ reply_len = -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
+ if (hostapd_ctrl_iface_radar(hapd, buf + 6))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
+ if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
+ reply_len = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
+ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+ if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -977,7 +1390,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
}
-static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
const char *txt, size_t len)
{
struct hostapd_data *hapd = ctx;
@@ -993,7 +1406,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
int s = -1;
char *fname = NULL;
- hapd->ctrl_sock = -1;
+ if (hapd->ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+ return 0;
+ }
if (hapd->conf->ctrl_interface == NULL)
return 0;
@@ -1009,12 +1425,35 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(hapd->conf->ctrl_interface, 0,
+ chown(hapd->conf->ctrl_interface, -1,
hapd->conf->ctrl_interface_gid) < 0) {
perror("chown[ctrl_interface]");
return -1;
}
+ if (!hapd->conf->ctrl_interface_gid_set &&
+ hapd->iface->interfaces->ctrl_iface_group &&
+ chown(hapd->conf->ctrl_interface, -1,
+ hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ perror("chown[ctrl_interface]");
+ return -1;
+ }
+
+#ifdef ANDROID
+ /*
+ * Android is using umask 0077 which would leave the control interface
+ * directory without group access. This breaks things since Wi-Fi
+ * framework assumes that this directory can be accessed by other
+ * applications in the wifi group. Fix this by adding group access even
+ * if umask value would prevent this.
+ */
+ if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+#endif /* ANDROID */
+
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
goto fail;
@@ -1050,7 +1489,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("bind(PF_UNIX)");
+ perror("hostapd-ctrl-iface: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1067,7 +1506,14 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
+ chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface/ifname]");
+ goto fail;
+ }
+
+ if (!hapd->conf->ctrl_interface_gid_set &&
+ hapd->iface->interfaces->ctrl_iface_group &&
+ chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
perror("chown[ctrl_interface/ifname]");
goto fail;
}
@@ -1118,7 +1564,10 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ hapd->conf->ctrl_interface,
+ strerror(errno));
}
}
}
@@ -1132,6 +1581,250 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
}
+static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_add_iface(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_remove_iface(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
+static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
+{
+#ifdef CONFIG_WPS_TESTING
+ wps_version_number = 0x20;
+ wps_testing_dummy_cred = 0;
+ wps_corrupt_pkhash = 0;
+#endif /* CONFIG_WPS_TESTING */
+}
+
+
+static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ void *interfaces = eloop_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char reply[24];
+ int reply_len;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+ wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
+
+ os_memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (os_strcmp(buf, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+ if (wpa_debug_reopen_file() < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ hostapd_ctrl_iface_flush(interfaces);
+ } else if (os_strncmp(buf, "ADD ", 4) == 0) {
+ if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
+ if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
+ reply_len = -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
+ "ignored");
+ reply_len = -1;
+ }
+
+ if (reply_len < 0) {
+ os_memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+}
+
+
+static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
+{
+ char *buf;
+ size_t len;
+
+ if (interface->global_iface_path == NULL)
+ return NULL;
+
+ len = os_strlen(interface->global_iface_path) +
+ os_strlen(interface->global_iface_name) + 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+
+ os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
+ interface->global_iface_name);
+ buf[len - 1] = '\0';
+ return buf;
+}
+
+
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+ struct sockaddr_un addr;
+ int s = -1;
+ char *fname = NULL;
+
+ if (interface->global_iface_path == NULL) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
+ return 0;
+ }
+
+ if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ } else if (interface->ctrl_iface_group &&
+ chown(interface->global_iface_path, -1,
+ interface->ctrl_iface_group) < 0) {
+ perror("chown[ctrl_interface]");
+ goto fail;
+ }
+
+ if (os_strlen(interface->global_iface_path) + 1 +
+ os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+ addr.sun_family = AF_UNIX;
+ fname = hostapd_global_ctrl_iface_path(interface);
+ if (fname == NULL)
+ goto fail;
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+ strerror(errno));
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+ " allow connections - assuming it was left"
+ "over from forced program termination");
+ if (unlink(fname) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ fname);
+ goto fail;
+ }
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'", fname);
+ } else {
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+ "be in use - cannot override it");
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+ "not used anymore", fname);
+ os_free(fname);
+ fname = NULL;
+ goto fail;
+ }
+ }
+
+ if (interface->ctrl_iface_group &&
+ chown(fname, -1, interface->ctrl_iface_group) < 0) {
+ perror("chown[ctrl_interface]");
+ goto fail;
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ os_free(fname);
+
+ interface->global_ctrl_sock = s;
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ interface, NULL);
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+ return -1;
+}
+
+
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
+{
+ char *fname = NULL;
+
+ if (interfaces->global_ctrl_sock > -1) {
+ eloop_unregister_read_sock(interfaces->global_ctrl_sock);
+ close(interfaces->global_ctrl_sock);
+ interfaces->global_ctrl_sock = -1;
+ fname = hostapd_global_ctrl_iface_path(interfaces);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+
+ if (interfaces->global_iface_path &&
+ rmdir(interfaces->global_iface_path) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ interfaces->global_iface_path,
+ strerror(errno));
+ }
+ }
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+ }
+}
+
+
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
const char *buf, size_t len)
{
diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h
index c997141..3341a66 100644
--- a/hostapd/ctrl_iface.h
+++ b/hostapd/ctrl_iface.h
@@ -2,14 +2,8 @@
* hostapd / UNIX domain socket -based control interface
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_H
@@ -18,6 +12,8 @@
#ifndef CONFIG_NO_CTRL_IFACE
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
@@ -27,6 +23,17 @@ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
{
}
+
+static inline int
+hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+ return 0;
+}
+
+static inline void
+hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
+{
+}
#endif /* CONFIG_NO_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
diff --git a/hostapd/defconfig b/hostapd/defconfig
index f4c3666..e329a11 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -22,6 +22,19 @@ CONFIG_DRIVER_HOSTAP=y
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires libnl. If you are compiling it yourself
+# you may need to point hostapd to your version of libnl.
+#
+#CFLAGS += -I$<path to libnl include files>
+#LIBS += -L$<path to libnl library files>
+
+# Use libnl v2.0 (or 3.0) libraries.
+#CONFIG_LIBNL20=y
+
+# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
+#CONFIG_LIBNL32=y
+
+
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -96,10 +109,9 @@ CONFIG_EAP_TTLS=y
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
-# to add the needed functions.
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
#CONFIG_EAP_FAST=y
# Wi-Fi Protected Setup (WPS)
@@ -108,6 +120,8 @@ CONFIG_EAP_TTLS=y
#CONFIG_WPS2=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
@@ -115,6 +129,9 @@ CONFIG_EAP_TTLS=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
+# EAP-EKE for the integrated EAP server
+#CONFIG_EAP_EKE=y
+
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@@ -136,6 +153,13 @@ CONFIG_IPV6=y
# IEEE 802.11n (High Throughput) support
#CONFIG_IEEE80211N=y
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# IEEE 802.11ac (Very High Throughput) support
+#CONFIG_IEEE80211AC=y
+
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
@@ -145,6 +169,12 @@ CONFIG_IPV6=y
# Disabled by default.
#CONFIG_DEBUG_FILE=y
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
@@ -158,7 +188,11 @@ CONFIG_IPV6=y
# automatically create bridge and VLAN interfaces if necessary.
#CONFIG_FULL_DYNAMIC_VLAN=y
-# Remove support for dumping state into a file on SIGUSR1 signal
+# Use netlink-based kernel API for VLAN operations instead of ioctl()
+# Note: This requires libnl 3.1 or newer.
+#CONFIG_VLAN_NETLINK=y
+
+# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
#CONFIG_NO_DUMP_STATE=y
@@ -224,6 +258,10 @@ CONFIG_IPV6=y
# are used.
#CONFIG_TLSV11=y
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms.
+#CONFIG_TLSV12=y
+
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
@@ -244,3 +282,41 @@ CONFIG_IPV6=y
# This can be used to enable functionality to improve interworking with
# external networks.
#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
+#CONFIG_SQLITE=y
+
+# Testing options
+# This can be used to enable some testing options (see also the example
+# configuration file) that are really useful only for testing clients that
+# connect to this hostapd. These options allow, for example, to drop a
+# certain percentage of probe requests or auth/(re)assoc frames.
+#
+#CONFIG_TESTING_OPTIONS=y
+
+# Automatic Channel Selection
+# This will allow hostapd to pick the channel automatically when channel is set
+# to "acs_survey" or "0". Eventually, other ACS algorithms can be added in
+# similar way.
+#
+# Automatic selection is currently only done through initialization, later on
+# we hope to do background checks to keep us moving to more ideal channels as
+# time goes by. ACS is currently only supported through the nl80211 driver and
+# your driver must have survey dump capability that is filled by the driver
+# during scanning.
+#
+# You can customize the ACS survey algorithm with the hostapd.conf variable
+# acs_num_scans.
+#
+# Supported ACS drivers:
+# * ath9k
+# * ath5k
+# * ath10k
+#
+# For more details refer to:
+# http://wireless.kernel.org/en/users/Documentation/acs
+#
+#CONFIG_ACS=y
diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c
deleted file mode 100644
index 110cedc..0000000
--- a/hostapd/dump_state.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-#include <time.h>
-
-#include "utils/common.h"
-#include "radius/radius_client.h"
-#include "radius/radius_server.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "eap_server/eap.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#include "ap/sta_info.h"
-#include "dump_state.h"
-
-
-static void fprint_char(FILE *f, char c)
-{
- if (c >= 32 && c < 127)
- fprintf(f, "%c", c);
- else
- fprintf(f, "<%02x>", c);
-}
-
-
-static void ieee802_1x_dump_state(FILE *f, const char *prefix,
- struct sta_info *sta)
-{
- struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
- return;
-
- fprintf(f, "%sIEEE 802.1X:\n", prefix);
-
- if (sm->identity) {
- size_t i;
- fprintf(f, "%sidentity=", prefix);
- for (i = 0; i < sm->identity_len; i++)
- fprint_char(f, sm->identity[i]);
- fprintf(f, "\n");
- }
-
- fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
- "Supplicant: %d (%s)\n", prefix,
- sm->eap_type_authsrv,
- eap_server_get_name(0, sm->eap_type_authsrv),
- sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
-
- fprintf(f, "%scached_packets=%s\n", prefix,
- sm->last_recv_radius ? "[RX RADIUS]" : "");
-
- eapol_auth_dump_state(f, prefix, sm);
-}
-
-
-/**
- * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
- */
-static void hostapd_dump_state(struct hostapd_data *hapd)
-{
- FILE *f;
- time_t now;
- struct sta_info *sta;
- int i;
-#ifndef CONFIG_NO_RADIUS
- char *buf;
-#endif /* CONFIG_NO_RADIUS */
-
- if (!hapd->conf->dump_log_name) {
- wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
- "request");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
- hapd->conf->dump_log_name);
- f = fopen(hapd->conf->dump_log_name, "w");
- if (f == NULL) {
- wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
- "writing.", hapd->conf->dump_log_name);
- return;
- }
-
- time(&now);
- fprintf(f, "hostapd state dump - %s", ctime(&now));
- fprintf(f, "num_sta=%d num_sta_non_erp=%d "
- "num_sta_no_short_slot_time=%d\n"
- "num_sta_no_short_preamble=%d\n",
- hapd->num_sta, hapd->iface->num_sta_non_erp,
- hapd->iface->num_sta_no_short_slot_time,
- hapd->iface->num_sta_no_short_preamble);
-
- for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
- fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
-
- fprintf(f,
- " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
- "\n"
- " capability=0x%x listen_interval=%d\n",
- sta->aid,
- sta->flags,
- (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
- (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
- (sta->flags & WLAN_STA_PS ? "[PS]" : ""),
- (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
- (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
- (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
- (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
- ""),
- (sta->flags & WLAN_STA_SHORT_PREAMBLE ?
- "[SHORT_PREAMBLE]" : ""),
- (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
- (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
- (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
- (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
- (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
- (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
- (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
- (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
- sta->capability,
- sta->listen_interval);
-
- fprintf(f, " supported_rates=");
- for (i = 0; i < sta->supported_rates_len; i++)
- fprintf(f, "%02x ", sta->supported_rates[i]);
- fprintf(f, "\n");
-
- fprintf(f,
- " timeout_next=%s\n",
- (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
- (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
- "DEAUTH")));
-
- ieee802_1x_dump_state(f, " ", sta);
- }
-
-#ifndef CONFIG_NO_RADIUS
- buf = os_malloc(4096);
- if (buf) {
- int count = radius_client_get_mib(hapd->radius, buf, 4096);
- if (count < 0)
- count = 0;
- else if (count > 4095)
- count = 4095;
- buf[count] = '\0';
- fprintf(f, "%s", buf);
-
-#ifdef RADIUS_SERVER
- count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
- if (count < 0)
- count = 0;
- else if (count > 4095)
- count = 4095;
- buf[count] = '\0';
- fprintf(f, "%s", buf);
-#endif /* RADIUS_SERVER */
-
- os_free(buf);
- }
-#endif /* CONFIG_NO_RADIUS */
- fclose(f);
-}
-
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
-{
- size_t i;
-
- for (i = 0; i < iface->num_bss; i++)
- hostapd_dump_state(iface->bss[i]);
-
- return 0;
-}
diff --git a/hostapd/dump_state.h b/hostapd/dump_state.h
deleted file mode 100644
index e14f08a..0000000
--- a/hostapd/dump_state.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DUMP_STATE_H
-#define DUMP_STATE_H
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
-
-#endif /* DUMP_STATE_H */
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
index bab2871..981e539 100644
--- a/hostapd/eap_register.c
+++ b/hostapd/eap_register.c
@@ -2,14 +2,8 @@
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -45,6 +39,11 @@ int eap_server_register_methods(void)
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
+#ifdef EAP_SERVER_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
@@ -135,5 +134,10 @@ int eap_server_register_methods(void)
ret = eap_server_pwd_register();
#endif /* EAP_SERVER_PWD */
+#ifdef EAP_SERVER_EKE
+ if (ret == 0)
+ ret = eap_server_eke_register();
+#endif /* EAP_SERVER_EKE */
+
return ret;
}
diff --git a/hostapd/eap_register.h b/hostapd/eap_register.h
index 82e7171..c342351 100644
--- a/hostapd/eap_register.h
+++ b/hostapd/eap_register.h
@@ -2,14 +2,8 @@
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef EAP_REGISTER_H
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 2fbf31f..c041887 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,15 +1,9 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This is an example implementation of the EAP-SIM/AKA database/authentication
* gateway interface to HLR/AuC. It is expected to be replaced with an
@@ -24,6 +18,9 @@
* SIM-REQ-AUTH <IMSI> <max_chal>
* SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
* SIM-RESP-AUTH <IMSI> FAILURE
+ * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
+ * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
+ * GSM-AUTH-RESP <IMSI> FAILURE
*
* EAP-AKA / UMTS query/response:
* AKA-REQ-AUTH <IMSI>
@@ -36,12 +33,16 @@
* IMSI and max_chal are sent as an ASCII string,
* Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
*
- * The example implementation here reads GSM authentication triplets from a
+ * An example implementation here reads GSM authentication triplets from a
* text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
* strings. This is used to simulate an HLR/AuC. As such, it is not very useful
* for real life authentication, but it is useful both as an example
* implementation and for EAP-SIM/AKA/AKA' testing.
*
+ * For a stronger example design, Milenage and GSM-Milenage algorithms can be
+ * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
+ * EAP-SIM, respectively, if Ki is known.
+ *
* SQN generation follows the not time-based Profile 2 described in
* 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
* can be changed with a command line options if needed.
@@ -49,6 +50,9 @@
#include "includes.h"
#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "crypto/milenage.h"
@@ -57,7 +61,11 @@
static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
static const char *socket_path;
static int serv_sock = -1;
+static char *milenage_file = NULL;
+static int update_milenage = 0;
+static int sqn_changes = 0;
static int ind_len = 5;
+static int stdout_debug = 1;
/* GSM triplets */
struct gsm_triplet {
@@ -78,6 +86,7 @@ struct milenage_parameters {
u8 opc[16];
u8 amf[2];
u8 sqn[6];
+ int set;
};
static struct milenage_parameters *milenage_db = NULL;
@@ -92,6 +101,147 @@ static struct milenage_parameters *milenage_db = NULL;
#define EAP_AKA_CK_LEN 16
+#ifdef CONFIG_SQLITE
+
+static sqlite3 *sqlite_db = NULL;
+static struct milenage_parameters db_tmp_milenage;
+
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_milenage(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE milenage("
+ " imsi INTEGER PRIMARY KEY NOT NULL,"
+ " ki CHAR(32) NOT NULL,"
+ " opc CHAR(32) NOT NULL,"
+ " amf CHAR(4) NOT NULL,"
+ " sqn CHAR(12) NOT NULL"
+ ");";
+
+ printf("Adding database table for milenage information\n");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ printf("SQLite error: %s\n", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+ sqlite3 *db;
+
+ if (sqlite3_open(db_file, &db)) {
+ printf("Failed to open database %s: %s\n",
+ db_file, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "milenage") &&
+ db_table_create_milenage(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+
+static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct milenage_parameters *m = ctx;
+ int i;
+
+ m->set = 1;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
+ printf("Invalid ki value in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
+ printf("Invalid opcvalue in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
+ printf("Invalid amf value in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
+ printf("Invalid sqn value in database\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
+{
+ char cmd[128];
+ unsigned long long imsi;
+
+ os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
+ imsi = atoll(imsi_txt);
+ os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
+ "%llu", imsi);
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
+ imsi);
+ if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
+ NULL) != SQLITE_OK)
+ return NULL;
+
+ if (!db_tmp_milenage.set)
+ return NULL;
+ return &db_tmp_milenage;
+}
+
+
+static int db_update_milenage_sqn(struct milenage_parameters *m)
+{
+ char cmd[128], val[13], *pos;
+
+ if (sqlite_db == NULL)
+ return 0;
+
+ pos = val;
+ pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
+ *pos = '\0';
+ os_snprintf(cmd, sizeof(cmd),
+ "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
+ val, m->imsi);
+ if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ printf("Failed to update SQN in database for IMSI %s\n",
+ m->imsi);
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
static int open_socket(const char *path)
{
struct sockaddr_un addr;
@@ -107,7 +257,7 @@ static int open_socket(const char *path)
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("hlr-auc-gw: bind(PF_UNIX)");
close(s);
return -1;
}
@@ -221,7 +371,7 @@ static int read_gsm_triplets(const char *fname)
gsm_db = g;
g = NULL;
}
- free(g);
+ os_free(g);
fclose(f);
@@ -371,7 +521,7 @@ static int read_milenage(const char *fname)
milenage_db = m;
m = NULL;
}
- free(m);
+ os_free(m);
fclose(f);
@@ -379,6 +529,80 @@ static int read_milenage(const char *fname)
}
+static void update_milenage_file(const char *fname)
+{
+ FILE *f, *f2;
+ char buf[500], *pos;
+ char *end = buf + sizeof(buf);
+ struct milenage_parameters *m;
+ size_t imsi_len;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ printf("Could not open Milenage data file '%s'\n", fname);
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "%s.new", fname);
+ f2 = fopen(buf, "w");
+ if (f2 == NULL) {
+ printf("Could not write Milenage data file '%s'\n", buf);
+ fclose(f);
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ /* IMSI Ki OPc AMF SQN */
+ buf[sizeof(buf) - 1] = '\0';
+
+ pos = strchr(buf, ' ');
+ if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
+ goto no_update;
+
+ imsi_len = pos - buf;
+
+ for (m = milenage_db; m; m = m->next) {
+ if (strncmp(buf, m->imsi, imsi_len) == 0 &&
+ m->imsi[imsi_len] == '\0')
+ break;
+ }
+
+ if (!m)
+ goto no_update;
+
+ pos = buf;
+ pos += snprintf(pos, end - pos, "%s ", m->imsi);
+ pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
+ *pos++ = ' ';
+ pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
+ *pos++ = ' ';
+ pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
+ *pos++ = ' ';
+ pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
+ *pos++ = '\n';
+
+ no_update:
+ fprintf(f2, "%s", buf);
+ }
+
+ fclose(f2);
+ fclose(f);
+
+ snprintf(buf, sizeof(buf), "%s.bak", fname);
+ if (rename(fname, buf) < 0) {
+ perror("rename");
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "%s.new", fname);
+ if (rename(buf, fname) < 0) {
+ perror("rename");
+ return;
+ }
+
+}
+
+
static struct milenage_parameters * get_milenage(const char *imsi)
{
struct milenage_parameters *m = milenage_db;
@@ -389,35 +613,39 @@ static struct milenage_parameters * get_milenage(const char *imsi)
m = m->next;
}
+#ifdef CONFIG_SQLITE
+ if (!m)
+ m = db_get_milenage(imsi);
+#endif /* CONFIG_SQLITE */
+
return m;
}
-static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
- char *imsi)
+static int sim_req_auth(char *imsi, char *resp, size_t resp_len)
{
int count, max_chal, ret;
char *pos;
- char reply[1000], *rpos, *rend;
+ char *rpos, *rend;
struct milenage_parameters *m;
struct gsm_triplet *g;
- reply[0] = '\0';
+ resp[0] = '\0';
pos = strchr(imsi, ' ');
if (pos) {
*pos++ = '\0';
max_chal = atoi(pos);
- if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+ if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
max_chal = EAP_SIM_MAX_CHAL;
} else
max_chal = EAP_SIM_MAX_CHAL;
- rend = &reply[sizeof(reply)];
- rpos = reply;
+ rend = resp + resp_len;
+ rpos = resp;
ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
if (ret < 0 || ret >= rend - rpos)
- return;
+ return -1;
rpos += ret;
m = get_milenage(imsi);
@@ -425,7 +653,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
u8 _rand[16], sres[4], kc[8];
for (count = 0; count < max_chal; count++) {
if (random_get_bytes(_rand, 16) < 0)
- return;
+ return -1;
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
*rpos++ = ' ';
rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
@@ -435,7 +663,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
}
*rpos = '\0';
- goto send;
+ return 0;
}
count = 0;
@@ -459,15 +687,61 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
printf("No GSM triplets found for %s\n", imsi);
ret = snprintf(rpos, rend - rpos, " FAILURE");
if (ret < 0 || ret >= rend - rpos)
- return;
+ return -1;
rpos += ret;
}
-send:
- printf("Send: %s\n", reply);
- if (sendto(s, reply, rpos - reply, 0,
- (struct sockaddr *) from, fromlen) < 0)
- perror("send");
+ return 0;
+}
+
+
+static int gsm_auth_req(char *imsi, char *resp, size_t resp_len)
+{
+ int count, ret;
+ char *pos, *rpos, *rend;
+ struct milenage_parameters *m;
+
+ resp[0] = '\0';
+
+ pos = os_strchr(imsi, ' ');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+
+ rend = resp + resp_len;
+ rpos = resp;
+ ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
+ if (ret < 0 || ret >= rend - rpos)
+ return -1;
+ rpos += ret;
+
+ m = get_milenage(imsi);
+ if (m) {
+ u8 _rand[16], sres[4], kc[8];
+ for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
+ if (hexstr2bin(pos, _rand, 16) != 0)
+ return -1;
+ gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+ *rpos++ = count == 0 ? ' ' : ':';
+ rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+ *rpos++ = ':';
+ rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+ pos += 16 * 2;
+ if (*pos != ':')
+ break;
+ pos++;
+ }
+ *rpos = '\0';
+ return 0;
+ }
+
+ printf("No GSM triplets found for %s\n", imsi);
+ ret = os_snprintf(rpos, rend - rpos, " FAILURE");
+ if (ret < 0 || ret >= rend - rpos)
+ return -1;
+ rpos += ret;
+
+ return 0;
}
@@ -493,11 +767,10 @@ static void inc_sqn(u8 *sqn)
}
-static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
- char *imsi)
+static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
{
/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
- char reply[1000], *pos, *end;
+ char *pos, *end;
u8 _rand[EAP_AKA_RAND_LEN];
u8 autn[EAP_AKA_AUTN_LEN];
u8 ik[EAP_AKA_IK_LEN];
@@ -506,16 +779,23 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
size_t res_len;
int ret;
struct milenage_parameters *m;
+ int failed = 0;
m = get_milenage(imsi);
if (m) {
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
- return;
+ return -1;
res_len = EAP_AKA_RES_MAX_LEN;
inc_sqn(m->sqn);
- printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
- m->sqn[0], m->sqn[1], m->sqn[2],
- m->sqn[3], m->sqn[4], m->sqn[5]);
+#ifdef CONFIG_SQLITE
+ db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
+ sqn_changes = 1;
+ if (stdout_debug) {
+ printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+ m->sqn[0], m->sqn[1], m->sqn[2],
+ m->sqn[3], m->sqn[4], m->sqn[5]);
+ }
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
autn, ik, ck, res, &res_len);
} else {
@@ -529,16 +809,23 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
memset(res, '2', EAP_AKA_RES_MAX_LEN);
res_len = EAP_AKA_RES_MAX_LEN;
#else /* AKA_USE_FIXED_TEST_VALUES */
- return;
+ failed = 1;
#endif /* AKA_USE_FIXED_TEST_VALUES */
}
- pos = reply;
- end = &reply[sizeof(reply)];
+ pos = resp;
+ end = resp + resp_len;
ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
if (ret < 0 || ret >= end - pos)
- return;
+ return -1;
pos += ret;
+ if (failed) {
+ ret = snprintf(pos, end - pos, "FAILURE");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ return 0;
+ }
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
@@ -549,60 +836,87 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
- printf("Send: %s\n", reply);
-
- if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
- fromlen) < 0)
- perror("send");
+ return 0;
}
-static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
- char *imsi)
+static int aka_auts(char *imsi, char *resp, size_t resp_len)
{
char *auts, *__rand;
u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
struct milenage_parameters *m;
+ resp[0] = '\0';
+
/* AKA-AUTS <IMSI> <AUTS> <RAND> */
auts = strchr(imsi, ' ');
if (auts == NULL)
- return;
+ return -1;
*auts++ = '\0';
__rand = strchr(auts, ' ');
if (__rand == NULL)
- return;
+ return -1;
*__rand++ = '\0';
- printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+ if (stdout_debug) {
+ printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
+ imsi, auts, __rand);
+ }
if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
printf("Could not parse AUTS/RAND\n");
- return;
+ return -1;
}
m = get_milenage(imsi);
if (m == NULL) {
printf("Unknown IMSI: %s\n", imsi);
- return;
+ return -1;
}
if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
printf("AKA-AUTS: Incorrect MAC-S\n");
} else {
memcpy(m->sqn, sqn, 6);
- printf("AKA-AUTS: Re-synchronized: "
- "SQN=%02x%02x%02x%02x%02x%02x\n",
- sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+ if (stdout_debug) {
+ printf("AKA-AUTS: Re-synchronized: "
+ "SQN=%02x%02x%02x%02x%02x%02x\n",
+ sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+ }
+#ifdef CONFIG_SQLITE
+ db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
+ sqn_changes = 1;
}
+
+ return 0;
+}
+
+
+static int process_cmd(char *cmd, char *resp, size_t resp_len)
+{
+ if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
+ return sim_req_auth(cmd + 13, resp, resp_len);
+
+ if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
+ return gsm_auth_req(cmd + 13, resp, resp_len);
+
+ if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
+ return aka_req_auth(cmd + 13, resp, resp_len);
+
+ if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
+ return aka_auts(cmd + 9, resp, resp_len);
+
+ printf("Unknown request: %s\n", cmd);
+ return -1;
}
static int process(int s)
{
- char buf[1000];
+ char buf[1000], resp[1000];
struct sockaddr_un from;
socklen_t fromlen;
ssize_t res;
@@ -624,14 +938,21 @@ static int process(int s)
printf("Received: %s\n", buf);
- if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
- sim_req_auth(s, &from, fromlen, buf + 13);
- else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
- aka_req_auth(s, &from, fromlen, buf + 13);
- else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
- aka_auts(s, &from, fromlen, buf + 9);
- else
- printf("Unknown request: %s\n", buf);
+ if (process_cmd(buf, resp, sizeof(resp)) < 0) {
+ printf("Failed to process request\n");
+ return -1;
+ }
+
+ if (resp[0] == '\0') {
+ printf("No response\n");
+ return 0;
+ }
+
+ printf("Send: %s\n", resp);
+
+ if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
+ fromlen) < 0)
+ perror("send");
return 0;
}
@@ -642,22 +963,34 @@ static void cleanup(void)
struct gsm_triplet *g, *gprev;
struct milenage_parameters *m, *prev;
+ if (update_milenage && milenage_file && sqn_changes)
+ update_milenage_file(milenage_file);
+
g = gsm_db;
while (g) {
gprev = g;
g = g->next;
- free(gprev);
+ os_free(gprev);
}
m = milenage_db;
while (m) {
prev = m;
m = m->next;
- free(prev);
+ os_free(prev);
}
- close(serv_sock);
- unlink(socket_path);
+ if (serv_sock >= 0)
+ close(serv_sock);
+ if (socket_path)
+ unlink(socket_path);
+
+#ifdef CONFIG_SQLITE
+ if (sqlite_db) {
+ sqlite3_close(sqlite_db);
+ sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
}
@@ -672,20 +1005,30 @@ static void usage(void)
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
- "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
+ "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>] \\\n"
- " [-i<IND len in bits>]\n"
+ " [-D<DB file>] [-i<IND len in bits>] [command]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
+ " -u = update SQN in Milenage file on exit\n"
" -s<socket path> = path for UNIX domain socket\n"
" (default: %s)\n"
" -g<triplet file> = path for GSM authentication triplets\n"
" -m<milenage file> = path for Milenage keys\n"
- " -i<IND len in bits> = IND length for SQN (default: 5)\n",
+ " -D<DB file> = path to SQLite database\n"
+ " -i<IND len in bits> = IND length for SQN (default: 5)\n"
+ "\n"
+ "If the optional command argument, like "
+ "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
+ "command is processed with response sent to stdout. Otherwise, "
+ "hlr_auc_gw opens\n"
+ "a control interface and processes commands sent through it "
+ "(e.g., by EAP server\n"
+ "in hostapd).\n",
default_socket_path);
}
@@ -693,16 +1036,28 @@ static void usage(void)
int main(int argc, char *argv[])
{
int c;
- char *milenage_file = NULL;
char *gsm_triplet_file = NULL;
+ char *sqlite_db_file = NULL;
+ int ret = 0;
+
+ if (os_program_init())
+ return -1;
socket_path = default_socket_path;
for (;;) {
- c = getopt(argc, argv, "g:hi:m:s:");
+ c = getopt(argc, argv, "D:g:hi:m:s:u");
if (c < 0)
break;
switch (c) {
+ case 'D':
+#ifdef CONFIG_SQLITE
+ sqlite_db_file = optarg;
+ break;
+#else /* CONFIG_SQLITE */
+ printf("No SQLite support included in the build\n");
+ return -1;
+#endif /* CONFIG_SQLITE */
case 'g':
gsm_triplet_file = optarg;
break;
@@ -722,30 +1077,65 @@ int main(int argc, char *argv[])
case 's':
socket_path = optarg;
break;
+ case 'u':
+ update_milenage = 1;
+ break;
default:
usage();
return -1;
}
}
+ if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
+ usage();
+ return -1;
+ }
+
+#ifdef CONFIG_SQLITE
+ if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
+ return -1;
+#endif /* CONFIG_SQLITE */
+
if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
return -1;
if (milenage_file && read_milenage(milenage_file) < 0)
return -1;
- serv_sock = open_socket(socket_path);
- if (serv_sock < 0)
- return -1;
+ if (optind == argc) {
+ serv_sock = open_socket(socket_path);
+ if (serv_sock < 0)
+ return -1;
- printf("Listening for requests on %s\n", socket_path);
+ printf("Listening for requests on %s\n", socket_path);
+
+ atexit(cleanup);
+ signal(SIGTERM, handle_term);
+ signal(SIGINT, handle_term);
+
+ for (;;)
+ process(serv_sock);
+ } else {
+ char buf[1000];
+ socket_path = NULL;
+ stdout_debug = 0;
+ if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
+ printf("FAIL\n");
+ ret = -1;
+ } else {
+ printf("%s\n", buf);
+ }
+ cleanup();
+ }
- atexit(cleanup);
- signal(SIGTERM, handle_term);
- signal(SIGINT, handle_term);
+#ifdef CONFIG_SQLITE
+ if (sqlite_db) {
+ sqlite3_close(sqlite_db);
+ sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
- for (;;)
- process(serv_sock);
+ os_program_deinit();
- return 0;
+ return ret;
}
diff --git a/hostapd/hlr_auc_gw.txt b/hostapd/hlr_auc_gw.txt
new file mode 100644
index 0000000..097bbce
--- /dev/null
+++ b/hostapd/hlr_auc_gw.txt
@@ -0,0 +1,104 @@
+HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+
+hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
+database/authentication gateway interface to HLR/AuC. It could be
+replaced with an implementation of SS7 gateway to GSM/UMTS
+authentication center (HLR/AuC). hostapd will send SIM/AKA
+authentication queries over a UNIX domain socket to and external
+program, e.g., hlr_auc_gw.
+
+hlr_auc_gw can be configured with GSM and UMTS authentication data with
+text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
+hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
+dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
+GSM triplet data is used for a more static configuration (e.g., triplets
+extracted from a SIM card).
+
+Alternatively, hlr_auc_gw can be built with support for an SQLite
+database for more dynamic operations. This is enabled by adding
+"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
+clean; make hlr_auc_gw" in this directory).
+
+hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
+hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
+is configured with command line parameters:
+
+hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
+ [-D<DB file>] [-i<IND len in bits>]
+
+options:
+ -h = show this usage help
+ -u = update SQN in Milenage file on exit
+ -s<socket path> = path for UNIX domain socket
+ (default: /tmp/hlr_auc_gw.sock)
+ -g<triplet file> = path for GSM authentication triplets
+ -m<milenage file> = path for Milenage keys
+ -D<DB file> = path to SQLite database
+ -i<IND len in bits> = IND length for SQN (default: 5)
+
+
+The SQLite database can be initialized with sqlite, e.g., by running
+following commands in "sqlite3 /path/to/hlr_auc_gw.db":
+
+CREATE TABLE milenage(
+ imsi INTEGER PRIMARY KEY NOT NULL,
+ ki CHAR(32) NOT NULL,
+ opc CHAR(32) NOT NULL,
+ amf CHAR(4) NOT NULL,
+ sqn CHAR(12) NOT NULL
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+ 232010000000000,
+ '90dca4eda45b53cf0f12d7c9c3bc6a89',
+ 'cb9cccc4b9258e6dca4760379fb82581',
+ '61df',
+ '000000000000'
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+ 555444333222111,
+ '5122250214c33e723a5dd523fc145fc0',
+ '981d464c7c52eb6e5036234984ad0bcf',
+ 'c3ab',
+ '16f3b3f70fc1'
+);
+
+
+hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
+pseudonyms and reauth information into a SQLite database. This is
+configured with the db parameter within the eap_sim_db configuration
+option.
+
+
+"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
+Milenage parameters based on IMSI from the database. The database can be
+updated dynamically while hlr_auc_gw is running to add/remove/modify
+entries.
+
+
+Example configuration files for hostapd to operate as a RADIUS
+authentication server for EAP-SIM/AKA/AKA':
+
+hostapd.conf:
+
+driver=none
+radius_server_clients=hostapd.radius_clients
+eap_server=1
+eap_user_file=hostapd.eap_user
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
+eap_sim_aka_result_ind=1
+
+hostapd.radius_clients:
+
+0.0.0.0/0 radius
+
+hostapd.eap_user:
+
+"0"* AKA
+"1"* SIM
+"2"* AKA
+"3"* SIM
+"4"* AKA
+"5"* SIM
+"6"* AKA'
+"7"* AKA'
+"8"* AKA'
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index a2e50bf..da7817f 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -51,9 +51,6 @@ logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
-# Dump file for state information (on SIGUSR1)
-dump_file=/tmp/hostapd.dump
-
# Interface for separate control program. If this is specified, hostapd
# will create this directory and a UNIX domain socket for listening to requests
# from external programs (CLI/GUI, etc.) for status information and
@@ -84,6 +81,14 @@ ctrl_interface_group=0
# SSID to be used in IEEE 802.11 management frames
ssid=test
+# Alternative formats for configuring SSID
+# (double quoted string, hexdump, printf-escaped string)
+#ssid2="test"
+#ssid2=74657374
+#ssid2=P"hello\nthere"
+
+# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
+#utf8_ssid=1
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
# Set as needed to indicate country in which device is operating.
@@ -97,7 +102,15 @@ ssid=test
# (default: 0 = disabled)
#ieee80211d=1
+# Enable IEEE 802.11h. This enables radar detection and DFS support if
+# available. DFS support is required on outdoor 5 GHz channels in most countries
+# of the world. This can be used only with ieee80211d=1.
+# (default: 0 = disabled)
+#ieee80211h=1
+
# 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)
# Default: IEEE 802.11b
hw_mode=g
@@ -105,8 +118,28 @@ hw_mode=g
# (default: 0, i.e., not set)
# Please note that some drivers do not use this value from hostapd and the
# channel will need to be configured separately with iwconfig.
+#
+# If CONFIG_ACS build option is enabled, the channel can be selected
+# automatically at run time by setting channel=acs_survey or channel=0, both of
+# which will enable the ACS survey based algorithm.
channel=1
+# ACS tuning - Automatic Channel Selection
+# See: http://wireless.kernel.org/en/users/Documentation/acs
+#
+# You can customize the ACS survey algorithm with following variables:
+#
+# acs_num_scans requirement is 1..100 - number of scans to be performed that
+# are used to trigger survey data gathering of an underlying device driver.
+# Scans are passive and typically take a little over 100ms (depending on the
+# driver) on each available channel for given hw_mode. Increasing this value
+# means sacrificing startup time and gathering more data wrt channel
+# interference that may help choosing a better channel. This can also help fine
+# tune the ACS scan time in case a driver has different scan dwell times.
+#
+# Defaults:
+#acs_num_scans=5
+
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -196,6 +229,13 @@ auth_algs=3
# requests for broadcast SSID
ignore_broadcast_ssid=0
+# Additional vendor specfic 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
+
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
# queues: data0, data1, data2, data3, after_beacon, beacon
@@ -339,6 +379,12 @@ wmm_ac_vo_acm=0
# the STA with a data frame.
# default: 300 (i.e., 5 minutes)
#ap_max_inactivity=300
+#
+# The inactivity polling can be disabled to disconnect stations based on
+# inactivity timeout so that idle stations are more likely to be disconnected
+# even if they are still in range of the AP. This can be done by setting
+# skip_inactivity_poll to 1 (default 0).
+#skip_inactivity_poll=0
# Disassociate stations based on excessive transmission failures or other
# indications of connection loss. This depends on the driver capabilities and
@@ -360,10 +406,19 @@ wmm_ac_vo_acm=0
# use a separate bridge.
#wds_bridge=wds-br0
+# Start the AP with beaconing disabled by default.
+#start_disabled=0
+
# Client isolation can be used to prevent low-level bridging of frames between
# associated stations in the BSS. By default, this bridging is allowed.
#ap_isolate=1
+# Fixed BSS Load value for testing purposes
+# This field can be used to configure hostapd to add a fixed BSS Load element
+# into Beacon and Probe Response frames for testing purposes. The format is
+# <station count>:<channel utilization>:<available admission capacity>
+#bss_load_test=12:80:20000
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -410,6 +465,164 @@ wmm_ac_vo_acm=0
# Require stations to support HT PHY (reject association if they do not)
#require_ht=1
+# If set non-zero, require stations to perform scans of overlapping
+# channels to test for stations which would be affected by 40 MHz traffic.
+# This parameter sets the interval in seconds between these scans. This
+# is useful only for testing that stations properly set the OBSS interval,
+# since the other parameters in the OBSS scan parameters IE are set to 0.
+#obss_interval=0
+
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+#ieee80211ac=1
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+# Beamformee's capability indicating the maximum number of beamformer
+# antennas the beamformee can support when sending compressed beamforming
+# feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# Beamformer's capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# MU Beamformee Capable: [MU-BEAMFORMEE]
+# Indicates support for operation as an MU beamformee
+# 0 = Not supported or sent by AP (default)
+# 1 = Supported
+#
+# 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
+# mode
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+# mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+# 0 = (no feedback) if the STA does not provide VHT MFB (default)
+# 1 = reserved
+# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+# STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
+#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -466,6 +679,8 @@ eapol_key_index_workaround=0
eap_server=0
# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
#eap_user_file=/etc/hostapd.eap_user
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
@@ -484,6 +699,11 @@ eap_server=0
# Passphrase for private key
#private_key_passwd=secret passphrase
+# Server identity
+# EAP methods that provide mechanism for authenticated server identity delivery
+# use this value. If not set, "hostapd" is used as a default.
+#server_id=server.example.com
+
# Enable CRL verification.
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
# valid CRL signed by the CA is required to be included in the ca_cert file.
@@ -495,6 +715,20 @@ eap_server=0
# 2 = check all CRLs in the certificate path
#check_crl=1
+# Cached OCSP stapling response (DER encoded)
+# If set, this file is sent as a certificate status response by the EAP server
+# if the EAP peer requests certificate status in the ClientHello message.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+# -no_nonce \
+# -CAfile /etc/hostapd.ca.pem \
+# -issuer /etc/hostapd.ca.pem \
+# -cert /etc/hostapd.server.pem \
+# -url http://ocsp.example.com:8888/ \
+# -respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-cache.der
+
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -510,12 +744,18 @@ eap_server=0
# Fragment size for EAP methods
#fragment_size=1400
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
# Configuration data for EAP-SIM database/authentication gateway interface.
# This is a text string in implementation specific format. The example
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
-# prefix.
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
# 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
@@ -622,13 +862,18 @@ own_ip_addr=127.0.0.1
# 60 (1 minute).
#radius_acct_interim_interval=600
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
-# VLANID as a string). vlan_file option below must be configured if dynamic
-# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
-# used to set static client MAC address to VLAN ID mapping.
+# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
+# be used to set static client MAC address to VLAN ID mapping.
# 0 = disabled (default)
# 1 = option; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
@@ -640,6 +885,8 @@ own_ip_addr=127.0.0.1
# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
# interface and the line must include VLAN ID and interface name separated by
# white space (space or tab).
+# If no entries are provided by this file, the station is statically mapped
+# to <bss-iface>.<vlan-id> interfaces.
#vlan_file=/etc/hostapd.vlan
# Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -649,6 +896,67 @@ own_ip_addr=127.0.0.1
# to the bridge.
#vlan_tagged_interface=eth0
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
##### RADIUS authentication server configuration ##############################
@@ -672,6 +980,7 @@ own_ip_addr=127.0.0.1
# Enable WPA. Setting this variable configures the AP to require WPA (either
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
# RADIUS authentication server must be configured, and WPA-EAP must be included
# in wpa_key_mgmt.
@@ -696,6 +1005,15 @@ own_ip_addr=127.0.0.1
# configuration reloads.
#wpa_psk_file=/etc/hostapd.wpa_psk
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+# Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+# Tunnel-Password
+#wpa_psk_radius=0
+
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
@@ -784,6 +1102,19 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#okc=1
+# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
+# This parameter defines how many open SAE instances can be in progress at the
+# same time before the anti-clogging mechanism is taken into use.
+#sae_anti_clogging_threshold=5
+
+# Enabled SAE finite cyclic groups
+# SAE implementation are required to support group 19 (ECC group defined over a
+# 256-bit prime order field). All groups that are supported by the
+# implementation are enabled by default. This configuration parameter can be
+# used to specify a limited set of allowed groups. The group values are listed
+# in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=19 20 21 25 26
##### IEEE 802.11r configuration ##############################################
@@ -858,6 +1189,14 @@ own_ip_addr=127.0.0.1
# 2 = WPS enabled, configured
#wps_state=2
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
# AP can be configured into a locked state where new WPS Registrar are not
# accepted, but previously authorized Registrars (including the internal one)
# can continue to add new Enrollees.
@@ -1007,6 +1346,24 @@ own_ip_addr=127.0.0.1
# 12-digit, all-numeric code that identifies the consumer package.
#upc=123456789012
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
@@ -1034,6 +1391,16 @@ own_ip_addr=127.0.0.1
# stdoffset[dst[offset][,start[/time],end[/time]]]
#time_zone=EST5
+# WNM-Sleep Mode (extended sleep mode for stations)
+# 0 = disabled (default)
+# 1 = enabled (allow stations to use WNM-Sleep Mode)
+#wnm_sleep_mode=1
+
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
@@ -1087,11 +1454,180 @@ own_ip_addr=127.0.0.1
# Arbitrary number of Roaming Consortium OIs can be configured with each line
# adding a new OI to the list. The first three entries are available through
# Beacon and Probe Response frames. Any additional entry will be available only
-# through ANQP queries. Each OI is between 3 and 15 octets and is configured a
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
# a hexstring.
#roaming_consortium=021122
#roaming_consortium=2233445566
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+# Alternative format for language:value strings:
+# (double quoted string, printf-escaped string)
+#venue_name=P"eng:Example\nvenue"
+
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+# 0 = Realm formatted in accordance with IETF RFC 4282
+# 1 = UTF-8 formatted character string that is not formatted in
+# accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+# 10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+# (encoded as two hex digits)
+# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+# 1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+# 1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
+##### TESTING OPTIONS #########################################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
+# testing some scenarios that are otherwise difficult to reproduce.
+#
+# Ignore probe requests sent to hostapd with the given probability, must be a
+# floating point number in the range [0, 1).
+#ignore_probe_probability=0.0
+#
+# Ignore authentication frames with the given probability
+#ignore_auth_probability=0.0
+#
+# Ignore association requests with the given probability
+#ignore_assoc_probability=0.0
+#
+# Ignore reassociation requests with the given probability
+#ignore_reassoc_probability=0.0
+#
+# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
+#corrupt_gtk_rekey_mic_probability=0.0
+
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
new file mode 100644
index 0000000..f688327
--- /dev/null
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -0,0 +1,17 @@
+CREATE TABLE users(
+ identity TEXT PRIMARY KEY,
+ methods TEXT,
+ password TEXT,
+ phase2 INTEGER
+);
+
+CREATE TABLE wildcards(
+ identity TEXT PRIMARY KEY,
+ methods TEXT
+);
+
+INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
+INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
+
+INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
+INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 1d77c0a..eee8504 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,15 +1,9 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -24,32 +18,15 @@
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n";
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
static const char *hostapd_cli_full_license =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
-"GNU General Public License for more details.\n"
-"\n"
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license.\n"
+"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"
@@ -94,11 +71,15 @@ static const char *commands_help =
" 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"
-#ifdef CONFIG_WPS_OOB
-" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
-#endif /* CONFIG_WPS_OOB */
+" 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"
@@ -110,7 +91,12 @@ static const char *commands_help =
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
static int hostapd_cli_attached = 0;
-static const char *ctrl_iface_dir = "/var/run/hostapd";
+
+#ifndef CONFIG_CTRL_IFACE_DIR
+#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
+#endif /* CONFIG_CTRL_IFACE_DIR */
+static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
@@ -230,8 +216,21 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
+ return wpa_ctrl_command(ctrl, "STATUS");
+}
+
+
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
+ if (argc > 0) {
+ char buf[100];
+ os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+ }
return wpa_ctrl_command(ctrl, "MIB");
}
@@ -284,12 +283,15 @@ static void hostapd_cli_action_process(char *msg, size_t len)
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char buf[64];
- if (argc != 1) {
- printf("Invalid 'sta' command - exactly one argument, STA "
+ if (argc < 1) {
+ printf("Invalid 'sta' command - at least one argument, STA "
"address, is required.\n");
return -1;
}
- snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+ if (argc > 1)
+ snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]);
+ else
+ snprintf(buf, sizeof(buf), "STA %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
@@ -415,38 +417,105 @@ static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
}
-#ifdef CONFIG_WPS_OOB
-static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
- char cmd[256];
+ return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_tag_read' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 18 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
int res;
- if (argc != 3 && argc != 4) {
- printf("Invalid WPS_OOB command: need three or four "
- "arguments:\n"
- "- DEV_TYPE: use 'ufd' or 'nfc'\n"
- "- PATH: path of OOB device like '/mnt'\n"
- "- METHOD: OOB method 'pin-e' or 'pin-r', "
- "'cred'\n"
- "- DEV_NAME: (only for NFC) device name like "
- "'pn531'\n");
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_config_token' command - one argument "
+ "is required.\n");
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
+ argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_token' command - one argument is "
+ "required.\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_NFC_TOKEN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid 'nfc_get_handover_sel' command - two arguments "
+ "are required.\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
+ argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_OOB command.\n");
+ printf("Too long NFC_GET_HANDOVER_SEL command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
-#endif /* CONFIG_WPS_OOB */
+
+#endif /* CONFIG_WPS_NFC */
static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
@@ -470,6 +539,13 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
+}
+
+
static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -515,19 +591,19 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_WPS */
-static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
{
char buf[300];
int res;
if (argc < 2) {
- printf("Invalid 'ess_disassoc' command - two arguments (STA "
- "addr and URL) are needed\n");
+ printf("Invalid 'disassoc_imminent' command - two arguments "
+ "(STA addr and Disassociation Timer) are needed\n");
return -1;
}
- res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+ res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
argv[0], argv[1]);
if (res < 0 || res >= (int) sizeof(buf))
return -1;
@@ -535,6 +611,26 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[300];
+ int res;
+
+ if (argc < 3) {
+ printf("Invalid 'ess_disassoc' command - three arguments (STA "
+ "addr, disassoc timer, and URL) are needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
+ argv[0], argv[1], argv[2]);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -608,6 +704,45 @@ static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_set_qos_map_set(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char buf[200];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'set_qos_map_set' command - "
+ "one argument (comma delimited QoS map set) "
+ "is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_send_qos_map_conf(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char buf[50];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'send_qos_map_conf' command - "
+ "one argument (STA addr) is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
hostapd_cli_quit = 1;
@@ -721,6 +856,45 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+ int i;
+ char *tmp;
+ int total;
+
+ if (argc < 2) {
+ printf("Invalid chan_switch command: needs at least two "
+ "arguments (count and freq)\n"
+ "usage: <cs_count> <freq> [sec_channel_offset=] "
+ "[center_freq1=] [center_freq2=] [bandwidth=] "
+ "[blocktx] [ht|vht]\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long CHAN_SWITCH command.\n");
+ return -1;
+ }
+
+ total = res;
+ for (i = 2; i < argc; i++) {
+ tmp = cmd + total;
+ res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+ printf("Too long CHAN_SWITCH command.\n");
+ return -1;
+ }
+ total += res;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -730,6 +904,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "relog", hostapd_cli_cmd_relog },
+ { "status", hostapd_cli_cmd_status },
{ "sta", hostapd_cli_cmd_sta },
{ "all_sta", hostapd_cli_cmd_all_sta },
{ "new_sta", hostapd_cli_cmd_new_sta },
@@ -742,12 +917,18 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "wps_pin", hostapd_cli_cmd_wps_pin },
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
-#ifdef CONFIG_WPS_OOB
- { "wps_oob", hostapd_cli_cmd_wps_oob },
-#endif /* CONFIG_WPS_OOB */
+ { "wps_cancel", hostapd_cli_cmd_wps_cancel },
+#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 },
+#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
+ { "wps_get_status", hostapd_cli_cmd_wps_get_status },
#endif /* CONFIG_WPS */
+ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
{ "get_config", hostapd_cli_cmd_get_config },
{ "help", hostapd_cli_cmd_help },
@@ -757,6 +938,9 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "quit", hostapd_cli_cmd_quit },
{ "set", hostapd_cli_cmd_set },
{ "get", hostapd_cli_cmd_get },
+ { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
+ { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
+ { "chan_switch", hostapd_cli_cmd_chan_switch },
{ NULL, NULL }
};
@@ -911,7 +1095,7 @@ static void hostapd_cli_interactive(void)
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, NULL, NULL, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
diff --git a/hostapd/main.c b/hostapd/main.c
index bf22559..5a1b0a9 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -2,19 +2,14 @@
* hostapd / main()
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <syslog.h>
+#include <grp.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include "utils/common.h"
@@ -27,19 +22,12 @@
#include "eap_server/tncs.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
#include "config_file.h"
#include "eap_register.h"
-#include "dump_state.h"
#include "ctrl_iface.h"
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
struct hapd_global {
void **drv_priv;
size_t drv_count;
@@ -48,29 +36,6 @@ struct hapd_global {
static struct hapd_global global;
-struct hapd_interfaces {
- size_t count;
- struct hostapd_iface **iface;
-};
-
-
-static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
- int (*cb)(struct hostapd_iface *iface,
- void *ctx), void *ctx)
-{
- size_t i;
- int ret;
-
- for (i = 0; i < interfaces->count; i++) {
- ret = cb(interfaces->iface[i], ctx);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-
#ifndef CONFIG_NO_HOSTAPD_LOGGER
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
int level, const char *txt, size_t len)
@@ -141,7 +106,7 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
if ((conf_stdout & module) && level >= conf_stdout_level) {
wpa_debug_print_timestamp();
- printf("%s\n", format);
+ wpa_printf(MSG_INFO, "%s", format);
}
#ifndef CONFIG_NATIVE_WINDOWS
@@ -175,68 +140,8 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
/**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
+ * hostapd_driver_init - Preparate driver interface
*/
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
- struct hostapd_iface *hapd_iface = NULL;
- struct hostapd_config *conf = NULL;
- struct hostapd_data *hapd;
- size_t i;
-
- hapd_iface = os_zalloc(sizeof(*hapd_iface));
- if (hapd_iface == NULL)
- goto fail;
-
- hapd_iface->reload_config = hostapd_reload_config;
- hapd_iface->config_read_cb = hostapd_config_read;
- hapd_iface->config_fname = os_strdup(config_file);
- if (hapd_iface->config_fname == NULL)
- goto fail;
- hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
- hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
- hapd_iface->for_each_interface = hostapd_for_each_interface;
-
- conf = hostapd_config_read(hapd_iface->config_fname);
- if (conf == NULL)
- goto fail;
- hapd_iface->conf = conf;
-
- hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_zalloc(conf->num_bss *
- sizeof(struct hostapd_data *));
- if (hapd_iface->bss == NULL)
- goto fail;
-
- for (i = 0; i < conf->num_bss; i++) {
- hapd = hapd_iface->bss[i] =
- hostapd_alloc_bss_data(hapd_iface, conf,
- &conf->bss[i]);
- if (hapd == NULL)
- goto fail;
- hapd->msg_ctx = hapd;
- }
-
- return hapd_iface;
-
-fail:
- if (conf)
- hostapd_config_free(conf);
- if (hapd_iface) {
- os_free(hapd_iface->config_fname);
- os_free(hapd_iface->bss);
- os_free(hapd_iface);
- }
- return NULL;
-}
-
-
static int hostapd_driver_init(struct hostapd_iface *iface)
{
struct wpa_init_params params;
@@ -276,13 +181,13 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
}
params.bssid = b;
params.ifname = hapd->conf->iface;
- params.ssid = (const u8 *) hapd->conf->ssid.ssid;
+ params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.test_socket = hapd->conf->test_socket;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
- params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
+ params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
if (params.bridge == NULL)
return -1;
for (i = 0; i < hapd->iface->num_bss; i++) {
@@ -303,28 +208,26 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
}
if (hapd->driver->get_capa &&
- hapd->driver->get_capa(hapd->drv_priv, &capa) == 0)
+ hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
iface->drv_flags = capa.flags;
+ iface->probe_resp_offloads = capa.probe_resp_offloads;
+ iface->extended_capa = capa.extended_capa;
+ iface->extended_capa_mask = capa.extended_capa_mask;
+ iface->extended_capa_len = capa.extended_capa_len;
+ iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
+ }
return 0;
}
-static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
-{
- const struct wpa_driver_ops *driver;
- void *drv_priv;
- if (iface == NULL)
- return;
- driver = iface->bss[0]->driver;
- drv_priv = iface->bss[0]->drv_priv;
- hostapd_interface_deinit(iface);
- if (driver && driver->hapd_deinit)
- driver->hapd_deinit(drv_priv);
- hostapd_interface_free(iface);
-}
-
-
+/**
+ * hostapd_interface_init - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a full interface (one
+ * or more BSSes sharing the same radio) and allocate memory for the BSS
+ * interfaces. No actiual driver operations are started.
+ */
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
@@ -333,7 +236,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
int k;
wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
- iface = hostapd_init(config_fname);
+ iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
iface->interfaces = interfaces;
@@ -343,8 +246,10 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
iface->bss[0]->conf->logger_stdout_level--;
}
- if (hostapd_driver_init(iface) ||
- hostapd_setup_interface(iface)) {
+ if (iface->conf->bss[0]->iface[0] == '\0' &&
+ !hostapd_drv_none(iface->bss[0])) {
+ wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ config_fname);
hostapd_interface_deinit_free(iface);
return NULL;
}
@@ -389,10 +294,7 @@ static void handle_reload(int sig, void *signal_ctx)
static void handle_dump_state(int sig, void *signal_ctx)
{
-#ifdef HOSTAPD_DUMP_STATE
- struct hapd_interfaces *interfaces = signal_ctx;
- hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
-#endif /* HOSTAPD_DUMP_STATE */
+ /* Not used anymore - ignore signal */
}
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -434,7 +336,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
wpa_printf(MSG_ERROR, "No drivers enabled");
return -1;
}
- global.drv_priv = os_zalloc(global.drv_count * sizeof(void *));
+ global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
if (global.drv_priv == NULL)
return -1;
@@ -511,7 +413,7 @@ static void show_version(void)
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
- "Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -522,18 +424,26 @@ static void usage(void)
fprintf(stderr,
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
- "<configuration file(s)>\n"
+ "\\\n"
+ " [-g <global ctrl_iface>] [-G <group>] \\\n"
+ " <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
" -d show more debug messages (-dd for even more)\n"
" -B run daemon in the background\n"
" -e entropy file\n"
+ " -g global control interface path\n"
+ " -G group for control interfaces\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ " -T = record to Linux tracing in addition to logging\n"
+ " (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@@ -544,27 +454,84 @@ static void usage(void)
static const char * hostapd_msg_ifname_cb(void *ctx)
{
struct hostapd_data *hapd = ctx;
- if (hapd && hapd->iconf && hapd->iconf->bss)
- return hapd->iconf->bss->iface;
+ if (hapd && hapd->iconf && hapd->iconf->bss &&
+ hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
+ return hapd->iconf->bss[0]->iface;
return NULL;
}
+static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
+ const char *path)
+{
+ char *pos;
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = os_strdup(path);
+ if (interfaces->global_iface_path == NULL)
+ return -1;
+ pos = os_strrchr(interfaces->global_iface_path, '/');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "No '/' in the global control interface "
+ "file");
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+ return -1;
+ }
+
+ *pos = '\0';
+ interfaces->global_iface_name = pos + 1;
+
+ return 0;
+}
+
+
+static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
+ const char *group)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+ struct group *grp;
+ grp = getgrnam(group);
+ if (grp == NULL) {
+ wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
+ return -1;
+ }
+ interfaces->ctrl_iface_group = grp->gr_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return 0;
+}
+
+
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
int ret = 1;
- size_t i;
+ size_t i, j;
int c, debug = 0, daemonize = 0;
char *pid_file = NULL;
const char *log_file = NULL;
const char *entropy_file = NULL;
+ char **bss_config = NULL, **tmp_bss;
+ size_t num_bss_configs = 0;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ int enable_trace_dbg = 0;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
if (os_program_init())
return -1;
+ os_memset(&interfaces, 0, sizeof(interfaces));
+ interfaces.reload_config = hostapd_reload_config;
+ interfaces.config_read_cb = hostapd_config_read;
+ interfaces.for_each_interface = hostapd_for_each_interface;
+ interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
+ interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+ interfaces.driver_init = hostapd_driver_init;
+ interfaces.global_iface_path = NULL;
+ interfaces.global_iface_name = NULL;
+ interfaces.global_ctrl_sock = -1;
+
for (;;) {
- c = getopt(argc, argv, "Bde:f:hKP:tv");
+ c = getopt(argc, argv, "b:Bde:f:hKP:Ttvg:G:");
if (c < 0)
break;
switch (c) {
@@ -595,51 +562,144 @@ int main(int argc, char *argv[])
case 't':
wpa_debug_timestamp++;
break;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ case 'T':
+ enable_trace_dbg = 1;
+ break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 'v':
show_version();
exit(1);
break;
-
+ case 'g':
+ if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
+ return -1;
+ break;
+ case 'G':
+ if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
+ return -1;
+ break;
+ case 'b':
+ tmp_bss = os_realloc_array(bss_config,
+ num_bss_configs + 1,
+ sizeof(char *));
+ if (tmp_bss == NULL)
+ goto out;
+ bss_config = tmp_bss;
+ bss_config[num_bss_configs++] = optarg;
+ break;
default:
usage();
break;
}
}
- if (optind == argc)
+ if (optind == argc && interfaces.global_iface_path == NULL &&
+ num_bss_configs == 0)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
if (log_file)
wpa_debug_open_file(log_file);
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ if (enable_trace_dbg) {
+ int tret = wpa_debug_open_linux_tracing();
+ if (tret) {
+ wpa_printf(MSG_ERROR, "Failed to enable trace logging");
+ return -1;
+ }
+ }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
interfaces.count = argc - optind;
- interfaces.iface = os_zalloc(interfaces.count *
- sizeof(struct hostapd_iface *));
- if (interfaces.iface == NULL) {
- wpa_printf(MSG_ERROR, "malloc failed");
- return -1;
+ if (interfaces.count || num_bss_configs) {
+ interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
+ sizeof(struct hostapd_iface *));
+ if (interfaces.iface == NULL) {
+ wpa_printf(MSG_ERROR, "malloc failed");
+ return -1;
+ }
}
- if (hostapd_global_init(&interfaces, entropy_file))
+ if (hostapd_global_init(&interfaces, entropy_file)) {
+ wpa_printf(MSG_ERROR, "Failed to initilize global context");
return -1;
+ }
- /* Initialize interfaces */
+ /* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
interfaces.iface[i] = hostapd_interface_init(&interfaces,
argv[optind + i],
debug);
- if (!interfaces.iface[i])
+ if (!interfaces.iface[i]) {
+ wpa_printf(MSG_ERROR, "Failed to initialize interface");
+ goto out;
+ }
+ }
+
+ /* Allocate and parse configuration for per-BSS files */
+ for (i = 0; i < num_bss_configs; i++) {
+ struct hostapd_iface *iface;
+ char *fname;
+
+ wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
+ fname = os_strchr(bss_config[i], ':');
+ if (fname == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Invalid BSS config identifier '%s'",
+ bss_config[i]);
+ goto out;
+ }
+ *fname++ = '\0';
+ iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
+ fname, debug);
+ if (iface == NULL)
goto out;
+ for (j = 0; j < interfaces.count; j++) {
+ if (interfaces.iface[j] == iface)
+ break;
+ }
+ if (j == interfaces.count) {
+ struct hostapd_iface **tmp;
+ tmp = os_realloc_array(interfaces.iface,
+ interfaces.count + 1,
+ sizeof(struct hostapd_iface *));
+ if (tmp == NULL) {
+ hostapd_interface_deinit_free(iface);
+ goto out;
+ }
+ interfaces.iface = tmp;
+ interfaces.iface[interfaces.count++] = iface;
+ }
}
- if (hostapd_global_run(&interfaces, daemonize, pid_file))
+ /*
+ * Enable configured interfaces. Depending on channel configuration,
+ * this may complete full initialization before returning or use a
+ * callback mechanism to complete setup in case of operations like HT
+ * co-ex scans, ACS, or DFS are needed to determine channel parameters.
+ * In such case, the interface will be enabled from eloop context within
+ * hostapd_global_run().
+ */
+ interfaces.terminate_on_error = interfaces.count;
+ for (i = 0; i < interfaces.count; i++) {
+ if (hostapd_driver_init(interfaces.iface[i]) ||
+ hostapd_setup_interface(interfaces.iface[i]))
+ goto out;
+ }
+
+ hostapd_global_ctrl_iface_init(&interfaces);
+
+ if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+ wpa_printf(MSG_ERROR, "Failed to start eloop");
goto out;
+ }
ret = 0;
out:
+ hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++)
hostapd_interface_deinit_free(interfaces.iface[i]);
@@ -650,6 +710,9 @@ int main(int argc, char *argv[])
if (log_file)
wpa_debug_close_file();
+ wpa_debug_close_linux_tracing();
+
+ os_free(bss_config);
os_program_deinit();
diff --git a/hostapd/nt_password_hash.c b/hostapd/nt_password_hash.c
index 839802a..7064b9c 100644
--- a/hostapd/nt_password_hash.c
+++ b/hostapd/nt_password_hash.c
@@ -2,14 +2,8 @@
* hostapd - Plaintext password to NtPasswordHash
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
new file mode 100644
index 0000000..58e538a
--- /dev/null
+++ b/hostapd/wps-ap-nfc.py
@@ -0,0 +1,282 @@
+#!/usr/bin/python
+#
+# Example nfcpy to hostapd wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import argparse
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+
+import wpaspy
+
+wpas_ctrl = '/var/run/hostapd'
+continue_loop = True
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find hostapd: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No hostapd control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return
+ if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
+ return False
+ return True
+
+
+def wpas_get_config_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.ho_server_processing = False
+ self.success = False
+
+ def process_request(self, request):
+ print "HandoverServer - request received"
+ try:
+ print "Parsed handover request: " + request.pretty()
+ except Exception, e:
+ print e
+ print str(request).encode("hex")
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - add WPS carrier record"
+ data = wpas_get_handover_sel()
+ if data is None:
+ print "Could not get handover select carrier record from hostapd"
+ continue
+ print "Handover select carrier record from hostapd:"
+ print data.encode("hex")
+ wpas_report_handover(carrier.record, data)
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ try:
+ print sel.pretty()
+ except Exception, e:
+ print e
+ print str(sel).encode("hex")
+
+ print "Sending handover select"
+ self.success = True
+ return sel
+
+
+def wps_tag_read(tag):
+ success = False
+ if len(tag.ndef.message):
+ for record in tag.ndef.message:
+ print "record type " + record.type
+ if record.type == "application/vnd.wfa.wsc":
+ print "WPS tag - send to hostapd"
+ success = wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ print "Empty tag"
+
+ return success
+
+
+def rdwr_connected_write(tag):
+ print "Tag found - writing"
+ global write_data
+ tag.ndef.message = str(write_data)
+ print "Done - remove tag"
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global write_wait_remove
+ while write_wait_remove and tag.is_present:
+ time.sleep(0.1)
+
+def wps_write_config_tag(clf, wait_remove=True):
+ print "Write WPS config token"
+ global write_data, write_wait_remove
+ write_wait_remove = wait_remove
+ write_data = wpas_get_config_token()
+ if write_data == None:
+ print "Could not get WPS config token from hostapd"
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def wps_write_password_tag(clf, wait_remove=True):
+ print "Write WPS password token"
+ global write_data, write_wait_remove
+ write_wait_remove = wait_remove
+ write_data = wpas_get_password_token()
+ if write_data == None:
+ print "Could not get WPS password token from hostapd"
+ return
+
+ print "Touch an NFC tag"
+ clf.connect(rdwr={'on-connect': rdwr_connected_write})
+
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ print "Tag connected: " + str(tag)
+
+ if tag.ndef:
+ print "NDEF tag: " + tag.type
+ try:
+ print tag.ndef.message.pretty()
+ except Exception, e:
+ print e
+ success = wps_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ print "Not an NDEF tag - remove tag"
+
+ return not no_wait
+
+
+def llcp_startup(clf, llc):
+ print "Start LLCP server"
+ global srv
+ srv = HandoverServer(llc)
+ return llc
+
+def llcp_connected(llc):
+ print "P2P LLCP connected"
+ global wait_connection
+ wait_connection = False
+ global srv
+ srv.start()
+ return True
+
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('command', choices=['write-config',
+ 'write-password'],
+ nargs='?')
+ args = parser.parse_args()
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ logging.basicConfig(level=args.loglevel)
+
+ try:
+ if not clf.open("usb"):
+ print "Could not open connection with an NFC device"
+ raise SystemExit
+
+ if args.command == "write-config":
+ wps_write_config_tag(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ if args.command == "write-password":
+ wps_write_password_tag(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ print "Waiting for a tag or peer to be touched"
+ wait_connection = True
+ try:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected}):
+ break
+ except Exception, e:
+ print "clf.connect failed"
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()