diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2010-06-14 15:37:48 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2010-06-14 15:37:48 +0000 |
commit | ce9c8f380b1fae326c166456a15ae504dce5c1d1 (patch) | |
tree | 14bf596282a14863f779d075d7a8f7e60c25f0a8 /contrib/wpa/hostapd | |
parent | da0290f8d3606ed387adb04fec5d24de81a39032 (diff) | |
parent | 60c44471bf25f9e84d8701afe1bbcbcc88e18c89 (diff) | |
download | FreeBSD-src-ce9c8f380b1fae326c166456a15ae504dce5c1d1.zip FreeBSD-src-ce9c8f380b1fae326c166456a15ae504dce5c1d1.tar.gz |
MFV hostapd & wpa_supplicant 0.6.10.
Diffstat (limited to 'contrib/wpa/hostapd')
35 files changed, 4400 insertions, 378 deletions
diff --git a/contrib/wpa/hostapd/.gitignore b/contrib/wpa/hostapd/.gitignore deleted file mode 100644 index 6dd2c2f..0000000 --- a/contrib/wpa/hostapd/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.d -.config -driver_conf.c -hostapd -hostapd_cli -hlr_auc_gw -nt_password_hash diff --git a/contrib/wpa/hostapd/ChangeLog b/contrib/wpa/hostapd/ChangeLog index 46f0852..18af4b1 100644 --- a/contrib/wpa/hostapd/ChangeLog +++ b/contrib/wpa/hostapd/ChangeLog @@ -1,5 +1,37 @@ ChangeLog for hostapd +2010-01-12 - v0.6.10 + * fixed SHA-256 based key derivation function to match with the + standard when using CCMP (for IEEE 802.11r and IEEE 802.11w) + (note: this breaks interoperability with previous version) [Bug 307] + * fixed WPS selected registrar expiration for internal PIN registrar + * disable PMTU discovery for RADIUS packets + * fixed WPS UPnP SSDP on 32-bit targets + * fixed WPS AP reconfiguration with drivers that do not use hostapd + MLME + * fixed RSN parameter setting for multi-BSS case + * added WPS workarounds for known interoperability issues with broken, + deployed implementation + * update IEEE 802.11w implementation to match with the published + standard + * fixed OpCode when proxying WSC_ACK or WSC_NACK from WPS ER + * fixed proxying of WSC_NACK to WPS ER + * fixed compilation with newer GnuTLS versions + * added support for defining timeout for WPS PINs + * fixed WPS Probe Request processing to handle missing required + attribute + * fixed PKCS#12 use with OpenSSL 1.0.0 + +2009-03-23 - v0.6.9 + * driver_nl80211: fixed STA accounting data collection (TX/RX bytes + reported correctly; TX/RX packets not yet available from kernel) + * fixed EAPOL/EAP reauthentication when using an external RADIUS + authentication server + * driver_prism54: fixed segmentation fault on initialization + * fixed TNC with EAP-TTLS + * fixed IEEE 802.11r key derivation function to match with the standard + (note: this breaks interoperability with previous version) [Bug 303] + 2009-02-15 - v0.6.8 * increased hostapd_cli ping interval to 5 seconds and made this configurable with a new command line options (-G<seconds>) diff --git a/contrib/wpa/hostapd/Makefile b/contrib/wpa/hostapd/Makefile new file mode 100644 index 0000000..3b3d7fe --- /dev/null +++ b/contrib/wpa/hostapd/Makefile @@ -0,0 +1,635 @@ +ifndef CC +CC=gcc +endif + +ifndef CFLAGS +CFLAGS = -MMD -O2 -Wall -g +endif + +# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to +# a file (undefine it, if you want to save in binary size) +CFLAGS += -DHOSTAPD_DUMP_STATE + +CFLAGS += -I../src +CFLAGS += -I../src/crypto +CFLAGS += -I../src/utils +CFLAGS += -I../src/common + +# Uncomment following line and set the path to your kernel tree include +# directory if your C library does not include all header files. +# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include + +-include .config + +ifndef CONFIG_OS +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_OS=win32 +else +CONFIG_OS=unix +endif +endif + +ifeq ($(CONFIG_OS), internal) +CFLAGS += -DOS_NO_C_LIB_DEFINES +endif + +ifdef CONFIG_NATIVE_WINDOWS +CFLAGS += -DCONFIG_NATIVE_WINDOWS +LIBS += -lws2_32 +endif + +OBJS = hostapd.o ieee802_1x.o eapol_sm.o \ + ieee802_11.o config.o ieee802_11_auth.o accounting.o \ + sta_info.o wpa.o ctrl_iface.o \ + drivers.o preauth.o pmksa_cache.o beacon.o \ + hw_features.o wme.o ap_list.o \ + mlme.o vlan_init.o wpa_auth_ie.o + +OBJS += ../src/utils/eloop.o +OBJS += ../src/utils/common.o +OBJS += ../src/utils/wpa_debug.o +OBJS += ../src/utils/wpabuf.o +OBJS += ../src/utils/os_$(CONFIG_OS).o +OBJS += ../src/utils/ip_addr.o + +OBJS += ../src/common/ieee802_11_common.o +OBJS += ../src/common/wpa_common.o + +OBJS += ../src/radius/radius.o +OBJS += ../src/radius/radius_client.o + +OBJS += ../src/crypto/md5.o +OBJS += ../src/crypto/rc4.o +OBJS += ../src/crypto/md4.o +OBJS += ../src/crypto/sha1.o +OBJS += ../src/crypto/des.o +OBJS += ../src/crypto/aes_wrap.o +OBJS += ../src/crypto/aes.o + +HOBJS=../src/hlr_auc_gw/hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/hlr_auc_gw/milenage.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o + +CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX + +ifdef CONFIG_IAPP +CFLAGS += -DCONFIG_IAPP +OBJS += iapp.o +endif + +ifdef CONFIG_RSN_PREAUTH +CFLAGS += -DCONFIG_RSN_PREAUTH +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_PEERKEY +CFLAGS += -DCONFIG_PEERKEY +OBJS += peerkey.o +endif + +ifdef CONFIG_IEEE80211W +CFLAGS += -DCONFIG_IEEE80211W +NEED_SHA256=y +endif + +ifdef CONFIG_IEEE80211R +CFLAGS += -DCONFIG_IEEE80211R +OBJS += wpa_ft.o +NEED_SHA256=y +endif + +ifdef CONFIG_IEEE80211N +CFLAGS += -DCONFIG_IEEE80211N +endif + +ifdef CONFIG_DRIVER_HOSTAP +CFLAGS += -DCONFIG_DRIVER_HOSTAP +OBJS += driver_hostap.o +endif + +ifdef CONFIG_DRIVER_WIRED +CFLAGS += -DCONFIG_DRIVER_WIRED +OBJS += driver_wired.o +endif + +ifdef CONFIG_DRIVER_MADWIFI +CFLAGS += -DCONFIG_DRIVER_MADWIFI +OBJS += driver_madwifi.o +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_DRIVER_ATHEROS +CFLAGS += -DCONFIG_DRIVER_ATHEROS +OBJS += driver_atheros.o +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_DRIVER_PRISM54 +CFLAGS += -DCONFIG_DRIVER_PRISM54 +OBJS += driver_prism54.o +endif + +ifdef CONFIG_DRIVER_NL80211 +CFLAGS += -DCONFIG_DRIVER_NL80211 +OBJS += driver_nl80211.o radiotap.o +LIBS += -lnl +ifdef CONFIG_LIBNL20 +LIBS += -lnl-genl +CFLAGS += -DCONFIG_LIBNL20 +endif +endif + +ifdef CONFIG_DRIVER_BSD +CFLAGS += -DCONFIG_DRIVER_BSD +OBJS += driver_bsd.o +CONFIG_L2_PACKET=y +CONFIG_DNET_PCAP=y +CONFIG_L2_FREEBSD=y +endif + +ifdef CONFIG_DRIVER_TEST +CFLAGS += -DCONFIG_DRIVER_TEST +OBJS += driver_test.o +endif + +ifdef CONFIG_DRIVER_NONE +CFLAGS += -DCONFIG_DRIVER_NONE +OBJS += driver_none.o +endif + +ifdef CONFIG_L2_PACKET +ifdef CONFIG_DNET_PCAP +ifdef CONFIG_L2_FREEBSD +LIBS += -lpcap +OBJS += ../src/l2_packet/l2_packet_freebsd.o +else +LIBS += -ldnet -lpcap +OBJS += ../src/l2_packet/l2_packet_pcap.o +endif +else +OBJS += ../src/l2_packet/l2_packet_linux.o +endif +else +OBJS += ../src/l2_packet/l2_packet_none.o +endif + + +ifdef CONFIG_EAP_MD5 +CFLAGS += -DEAP_MD5 +OBJS += ../src/eap_server/eap_md5.o +CHAP=y +endif + +ifdef CONFIG_EAP_TLS +CFLAGS += -DEAP_TLS +OBJS += ../src/eap_server/eap_tls.o +TLS_FUNCS=y +endif + +ifdef CONFIG_EAP_PEAP +CFLAGS += -DEAP_PEAP +OBJS += ../src/eap_server/eap_peap.o +OBJS += ../src/eap_common/eap_peap_common.o +TLS_FUNCS=y +CONFIG_EAP_MSCHAPV2=y +endif + +ifdef CONFIG_EAP_TTLS +CFLAGS += -DEAP_TTLS +OBJS += ../src/eap_server/eap_ttls.o +TLS_FUNCS=y +CHAP=y +endif + +ifdef CONFIG_EAP_MSCHAPV2 +CFLAGS += -DEAP_MSCHAPv2 +OBJS += ../src/eap_server/eap_mschapv2.o +MS_FUNCS=y +endif + +ifdef CONFIG_EAP_GTC +CFLAGS += -DEAP_GTC +OBJS += ../src/eap_server/eap_gtc.o +endif + +ifdef CONFIG_EAP_SIM +CFLAGS += -DEAP_SIM +OBJS += ../src/eap_server/eap_sim.o +CONFIG_EAP_SIM_COMMON=y +endif + +ifdef CONFIG_EAP_AKA +CFLAGS += -DEAP_AKA +OBJS += ../src/eap_server/eap_aka.o +CONFIG_EAP_SIM_COMMON=y +NEED_SHA256=y +endif + +ifdef CONFIG_EAP_AKA_PRIME +CFLAGS += -DEAP_AKA_PRIME +endif + +ifdef CONFIG_EAP_SIM_COMMON +OBJS += ../src/eap_common/eap_sim_common.o +# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be +# replaced with another file implementating the interface specified in +# eap_sim_db.h. +OBJS += ../src/eap_server/eap_sim_db.o +NEED_FIPS186_2_PRF=y +endif + +ifdef CONFIG_EAP_PAX +CFLAGS += -DEAP_PAX +OBJS += ../src/eap_server/eap_pax.o ../src/eap_common/eap_pax_common.o +endif + +ifdef CONFIG_EAP_PSK +CFLAGS += -DEAP_PSK +OBJS += ../src/eap_server/eap_psk.o ../src/eap_common/eap_psk_common.o +endif + +ifdef CONFIG_EAP_SAKE +CFLAGS += -DEAP_SAKE +OBJS += ../src/eap_server/eap_sake.o ../src/eap_common/eap_sake_common.o +endif + +ifdef CONFIG_EAP_GPSK +CFLAGS += -DEAP_GPSK +OBJS += ../src/eap_server/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o +ifdef CONFIG_EAP_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 +endif +NEED_SHA256=y +endif + +ifdef CONFIG_EAP_VENDOR_TEST +CFLAGS += -DEAP_VENDOR_TEST +OBJS += ../src/eap_server/eap_vendor_test.o +endif + +ifdef CONFIG_EAP_FAST +CFLAGS += -DEAP_FAST +OBJS += ../src/eap_server/eap_fast.o +OBJS += ../src/eap_common/eap_fast_common.o +TLS_FUNCS=y +NEED_T_PRF=y +endif + +ifdef CONFIG_WPS +CFLAGS += -DCONFIG_WPS -DEAP_WSC +OBJS += ../src/utils/uuid.o +OBJS += wps_hostapd.o +OBJS += ../src/eap_server/eap_wsc.o ../src/eap_common/eap_wsc_common.o +OBJS += ../src/wps/wps.o +OBJS += ../src/wps/wps_common.o +OBJS += ../src/wps/wps_attr_parse.o +OBJS += ../src/wps/wps_attr_build.o +OBJS += ../src/wps/wps_attr_process.o +OBJS += ../src/wps/wps_dev_attr.o +OBJS += ../src/wps/wps_enrollee.o +OBJS += ../src/wps/wps_registrar.o +NEED_DH_GROUPS=y +NEED_SHA256=y +NEED_CRYPTO=y +NEED_BASE64=y + +ifdef CONFIG_WPS_UPNP +CFLAGS += -DCONFIG_WPS_UPNP +OBJS += ../src/wps/wps_upnp.o +OBJS += ../src/wps/wps_upnp_ssdp.o +OBJS += ../src/wps/wps_upnp_web.o +OBJS += ../src/wps/wps_upnp_event.o +OBJS += ../src/wps/httpread.o +endif + +endif + +ifdef CONFIG_EAP_IKEV2 +CFLAGS += -DEAP_IKEV2 +OBJS += ../src/eap_server/eap_ikev2.o ../src/eap_server/ikev2.o +OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +endif + +ifdef CONFIG_EAP_TNC +CFLAGS += -DEAP_TNC +OBJS += ../src/eap_server/eap_tnc.o +OBJS += ../src/eap_server/tncs.o +NEED_BASE64=y +ifndef CONFIG_DRIVER_BSD +LIBS += -ldl +endif +endif + +# Basic EAP functionality is needed for EAPOL +OBJS += ../src/eap_server/eap.o +OBJS += ../src/eap_common/eap_common.o +OBJS += ../src/eap_server/eap_methods.o +OBJS += ../src/eap_server/eap_identity.o + +ifdef CONFIG_EAP +CFLAGS += -DEAP_SERVER +endif + +ifndef CONFIG_TLS +CONFIG_TLS=openssl +endif + +ifeq ($(CONFIG_TLS), internal) +ifndef CONFIG_CRYPTO +CONFIG_CRYPTO=internal +endif +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +CFLAGS += -DCONFIG_INTERNAL_X509 +endif +ifeq ($(CONFIG_CRYPTO), internal) +CFLAGS += -DCONFIG_INTERNAL_X509 +endif + + +ifdef TLS_FUNCS +# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) +CFLAGS += -DEAP_TLS_FUNCS +OBJS += ../src/eap_server/eap_tls_common.o +NEED_TLS_PRF=y +ifeq ($(CONFIG_TLS), openssl) +OBJS += ../src/crypto/tls_openssl.o +LIBS += -lssl -lcrypto +LIBS_p += -lcrypto +LIBS_h += -lcrypto +endif +ifeq ($(CONFIG_TLS), gnutls) +OBJS += ../src/crypto/tls_gnutls.o +LIBS += -lgnutls -lgcrypt -lgpg-error +LIBS_p += -lgcrypt +LIBS_h += -lgcrypt +endif +ifdef CONFIG_GNUTLS_EXTRA +CFLAGS += -DCONFIG_GNUTLS_EXTRA +LIBS += -lgnutls-extra +endif +ifeq ($(CONFIG_TLS), internal) +OBJS += ../src/crypto/tls_internal.o +OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o +OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_server.o +OBJS += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o +OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o +OBJS_p += ../src/tls/asn1.o +OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o +NEED_BASE64=y +CFLAGS += -DCONFIG_TLS_INTERNAL +CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER +ifeq ($(CONFIG_CRYPTO), internal) +ifdef CONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +else +LIBS += -ltommath +LIBS_p += -ltommath +endif +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +endif +endif +NEED_CRYPTO=y +else +OBJS += ../src/crypto/tls_none.o +endif + +ifdef CONFIG_PKCS12 +CFLAGS += -DPKCS12_FUNCS +endif + +ifdef MS_FUNCS +OBJS += ../src/crypto/ms_funcs.o +NEED_CRYPTO=y +endif + +ifdef CHAP +OBJS += ../src/eap_common/chap.o +endif + +ifdef NEED_CRYPTO +ifndef TLS_FUNCS +ifeq ($(CONFIG_TLS), openssl) +LIBS += -lcrypto +LIBS_p += -lcrypto +LIBS_h += -lcrypto +endif +ifeq ($(CONFIG_TLS), gnutls) +LIBS += -lgcrypt +LIBS_p += -lgcrypt +LIBS_h += -lgcrypt +endif +ifeq ($(CONFIG_TLS), internal) +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +endif +endif +endif +ifeq ($(CONFIG_TLS), openssl) +OBJS += ../src/crypto/crypto_openssl.o +OBJS_p += ../src/crypto/crypto_openssl.o +HOBJS += ../src/crypto/crypto_openssl.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_TLS), gnutls) +OBJS += ../src/crypto/crypto_gnutls.o +OBJS_p += ../src/crypto/crypto_gnutls.o +HOBJS += ../src/crypto/crypto_gnutls.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_TLS), internal) +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += ../src/crypto/crypto_libtomcrypt.o +OBJS_p += ../src/crypto/crypto_libtomcrypt.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o +OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o +CFLAGS += -DCONFIG_CRYPTO_INTERNAL +ifdef CONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST +CFLAGS += -DLTM_FAST +endif +else +LIBS += -ltommath +LIBS_p += -ltommath +endif +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +endif +endif +else +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +endif + +ifdef CONFIG_INTERNAL_AES +CFLAGS += -DINTERNAL_AES +endif +ifdef CONFIG_INTERNAL_SHA1 +CFLAGS += -DINTERNAL_SHA1 +endif +ifdef CONFIG_INTERNAL_SHA256 +CFLAGS += -DINTERNAL_SHA256 +endif +ifdef CONFIG_INTERNAL_MD5 +CFLAGS += -DINTERNAL_MD5 +endif +ifdef CONFIG_INTERNAL_MD4 +CFLAGS += -DINTERNAL_MD4 +endif +ifdef CONFIG_INTERNAL_DES +CFLAGS += -DINTERNAL_DES +endif + +ifdef NEED_SHA256 +OBJS += ../src/crypto/sha256.o +endif + +ifdef NEED_DH_GROUPS +OBJS += ../src/crypto/dh_groups.o +ifdef NEED_DH_GROUPS_ALL +CFLAGS += -DALL_DH_GROUPS +endif +endif + +ifndef NEED_FIPS186_2_PRF +CFLAGS += -DCONFIG_NO_FIPS186_2_PRF +endif + +ifndef NEED_T_PRF +CFLAGS += -DCONFIG_NO_T_PRF +endif + +ifndef NEED_TLS_PRF +CFLAGS += -DCONFIG_NO_TLS_PRF +endif + +ifdef CONFIG_RADIUS_SERVER +CFLAGS += -DRADIUS_SERVER +OBJS += ../src/radius/radius_server.o +endif + +ifdef CONFIG_IPV6 +CFLAGS += -DCONFIG_IPV6 +endif + +ifdef CONFIG_DRIVER_RADIUS_ACL +CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL +endif + +ifdef CONFIG_FULL_DYNAMIC_VLAN +# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges +# and vlan interfaces for the vlan feature. +CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN +endif + +ifdef NEED_BASE64 +OBJS += ../src/utils/base64.o +endif + +ifdef CONFIG_NO_STDOUT_DEBUG +CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +endif + +ifdef CONFIG_NO_AES_EXTRAS +CFLAGS += -DCONFIG_NO_AES_UNWRAP +CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1 +CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC +CFLAGS += -DCONFIG_NO_AES_DECRYPT +CFLAGS += -DCONFIG_NO_AES_ENCRYPT_BLOCK +endif + +ALL=hostapd hostapd_cli + +all: verify_config $(ALL) + +Q=@ +E=echo +ifeq ($(V), 1) +Q= +E=true +endif + +%.o: %.c + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + @$(E) " CC " $< + +verify_config: + @if [ ! -r .config ]; then \ + echo 'Building hostapd requires a configuration file'; \ + echo '(.config). See README for more instructions. You can'; \ + echo 'run "cp defconfig .config" to create an example'; \ + echo 'configuration.'; \ + exit 1; \ + fi + +install: all + for i in $(ALL); do cp $$i /usr/local/bin/$$i; done + +hostapd: $(OBJS) + $(CC) -o hostapd $(OBJS) $(LIBS) + +OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o +hostapd_cli: $(OBJS_c) + $(CC) -o hostapd_cli $(OBJS_c) + +NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o ../src/crypto/sha1.o ../src/crypto/rc4.o ../src/crypto/md5.o +NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o +ifdef TLS_FUNCS +LIBS_n += -lcrypto +endif + +nt_password_hash: $(NOBJS) + $(CC) -o nt_password_hash $(NOBJS) $(LIBS_n) + +hlr_auc_gw: $(HOBJS) + $(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h) + +clean: + $(MAKE) -C ../src clean + rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw + rm -f *.d + +%.eps: %.fig + fig2dev -L eps $*.fig $*.eps + +%.png: %.fig + fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \ + > $*.png + +docs-pics: doc/hostapd.png doc/hostapd.eps + +docs: docs-pics + (cd ..; doxygen hostapd/doc/doxygen.full; cd hostapd) + $(MAKE) -C doc/latex + cp doc/latex/refman.pdf hostapd-devel.pdf + +docs-fast: docs-pics + (cd ..; doxygen hostapd/doc/doxygen.fast; cd hostapd) + +clean-docs: + rm -rf doc/latex doc/html + rm -f doc/hostapd.{eps,png} hostapd-devel.pdf + +TEST_SRC_MILENAGE = ../src/hlr_auc_gw/milenage.c ../src/crypto/aes_wrap.c ../src/crypto/aes.c ../src/utils/common.c ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).c +test-milenage: $(TEST_SRC_MILENAGE) + $(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \ + -DTEST_MAIN_MILENAGE -I. -DINTERNAL_AES \ + -I../src/crypto -I../src/utils + ./test-milenage + rm test-milenage + +-include $(OBJS:%.o=%.d) diff --git a/contrib/wpa/hostapd/README-WPS b/contrib/wpa/hostapd/README-WPS index b46d767..e0e370b 100644 --- a/contrib/wpa/hostapd/README-WPS +++ b/contrib/wpa/hostapd/README-WPS @@ -165,10 +165,17 @@ Example command to add a PIN (12345670) for an Enrollee: hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670 If the UUID-E is not available (e.g., Enrollee waits for the Registrar -to be selected before connecting), wildcard UUID may be used to allow the PIN to be used once with any UUID: +to be selected before connecting), wildcard UUID may be used to allow +the PIN to be used once with any UUID: hostapd_cli wps_pin any 12345670 +To reduce likelihood of PIN being used with other devices or of +forgetting an active PIN available for potential attackers, expiration +time can be set for the new PIN: + +hostapd_cli wps_pin any 12345670 300 + After this, the Enrollee can connect to the AP again and complete WPS negotiation. At that point, a new, random WPA PSK is generated for the diff --git a/contrib/wpa/hostapd/ap.h b/contrib/wpa/hostapd/ap.h index 98f8ee7..2c6d7e9 100644 --- a/contrib/wpa/hostapd/ap.h +++ b/contrib/wpa/hostapd/ap.h @@ -30,7 +30,7 @@ #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ #define WLAN_STA_SHORT_PREAMBLE BIT(7) #define WLAN_STA_PREAUTH BIT(8) -#define WLAN_STA_WME BIT(9) +#define WLAN_STA_WMM BIT(9) #define WLAN_STA_MFP BIT(10) #define WLAN_STA_HT BIT(11) #define WLAN_STA_WPS BIT(12) diff --git a/contrib/wpa/hostapd/beacon.c b/contrib/wpa/hostapd/beacon.c index 31323e8..1f82d9c 100644 --- a/contrib/wpa/hostapd/beacon.c +++ b/contrib/wpa/hostapd/beacon.c @@ -298,8 +298,8 @@ void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); - /* Wi-Fi Wireless Multimedia Extensions */ - pos = hostapd_eid_wme(hapd, pos); + /* Wi-Fi Alliance WMM */ + pos = hostapd_eid_wmm(hapd, pos); pos = hostapd_eid_ht_capabilities_info(hapd, pos); pos = hostapd_eid_ht_operation(hapd, pos); @@ -395,8 +395,8 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - tailpos, NULL); - /* Wi-Fi Wireless Multimedia Extensions */ - tailpos = hostapd_eid_wme(hapd, tailpos); + /* Wi-Fi Alliance WMM */ + tailpos = hostapd_eid_wmm(hapd, tailpos); #ifdef CONFIG_IEEE80211N if (hapd->iconf->ieee80211n) { diff --git a/contrib/wpa/hostapd/config.c b/contrib/wpa/hostapd/config.c index 6ad14d2..692b1a4 100644 --- a/contrib/wpa/hostapd/config.c +++ b/contrib/wpa/hostapd/config.c @@ -201,15 +201,15 @@ static struct hostapd_config * hostapd_config_defaults(void) struct hostapd_config *conf; struct hostapd_bss_config *bss; int i; - const int aCWmin = 15, aCWmax = 1024; - const struct hostapd_wme_ac_params ac_bk = + const int aCWmin = 4, aCWmax = 10; + const struct hostapd_wmm_ac_params ac_bk = { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ - const struct hostapd_wme_ac_params ac_be = + const struct hostapd_wmm_ac_params ac_be = { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ - const struct hostapd_wme_ac_params ac_vi = /* video traffic */ - { aCWmin >> 1, aCWmin, 2, 3000 / 32, 1 }; - const struct hostapd_wme_ac_params ac_vo = /* voice traffic */ - { aCWmin >> 2, aCWmin >> 1, 2, 1500 / 32, 1 }; + const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ + { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 }; + const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ + { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 }; conf = os_zalloc(sizeof(*conf)); bss = os_zalloc(sizeof(*bss)); @@ -251,10 +251,10 @@ static struct hostapd_config * hostapd_config_defaults(void) for (i = 0; i < NUM_TX_QUEUES; i++) conf->tx_queue[i].aifs = -1; /* use hw default */ - conf->wme_ac_params[0] = ac_be; - conf->wme_ac_params[1] = ac_bk; - conf->wme_ac_params[2] = ac_vi; - conf->wme_ac_params[3] = ac_vo; + conf->wmm_ac_params[0] = ac_be; + conf->wmm_ac_params[1] = ac_bk; + conf->wmm_ac_params[2] = ac_vi; + conf->wmm_ac_params[3] = ac_vo; #ifdef CONFIG_IEEE80211N conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED; @@ -1166,14 +1166,14 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name, } -static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name, - char *val) +static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name, + char *val) { int num, v; char *pos; - struct hostapd_wme_ac_params *ac; + struct hostapd_wmm_ac_params *ac; - /* skip 'wme_ac_' prefix */ + /* skip 'wme_ac_' or 'wmm_ac_' prefix */ pos = name + 7; if (os_strncmp(pos, "be_", 3) == 0) { num = 0; @@ -1188,11 +1188,11 @@ static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name, num = 3; pos += 3; } else { - wpa_printf(MSG_ERROR, "Unknown wme name '%s'", pos); + wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); return -1; } - ac = &conf->wme_ac_params[num]; + ac = &conf->wmm_ac_params[num]; if (os_strcmp(pos, "aifs") == 0) { v = atoi(val); @@ -1221,7 +1221,7 @@ static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name, wpa_printf(MSG_ERROR, "Invalid txop value %d", v); return -1; } - ac->txopLimit = v; + ac->txop_limit = v; } else if (os_strcmp(pos, "acm") == 0) { v = atoi(val); if (v < 0 || v > 1) { @@ -1230,7 +1230,7 @@ static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name, } ac->admission_control_mandatory = v; } else { - wpa_printf(MSG_ERROR, "Unknown wme_ac_ field '%s'", pos); + wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); return -1; } @@ -1452,13 +1452,13 @@ struct hostapd_config * hostapd_config_read(const char *fname) } else if (os_strcmp(buf, "bridge") == 0) { os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); } else if (os_strcmp(buf, "driver") == 0) { - int i; + int j; /* clear to get error below if setting is invalid */ conf->driver = NULL; - for (i = 0; hostapd_drivers[i]; i++) { - if (os_strcmp(pos, hostapd_drivers[i]->name) == + for (j = 0; hostapd_drivers[j]; j++) { + if (os_strcmp(pos, hostapd_drivers[j]->name) == 0) { - conf->driver = hostapd_drivers[i]; + conf->driver = hostapd_drivers[j]; break; } } @@ -2070,11 +2070,13 @@ struct hostapd_config * hostapd_config_read(const char *fname) "queue item", line); errors++; } - } else if (os_strcmp(buf, "wme_enabled") == 0) { - bss->wme_enabled = atoi(pos); - } else if (os_strncmp(buf, "wme_ac_", 7) == 0) { - if (hostapd_config_wme_ac(conf, buf, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid wme " + } else if (os_strcmp(buf, "wme_enabled") == 0 || + os_strcmp(buf, "wmm_enabled") == 0) { + bss->wmm_enabled = 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)) { + wpa_printf(MSG_ERROR, "Line %d: invalid WMM " "ac item", line); errors++; } @@ -2255,29 +2257,30 @@ struct hostapd_config * hostapd_config_read(const char *fname) fclose(f); - if (bss->individual_wep_key_len == 0) { - /* individual keys are not use; can use key idx0 for broadcast - * keys */ - bss->broadcast_key_idx_min = 0; - } - - /* Select group cipher based on the enabled pairwise cipher suites */ - pairwise = 0; - if (bss->wpa & 1) - pairwise |= bss->wpa_pairwise; - if (bss->wpa & 2) { - if (bss->rsn_pairwise == 0) - bss->rsn_pairwise = bss->wpa_pairwise; - pairwise |= bss->rsn_pairwise; - } - if (pairwise & WPA_CIPHER_TKIP) - bss->wpa_group = WPA_CIPHER_TKIP; - else - bss->wpa_group = WPA_CIPHER_CCMP; - 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; + } + + /* Select group cipher based on the enabled pairwise cipher + * suites */ + pairwise = 0; + if (bss->wpa & 1) + pairwise |= bss->wpa_pairwise; + if (bss->wpa & 2) { + if (bss->rsn_pairwise == 0) + bss->rsn_pairwise = bss->wpa_pairwise; + pairwise |= bss->rsn_pairwise; + } + if (pairwise & WPA_CIPHER_TKIP) + bss->wpa_group = WPA_CIPHER_TKIP; + else + bss->wpa_group = WPA_CIPHER_CCMP; + bss->radius->auth_server = bss->radius->auth_servers; bss->radius->acct_server = bss->radius->acct_servers; @@ -2476,6 +2479,8 @@ void hostapd_config_free(struct hostapd_config *conf) for (i = 0; i < conf->num_bss; i++) hostapd_config_free_bss(&conf->bss[i]); os_free(conf->bss); + os_free(conf->supported_rates); + os_free(conf->basic_rates); os_free(conf); } diff --git a/contrib/wpa/hostapd/config.h b/contrib/wpa/hostapd/config.h index a3247f2..ea530d4 100644 --- a/contrib/wpa/hostapd/config.h +++ b/contrib/wpa/hostapd/config.h @@ -135,11 +135,11 @@ struct hostapd_tx_queue_params { int configured; }; -struct hostapd_wme_ac_params { +struct hostapd_wmm_ac_params { int cwmin; int cwmax; int aifs; - int txopLimit; /* in units of 32us */ + int txop_limit; /* in units of 32us */ int admission_control_mandatory; }; @@ -271,7 +271,7 @@ struct hostapd_bss_config { int ap_max_inactivity; int ignore_broadcast_ssid; - int wme_enabled; + int wmm_enabled; struct hostapd_vlan *vlan, *vlan_tail; @@ -371,13 +371,13 @@ struct hostapd_config { struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; /* - * WME AC parameters, in same order as 802.1D, i.e. + * WMM AC parameters, in same order as 802.1D, i.e. * 0 = BE (best effort) * 1 = BK (background) * 2 = VI (video) * 3 = VO (voice) */ - struct hostapd_wme_ac_params wme_ac_params[4]; + struct hostapd_wmm_ac_params wmm_ac_params[4]; enum { INTERNAL_BRIDGE_DO_NOT_CONTROL = -1, diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c index fe63e7c..9dec724 100644 --- a/contrib/wpa/hostapd/ctrl_iface.c +++ b/contrib/wpa/hostapd/ctrl_iface.c @@ -18,6 +18,7 @@ #include <sys/un.h> #include <sys/stat.h> +#include <stddef.h> #include "hostapd.h" #include "eloop.h" @@ -60,7 +61,8 @@ static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, dst->next = hapd->ctrl_dst; hapd->ctrl_dst = dst; wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, fromlen); + (u8 *) from->sun_path, + fromlen - offsetof(struct sockaddr_un, sun_path)); return 0; } @@ -74,15 +76,18 @@ static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, dst = hapd->ctrl_dst; while (dst) { if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) == - 0) { + os_memcmp(from->sun_path, dst->addr.sun_path, + fromlen - offsetof(struct sockaddr_un, sun_path)) + == 0) { 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); + (u8 *) from->sun_path, + fromlen - + offsetof(struct sockaddr_un, sun_path)); return 0; } prev = dst; @@ -104,10 +109,12 @@ static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, dst = hapd->ctrl_dst; while (dst) { if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) == - 0) { + os_memcmp(from->sun_path, dst->addr.sun_path, + fromlen - offsetof(struct sockaddr_un, sun_path)) + == 0) { wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, fromlen); + "level", (u8 *) from->sun_path, fromlen - + offsetof(struct sockaddr_un, sun_path)); dst->debug_level = atoi(level); return 0; } @@ -246,10 +253,21 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) { char *pin = os_strchr(txt, ' '); + char *timeout_txt; + int timeout; + if (pin == NULL) return -1; *pin++ = '\0'; - return hostapd_wps_add_pin(hapd, txt, pin); + + timeout_txt = os_strchr(pin, ' '); + if (timeout_txt) { + *timeout_txt++ = '\0'; + timeout = atoi(timeout_txt); + } else + timeout = 0; + + return hostapd_wps_add_pin(hapd, txt, pin, timeout); } #endif /* CONFIG_WPS */ @@ -434,14 +452,44 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) } os_memset(&addr, 0, sizeof(addr)); +#ifdef __FreeBSD__ + addr.sun_len = sizeof(addr); +#endif /* __FreeBSD__ */ addr.sun_family = AF_UNIX; fname = hostapd_ctrl_iface_path(hapd); if (fname == NULL) goto fail; os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(PF_UNIX)"); - goto fail; + 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 (hapd->conf->ctrl_interface_gid_set && @@ -536,15 +584,17 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, next = dst->next; if (level >= dst->debug_level) { wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen); + (u8 *) dst->addr.sun_path, dst->addrlen - + offsetof(struct sockaddr_un, sun_path)); msg.msg_name = &dst->addr; msg.msg_namelen = dst->addrlen; if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { - fprintf(stderr, "CTRL_IFACE monitor[%d]: ", - idx); - perror("sendmsg"); + int _errno = errno; + wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " + "%d - %s", + idx, errno, strerror(errno)); dst->errors++; - if (dst->errors > 10) { + if (dst->errors > 10 || _errno == ENOENT) { hostapd_ctrl_iface_detach( hapd, &dst->addr, dst->addrlen); diff --git a/contrib/wpa/hostapd/doc/.gitignore b/contrib/wpa/hostapd/doc/.gitignore deleted file mode 100644 index 987a5e9..0000000 --- a/contrib/wpa/hostapd/doc/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -html -latex -hostapd.eps -hostapd.png diff --git a/contrib/wpa/hostapd/driver_bsd.c b/contrib/wpa/hostapd/driver_bsd.c new file mode 100644 index 0000000..43d57d9 --- /dev/null +++ b/contrib/wpa/hostapd/driver_bsd.c @@ -0,0 +1,839 @@ +/* + * hostapd / Driver interaction with BSD net80211 layer + * Copyright (c) 2004, Sam Leffler <sam@errno.com> + * Copyright (c) 2004, 2Wire, Inc + * + * 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 "includes.h" +#include <sys/ioctl.h> + +#include <net/if.h> + +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_crypto.h> +#include <net80211/ieee80211_ioctl.h> + +/* + * Avoid conflicts with hostapd definitions by undefining couple of defines + * from net80211 header files. + */ +#undef RSN_VERSION +#undef WPA_VERSION +#undef WPA_OUI_TYPE +#undef WME_OUI_TYPE + +#include "hostapd.h" +#include "driver.h" +#include "ieee802_1x.h" +#include "eloop.h" +#include "sta_info.h" +#include "l2_packet/l2_packet.h" + +#include "eapol_sm.h" +#include "wpa.h" +#include "radius/radius.h" +#include "ieee802_11.h" +#include "common.h" + +struct bsd_driver_data { + struct hostapd_data *hapd; /* back pointer */ + + char iface[IFNAMSIZ + 1]; + struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ + int ioctl_sock; /* socket for ioctl() use */ + int wext_sock; /* socket for wireless events */ +}; + +static int bsd_sta_deauth(void *priv, const u8 *addr, int reason_code); + +static int +set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) +{ + struct ieee80211req ireq; + + memset(&ireq, 0, sizeof(ireq)); + os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ); + ireq.i_type = op; + ireq.i_len = arg_len; + ireq.i_data = (void *) arg; + + if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) { + perror("ioctl[SIOCS80211]"); + return -1; + } + return 0; +} + +static int +get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) +{ + struct ieee80211req ireq; + + memset(&ireq, 0, sizeof(ireq)); + os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ); + ireq.i_type = op; + ireq.i_len = arg_len; + ireq.i_data = arg; + + if (ioctl(drv->ioctl_sock, SIOCG80211, &ireq) < 0) { + perror("ioctl[SIOCG80211]"); + return -1; + } + return ireq.i_len; +} + +static int +set80211param(struct bsd_driver_data *drv, int op, int arg) +{ + struct ieee80211req ireq; + + memset(&ireq, 0, sizeof(ireq)); + os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ); + ireq.i_type = op; + ireq.i_val = arg; + + if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) { + perror("ioctl[SIOCS80211]"); + return -1; + } + return 0; +} + +static const char * +ether_sprintf(const u8 *addr) +{ + static char buf[sizeof(MACSTR)]; + + if (addr != NULL) + snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + else + snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); + return buf; +} + +/* + * Configure WPA parameters. + */ +static int +bsd_configure_wpa(struct bsd_driver_data *drv) +{ + static const char *ciphernames[] = + { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; + struct hostapd_data *hapd = drv->hapd; + struct hostapd_bss_config *conf = hapd->conf; + int v; + + switch (conf->wpa_group) { + case WPA_CIPHER_CCMP: + v = IEEE80211_CIPHER_AES_CCM; + break; + case WPA_CIPHER_TKIP: + v = IEEE80211_CIPHER_TKIP; + break; + case WPA_CIPHER_WEP104: + v = IEEE80211_CIPHER_WEP; + break; + case WPA_CIPHER_WEP40: + v = IEEE80211_CIPHER_WEP; + break; + case WPA_CIPHER_NONE: + v = IEEE80211_CIPHER_NONE; + break; + default: + printf("Unknown group key cipher %u\n", + conf->wpa_group); + return -1; + } + wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", + __func__, ciphernames[v], v); + if (set80211param(drv, IEEE80211_IOC_MCASTCIPHER, v)) { + printf("Unable to set group key cipher to %u (%s)\n", + v, ciphernames[v]); + return -1; + } + if (v == IEEE80211_CIPHER_WEP) { + /* key length is done only for specific ciphers */ + v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); + if (set80211param(drv, IEEE80211_IOC_MCASTKEYLEN, v)) { + printf("Unable to set group key length to %u\n", v); + return -1; + } + } + + v = 0; + if (conf->wpa_pairwise & WPA_CIPHER_CCMP) + v |= 1<<IEEE80211_CIPHER_AES_CCM; + if (conf->wpa_pairwise & WPA_CIPHER_TKIP) + v |= 1<<IEEE80211_CIPHER_TKIP; + if (conf->wpa_pairwise & WPA_CIPHER_NONE) + v |= 1<<IEEE80211_CIPHER_NONE; + wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v); + if (set80211param(drv, IEEE80211_IOC_UCASTCIPHERS, v)) { + printf("Unable to set pairwise key ciphers to 0x%x\n", v); + return -1; + } + + wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x", + __func__, conf->wpa_key_mgmt); + if (set80211param(drv, IEEE80211_IOC_KEYMGTALGS, conf->wpa_key_mgmt)) { + printf("Unable to set key management algorithms to 0x%x\n", + conf->wpa_key_mgmt); + return -1; + } + + v = 0; + if (conf->rsn_preauth) + v |= BIT(0); + wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", + __func__, conf->rsn_preauth); + if (set80211param(drv, IEEE80211_IOC_RSNCAPS, v)) { + printf("Unable to set RSN capabilities to 0x%x\n", v); + return -1; + } + + wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, conf->wpa); + if (set80211param(drv, IEEE80211_IOC_WPA, conf->wpa)) { + printf("Unable to set WPA to %u\n", conf->wpa); + return -1; + } + return 0; +} + + +static int +bsd_set_iface_flags(void *priv, int dev_up) +{ + struct bsd_driver_data *drv = priv; + struct ifreq ifr; + + wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up); + + if (drv->ioctl_sock < 0) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); + + if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { + perror("ioctl[SIOCGIFFLAGS]"); + return -1; + } + + if (dev_up) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; + + if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { + perror("ioctl[SIOCSIFFLAGS]"); + return -1; + } + + if (dev_up) { + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); + ifr.ifr_mtu = HOSTAPD_MTU; + if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { + perror("ioctl[SIOCSIFMTU]"); + printf("Setting MTU failed - trying to survive with " + "current value\n"); + } + } + + return 0; +} + +static int +bsd_set_ieee8021x(const char *ifname, void *priv, int enabled) +{ + struct bsd_driver_data *drv = priv; + struct hostapd_data *hapd = drv->hapd; + struct hostapd_bss_config *conf = hapd->conf; + + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); + + if (!enabled) { + /* XXX restore state */ + return set80211param(priv, IEEE80211_IOC_AUTHMODE, + IEEE80211_AUTH_AUTO); + } + if (!conf->wpa && !conf->ieee802_1x) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, + HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); + return -1; + } + if (conf->wpa && bsd_configure_wpa(drv) != 0) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, + HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); + return -1; + } + if (set80211param(priv, IEEE80211_IOC_AUTHMODE, + (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, + HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); + return -1; + } + return bsd_set_iface_flags(priv, 1); +} + +static int +bsd_set_privacy(const char *ifname, void *priv, int enabled) +{ + struct bsd_driver_data *drv = priv; + + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); + + return set80211param(drv, IEEE80211_IOC_PRIVACY, enabled); +} + +static int +bsd_set_sta_authorized(void *priv, const u8 *addr, int authorized) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + + wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", + __func__, ether_sprintf(addr), authorized); + + if (authorized) + mlme.im_op = IEEE80211_MLME_AUTHORIZE; + else + mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; + mlme.im_reason = 0; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); +} + +static int +bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, + int flags_and) +{ + /* For now, only support setting Authorized flag */ + if (flags_or & WLAN_STA_AUTHORIZED) + return bsd_set_sta_authorized(priv, addr, 1); + if (!(flags_and & WLAN_STA_AUTHORIZED)) + return bsd_set_sta_authorized(priv, addr, 0); + return 0; +} + +static int +bsd_del_key(void *priv, const u8 *addr, int key_idx) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_del_key wk; + + wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", + __func__, ether_sprintf(addr), key_idx); + + memset(&wk, 0, sizeof(wk)); + if (addr != NULL) { + memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); + wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ + } else { + wk.idk_keyix = key_idx; + } + + return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); +} + +static int +bsd_set_key(const char *ifname, void *priv, const char *alg, + const u8 *addr, int key_idx, + const u8 *key, size_t key_len, int txkey) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_key wk; + u_int8_t cipher; + + if (strcmp(alg, "none") == 0) + return bsd_del_key(drv, addr, key_idx); + + wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d", + __func__, alg, ether_sprintf(addr), key_idx); + + if (strcmp(alg, "WEP") == 0) + cipher = IEEE80211_CIPHER_WEP; + else if (strcmp(alg, "TKIP") == 0) + cipher = IEEE80211_CIPHER_TKIP; + else if (strcmp(alg, "CCMP") == 0) + cipher = IEEE80211_CIPHER_AES_CCM; + else { + printf("%s: unknown/unsupported algorithm %s\n", + __func__, alg); + return -1; + } + + if (key_len > sizeof(wk.ik_keydata)) { + printf("%s: key length %d too big\n", __func__, key_len); + return -3; + } + + memset(&wk, 0, sizeof(wk)); + wk.ik_type = cipher; + wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; + if (addr == NULL) { + memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + wk.ik_keyix = key_idx; + wk.ik_flags |= IEEE80211_KEY_DEFAULT; + } else { + memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + wk.ik_keyix = IEEE80211_KEYIX_NONE; + } + wk.ik_keylen = key_len; + memcpy(wk.ik_keydata, key, key_len); + + return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); +} + + +static int +bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, + u8 *seq) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_key wk; + + wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", + __func__, ether_sprintf(addr), idx); + + memset(&wk, 0, sizeof(wk)); + if (addr == NULL) + memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + else + memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + wk.ik_keyix = idx; + + if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { + printf("Failed to get encryption.\n"); + return -1; + } + +#ifdef WORDS_BIGENDIAN + { + /* + * wk.ik_keytsc is in host byte order (big endian), need to + * swap it to match with the byte order used in WPA. + */ + int i; + u8 tmp[WPA_KEY_RSC_LEN]; + memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + for (i = 0; i < WPA_KEY_RSC_LEN; i++) { + seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; + } + } +#else /* WORDS_BIGENDIAN */ + memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); +#endif /* WORDS_BIGENDIAN */ + return 0; +} + + +static int +bsd_flush(void *priv) +{ + u8 allsta[IEEE80211_ADDR_LEN]; + + memset(allsta, 0xff, IEEE80211_ADDR_LEN); + return bsd_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE); +} + + +static int +bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_sta_stats stats; + + memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); + if (get80211var(drv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) { + /* XXX? do packets counts include non-data frames? */ + data->rx_packets = stats.is_stats.ns_rx_data; + data->rx_bytes = stats.is_stats.ns_rx_bytes; + data->tx_packets = stats.is_stats.ns_tx_data; + data->tx_bytes = stats.is_stats.ns_tx_bytes; + } + return 0; +} + +static int +bsd_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len) +{ + /* + * Do nothing; we setup parameters at startup that define the + * contents of the beacon information element. + */ + return 0; +} + +static int +bsd_sta_deauth(void *priv, const u8 *addr, int reason_code) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + + wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", + __func__, ether_sprintf(addr), reason_code); + + mlme.im_op = IEEE80211_MLME_DEAUTH; + mlme.im_reason = reason_code; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); +} + +static int +bsd_sta_disassoc(void *priv, const u8 *addr, int reason_code) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + + wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", + __func__, ether_sprintf(addr), reason_code); + + mlme.im_op = IEEE80211_MLME_DISASSOC; + mlme.im_reason = reason_code; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); +} + +static int +bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) +{ + struct hostapd_data *hapd = drv->hapd; + struct hostapd_bss_config *conf = hapd->conf; + struct sta_info *sta; + + hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "deassociated"); + + sta = ap_get_sta(hapd, addr); + if (sta != NULL) { + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + if (conf->wpa) + wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); + sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); + ap_free_sta(hapd, sta); + } + return 0; +} + +static int +bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) +{ + struct hostapd_data *hapd = drv->hapd; + struct hostapd_bss_config *conf = hapd->conf; + struct sta_info *sta; + struct ieee80211req_wpaie ie; + int new_assoc, ielen, res; + + hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "associated"); + + sta = ap_sta_add(hapd, addr); + if (sta == NULL) + return -1; + /* + * Fetch and validate any negotiated WPA/RSN parameters. + */ + if (conf->wpa) { + memset(&ie, 0, sizeof(ie)); + memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); + if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { + printf("Failed to get WPA/RSN information element.\n"); + return -1; /* XXX not right */ + } + ielen = ie.wpa_ie[1]; + if (ielen == 0) { + printf("No WPA/RSN information element for station!\n"); + return -1; /* XXX not right */ + } + ielen += 2; + if (sta->wpa_sm == NULL) + sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, + sta->addr); + if (sta->wpa_sm == NULL) { + printf("Failed to initialize WPA state machine\n"); + return -1; + } + res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, + ie.wpa_ie, ielen, NULL, 0); + if (res != WPA_IE_OK) { + printf("WPA/RSN information element rejected? " + "(res %u)\n", res); + return -1; + } + } + + /* + * Now that the internal station state is setup + * kick the authenticator into action. + */ + new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; + wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); + hostapd_new_assoc_sta(hapd, sta, !new_assoc); + ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); + return 0; +} + +#include <net/route.h> +#include <net80211/ieee80211_freebsd.h> + +static void +bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) +{ + struct bsd_driver_data *drv = ctx; + struct hostapd_data *hapd = drv->hapd; + char buf[2048]; + struct if_announcemsghdr *ifan; + struct rt_msghdr *rtm; + struct ieee80211_michael_event *mic; + struct ieee80211_join_event *join; + struct ieee80211_leave_event *leave; + int n; + + n = read(sock, buf, sizeof(buf)); + if (n < 0) { + if (errno != EINTR && errno != EAGAIN) + perror("read(PF_ROUTE)"); + return; + } + + rtm = (struct rt_msghdr *) buf; + if (rtm->rtm_version != RTM_VERSION) { + wpa_printf(MSG_DEBUG, "Routing message version %d not " + "understood\n", rtm->rtm_version); + return; + } + ifan = (struct if_announcemsghdr *) rtm; + switch (rtm->rtm_type) { + case RTM_IEEE80211: + switch (ifan->ifan_what) { + case RTM_IEEE80211_ASSOC: + case RTM_IEEE80211_REASSOC: + case RTM_IEEE80211_DISASSOC: + case RTM_IEEE80211_SCAN: + break; + case RTM_IEEE80211_LEAVE: + leave = (struct ieee80211_leave_event *) &ifan[1]; + bsd_del_sta(drv, leave->iev_addr); + break; + case RTM_IEEE80211_JOIN: +#ifdef RTM_IEEE80211_REJOIN + case RTM_IEEE80211_REJOIN: +#endif + join = (struct ieee80211_join_event *) &ifan[1]; + bsd_new_sta(drv, join->iev_addr); + break; + case RTM_IEEE80211_REPLAY: + /* ignore */ + break; + case RTM_IEEE80211_MICHAEL: + mic = (struct ieee80211_michael_event *) &ifan[1]; + wpa_printf(MSG_DEBUG, + "Michael MIC failure wireless event: " + "keyix=%u src_addr=" MACSTR, mic->iev_keyix, + MAC2STR(mic->iev_src)); + ieee80211_michael_mic_failure(hapd, mic->iev_src, 1); + break; + } + break; + } +} + +static int +bsd_wireless_event_init(void *priv) +{ + struct bsd_driver_data *drv = priv; + int s; + + drv->wext_sock = -1; + + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) { + perror("socket(PF_ROUTE,SOCK_RAW)"); + return -1; + } + eloop_register_read_sock(s, bsd_wireless_event_receive, drv, NULL); + drv->wext_sock = s; + + return 0; +} + +static void +bsd_wireless_event_deinit(void *priv) +{ + struct bsd_driver_data *drv = priv; + + if (drv != NULL) { + if (drv->wext_sock < 0) + return; + eloop_unregister_read_sock(drv->wext_sock); + close(drv->wext_sock); + } +} + + +static int +bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, + int encrypt, const u8 *own_addr) +{ + struct bsd_driver_data *drv = priv; + unsigned char buf[3000]; + unsigned char *bp = buf; + struct l2_ethhdr *eth; + size_t len; + int status; + + /* + * Prepend the Etherent header. If the caller left us + * space at the front we could just insert it but since + * we don't know we copy to a local buffer. Given the frequency + * and size of frames this probably doesn't matter. + */ + len = data_len + sizeof(struct l2_ethhdr); + if (len > sizeof(buf)) { + bp = malloc(len); + if (bp == NULL) { + printf("EAPOL frame discarded, cannot malloc temp " + "buffer of size %u!\n", len); + return -1; + } + } + eth = (struct l2_ethhdr *) bp; + memcpy(eth->h_dest, addr, ETH_ALEN); + memcpy(eth->h_source, own_addr, ETH_ALEN); + eth->h_proto = htons(ETH_P_EAPOL); + memcpy(eth+1, data, data_len); + + wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); + + status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); + + if (bp != buf) + free(bp); + return status; +} + +static void +handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) +{ + struct bsd_driver_data *drv = ctx; + struct hostapd_data *hapd = drv->hapd; + struct sta_info *sta; + + sta = ap_get_sta(hapd, src_addr); + if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { + printf("Data frame from not associated STA %s\n", + ether_sprintf(src_addr)); + /* XXX cannot happen */ + return; + } + ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr), + len - sizeof(struct l2_ethhdr)); +} + +static int +bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len) +{ + struct bsd_driver_data *drv = priv; + int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len); + + wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf); + + return ssid_len; +} + +static int +bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len) +{ + struct bsd_driver_data *drv = priv; + + wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, len, buf); + + return set80211var(drv, IEEE80211_IOC_SSID, buf, len); +} + +static void * +bsd_init(struct hostapd_data *hapd) +{ + struct bsd_driver_data *drv; + + drv = os_zalloc(sizeof(struct bsd_driver_data)); + if (drv == NULL) { + printf("Could not allocate memory for bsd driver data\n"); + goto bad; + } + + drv->hapd = hapd; + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->ioctl_sock < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + goto bad; + } + memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); + + drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, + handle_read, drv, 1); + if (drv->sock_xmit == NULL) + goto bad; + if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr)) + goto bad; + + bsd_set_iface_flags(drv, 0); /* mark down during setup */ + + return drv; +bad: + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + if (drv != NULL) + free(drv); + return NULL; +} + + +static void +bsd_deinit(void *priv) +{ + struct bsd_driver_data *drv = priv; + + (void) bsd_set_iface_flags(drv, 0); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); + free(drv); +} + +const struct wpa_driver_ops wpa_driver_bsd_ops = { + .name = "bsd", + .init = bsd_init, + .deinit = bsd_deinit, + .set_ieee8021x = bsd_set_ieee8021x, + .set_privacy = bsd_set_privacy, + .set_encryption = bsd_set_key, + .get_seqnum = bsd_get_seqnum, + .flush = bsd_flush, + .set_generic_elem = bsd_set_opt_ie, + .wireless_event_init = bsd_wireless_event_init, + .wireless_event_deinit = bsd_wireless_event_deinit, + .sta_set_flags = bsd_sta_set_flags, + .read_sta_data = bsd_read_sta_driver_data, + .send_eapol = bsd_send_eapol, + .sta_disassoc = bsd_sta_disassoc, + .sta_deauth = bsd_sta_deauth, + .set_ssid = bsd_set_ssid, + .get_ssid = bsd_get_ssid, +}; diff --git a/contrib/wpa/hostapd/driver_hostap.c b/contrib/wpa/hostapd/driver_hostap.c new file mode 100644 index 0000000..ceff099 --- /dev/null +++ b/contrib/wpa/hostapd/driver_hostap.c @@ -0,0 +1,1279 @@ +/* + * hostapd / Kernel driver communication with Linux Host AP driver + * Copyright (c) 2002-2007, 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 "includes.h" +#include <sys/ioctl.h> + +#ifdef USE_KERNEL_HEADERS +/* compat-wireless does not include linux/compiler.h to define __user, so + * define it here */ +#ifndef __user +#define __user +#endif /* __user */ +#include <asm/types.h> +#include <linux/if_packet.h> +#include <linux/if_ether.h> /* The L2 protocols */ +#include <linux/if_arp.h> +#include <linux/wireless.h> +#else /* USE_KERNEL_HEADERS */ +#include <net/if_arp.h> +#include <netpacket/packet.h> +#include "wireless_copy.h" +#endif /* USE_KERNEL_HEADERS */ + +#include "hostapd.h" +#include "driver.h" +#include "ieee802_1x.h" +#include "eloop.h" +#include "priv_netlink.h" +#include "ieee802_11.h" +#include "sta_info.h" +#include "hostap_common.h" +#include "hw_features.h" + + +struct hostap_driver_data { + struct hostapd_data *hapd; + + char iface[IFNAMSIZ + 1]; + int sock; /* raw packet socket for driver access */ + int ioctl_sock; /* socket for ioctl() use */ + int wext_sock; /* socket for wireless events */ + + int we_version; + + u8 *generic_ie; + size_t generic_ie_len; + u8 *wps_ie; + size_t wps_ie_len; +}; + + +static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, + int len); +static int hostap_set_iface_flags(void *priv, int dev_up); + +static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len, + u16 stype) +{ + struct ieee80211_hdr *hdr; + u16 fc, ethertype; + u8 *pos, *sa; + size_t left; + struct sta_info *sta; + + if (len < sizeof(struct ieee80211_hdr)) + return; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) { + printf("Not ToDS data frame (fc=0x%04x)\n", fc); + return; + } + + sa = hdr->addr2; + sta = ap_get_sta(hapd, sa); + if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { + printf("Data frame from not associated STA " MACSTR "\n", + MAC2STR(sa)); + if (sta && (sta->flags & WLAN_STA_AUTH)) + hostapd_sta_disassoc( + hapd, sa, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + else + hostapd_sta_deauth( + hapd, sa, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + return; + } + + pos = (u8 *) (hdr + 1); + left = len - sizeof(*hdr); + + if (left < sizeof(rfc1042_header)) { + printf("Too short data frame\n"); + return; + } + + if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) { + printf("Data frame with no RFC1042 header\n"); + return; + } + pos += sizeof(rfc1042_header); + left -= sizeof(rfc1042_header); + + if (left < 2) { + printf("No ethertype in data frame\n"); + return; + } + + ethertype = WPA_GET_BE16(pos); + pos += 2; + left -= 2; + switch (ethertype) { + case ETH_P_PAE: + ieee802_1x_receive(hapd, sa, pos, left); + break; + + default: + printf("Unknown ethertype 0x%04x in data frame\n", ethertype); + break; + } +} + + +static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len, + int ok) +{ + struct ieee80211_hdr *hdr; + u16 fc, type, stype; + struct sta_info *sta; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + switch (type) { + case WLAN_FC_TYPE_MGMT: + wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s", + ok ? "ACK" : "fail"); + ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); + break; + case WLAN_FC_TYPE_CTRL: + wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s", + ok ? "ACK" : "fail"); + break; + case WLAN_FC_TYPE_DATA: + wpa_printf(MSG_DEBUG, "DATA (TX callback) %s", + ok ? "ACK" : "fail"); + sta = ap_get_sta(hapd, hdr->addr1); + if (sta && sta->flags & WLAN_STA_PENDING_POLL) { + wpa_printf(MSG_DEBUG, "STA " MACSTR + " %s pending activity poll", + MAC2STR(sta->addr), + ok ? "ACKed" : "did not ACK"); + if (ok) + sta->flags &= ~WLAN_STA_PENDING_POLL; + } + if (sta) + ieee802_1x_tx_status(hapd, sta, buf, len, ok); + break; + default: + printf("unknown TX callback frame type %d\n", type); + break; + } +} + + +static void handle_frame(struct hostapd_data *hapd, u8 *buf, size_t len) +{ + struct ieee80211_hdr *hdr; + u16 fc, extra_len, type, stype; + unsigned char *extra = NULL; + size_t data_len = len; + int ver; + + /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass + * these to user space */ + if (len < 24) { + wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)", + (unsigned long) len); + return; + } + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) { + wpa_hexdump(MSG_MSGDUMP, "Received management frame", + buf, len); + } + + ver = fc & WLAN_FC_PVER; + + /* protocol version 3 is reserved for indicating extra data after the + * payload, version 2 for indicating ACKed frame (TX callbacks), and + * version 1 for indicating failed frame (no ACK, TX callbacks) */ + if (ver == 3) { + u8 *pos = buf + len - 2; + extra_len = WPA_GET_LE16(pos); + printf("extra data in frame (elen=%d)\n", extra_len); + if ((size_t) extra_len + 2 > len) { + printf(" extra data overflow\n"); + return; + } + len -= extra_len + 2; + extra = buf + len; + } else if (ver == 1 || ver == 2) { + handle_tx_callback(hapd, buf, data_len, ver == 2 ? 1 : 0); + return; + } else if (ver != 0) { + printf("unknown protocol version %d\n", ver); + return; + } + + switch (type) { + case WLAN_FC_TYPE_MGMT: + if (stype != WLAN_FC_STYPE_BEACON) + wpa_printf(MSG_MSGDUMP, "MGMT"); + ieee802_11_mgmt(hapd, buf, data_len, stype, NULL); + break; + case WLAN_FC_TYPE_CTRL: + wpa_printf(MSG_DEBUG, "CTRL"); + break; + case WLAN_FC_TYPE_DATA: + wpa_printf(MSG_DEBUG, "DATA"); + handle_data(hapd, buf, data_len, stype); + break; + default: + wpa_printf(MSG_DEBUG, "unknown frame type %d", type); + break; + } +} + + +static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; + int len; + unsigned char buf[3000]; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + handle_frame(hapd, buf, len); +} + + +static int hostap_init_sockets(struct hostap_driver_data *drv) +{ + struct ifreq ifr; + struct sockaddr_ll addr; + + drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (drv->sock < 0) { + perror("socket[PF_PACKET,SOCK_RAW]"); + return -1; + } + + if (eloop_register_read_sock(drv->sock, handle_read, drv->hapd, NULL)) + { + printf("Could not register read socket\n"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); + if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { + perror("ioctl(SIOCGIFINDEX)"); + return -1; + } + + if (hostap_set_iface_flags(drv, 1)) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = ifr.ifr_ifindex; + wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", + addr.sll_ifindex); + + if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); + if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { + perror("ioctl(SIOCGIFHWADDR)"); + return -1; + } + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { + printf("Invalid HW-addr family 0x%04x\n", + ifr.ifr_hwaddr.sa_family); + return -1; + } + memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + return 0; +} + + +static int hostap_send_mgmt_frame(void *priv, const void *msg, size_t len, + int flags) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; + int res; + + /* Request TX callback */ + hdr->frame_control |= host_to_le16(BIT(1)); + res = send(drv->sock, msg, len, flags); + hdr->frame_control &= ~host_to_le16(BIT(1)); + + return res; +} + + +static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, const u8 *own_addr) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_hdr *hdr; + size_t len; + u8 *pos; + int res; + + len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + printf("malloc() failed for hostapd_send_data(len=%lu)\n", + (unsigned long) len); + return -1; + } + + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); + hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); + if (encrypt) + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); + memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); + memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + + pos = (u8 *) (hdr + 1); + memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); + pos += sizeof(rfc1042_header); + *((u16 *) pos) = htons(ETH_P_PAE); + pos += 2; + memcpy(pos, data, data_len); + + res = hostap_send_mgmt_frame(drv, (u8 *) hdr, len, 0); + free(hdr); + + if (res < 0) { + perror("hostapd_send_eapol: send"); + printf("hostapd_send_eapol - packet len: %lu - failed\n", + (unsigned long) len); + } + + return res; +} + + +static int hostap_sta_set_flags(void *priv, const u8 *addr, + int total_flags, int flags_or, int flags_and) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + param.u.set_flags_sta.flags_or = flags_or; + param.u.set_flags_sta.flags_and = flags_and; + return hostapd_ioctl(drv, ¶m, sizeof(param)); +} + + +static int hostap_set_iface_flags(void *priv, int dev_up) +{ + struct hostap_driver_data *drv = priv; + struct ifreq ifr; + + if (drv->ioctl_sock < 0) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface); + + if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { + perror("ioctl[SIOCGIFFLAGS]"); + return -1; + } + + if (dev_up) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; + + if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { + perror("ioctl[SIOCSIFFLAGS]"); + return -1; + } + + if (dev_up) { + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface); + ifr.ifr_mtu = HOSTAPD_MTU; + if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { + perror("ioctl[SIOCSIFMTU]"); + printf("Setting MTU failed - trying to survive with " + "current value\n"); + } + } + + return 0; +} + + +static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, + int len) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) param; + iwr.u.data.length = len; + + if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { + perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); + return -1; + } + + return 0; +} + + +static int hostap_set_encryption(const char *ifname, void *priv, + const char *alg, const u8 *addr, + int idx, const u8 *key, size_t key_len, + int txkey) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param *param; + u8 *buf; + size_t blen; + int ret = 0; + + blen = sizeof(*param) + key_len; + buf = os_zalloc(blen); + if (buf == NULL) + return -1; + + param = (struct prism2_hostapd_param *) buf; + param->cmd = PRISM2_SET_ENCRYPTION; + if (addr == NULL) + memset(param->sta_addr, 0xff, ETH_ALEN); + else + memcpy(param->sta_addr, addr, ETH_ALEN); + os_strlcpy((char *) param->u.crypt.alg, alg, + HOSTAP_CRYPT_ALG_NAME_LEN); + param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; + param->u.crypt.idx = idx; + param->u.crypt.key_len = key_len; + memcpy((u8 *) (param + 1), key, key_len); + + if (hostapd_ioctl(drv, param, blen)) { + printf("Failed to set encryption.\n"); + ret = -1; + } + free(buf); + + return ret; +} + + +static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, + int idx, u8 *seq) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param *param; + u8 *buf; + size_t blen; + int ret = 0; + + blen = sizeof(*param) + 32; + buf = os_zalloc(blen); + if (buf == NULL) + return -1; + + param = (struct prism2_hostapd_param *) buf; + param->cmd = PRISM2_GET_ENCRYPTION; + if (addr == NULL) + memset(param->sta_addr, 0xff, ETH_ALEN); + else + memcpy(param->sta_addr, addr, ETH_ALEN); + param->u.crypt.idx = idx; + + if (hostapd_ioctl(drv, param, blen)) { + printf("Failed to get encryption.\n"); + ret = -1; + } else { + memcpy(seq, param->u.crypt.seq, 8); + } + free(buf); + + return ret; +} + + +static int hostap_ioctl_prism2param(void *priv, int param, int value) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + int *i; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + i = (int *) iwr.u.name; + *i++ = param; + *i++ = value; + + if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { + perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); + return -1; + } + + return 0; +} + + +static int hostap_set_ieee8021x(const char *ifname, void *priv, int enabled) +{ + struct hostap_driver_data *drv = priv; + + /* enable kernel driver support for IEEE 802.1X */ + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) { + printf("Could not setup IEEE 802.1X support in kernel driver." + "\n"); + return -1; + } + + if (!enabled) + return 0; + + /* use host driver implementation of encryption to allow + * individual keys and passing plaintext EAPOL frames */ + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) || + hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) { + printf("Could not setup host-based encryption in kernel " + "driver.\n"); + return -1; + } + + return 0; +} + + +static int hostap_set_privacy(const char *ifname, void *priv, int enabled) +{ + struct hostap_drvier_data *drv = priv; + + return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, + enabled); +} + + +static int hostap_set_ssid(const char *ifname, void *priv, const u8 *buf, + int len) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.essid.flags = 1; /* SSID active */ + iwr.u.essid.pointer = (caddr_t) buf; + iwr.u.essid.length = len + 1; + + if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { + perror("ioctl[SIOCSIWESSID]"); + printf("len=%d\n", len); + return -1; + } + + return 0; +} + + +static int hostap_flush(void *priv) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_FLUSH; + return hostapd_ioctl(drv, ¶m, sizeof(param)); +} + + +static int hostap_read_sta_data(void *priv, + struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + char buf[1024], line[128], *pos; + FILE *f; + unsigned long val; + + memset(data, 0, sizeof(*data)); + snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR, + drv->iface, MAC2STR(addr)); + + f = fopen(buf, "r"); + if (!f) + return -1; + /* Need to read proc file with in one piece, so use large enough + * buffer. */ + setbuffer(f, buf, sizeof(buf)); + + while (fgets(line, sizeof(line), f)) { + pos = strchr(line, '='); + if (!pos) + continue; + *pos++ = '\0'; + val = strtoul(pos, NULL, 10); + if (strcmp(line, "rx_packets") == 0) + data->rx_packets = val; + else if (strcmp(line, "tx_packets") == 0) + data->tx_packets = val; + else if (strcmp(line, "rx_bytes") == 0) + data->rx_bytes = val; + else if (strcmp(line, "tx_bytes") == 0) + data->tx_bytes = val; + } + + fclose(f); + + return 0; +} + + +static int hostap_sta_add(const char *ifname, void *priv, const u8 *addr, + u16 aid, u16 capability, u8 *supp_rates, + size_t supp_rates_len, int flags, + u16 listen_interval) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + int tx_supp_rates = 0; + size_t i; + +#define WLAN_RATE_1M BIT(0) +#define WLAN_RATE_2M BIT(1) +#define WLAN_RATE_5M5 BIT(2) +#define WLAN_RATE_11M BIT(3) + + for (i = 0; i < supp_rates_len; i++) { + if ((supp_rates[i] & 0x7f) == 2) + tx_supp_rates |= WLAN_RATE_1M; + if ((supp_rates[i] & 0x7f) == 4) + tx_supp_rates |= WLAN_RATE_2M; + if ((supp_rates[i] & 0x7f) == 11) + tx_supp_rates |= WLAN_RATE_5M5; + if ((supp_rates[i] & 0x7f) == 22) + tx_supp_rates |= WLAN_RATE_11M; + } + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_ADD_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + param.u.add_sta.aid = aid; + param.u.add_sta.capability = capability; + param.u.add_sta.tx_supp_rates = tx_supp_rates; + return hostapd_ioctl(drv, ¶m, sizeof(param)); +} + + +static int hostap_sta_remove(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED); + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_REMOVE_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) { + printf("Could not remove station from kernel driver.\n"); + return -1; + } + return 0; +} + + +static int hostap_get_inact_sec(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) { + return -1; + } + + return param.u.get_info_sta.inactive_sec; +} + + +static int hostap_sta_clear_stats(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) { + return -1; + } + + return 0; +} + + +static int hostap_set_assoc_ap(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) + return -1; + + return 0; +} + + +static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv) +{ + struct prism2_hostapd_param *param; + int res; + size_t blen, elem_len; + + elem_len = drv->generic_ie_len + drv->wps_ie_len; + blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len; + if (blen < sizeof(*param)) + blen = sizeof(*param); + + param = os_zalloc(blen); + if (param == NULL) + return -1; + + param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; + param->u.generic_elem.len = elem_len; + if (drv->generic_ie) { + os_memcpy(param->u.generic_elem.data, drv->generic_ie, + drv->generic_ie_len); + } + if (drv->wps_ie) { + os_memcpy(¶m->u.generic_elem.data[drv->generic_ie_len], + drv->wps_ie, drv->wps_ie_len); + } + wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE", + param->u.generic_elem.data, elem_len); + res = hostapd_ioctl(drv, param, blen); + + os_free(param); + + return res; +} + + +static int hostap_set_generic_elem(const char *ifname, void *priv, + const u8 *elem, size_t elem_len) +{ + struct hostap_driver_data *drv = priv; + + os_free(drv->generic_ie); + drv->generic_ie = NULL; + drv->generic_ie_len = 0; + if (elem) { + drv->generic_ie = os_malloc(elem_len); + if (drv->generic_ie == NULL) + return -1; + os_memcpy(drv->generic_ie, elem, elem_len); + drv->generic_ie_len = elem_len; + } + + return hostapd_ioctl_set_generic_elem(drv); +} + + +static int hostap_set_wps_beacon_ie(const char *ifname, void *priv, + const u8 *ie, size_t len) +{ + /* Host AP driver supports only one set of extra IEs, so we need to + * use the ProbeResp IEs also for Beacon frames since they include more + * information. */ + return 0; +} + + +static int hostap_set_wps_probe_resp_ie(const char *ifname, void *priv, + const u8 *ie, size_t len) +{ + struct hostap_driver_data *drv = priv; + + os_free(drv->wps_ie); + drv->wps_ie = NULL; + drv->wps_ie_len = 0; + if (ie) { + drv->wps_ie = os_malloc(len); + if (drv->wps_ie == NULL) + return -1; + os_memcpy(drv->wps_ie, ie, len); + drv->wps_ie_len = len; + } + + return hostapd_ioctl_set_generic_elem(drv); +} + + +static void +hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv, + char *custom) +{ + wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); + + if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { + char *pos; + u8 addr[ETH_ALEN]; + pos = strstr(custom, "addr="); + if (pos == NULL) { + wpa_printf(MSG_DEBUG, + "MLME-MICHAELMICFAILURE.indication " + "without sender address ignored"); + return; + } + pos += 5; + if (hwaddr_aton(pos, addr) == 0) { + ieee80211_michael_mic_failure(drv->hapd, addr, 1); + } else { + wpa_printf(MSG_DEBUG, + "MLME-MICHAELMICFAILURE.indication " + "with invalid MAC address"); + } + } +} + + +static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv, + char *data, int len) +{ + struct iw_event iwe_buf, *iwe = &iwe_buf; + char *pos, *end, *custom, *buf; + + pos = data; + end = data + len; + + while (pos + IW_EV_LCP_LEN <= end) { + /* Event data may be unaligned, so make a local, aligned copy + * before processing. */ + memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); + wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", + iwe->cmd, iwe->len); + if (iwe->len <= IW_EV_LCP_LEN) + return; + + custom = pos + IW_EV_POINT_LEN; + if (drv->we_version > 18 && + (iwe->cmd == IWEVMICHAELMICFAILURE || + iwe->cmd == IWEVCUSTOM)) { + /* WE-19 removed the pointer from struct iw_point */ + char *dpos = (char *) &iwe_buf.u.data.length; + int dlen = dpos - (char *) &iwe_buf; + memcpy(dpos, pos + IW_EV_LCP_LEN, + sizeof(struct iw_event) - dlen); + } else { + memcpy(&iwe_buf, pos, sizeof(struct iw_event)); + custom += IW_EV_POINT_OFF; + } + + switch (iwe->cmd) { + case IWEVCUSTOM: + if (custom + iwe->u.data.length > end) + return; + buf = malloc(iwe->u.data.length + 1); + if (buf == NULL) + return; + memcpy(buf, custom, iwe->u.data.length); + buf[iwe->u.data.length] = '\0'; + hostapd_wireless_event_wireless_custom(drv, buf); + free(buf); + break; + } + + pos += iwe->len; + } +} + + +static void hostapd_wireless_event_rtm_newlink(struct hostap_driver_data *drv, + struct nlmsghdr *h, int len) +{ + struct ifinfomsg *ifi; + int attrlen, nlmsg_len, rta_len; + struct rtattr * attr; + + if (len < (int) sizeof(*ifi)) + return; + + ifi = NLMSG_DATA(h); + + /* TODO: use ifi->ifi_index to filter out wireless events from other + * interfaces */ + + nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); + + attrlen = h->nlmsg_len - nlmsg_len; + if (attrlen < 0) + return; + + attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + + rta_len = RTA_ALIGN(sizeof(struct rtattr)); + while (RTA_OK(attr, attrlen)) { + if (attr->rta_type == IFLA_WIRELESS) { + hostapd_wireless_event_wireless( + drv, ((char *) attr) + rta_len, + attr->rta_len - rta_len); + } + attr = RTA_NEXT(attr, attrlen); + } +} + + +static void hostapd_wireless_event_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + char buf[256]; + int left; + struct sockaddr_nl from; + socklen_t fromlen; + struct nlmsghdr *h; + struct hostap_driver_data *drv = eloop_ctx; + + fromlen = sizeof(from); + left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, + (struct sockaddr *) &from, &fromlen); + if (left < 0) { + if (errno != EINTR && errno != EAGAIN) + perror("recvfrom(netlink)"); + return; + } + + h = (struct nlmsghdr *) buf; + while (left >= (int) sizeof(*h)) { + int len, plen; + + len = h->nlmsg_len; + plen = len - sizeof(*h); + if (len > left || plen < 0) { + printf("Malformed netlink message: " + "len=%d left=%d plen=%d\n", + len, left, plen); + break; + } + + switch (h->nlmsg_type) { + case RTM_NEWLINK: + hostapd_wireless_event_rtm_newlink(drv, h, plen); + break; + } + + len = NLMSG_ALIGN(len); + left -= len; + h = (struct nlmsghdr *) ((char *) h + len); + } + + if (left > 0) { + printf("%d extra bytes in the end of netlink message\n", left); + } +} + + +static int hostap_get_we_version(struct hostap_driver_data *drv) +{ + struct iw_range *range; + struct iwreq iwr; + int minlen; + size_t buflen; + + drv->we_version = 0; + + /* + * Use larger buffer than struct iw_range in order to allow the + * structure to grow in the future. + */ + buflen = sizeof(struct iw_range) + 500; + range = os_zalloc(buflen); + if (range == NULL) + return -1; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) range; + iwr.u.data.length = buflen; + + minlen = ((char *) &range->enc_capa) - (char *) range + + sizeof(range->enc_capa); + + if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { + perror("ioctl[SIOCGIWRANGE]"); + free(range); + return -1; + } else if (iwr.u.data.length >= minlen && + range->we_version_compiled >= 18) { + wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " + "WE(source)=%d enc_capa=0x%x", + range->we_version_compiled, + range->we_version_source, + range->enc_capa); + drv->we_version = range->we_version_compiled; + } + + free(range); + return 0; +} + + +static int hostap_wireless_event_init(void *priv) +{ + struct hostap_driver_data *drv = priv; + int s; + struct sockaddr_nl local; + + hostap_get_we_version(drv); + + drv->wext_sock = -1; + + s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (s < 0) { + perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); + return -1; + } + + memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_groups = RTMGRP_LINK; + if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { + perror("bind(netlink)"); + close(s); + return -1; + } + + eloop_register_read_sock(s, hostapd_wireless_event_receive, drv, + NULL); + drv->wext_sock = s; + + return 0; +} + + +static void hostap_wireless_event_deinit(void *priv) +{ + struct hostap_driver_data *drv = priv; + if (drv->wext_sock < 0) + return; + eloop_unregister_read_sock(drv->wext_sock); + close(drv->wext_sock); +} + + +static void * hostap_init(struct hostapd_data *hapd) +{ + struct hostap_driver_data *drv; + + drv = os_zalloc(sizeof(struct hostap_driver_data)); + if (drv == NULL) { + printf("Could not allocate memory for hostapd driver data\n"); + return NULL; + } + + drv->hapd = hapd; + drv->ioctl_sock = drv->sock = -1; + memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); + + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->ioctl_sock < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + free(drv); + return NULL; + } + + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) { + printf("Could not enable hostapd mode for interface %s\n", + drv->iface); + close(drv->ioctl_sock); + free(drv); + return NULL; + } + + if (hostap_init_sockets(drv)) { + close(drv->ioctl_sock); + free(drv); + return NULL; + } + + return drv; +} + + +static void hostap_driver_deinit(void *priv) +{ + struct hostap_driver_data *drv = priv; + + (void) hostap_set_iface_flags(drv, 0); + (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0); + (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0); + + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + + if (drv->sock >= 0) + close(drv->sock); + + os_free(drv->generic_ie); + os_free(drv->wps_ie); + + free(drv); +} + + +static int hostap_sta_deauth(void *priv, const u8 *addr, int reason) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_mgmt mgmt; + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DEAUTH); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); + memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); + mgmt.u.deauth.reason_code = host_to_le16(reason); + return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth), 0); +} + + +static int hostap_sta_disassoc(void *priv, const u8 *addr, int reason) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_mgmt mgmt; + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DISASSOC); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); + memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); + mgmt.u.disassoc.reason_code = host_to_le16(reason); + return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + + sizeof(mgmt.u.disassoc), 0); +} + + +static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, + u16 *num_modes, + u16 *flags) +{ + struct hostapd_hw_modes *mode; + int i, clen, rlen; + const short chan2freq[14] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 + }; + + mode = os_zalloc(sizeof(struct hostapd_hw_modes)); + if (mode == NULL) + return NULL; + + *num_modes = 1; + *flags = 0; + + mode->mode = HOSTAPD_MODE_IEEE80211B; + mode->num_channels = 14; + mode->num_rates = 4; + + clen = mode->num_channels * sizeof(struct hostapd_channel_data); + rlen = mode->num_rates * sizeof(struct hostapd_rate_data); + + mode->channels = os_zalloc(clen); + mode->rates = os_zalloc(rlen); + if (mode->channels == NULL || mode->rates == NULL) { + hostapd_free_hw_features(mode, *num_modes); + return NULL; + } + + for (i = 0; i < 14; i++) { + mode->channels[i].chan = i + 1; + mode->channels[i].freq = chan2freq[i]; + /* TODO: Get allowed channel list from the driver */ + if (i >= 11) + mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; + } + + mode->rates[0].rate = 10; + mode->rates[0].flags = HOSTAPD_RATE_CCK; + mode->rates[1].rate = 20; + mode->rates[1].flags = HOSTAPD_RATE_CCK; + mode->rates[2].rate = 55; + mode->rates[2].flags = HOSTAPD_RATE_CCK; + mode->rates[3].rate = 110; + mode->rates[3].flags = HOSTAPD_RATE_CCK; + + return mode; +} + + +const struct wpa_driver_ops wpa_driver_hostap_ops = { + .name = "hostap", + .init = hostap_init, + .deinit = hostap_driver_deinit, + .wireless_event_init = hostap_wireless_event_init, + .wireless_event_deinit = hostap_wireless_event_deinit, + .set_ieee8021x = hostap_set_ieee8021x, + .set_privacy = hostap_set_privacy, + .set_encryption = hostap_set_encryption, + .get_seqnum = hostap_get_seqnum, + .flush = hostap_flush, + .set_generic_elem = hostap_set_generic_elem, + .read_sta_data = hostap_read_sta_data, + .send_eapol = hostap_send_eapol, + .sta_set_flags = hostap_sta_set_flags, + .sta_deauth = hostap_sta_deauth, + .sta_disassoc = hostap_sta_disassoc, + .sta_remove = hostap_sta_remove, + .set_ssid = hostap_set_ssid, + .send_mgmt_frame = hostap_send_mgmt_frame, + .set_assoc_ap = hostap_set_assoc_ap, + .sta_add = hostap_sta_add, + .get_inact_sec = hostap_get_inact_sec, + .sta_clear_stats = hostap_sta_clear_stats, + .get_hw_feature_data = hostap_get_hw_feature_data, + .set_wps_beacon_ie = hostap_set_wps_beacon_ie, + .set_wps_probe_resp_ie = hostap_set_wps_probe_resp_ie, +}; diff --git a/contrib/wpa/hostapd/driver_wired.c b/contrib/wpa/hostapd/driver_wired.c new file mode 100644 index 0000000..61cb667 --- /dev/null +++ b/contrib/wpa/hostapd/driver_wired.c @@ -0,0 +1,372 @@ +/* + * hostapd / Kernel driver communication for wired (Ethernet) drivers + * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004, Gunter Burchardt <tira@isx.de> + * + * 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 "includes.h" +#include <sys/ioctl.h> + +#ifdef USE_KERNEL_HEADERS +#include <asm/types.h> +#include <linux/if_packet.h> +#include <linux/if_ether.h> /* The L2 protocols */ +#include <linux/if_arp.h> +#include <linux/if.h> +#else /* USE_KERNEL_HEADERS */ +#include <net/if_arp.h> +#include <net/if.h> +#include <netpacket/packet.h> +#endif /* USE_KERNEL_HEADERS */ + +#include "hostapd.h" +#include "ieee802_1x.h" +#include "eloop.h" +#include "sta_info.h" +#include "driver.h" +#include "accounting.h" + + +struct wired_driver_data { + struct hostapd_data *hapd; + + int sock; /* raw packet socket for driver access */ + int dhcp_sock; /* socket for dhcp packets */ + int use_pae_group_addr; +}; + + +#define WIRED_EAPOL_MULTICAST_GROUP {0x01,0x80,0xc2,0x00,0x00,0x03} + + +/* TODO: detecting new devices should eventually be changed from using DHCP + * snooping to trigger on any packet from a new layer 2 MAC address, e.g., + * based on ebtables, etc. */ + +struct dhcp_message { + u_int8_t op; + u_int8_t htype; + u_int8_t hlen; + u_int8_t hops; + u_int32_t xid; + u_int16_t secs; + u_int16_t flags; + u_int32_t ciaddr; + u_int32_t yiaddr; + u_int32_t siaddr; + u_int32_t giaddr; + u_int8_t chaddr[16]; + u_int8_t sname[64]; + u_int8_t file[128]; + u_int32_t cookie; + u_int8_t options[308]; /* 312 - cookie */ +}; + + +static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr) +{ + struct sta_info *sta; + + sta = ap_get_sta(hapd, addr); + if (sta) + return; + + wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR + " - adding a new STA", MAC2STR(addr)); + sta = ap_sta_add(hapd, addr); + if (sta) { + hostapd_new_assoc_sta(hapd, sta, 0); + } else { + wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, + MAC2STR(addr)); + } +} + + +static void handle_data(struct hostapd_data *hapd, unsigned char *buf, + size_t len) +{ + struct ieee8023_hdr *hdr; + u8 *pos, *sa; + size_t left; + + /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, + * 2 byte ethertype */ + if (len < 14) { + wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", + (unsigned long) len); + return; + } + + hdr = (struct ieee8023_hdr *) buf; + + switch (ntohs(hdr->ethertype)) { + case ETH_P_PAE: + wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); + sa = hdr->src; + wired_possible_new_sta(hapd, sa); + + pos = (u8 *) (hdr + 1); + left = len - sizeof(*hdr); + + ieee802_1x_receive(hapd, sa, pos, left); + break; + + default: + wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", + ntohs(hdr->ethertype)); + break; + } +} + + +static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; + int len; + unsigned char buf[3000]; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + handle_data(hapd, buf, len); +} + + +static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; + int len; + unsigned char buf[3000]; + struct dhcp_message *msg; + u8 *mac_address; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + /* must contain at least dhcp_message->chaddr */ + if (len < 44) { + wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); + return; + } + + msg = (struct dhcp_message *) buf; + mac_address = (u8 *) &(msg->chaddr); + + wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, + MAC2STR(mac_address)); + + wired_possible_new_sta(hapd, mac_address); +} + + +static int wired_init_sockets(struct wired_driver_data *drv) +{ + struct hostapd_data *hapd = drv->hapd; + struct ifreq ifr; + struct sockaddr_ll addr; + struct sockaddr_in addr2; + struct packet_mreq mreq; + u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP; + int n = 1; + + drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); + if (drv->sock < 0) { + perror("socket[PF_PACKET,SOCK_RAW]"); + return -1; + } + + if (eloop_register_read_sock(drv->sock, handle_read, hapd, NULL)) { + printf("Could not register read socket\n"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name)); + if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { + perror("ioctl(SIOCGIFINDEX)"); + return -1; + } + + + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = ifr.ifr_ifindex; + wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", + addr.sll_ifindex); + + if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind"); + return -1; + } + + /* filter multicast address */ + memset(&mreq, 0, sizeof(mreq)); + mreq.mr_ifindex = ifr.ifr_ifindex; + mreq.mr_type = PACKET_MR_MULTICAST; + mreq.mr_alen = 6; + memcpy(mreq.mr_address, multicastgroup_eapol, mreq.mr_alen); + + if (setsockopt(drv->sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) < 0) { + perror("setsockopt[SOL_SOCKET,PACKET_ADD_MEMBERSHIP]"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name)); + if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { + perror("ioctl(SIOCGIFHWADDR)"); + return -1; + } + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { + printf("Invalid HW-addr family 0x%04x\n", + ifr.ifr_hwaddr.sa_family); + return -1; + } + memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + /* setup dhcp listen socket for sta detection */ + if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + perror("socket call failed for dhcp"); + return -1; + } + + if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL)) + { + printf("Could not register read socket\n"); + return -1; + } + + memset(&addr2, 0, sizeof(addr2)); + addr2.sin_family = AF_INET; + addr2.sin_port = htons(67); + addr2.sin_addr.s_addr = INADDR_ANY; + + if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, + sizeof(n)) == -1) { + perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); + return -1; + } + if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, + sizeof(n)) == -1) { + perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ); + if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, + (char *) &ifr, sizeof(ifr)) < 0) { + perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); + return -1; + } + + if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, + sizeof(struct sockaddr)) == -1) { + perror("bind"); + return -1; + } + + return 0; +} + + +static int wired_send_eapol(void *priv, const u8 *addr, + const u8 *data, size_t data_len, int encrypt, + const u8 *own_addr) +{ + struct wired_driver_data *drv = priv; + u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP; + struct ieee8023_hdr *hdr; + size_t len; + u8 *pos; + int res; + + len = sizeof(*hdr) + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + printf("malloc() failed for wired_send_eapol(len=%lu)\n", + (unsigned long) len); + return -1; + } + + memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, + ETH_ALEN); + memcpy(hdr->src, own_addr, ETH_ALEN); + hdr->ethertype = htons(ETH_P_PAE); + + pos = (u8 *) (hdr + 1); + memcpy(pos, data, data_len); + + res = send(drv->sock, (u8 *) hdr, len, 0); + free(hdr); + + if (res < 0) { + perror("wired_send_eapol: send"); + printf("wired_send_eapol - packet len: %lu - failed\n", + (unsigned long) len); + } + + return res; +} + + +static void * wired_driver_init(struct hostapd_data *hapd) +{ + struct wired_driver_data *drv; + + drv = os_zalloc(sizeof(struct wired_driver_data)); + if (drv == NULL) { + printf("Could not allocate memory for wired driver data\n"); + return NULL; + } + + drv->hapd = hapd; + drv->use_pae_group_addr = hapd->conf->use_pae_group_addr; + + if (wired_init_sockets(drv)) { + free(drv); + return NULL; + } + + return drv; +} + + +static void wired_driver_deinit(void *priv) +{ + struct wired_driver_data *drv = priv; + + if (drv->sock >= 0) + close(drv->sock); + + if (drv->dhcp_sock >= 0) + close(drv->dhcp_sock); + + free(drv); +} + + +const struct wpa_driver_ops wpa_driver_wired_ops = { + .name = "wired", + .init = wired_driver_init, + .deinit = wired_driver_deinit, + .send_eapol = wired_send_eapol, +}; diff --git a/contrib/wpa/hostapd/drivers.c b/contrib/wpa/hostapd/drivers.c index 3006190..bde6e60 100644 --- a/contrib/wpa/hostapd/drivers.c +++ b/contrib/wpa/hostapd/drivers.c @@ -27,6 +27,9 @@ extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */ #ifdef CONFIG_DRIVER_MADWIFI extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */ #endif /* CONFIG_DRIVER_MADWIFI */ +#ifdef CONFIG_DRIVER_ATHEROS +extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ +#endif /* CONFIG_DRIVER_ATHEROS */ #ifdef CONFIG_DRIVER_BSD extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ #endif /* CONFIG_DRIVER_BSD */ @@ -55,6 +58,9 @@ struct wpa_driver_ops *hostapd_drivers[] = #ifdef CONFIG_DRIVER_MADWIFI &wpa_driver_madwifi_ops, #endif /* CONFIG_DRIVER_MADWIFI */ +#ifdef CONFIG_DRIVER_ATHEROS + &wpa_driver_atheros_ops, +#endif /* CONFIG_DRIVER_ATHEROS */ #ifdef CONFIG_DRIVER_BSD &wpa_driver_bsd_ops, #endif /* CONFIG_DRIVER_BSD */ diff --git a/contrib/wpa/hostapd/hostapd.8 b/contrib/wpa/hostapd/hostapd.8 index 9258512..a67a1bc 100644 --- a/contrib/wpa/hostapd/hostapd.8 +++ b/contrib/wpa/hostapd/hostapd.8 @@ -3,7 +3,7 @@ hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator .SH SYNOPSIS .B hostapd -[-hdBKtv] [-P <PID file>] <configuration file(s)> +[\-hdBKtv] [\-P <PID file>] <configuration file(s)> .SH DESCRIPTION This manual page documents briefly the .B hostapd diff --git a/contrib/wpa/hostapd/hostapd.c b/contrib/wpa/hostapd/hostapd.c index 065a5fd..b1c5a2c 100644 --- a/contrib/wpa/hostapd/hostapd.c +++ b/contrib/wpa/hostapd/hostapd.c @@ -249,7 +249,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) accounting_sta_start(hapd, sta); - hostapd_wme_sta_config(hapd, sta); + hostapd_wmm_sta_config(hapd, sta); /* Start IEEE 802.1X authentication process for new stations */ ieee802_1x_new_station(hapd, sta); @@ -306,7 +306,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->rsn_preauth = conf->rsn_preauth; wconf->eapol_version = conf->eapol_version; wconf->peerkey = conf->peerkey; - wconf->wme_enabled = conf->wme_enabled; + wconf->wmm_enabled = conf->wmm_enabled; wconf->okc = conf->okc; #ifdef CONFIG_IEEE80211W wconf->ieee80211w = conf->ieee80211w; @@ -339,6 +339,7 @@ int hostapd_reload_config(struct hostapd_iface *iface) struct hostapd_data *hapd = iface->bss[0]; struct hostapd_config *newconf, *oldconf; struct wpa_auth_config wpa_auth_conf; + size_t j; newconf = hostapd_config_read(iface->config_fname); if (newconf == NULL) @@ -348,7 +349,8 @@ int hostapd_reload_config(struct hostapd_iface *iface) * Deauthenticate all stations since the new configuration may not * allow them to use the BSS anymore. */ - hostapd_flush_old_stations(hapd); + for (j = 0; j < iface->num_bss; j++) + hostapd_flush_old_stations(iface->bss[j]); /* TODO: update dynamic data based on changed configuration * items (e.g., open/close sockets, etc.) */ @@ -378,6 +380,16 @@ int hostapd_reload_config(struct hostapd_iface *iface) ieee802_11_set_beacon(hapd); + if (hapd->conf->ssid.ssid_set && + hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len)) { + wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); + /* try to continue */ + } + + if (hapd->conf->ieee802_1x || hapd->conf->wpa) + hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1); + hostapd_config_free(oldconf); wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); @@ -465,7 +477,7 @@ static void hostapd_dump_state(struct hostapd_data *hapd) (sta->flags & WLAN_STA_SHORT_PREAMBLE ? "[SHORT_PREAMBLE]" : ""), (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), - (sta->flags & WLAN_STA_WME ? "[WME]" : ""), + (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]" : ""), @@ -1308,6 +1320,13 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) } } + hostapd_flush_old_stations(hapd); + hostapd_set_privacy(hapd, 0); + + hostapd_broadcast_wep_clear(hapd); + if (hostapd_setup_encryption(hapd->conf->iface, hapd)) + return -1; + /* * Fetch the SSID from the system and use it or, * if one was specified in the config file, verify they @@ -1510,7 +1529,6 @@ static int setup_interface(struct hostapd_iface *iface) u8 *b = conf->bssid; int freq; size_t j; - int ret = 0; u8 *prev_addr; /* @@ -1582,9 +1600,6 @@ static int setup_interface(struct hostapd_iface *iface) } } - hostapd_flush_old_stations(hapd); - hostapd_set_privacy(hapd, 0); - if (hapd->iconf->channel) { freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel); wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " @@ -1601,12 +1616,7 @@ static int setup_interface(struct hostapd_iface *iface) } } - hostapd_broadcast_wep_clear(hapd); - if (hostapd_setup_encryption(hapd->conf->iface, hapd)) - return -1; - hostapd_set_beacon_int(hapd, hapd->iconf->beacon_int); - ieee802_11_set_beacon(hapd); if (hapd->iconf->rts_threshold > -1 && hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { @@ -1644,7 +1654,7 @@ static int setup_interface(struct hostapd_iface *iface) return -1; } - return ret; + return 0; } @@ -1867,7 +1877,7 @@ int main(int argc, char *argv[]) int ret = 1, k; size_t i, j; int c, debug = 0, daemonize = 0, tnc = 0; - const char *pid_file = NULL; + char *pid_file = NULL; hostapd_logger_register_cb(hostapd_logger_cb); @@ -1891,7 +1901,8 @@ int main(int argc, char *argv[]) wpa_debug_show_keys++; break; case 'P': - pid_file = optarg; + os_free(pid_file); + pid_file = os_rel2abs_path(optarg); break; case 't': wpa_debug_timestamp++; @@ -2026,6 +2037,7 @@ int main(int argc, char *argv[]) #endif /* EAP_SERVER */ os_daemonize_terminate(pid_file); + os_free(pid_file); return ret; } diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf index 0602cb0..703b646 100644 --- a/contrib/wpa/hostapd/hostapd.conf +++ b/contrib/wpa/hostapd/hostapd.conf @@ -245,14 +245,14 @@ ignore_broadcast_ssid=0 #tx_queue_beacon_cwmax=7 #tx_queue_beacon_burst=1.5 -# 802.1D Tag to AC mappings +# 802.1D Tag (= UP) to AC mappings # WMM specifies following mapping of data frames to different ACs. This mapping # can be configured using Linux QoS/tc and sch_pktpri.o module. # 802.1D Tag 802.1D Designation Access Category WMM Designation # 1 BK AC_BK Background # 2 - AC_BK Background # 0 BE AC_BE Best Effort -# 3 EE AC_VI Video +# 3 EE AC_BE Best Effort # 4 CL AC_VI Video # 5 VI AC_VI Video # 6 VO AC_VO Voice @@ -273,38 +273,38 @@ ignore_broadcast_ssid=0 # note - here cwMin and cmMax are in exponent form. the actual cw value used # will be (2^n)-1 where n is the value given here # -wme_enabled=1 +wmm_enabled=1 # # Low priority / AC_BK = background -wme_ac_bk_cwmin=4 -wme_ac_bk_cwmax=10 -wme_ac_bk_aifs=7 -wme_ac_bk_txop_limit=0 -wme_ac_bk_acm=0 +wmm_ac_bk_cwmin=4 +wmm_ac_bk_cwmax=10 +wmm_ac_bk_aifs=7 +wmm_ac_bk_txop_limit=0 +wmm_ac_bk_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=10 # # Normal priority / AC_BE = best effort -wme_ac_be_aifs=3 -wme_ac_be_cwmin=4 -wme_ac_be_cwmax=10 -wme_ac_be_txop_limit=0 -wme_ac_be_acm=0 +wmm_ac_be_aifs=3 +wmm_ac_be_cwmin=4 +wmm_ac_be_cwmax=10 +wmm_ac_be_txop_limit=0 +wmm_ac_be_acm=0 # Note: for IEEE 802.11b mode: cWmin=5 cWmax=7 # # High priority / AC_VI = video -wme_ac_vi_aifs=2 -wme_ac_vi_cwmin=3 -wme_ac_vi_cwmax=4 -wme_ac_vi_txop_limit=94 -wme_ac_vi_acm=0 +wmm_ac_vi_aifs=2 +wmm_ac_vi_cwmin=3 +wmm_ac_vi_cwmax=4 +wmm_ac_vi_txop_limit=94 +wmm_ac_vi_acm=0 # Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188 # # Highest priority / AC_VO = voice -wme_ac_vo_aifs=2 -wme_ac_vo_cwmin=2 -wme_ac_vo_cwmax=3 -wme_ac_vo_txop_limit=47 -wme_ac_vo_acm=0 +wmm_ac_vo_aifs=2 +wmm_ac_vo_cwmin=2 +wmm_ac_vo_cwmax=3 +wmm_ac_vo_txop_limit=47 +wmm_ac_vo_acm=0 # Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 # Static WEP key configuration @@ -375,6 +375,7 @@ wme_ac_vo_acm=0 # ieee80211n: Whether IEEE 802.11n (HT) is enabled # 0 = disabled (default) # 1 = enabled +# Note: You will also need to enable WMM for full HT functionality. #ieee80211n=1 # ht_capab: HT capabilities (list of flags) diff --git a/contrib/wpa/hostapd/hostapd_cli.1 b/contrib/wpa/hostapd/hostapd_cli.1 index 8d6587f..2fe4907 100644 --- a/contrib/wpa/hostapd/hostapd_cli.1 +++ b/contrib/wpa/hostapd/hostapd_cli.1 @@ -3,7 +3,7 @@ hostapd_cli \- hostapd command-line interface .SH SYNOPSIS .B hostapd_cli -[-p<path>] [-i<ifname>] [-hv] [command..] +[\-p<path>] [\-i<ifname>] [\-hv] [command..] .SH DESCRIPTION This manual page documents briefly the .B hostapd_cli diff --git a/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c index 2614113..c2ecd4e 100644 --- a/contrib/wpa/hostapd/hostapd_cli.c +++ b/contrib/wpa/hostapd/hostapd_cli.c @@ -87,7 +87,7 @@ static const char *commands_help = " sa_query <addr> send SA Query to a station\n" #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS -" wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n" +" wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n" " wps_pbc indicate button pushed to initiate PBC\n" #endif /* CONFIG_WPS */ " help show this usage help\n" @@ -260,12 +260,16 @@ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char buf[64]; - if (argc != 2) { - printf("Invalid 'wps_pin' command - exactly two arguments, " + if (argc < 2) { + printf("Invalid 'wps_pin' command - at least two arguments, " "UUID and PIN, are required.\n"); return -1; } - snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); + if (argc > 2) + snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", + argv[0], argv[1], argv[2]); + else + snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); return wpa_ctrl_command(ctrl, buf); } diff --git a/contrib/wpa/hostapd/hw_features.c b/contrib/wpa/hostapd/hw_features.c index f1288e0..1d6299e 100644 --- a/contrib/wpa/hostapd/hw_features.c +++ b/contrib/wpa/hostapd/hw_features.c @@ -382,6 +382,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) break; } } + if (iface->conf->channel == 0) { + /* TODO: could request a scan of neighboring BSSes and select + * the channel automatically */ + wpa_printf(MSG_ERROR, "Channel not configured " + "(hw_mode/channel in hostapd.conf)"); + return -1; + } if (ok == 0 && iface->conf->channel != 0) { hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, diff --git a/contrib/wpa/hostapd/ieee802_11.c b/contrib/wpa/hostapd/ieee802_11.c index 8399d88..70491b4 100644 --- a/contrib/wpa/hostapd/ieee802_11.c +++ b/contrib/wpa/hostapd/ieee802_11.c @@ -384,8 +384,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, r = random(); os_memcpy(key, &now, 4); os_memcpy(key + 4, &r, 4); - rc4(sta->challenge, WLAN_AUTH_CHALLENGE_LEN, - key, sizeof(key)); + rc4_skip(key, sizeof(key), 0, + sta->challenge, WLAN_AUTH_CHALLENGE_LEN); } return 0; } @@ -585,7 +585,7 @@ static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, if (vlan_id > 0) { if (hostapd_get_vlan_id_ifname(hapd->conf->vlan, - sta->vlan_id) == NULL) { + vlan_id) == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "Invalid VLAN ID " "%d received from RADIUS server", @@ -766,16 +766,16 @@ static void handle_assoc(struct hostapd_data *hapd, goto fail; } - sta->flags &= ~WLAN_STA_WME; - if (elems.wme && hapd->conf->wme_enabled) { - if (hostapd_eid_wme_valid(hapd, elems.wme, elems.wme_len)) + sta->flags &= ~WLAN_STA_WMM; + if (elems.wmm && hapd->conf->wmm_enabled) { + if (hostapd_eid_wmm_valid(hapd, elems.wmm, elems.wmm_len)) hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, - "invalid WME element in association " + "invalid WMM element in association " "request"); else - sta->flags |= WLAN_STA_WME; + sta->flags |= WLAN_STA_WMM; } if (!elems.supp_rates) { @@ -1124,8 +1124,8 @@ static void handle_assoc(struct hostapd_data *hapd, p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable); /* Extended supported rates */ p = hostapd_eid_ext_supp_rates(hapd, p); - if (sta->flags & WLAN_STA_WME) - p = hostapd_eid_wme(hapd, p); + if (sta->flags & WLAN_STA_WMM) + p = hostapd_eid_wmm(hapd, p); p = hostapd_eid_ht_capabilities_info(hapd, p); p = hostapd_eid_ht_operation(hapd, p); @@ -1265,6 +1265,11 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, struct ieee80211_mgmt mgmt; u8 *end; + wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " + MACSTR, MAC2STR(addr)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + trans_id, WLAN_SA_QUERY_TR_ID_LEN); + os_memset(&mgmt, 0, sizeof(mgmt)); mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); @@ -1302,6 +1307,12 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, return; } + wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " + MACSTR, MAC2STR(mgmt->sa)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + mgmt->u.action.u.sa_query_resp.trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + /* MLME-SAQuery.confirm */ sta = ap_get_sta(hapd, mgmt->sa); @@ -1330,12 +1341,21 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, "Reply to pending SA Query received"); ap_sta_stop_sa_query(hapd, sta); } + + +static int robust_action_frame(u8 category) +{ + return category != WLAN_ACTION_PUBLIC && + category != WLAN_ACTION_HT; +} #endif /* CONFIG_IEEE80211W */ static void handle_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, size_t len) { + struct sta_info *sta; + if (len < IEEE80211_HDRLEN + 1) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -1344,13 +1364,23 @@ static void handle_action(struct hostapd_data *hapd, return; } + sta = ap_get_sta(hapd, mgmt->sa); +#ifdef CONFIG_IEEE80211W + if (sta && (sta->flags & WLAN_STA_MFP) && + !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) && + robust_action_frame(mgmt->u.action.category))) { + hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "Dropped unprotected Robust Action frame from " + "an MFP STA"); + return; + } +#endif /* CONFIG_IEEE80211W */ + switch (mgmt->u.action.category) { #ifdef CONFIG_IEEE80211R case WLAN_ACTION_FT: { - struct sta_info *sta; - - sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action " "frame from unassociated STA " MACSTR, @@ -1366,7 +1396,7 @@ static void handle_action(struct hostapd_data *hapd, } #endif /* CONFIG_IEEE80211R */ case WLAN_ACTION_WMM: - hostapd_wme_action(hapd, mgmt, len); + hostapd_wmm_action(hapd, mgmt, len); return; #ifdef CONFIG_IEEE80211W case WLAN_ACTION_SA_QUERY: @@ -1527,6 +1557,26 @@ static void handle_auth_cb(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211N +static void +hostapd_get_ht_capab(struct hostapd_data *hapd, + struct ht_cap_ie *ht_cap_ie, + struct ht_cap_ie *neg_ht_cap_ie) +{ + u16 cap; + + os_memcpy(neg_ht_cap_ie, ht_cap_ie, sizeof(struct ht_cap_ie)); + cap = le_to_host16(neg_ht_cap_ie->data.capabilities_info); + cap &= hapd->iconf->ht_capab; + cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED); + + /* FIXME: Rx STBC needs to be handled specially */ + cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK); + neg_ht_cap_ie->data.capabilities_info = host_to_le16(cap); +} +#endif /* CONFIG_IEEE80211N */ + + static void handle_assoc_cb(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int ok) @@ -1534,7 +1584,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, u16 status; struct sta_info *sta; int new_assoc = 1; - struct ht_cap_ie *ht_cap = NULL; +#ifdef CONFIG_IEEE80211N + struct ht_cap_ie ht_cap; +#endif /* CONFIG_IEEE80211N */ + struct ht_cap_ie *ht_cap_ptr = NULL; + int set_flags, flags_and, flags_or; if (!ok) { hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, @@ -1584,18 +1638,27 @@ static void handle_assoc_cb(struct hostapd_data *hapd, mlme_associate_indication(hapd, sta); #ifdef CONFIG_IEEE80211N - if (sta->flags & WLAN_STA_HT) - ht_cap = &sta->ht_capabilities; + if (sta->flags & WLAN_STA_HT) { + ht_cap_ptr = &ht_cap; + hostapd_get_ht_capab(hapd, &sta->ht_capabilities, ht_cap_ptr); + } #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211W sta->sa_query_timed_out = 0; #endif /* CONFIG_IEEE80211W */ + /* + * Remove the STA entry in order to make sure the STA PS state gets + * cleared and configuration gets updated in case of reassociation back + * to the same AP. + */ + hostapd_sta_remove(hapd, sta->addr); + if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid, sta->capability, sta->supported_rates, sta->supported_rates_len, 0, sta->listen_interval, - ht_cap)) + ht_cap_ptr)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, @@ -1613,13 +1676,15 @@ static void handle_assoc_cb(struct hostapd_data *hapd, /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ ap_sta_bind_vlan(hapd, sta, 0); } - if (sta->flags & WLAN_STA_SHORT_PREAMBLE) { - hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - WLAN_STA_SHORT_PREAMBLE, ~0); - } else { - hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - 0, ~WLAN_STA_SHORT_PREAMBLE); - } + + set_flags = WLAN_STA_SHORT_PREAMBLE | WLAN_STA_WMM | WLAN_STA_MFP; + if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && + sta->flags & WLAN_STA_AUTHORIZED) + set_flags |= WLAN_STA_AUTHORIZED; + flags_or = sta->flags & set_flags; + flags_and = sta->flags | ~set_flags; + hostapd_sta_set_flags(hapd, sta->addr, sta->flags, + flags_or, flags_and); if (sta->auth_alg == WLAN_AUTH_FT) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); diff --git a/contrib/wpa/hostapd/ieee802_1x.c b/contrib/wpa/hostapd/ieee802_1x.c index 9b096d4..7fd8028 100644 --- a/contrib/wpa/hostapd/ieee802_1x.c +++ b/contrib/wpa/hostapd/ieee802_1x.c @@ -164,7 +164,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, } os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); - rc4((u8 *) (key + 1), key_len, ekey, ekey_len); + rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); os_free(ekey); /* This header is needed here for HMAC-MD5, but it will be regenerated diff --git a/contrib/wpa/hostapd/preauth.c b/contrib/wpa/hostapd/preauth.c index 36af4e3..9ab41ed 100644 --- a/contrib/wpa/hostapd/preauth.c +++ b/contrib/wpa/hostapd/preauth.c @@ -171,6 +171,7 @@ int rsn_preauth_iface_init(struct hostapd_data *hapd) if (rsn_preauth_iface_add(hapd, start)) { rsn_preauth_iface_deinit(hapd); + os_free(tmp); return -1; } diff --git a/contrib/wpa/hostapd/radiotap.c b/contrib/wpa/hostapd/radiotap.c new file mode 100644 index 0000000..804473f --- /dev/null +++ b/contrib/wpa/hostapd/radiotap.c @@ -0,0 +1,287 @@ +/* + * Radiotap parser + * + * Copyright 2007 Andy Green <andy@warmcat.com> + * + * 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. + * + * + * Modified for userspace by Johannes Berg <johannes@sipsolutions.net> + * I only modified some things on top to ease syncing should bugs be found. + */ + +#include "includes.h" + +#include "common.h" +#include "radiotap_iter.h" + +#define le16_to_cpu le_to_host16 +#define le32_to_cpu le_to_host32 +#define __le32 uint32_t +#define ulong unsigned long +#define unlikely(cond) (cond) +#define get_unaligned(p) \ +({ \ + struct packed_dummy_struct { \ + typeof(*(p)) __val; \ + } __attribute__((packed)) *__ptr = (void *) (p); \ + \ + __ptr->__val; \ +}) + +/* function prototypes and related defs are in radiotap_iter.h */ + +/** + * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization + * @iterator: radiotap_iterator to initialize + * @radiotap_header: radiotap header to parse + * @max_length: total length we can parse into (eg, whole packet length) + * + * Returns: 0 or a negative error code if there is a problem. + * + * This function initializes an opaque iterator struct which can then + * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap + * argument which is present in the header. It knows about extended + * present headers and handles them. + * + * How to use: + * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator + * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) + * checking for a good 0 return code. Then loop calling + * __ieee80211_radiotap_iterator_next()... it returns either 0, + * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. + * The iterator's @this_arg member points to the start of the argument + * associated with the current argument index that is present, which can be + * found in the iterator's @this_arg_index member. This arg index corresponds + * to the IEEE80211_RADIOTAP_... defines. + * + * Radiotap header length: + * You can find the CPU-endian total radiotap header length in + * iterator->max_length after executing ieee80211_radiotap_iterator_init() + * successfully. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + * + * Example code: + * See Documentation/networking/radiotap-headers.txt + */ + +int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length) +{ + /* Linux only supports version 0 radiotap format */ + if (radiotap_header->it_version) + return -EINVAL; + + /* sanity check for allowed length and radiotap length field */ + if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) + return -EINVAL; + + iterator->rtheader = radiotap_header; + iterator->max_length = le16_to_cpu(get_unaligned( + &radiotap_header->it_len)); + iterator->arg_index = 0; + iterator->bitmap_shifter = le32_to_cpu(get_unaligned( + &radiotap_header->it_present)); + iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); + iterator->this_arg = NULL; + + /* find payload start allowing for extended bitmap(s) */ + + if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { + while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & + (1<<IEEE80211_RADIOTAP_EXT)) { + iterator->arg += sizeof(u32); + + /* + * check for insanity where the present bitmaps + * keep claiming to extend up to or even beyond the + * stated radiotap header length + */ + + if (((ulong)iterator->arg - (ulong)iterator->rtheader) + > (ulong)iterator->max_length) + return -EINVAL; + } + + iterator->arg += sizeof(u32); + + /* + * no need to check again for blowing past stated radiotap + * header length, because ieee80211_radiotap_iterator_next + * checks it before it is dereferenced + */ + } + + /* we are all initialized happily */ + + return 0; +} + + +/** + * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg + * @iterator: radiotap_iterator to move to next arg (if any) + * + * Returns: 0 if there is an argument to handle, + * -ENOENT if there are no more args or -EINVAL + * if there is something else wrong. + * + * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) + * in @this_arg_index and sets @this_arg to point to the + * payload for the field. It takes care of alignment handling and extended + * present fields. @this_arg can be changed by the caller (eg, + * incremented to move inside a compound argument like + * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in + * little-endian format whatever the endianess of your CPU. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + */ + +int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator) +{ + + /* + * small length lookup table for all radiotap types we heard of + * starting from b0 in the bitmap, so we can walk the payload + * area of the radiotap header + * + * There is a requirement to pad args, so that args + * of a given length must begin at a boundary of that length + * -- but note that compound args are allowed (eg, 2 x u16 + * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not + * a reliable indicator of alignment requirement. + * + * upper nybble: content alignment for arg + * lower nybble: content length for arg + */ + + static const u8 rt_sizes[] = { + [IEEE80211_RADIOTAP_TSFT] = 0x88, + [IEEE80211_RADIOTAP_FLAGS] = 0x11, + [IEEE80211_RADIOTAP_RATE] = 0x11, + [IEEE80211_RADIOTAP_CHANNEL] = 0x24, + [IEEE80211_RADIOTAP_FHSS] = 0x22, + [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, + [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, + [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, + [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, + [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, + [IEEE80211_RADIOTAP_ANTENNA] = 0x11, + [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, + [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, + [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, + [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, + [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, + /* + * add more here as they are defined in + * include/net/ieee80211_radiotap.h + */ + }; + + /* + * for every radiotap entry we can at + * least skip (by knowing the length)... + */ + + while (iterator->arg_index < (int) sizeof(rt_sizes)) { + int hit = 0; + int pad; + + if (!(iterator->bitmap_shifter & 1)) + goto next_entry; /* arg not present */ + + /* + * arg is present, account for alignment padding + * 8-bit args can be at any alignment + * 16-bit args must start on 16-bit boundary + * 32-bit args must start on 32-bit boundary + * 64-bit args must start on 64-bit boundary + * + * note that total arg size can differ from alignment of + * elements inside arg, so we use upper nybble of length + * table to base alignment on + * + * also note: these alignments are ** relative to the + * start of the radiotap header **. There is no guarantee + * that the radiotap header itself is aligned on any + * kind of boundary. + * + * the above is why get_unaligned() is used to dereference + * multibyte elements from the radiotap area + */ + + pad = (((ulong)iterator->arg) - + ((ulong)iterator->rtheader)) & + ((rt_sizes[iterator->arg_index] >> 4) - 1); + + if (pad) + iterator->arg += + (rt_sizes[iterator->arg_index] >> 4) - pad; + + /* + * this is what we will return to user, but we need to + * move on first so next call has something fresh to test + */ + iterator->this_arg_index = iterator->arg_index; + iterator->this_arg = iterator->arg; + hit = 1; + + /* internally move on the size of this arg */ + iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; + + /* + * check for insanity where we are given a bitmap that + * claims to have more arg content than the length of the + * radiotap section. We will normally end up equalling this + * max_length on the last arg, never exceeding it. + */ + + if (((ulong)iterator->arg - (ulong)iterator->rtheader) > + (ulong) iterator->max_length) + return -EINVAL; + + next_entry: + iterator->arg_index++; + if (unlikely((iterator->arg_index & 31) == 0)) { + /* completed current u32 bitmap */ + if (iterator->bitmap_shifter & 1) { + /* b31 was set, there is more */ + /* move to next u32 bitmap */ + iterator->bitmap_shifter = le32_to_cpu( + get_unaligned(iterator->next_bitmap)); + iterator->next_bitmap++; + } else + /* no more bitmaps: end */ + iterator->arg_index = sizeof(rt_sizes); + } else /* just try the next bit */ + iterator->bitmap_shifter >>= 1; + + /* if we found a valid arg earlier, return it now */ + if (hit) + return 0; + } + + /* we don't know how to handle any more args, we're done */ + return -ENOENT; +} diff --git a/contrib/wpa/hostapd/radiotap.h b/contrib/wpa/hostapd/radiotap.h new file mode 100644 index 0000000..508264c --- /dev/null +++ b/contrib/wpa/hostapd/radiotap.h @@ -0,0 +1,242 @@ +/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ +/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ + +/*- + * Copyright (c) 2003, 2004 David Young. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of David Young may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID + * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * Modifications to fit into the linux IEEE 802.11 stack, + * Mike Kershaw (dragorn@kismetwireless.net) + */ + +#ifndef IEEE80211RADIOTAP_H +#define IEEE80211RADIOTAP_H + +#include <stdint.h> + +/* Base version of the radiotap packet header data */ +#define PKTHDR_RADIOTAP_VERSION 0 + +/* A generic radio capture format is desirable. There is one for + * Linux, but it is neither rigidly defined (there were not even + * units given for some fields) nor easily extensible. + * + * I suggest the following extensible radio capture format. It is + * based on a bitmap indicating which fields are present. + * + * I am trying to describe precisely what the application programmer + * should expect in the following, and for that reason I tell the + * units and origin of each measurement (where it applies), or else I + * use sufficiently weaselly language ("is a monotonically nondecreasing + * function of...") that I cannot set false expectations for lawyerly + * readers. + */ + +/* The radio capture header precedes the 802.11 header. + * All data in the header is little endian on all platforms. + */ +struct ieee80211_radiotap_header { + uint8_t it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + uint8_t it_pad; + uint16_t it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + uint32_t it_present; /* A bitmap telling which + * fields are present. Set bit 31 + * (0x80000000) to extend the + * bitmap by another 32 bits. + * Additional extensions are made + * by setting bit 31. + */ +}; + +/* Name Data type Units + * ---- --------- ----- + * + * IEEE80211_RADIOTAP_TSFT __le64 microseconds + * + * Value in microseconds of the MAC's 64-bit 802.11 Time + * Synchronization Function timer when the first bit of the + * MPDU arrived at the MAC. For received frames, only. + * + * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + * + * IEEE80211_RADIOTAP_FHSS uint16_t see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + * + * IEEE80211_RADIOTAP_RATE u8 500kb/s + * + * Tx/Rx data rate + * + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + * + * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + * + * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + * + * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + * + * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless + * + * Quality of Barker code lock. Unitless. Monotonically + * nondecreasing with "better" lock strength. Called "Signal + * Quality" in datasheets. (Is there a standard way to measure + * this?) + * + * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless + * + * Transmit power expressed as unitless distance from max + * power set at factory calibration. 0 is max power. + * Monotonically nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) + * + * Transmit power expressed as decibel distance from max power + * set at factory calibration. 0 is max power. Monotonically + * nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from + * one milliwatt (dBm) + * + * Transmit power expressed as dBm (decibels from a 1 milliwatt + * reference). This is the absolute power level measured at + * the antenna port. + * + * IEEE80211_RADIOTAP_FLAGS u8 bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + * + * IEEE80211_RADIOTAP_ANTENNA u8 antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + * + * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap + * + * Properties of transmitted frames. See flags defined below. + * + * IEEE80211_RADIOTAP_RTS_RETRIES u8 data + * + * Number of rts retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_DATA_RETRIES u8 data + * + * Number of unicast retries a transmitted frame used. + * + */ +enum ieee80211_radiotap_type { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + IEEE80211_RADIOTAP_EXT = 31 +}; + +/* Channel flags. */ +#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ + +/* For IEEE80211_RADIOTAP_FLAGS */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received + * during CFP + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received + * with short + * preamble + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received + * with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received + * with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between + * 802.11 header and payload + * (to 32-bit boundary) + */ +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ + +/* For IEEE80211_RADIOTAP_TX_FLAGS */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive + * retries */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ + +#endif /* IEEE80211_RADIOTAP_H */ diff --git a/contrib/wpa/hostapd/radiotap_iter.h b/contrib/wpa/hostapd/radiotap_iter.h new file mode 100644 index 0000000..92a798a --- /dev/null +++ b/contrib/wpa/hostapd/radiotap_iter.h @@ -0,0 +1,41 @@ +#ifndef __RADIOTAP_ITER_H +#define __RADIOTAP_ITER_H + +#include "radiotap.h" + +/* Radiotap header iteration + * implemented in radiotap.c + */ +/** + * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args + * @rtheader: pointer to the radiotap header we are walking through + * @max_length: length of radiotap header in cpu byte ordering + * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg + * @this_arg: pointer to current radiotap arg + * @arg_index: internal next argument index + * @arg: internal next argument pointer + * @next_bitmap: internal pointer to next present u32 + * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + */ + +struct ieee80211_radiotap_iterator { + struct ieee80211_radiotap_header *rtheader; + int max_length; + int this_arg_index; + unsigned char *this_arg; + + int arg_index; + unsigned char *arg; + uint32_t *next_bitmap; + uint32_t bitmap_shifter; +}; + +extern int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length); + +extern int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator); + +#endif /* __RADIOTAP_ITER_H */ diff --git a/contrib/wpa/hostapd/wme.c b/contrib/wpa/hostapd/wme.c index 727ee7e..f2bbbd9 100644 --- a/contrib/wpa/hostapd/wme.c +++ b/contrib/wpa/hostapd/wme.c @@ -24,47 +24,63 @@ /* TODO: maintain separate sequence and fragment numbers for each AC * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA - * if only WME stations are receiving a certain group */ + * if only WMM stations are receiving a certain group */ -static u8 wme_oui[3] = { 0x00, 0x50, 0xf2 }; +static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci) +{ + u8 ret; + ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK; + if (acm) + ret |= WMM_AC_ACM; + ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK; + return ret; +} + + +static inline u8 wmm_ecw(int ecwmin, int ecwmax) +{ + return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) | + ((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK); +} -/* Add WME Parameter Element to Beacon and Probe Response frames. */ -u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid) +/* + * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association + * Response frames. + */ +u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) { u8 *pos = eid; - struct wme_parameter_element *wme = - (struct wme_parameter_element *) (pos + 2); + struct wmm_parameter_element *wmm = + (struct wmm_parameter_element *) (pos + 2); int e; - if (!hapd->conf->wme_enabled) + if (!hapd->conf->wmm_enabled) return eid; eid[0] = WLAN_EID_VENDOR_SPECIFIC; - wme->oui[0] = 0x00; - wme->oui[1] = 0x50; - wme->oui[2] = 0xf2; - wme->oui_type = WME_OUI_TYPE; - wme->oui_subtype = WME_OUI_SUBTYPE_PARAMETER_ELEMENT; - wme->version = WME_VERSION; - wme->acInfo = hapd->parameter_set_count & 0xf; + wmm->oui[0] = 0x00; + wmm->oui[1] = 0x50; + wmm->oui[2] = 0xf2; + wmm->oui_type = WMM_OUI_TYPE; + wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT; + wmm->version = WMM_VERSION; + wmm->qos_info = hapd->parameter_set_count & 0xf; /* fill in a parameter set record for each AC */ for (e = 0; e < 4; e++) { - struct wme_ac_parameter *ac = &wme->ac[e]; - struct hostapd_wme_ac_params *acp = - &hapd->iconf->wme_ac_params[e]; - - ac->aifsn = acp->aifs; - ac->acm = acp->admission_control_mandatory; - ac->aci = e; - ac->reserved = 0; - ac->eCWmin = acp->cwmin; - ac->eCWmax = acp->cwmax; - ac->txopLimit = host_to_le16(acp->txopLimit); + struct wmm_ac_parameter *ac = &wmm->ac[e]; + struct hostapd_wmm_ac_params *acp = + &hapd->iconf->wmm_ac_params[e]; + + ac->aci_aifsn = wmm_aci_aifsn(acp->aifs, + acp->admission_control_mandatory, + e); + ac->cw = wmm_ecw(acp->cwmin, acp->cwmax); + ac->txop_limit = host_to_le16(acp->txop_limit); } - pos = (u8 *) (wme + 1); + pos = (u8 *) (wmm + 1); eid[1] = pos - eid - 2; /* element length */ return pos; @@ -72,31 +88,28 @@ u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid) /* This function is called when a station sends an association request with - * WME info element. The function returns zero on success or non-zero on any - * error in WME element. eid does not include Element ID and Length octets. */ -int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len) + * WMM info element. The function returns zero on success or non-zero on any + * error in WMM element. eid does not include Element ID and Length octets. */ +int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len) { - struct wme_information_element *wme; + struct wmm_information_element *wmm; - wpa_hexdump(MSG_MSGDUMP, "WME IE", eid, len); + wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len); - if (len < sizeof(struct wme_information_element)) { - wpa_printf(MSG_DEBUG, "Too short WME IE (len=%lu)", + if (len < sizeof(struct wmm_information_element)) { + wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)", (unsigned long) len); return -1; } - wme = (struct wme_information_element *) eid; - wpa_printf(MSG_DEBUG, "Validating WME IE: OUI %02x:%02x:%02x " - "OUI type %d OUI sub-type %d version %d", - wme->oui[0], wme->oui[1], wme->oui[2], wme->oui_type, - wme->oui_subtype, wme->version); - if (os_memcmp(wme->oui, wme_oui, sizeof(wme_oui)) != 0 || - wme->oui_type != WME_OUI_TYPE || - wme->oui_subtype != WME_OUI_SUBTYPE_INFORMATION_ELEMENT || - wme->version != WME_VERSION) { - wpa_printf(MSG_DEBUG, "Unsupported WME IE OUI/Type/Subtype/" - "Version"); + wmm = (struct wmm_information_element *) eid; + wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x " + "OUI type %d OUI sub-type %d version %d QoS info 0x%x", + wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type, + wmm->oui_subtype, wmm->version, wmm->qos_info); + if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT || + wmm->version != WMM_VERSION) { + wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version"); return -1; } @@ -105,31 +118,30 @@ int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len) /* This function is called when a station sends an ACK frame for an AssocResp - * frame (status=success) and the matching AssocReq contained a WME element. + * frame (status=success) and the matching AssocReq contained a WMM element. */ -int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta) +int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta) { - /* update kernel STA data for WME related items (WLAN_STA_WPA flag) */ - if (sta->flags & WLAN_STA_WME) + /* update kernel STA data for WMM related items (WLAN_STA_WPA flag) */ + if (sta->flags & WLAN_STA_WMM) hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - WLAN_STA_WME, ~0); + WLAN_STA_WMM, ~0); else hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - 0, ~WLAN_STA_WME); + 0, ~WLAN_STA_WMM); return 0; } -static void wme_send_action(struct hostapd_data *hapd, const u8 *addr, - const struct wme_tspec_info_element *tspec, +static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, + const struct wmm_tspec_element *tspec, u8 action_code, u8 dialogue_token, u8 status_code) { u8 buf[256]; struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf; - struct wme_tspec_info_element *t = - (struct wme_tspec_info_element *) - m->u.action.u.wme_action.variable; + struct wmm_tspec_element *t = (struct wmm_tspec_element *) + m->u.action.u.wmm_action.variable; int len; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, @@ -142,55 +154,117 @@ static void wme_send_action(struct hostapd_data *hapd, const u8 *addr, os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); m->u.action.category = WLAN_ACTION_WMM; - m->u.action.u.wme_action.action_code = action_code; - m->u.action.u.wme_action.dialog_token = dialogue_token; - m->u.action.u.wme_action.status_code = status_code; - os_memcpy(t, tspec, sizeof(struct wme_tspec_info_element)); + m->u.action.u.wmm_action.action_code = action_code; + m->u.action.u.wmm_action.dialog_token = dialogue_token; + m->u.action.u.wmm_action.status_code = status_code; + os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); len = ((u8 *) (t + 1)) - buf; if (hostapd_send_mgmt_frame(hapd, m, len, 0) < 0) - perror("wme_send_action: send"); + perror("wmm_send_action: send"); } -/* given frame data payload size in bytes, and data_rate in bits per second - * returns time to complete frame exchange */ -/* FIX: should not use floating point types */ -static double wme_frame_exchange_time(int bytes, int data_rate, int encryption, - int cts_protection) +static void wmm_addts_req(struct hostapd_data *hapd, + struct ieee80211_mgmt *mgmt, + struct wmm_tspec_element *tspec, size_t len) { - /* TODO: account for MAC/PHY headers correctly */ - /* TODO: account for encryption headers */ - /* TODO: account for WDS headers */ - /* TODO: account for CTS protection */ - /* TODO: account for SIFS + ACK at minimum PHY rate */ - return (bytes + 400) * 8.0 / data_rate; -} + u8 *end = ((u8 *) mgmt) + len; + int medium_time, pps, duration; + int up, psb, dir, tid; + u16 val, surplus; + if ((u8 *) (tspec + 1) > end) { + wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request"); + return; + } -static void wme_setup_request(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, - struct wme_tspec_info_element *tspec, size_t len) -{ - /* FIX: should not use floating point types */ - double medium_time, pps; + wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC " + "from " MACSTR, + mgmt->u.action.u.wmm_action.dialog_token, + MAC2STR(mgmt->sa)); + + up = (tspec->ts_info[1] >> 3) & 0x07; + psb = (tspec->ts_info[1] >> 2) & 0x01; + dir = (tspec->ts_info[0] >> 5) & 0x03; + tid = (tspec->ts_info[0] >> 1) & 0x0f; + wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d", + up, psb, dir, tid); + val = le_to_host16(tspec->nominal_msdu_size); + wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s", + val & 0x7fff, val & 0x8000 ? " (fixed)" : ""); + wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps", + le_to_host32(tspec->mean_data_rate)); + wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps", + le_to_host32(tspec->minimum_phy_rate)); + val = le_to_host16(tspec->surplus_bandwidth_allowance); + wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u", + val >> 13, 10000 * (val & 0x1fff) / 0x2000); + + val = le_to_host16(tspec->nominal_msdu_size); + if (val == 0) { + wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)"); + goto invalid; + } + /* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */ + pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val; + wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d", + pps); + + if (le_to_host32(tspec->minimum_phy_rate) < 1000000) { + wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate"); + goto invalid; + } + + duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 / + (le_to_host32(tspec->minimum_phy_rate) / 1000000) + + 50 /* FIX: proper SIFS + ACK duration */; + + /* unsigned binary number with an implicit binary point after the + * leftmost 3 bits, i.e., 0x2000 = 1.0 */ + surplus = le_to_host16(tspec->surplus_bandwidth_allowance); + if (surplus <= 0x2000) { + wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not " + "greater than unity"); + goto invalid; + } + + medium_time = surplus * pps * duration / 0x2000; + wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time); + + /* + * TODO: store list of granted (and still active) TSPECs and check + * whether there is available medium time for this request. For now, + * just refuse requests that would by themselves take very large + * portion of the available bandwidth. + */ + if (medium_time > 750000) { + wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over " + "75%% of available bandwidth"); + wmm_send_action(hapd, mgmt->sa, tspec, + WMM_ACTION_CODE_ADDTS_RESP, + mgmt->u.action.u.wmm_action.dialog_token, + WMM_ADDTS_STATUS_REFUSED); + return; + } - /* TODO: account for airtime and answer no to tspec setup requests - * when none left!! */ + /* Convert to 32 microseconds per second unit */ + tspec->medium_time = host_to_le16(medium_time / 32); - pps = (tspec->mean_data_rate / 8.0) / tspec->nominal_msdu_size; - medium_time = (tspec->surplus_bandwidth_allowance / 8) * pps * - wme_frame_exchange_time(tspec->nominal_msdu_size, - tspec->minimum_phy_rate, 0, 0); - tspec->medium_time = medium_time * 1000000.0 / 32.0; + wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP, + mgmt->u.action.u.wmm_action.dialog_token, + WMM_ADDTS_STATUS_ADMISSION_ACCEPTED); + return; - wme_send_action(hapd, mgmt->sa, tspec, WME_ACTION_CODE_SETUP_RESPONSE, - mgmt->u.action.u.wme_action.dialog_token, - WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED); +invalid: + wmm_send_action(hapd, mgmt->sa, tspec, + WMM_ACTION_CODE_ADDTS_RESP, + mgmt->u.action.u.wmm_action.dialog_token, + WMM_ADDTS_STATUS_INVALID_PARAMETERS); } -void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, +void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, size_t len) { int action_code; @@ -201,11 +275,11 @@ void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, /* check that the request comes from a valid station */ if (!sta || - (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WME)) != - (WLAN_STA_ASSOC | WLAN_STA_WME)) { + (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) != + (WLAN_STA_ASSOC | WLAN_STA_WMM)) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, - "wme action received is not from associated wme" + "wmm action received is not from associated wmm" " station"); /* TODO: respond with action frame refused status code */ return; @@ -215,19 +289,18 @@ void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, - "hostapd_wme_action - could not parse wme " + "hostapd_wmm_action - could not parse wmm " "action"); /* TODO: respond with action frame invalid parameters status * code */ return; } - if (!elems.wme_tspec || - elems.wme_tspec_len != (sizeof(struct wme_tspec_info_element) - 2)) - { + if (!elems.wmm_tspec || + elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, - "hostapd_wme_action - missing or wrong length " + "hostapd_wmm_action - missing or wrong length " "tspec"); /* TODO: respond with action frame invalid parameters status * code */ @@ -237,26 +310,26 @@ void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, /* TODO: check the request is for an AC with ACM set, if not, refuse * request */ - action_code = mgmt->u.action.u.wme_action.action_code; + action_code = mgmt->u.action.u.wmm_action.action_code; switch (action_code) { - case WME_ACTION_CODE_SETUP_REQUEST: - wme_setup_request(hapd, mgmt, (struct wme_tspec_info_element *) - elems.wme_tspec, len); + case WMM_ACTION_CODE_ADDTS_REQ: + wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *) + (elems.wmm_tspec - 2), len); return; #if 0 /* TODO: needed for client implementation */ - case WME_ACTION_CODE_SETUP_RESPONSE: - wme_setup_request(hapd, mgmt, len); + case WMM_ACTION_CODE_ADDTS_RESP: + wmm_setup_request(hapd, mgmt, len); return; /* TODO: handle station teardown requests */ - case WME_ACTION_CODE_TEARDOWN: - wme_teardown(hapd, mgmt, len); + case WMM_ACTION_CODE_DELTS: + wmm_teardown(hapd, mgmt, len); return; #endif } hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, - "hostapd_wme_action - unknown action code %d", + "hostapd_wmm_action - unknown action code %d", action_code); } diff --git a/contrib/wpa/hostapd/wme.h b/contrib/wpa/hostapd/wme.h index 3c80c01..9bc48cb 100644 --- a/contrib/wpa/hostapd/wme.h +++ b/contrib/wpa/hostapd/wme.h @@ -16,9 +16,19 @@ #ifndef WME_H #define WME_H -#ifdef __linux__ -#include <endian.h> -#endif /* __linux__ */ +/* + * WMM Information Element (used in (Re)Association Request frames; may also be + * used in Beacon frames) + */ +struct wmm_information_element { + /* Element ID: 221 (0xdd); Length: 7 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 0 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specific QoS info */ +}; #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include <sys/types.h> @@ -44,86 +54,82 @@ struct wme_information_element { } __attribute__ ((packed)); -struct wme_ac_parameter { -#if __BYTE_ORDER == __LITTLE_ENDIAN - /* byte 1 */ - u8 aifsn:4, - acm:1, - aci:2, - reserved:1; - - /* byte 2 */ - u8 eCWmin:4, - eCWmax:4; -#elif __BYTE_ORDER == __BIG_ENDIAN - /* byte 1 */ - u8 reserved:1, - aci:2, - acm:1, - aifsn:4; - - /* byte 2 */ - u8 eCWmax:4, - eCWmin:4; -#else -#error "Please fix <endian.h>" -#endif - - /* bytes 3 & 4 */ - le16 txopLimit; +#define WMM_AC_AIFSN_MASK 0x0f +#define WMM_AC_AIFNS_SHIFT 0 +#define WMM_AC_ACM 0x10 +#define WMM_AC_ACI_MASK 0x60 +#define WMM_AC_ACI_SHIFT 5 + +#define WMM_AC_ECWMIN_MASK 0x0f +#define WMM_AC_ECWMIN_SHIFT 0 +#define WMM_AC_ECWMAX_MASK 0xf0 +#define WMM_AC_ECWMAX_SHIFT 4 + +struct wmm_ac_parameter { + u8 aci_aifsn; /* AIFSN, ACM, ACI */ + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ + le16 txop_limit; } __attribute__ ((packed)); -struct wme_parameter_element { - /* required fields for WME version 1 */ - u8 oui[3]; - u8 oui_type; - u8 oui_subtype; - u8 version; - u8 acInfo; - u8 reserved; - struct wme_ac_parameter ac[4]; +/* + * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association + * Response frmaes) + */ +struct wmm_parameter_element { + /* Element ID: 221 (0xdd); Length: 24 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 1 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specif QoS info */ + u8 reserved; /* 0 */ + struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ } __attribute__ ((packed)); -struct wme_tspec_info_element { - u8 eid; - u8 length; - u8 oui[3]; - u8 oui_type; - u8 oui_subtype; - u8 version; - u16 ts_info; - u16 nominal_msdu_size; - u16 maximum_msdu_size; - u32 minimum_service_interval; - u32 maximum_service_interval; - u32 inactivity_interval; - u32 start_time; - u32 minimum_data_rate; - u32 mean_data_rate; - u32 maximum_burst_size; - u32 minimum_phy_rate; - u32 peak_data_rate; - u32 delay_bound; - u16 surplus_bandwidth_allowance; - u16 medium_time; +/* WMM TSPEC Element */ +struct wmm_tspec_element { + u8 eid; /* 221 = 0xdd */ + u8 length; /* 6 + 55 = 61 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 2 */ + u8 version; /* 1 */ + /* WMM TSPEC body (55 octets): */ + u8 ts_info[3]; + le16 nominal_msdu_size; + le16 maximum_msdu_size; + le32 minimum_service_interval; + le32 maximum_service_interval; + le32 inactivity_interval; + le32 suspension_interval; + le32 service_start_time; + le32 minimum_data_rate; + le32 mean_data_rate; + le32 peak_data_rate; + le32 maximum_burst_size; + le32 delay_bound; + le32 minimum_phy_rate; + le16 surplus_bandwidth_allowance; + le16 medium_time; } __attribute__ ((packed)); -/* Access Categories */ +/* Access Categories / ACI to AC coding */ enum { - WME_AC_BK = 1, - WME_AC_BE = 0, - WME_AC_VI = 2, - WME_AC_VO = 3 + WMM_AC_BE = 0 /* Best Effort */, + WMM_AC_BK = 1 /* Background */, + WMM_AC_VI = 2 /* Video */, + WMM_AC_VO = 3 /* Voice */ }; struct ieee80211_mgmt; -u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid); -int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len); -int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta); -void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, +u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid); +int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len); +int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta); +void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, size_t len); #endif /* WME_H */ diff --git a/contrib/wpa/hostapd/wpa.c b/contrib/wpa/hostapd/wpa.c index cf285b6..19b11d5 100644 --- a/contrib/wpa/hostapd/wpa.c +++ b/contrib/wpa/hostapd/wpa.c @@ -1,6 +1,6 @@ /* * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> + * 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 @@ -44,6 +44,8 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx); static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_request_new_ptk(struct wpa_state_machine *sm); +static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); static const u32 dot11RSNAConfigGroupUpdateCount = 4; static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; @@ -286,21 +288,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, } -static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, - int vlan_id) +static void wpa_group_set_key_len(struct wpa_group *group, int cipher) { - struct wpa_group *group; - u8 buf[ETH_ALEN + 8 + sizeof(group)]; - u8 rkey[32]; - - group = os_zalloc(sizeof(struct wpa_group)); - if (group == NULL) - return NULL; - - group->GTKAuthenticator = TRUE; - group->vlan_id = vlan_id; - - switch (wpa_auth->conf.wpa_group) { + switch (cipher) { case WPA_CIPHER_CCMP: group->GTK_len = 16; break; @@ -314,6 +304,24 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, group->GTK_len = 5; break; } +} + + +static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, + int vlan_id) +{ + struct wpa_group *group; + u8 buf[ETH_ALEN + 8 + sizeof(group)]; + u8 rkey[32]; + + group = os_zalloc(sizeof(struct wpa_group)); + if (group == NULL) + return NULL; + + group->GTKAuthenticator = TRUE; + group->vlan_id = vlan_id; + + wpa_group_set_key_len(group, wpa_auth->conf.wpa_group); /* Counter = PRF-256(Random number, "Init Counter", * Local MAC Address || Time) @@ -451,6 +459,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth) int wpa_reconfig(struct wpa_authenticator *wpa_auth, struct wpa_auth_config *conf) { + struct wpa_group *group; if (wpa_auth == NULL) return 0; @@ -460,6 +469,17 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth, return -1; } + /* + * Reinitialize GTK to make sure it is suitable for the new + * configuration. + */ + group = wpa_auth->group; + wpa_group_set_key_len(group, wpa_auth->conf.wpa_group); + group->GInit = TRUE; + wpa_group_sm_step(wpa_auth, group); + group->GInit = FALSE; + wpa_group_sm_step(wpa_auth, group); + return 0; } @@ -619,6 +639,22 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, return; } + if (sm->wpa == WPA_VERSION_WPA2) { + if (key->type != EAPOL_KEY_TYPE_RSN) { + wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " + "unexpected type %d in RSN mode", + key->type); + return; + } + } else { + if (key->type != EAPOL_KEY_TYPE_WPA) { + wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " + "unexpected type %d in WPA mode", + key->type); + return; + } + } + /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys * are set */ @@ -1403,14 +1439,15 @@ SM_STATE(WPA_PTK, PTKSTART) static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk, struct wpa_ptk *ptk) { + size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64; #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) - return wpa_auth_derive_ptk_ft(sm, pmk, ptk); + return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len); #endif /* CONFIG_IEEE80211R */ wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce, - (u8 *) ptk, sizeof(*ptk), + (u8 *) ptk, ptk_len, wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); return 0; diff --git a/contrib/wpa/hostapd/wpa.h b/contrib/wpa/hostapd/wpa.h index d353844..7d9b3d3 100644 --- a/contrib/wpa/hostapd/wpa.h +++ b/contrib/wpa/hostapd/wpa.h @@ -141,7 +141,7 @@ struct wpa_auth_config { int rsn_preauth; int eapol_version; int peerkey; - int wme_enabled; + int wmm_enabled; int okc; #ifdef CONFIG_IEEE80211W enum { diff --git a/contrib/wpa/hostapd/wpa_auth_i.h b/contrib/wpa/hostapd/wpa_auth_i.h index bcaeda5..925d3ee 100644 --- a/contrib/wpa/hostapd/wpa_auth_i.h +++ b/contrib/wpa/hostapd/wpa_auth_i.h @@ -213,7 +213,7 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211R int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, - struct wpa_ptk *ptk); + struct wpa_ptk *ptk, size_t ptk_len); struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); #endif /* CONFIG_IEEE80211R */ diff --git a/contrib/wpa/hostapd/wpa_auth_ie.c b/contrib/wpa/hostapd/wpa_auth_ie.c index 3ac9d67..7e01635 100644 --- a/contrib/wpa/hostapd/wpa_auth_ie.c +++ b/contrib/wpa/hostapd/wpa_auth_ie.c @@ -215,8 +215,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, capab |= WPA_CAPABILITY_PREAUTH; if (conf->peerkey) capab |= WPA_CAPABILITY_PEERKEY_ENABLED; - if (conf->wme_enabled) { - /* 4 PTKSA replay counters when using WME */ + if (conf->wmm_enabled) { + /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W diff --git a/contrib/wpa/hostapd/wpa_ft.c b/contrib/wpa/hostapd/wpa_ft.c index 9cf6713..3139105 100644 --- a/contrib/wpa/hostapd/wpa_ft.c +++ b/contrib/wpa/hostapd/wpa_ft.c @@ -321,7 +321,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth, int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, - struct wpa_ptk *ptk) + struct wpa_ptk *ptk, size_t ptk_len) { u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN]; u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN]; @@ -354,8 +354,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, sm->wpa_auth->addr, pmk_r1_name, - (u8 *) ptk, sizeof(*ptk), ptk_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk)); + (u8 *) ptk, ptk_len, ptk_name); + wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); return 0; @@ -714,7 +714,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, u8 ptk_name[WPA_PMK_NAME_LEN]; struct wpa_auth_config *conf; struct wpa_ft_ies parse; - size_t buflen; + size_t buflen, ptk_len; int ret; u8 *pos, *end; @@ -804,11 +804,12 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce", sm->ANonce, WPA_NONCE_LEN); + ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64; wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, sm->wpa_auth->addr, pmk_r1_name, - (u8 *) &sm->PTK, sizeof(sm->PTK), ptk_name); + (u8 *) &sm->PTK, ptk_len, ptk_name); wpa_hexdump_key(MSG_DEBUG, "FT: PTK", - (u8 *) &sm->PTK, sizeof(sm->PTK)); + (u8 *) &sm->PTK, ptk_len); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); wpa_ft_install_ptk(sm); diff --git a/contrib/wpa/hostapd/wps_hostapd.c b/contrib/wpa/hostapd/wps_hostapd.c index a824c16..818767e 100644 --- a/contrib/wpa/hostapd/wps_hostapd.c +++ b/contrib/wpa/hostapd/wps_hostapd.c @@ -219,13 +219,13 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) if ((hapd->conf->wps_cred_processing == 1 || hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { size_t blen = cred->cred_attr_len * 2 + 1; - char *buf = os_malloc(blen); - if (buf) { - wpa_snprintf_hex(buf, blen, + char *_buf = os_malloc(blen); + if (_buf) { + wpa_snprintf_hex(_buf, blen, cred->cred_attr, cred->cred_attr_len); wpa_msg(hapd, MSG_INFO, "%s%s", - WPS_EVENT_NEW_AP_SETTINGS, buf); - os_free(buf); + WPS_EVENT_NEW_AP_SETTINGS, _buf); + os_free(_buf); } } else wpa_msg(hapd, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); @@ -233,6 +233,28 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) if (hapd->conf->wps_cred_processing == 1) return 0; + os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len); + hapd->wps->ssid_len = cred->ssid_len; + hapd->wps->encr_types = cred->encr_type; + hapd->wps->auth_types = cred->auth_type; + if (cred->key_len == 0) { + os_free(hapd->wps->network_key); + hapd->wps->network_key = NULL; + hapd->wps->network_key_len = 0; + } else { + if (hapd->wps->network_key == NULL || + hapd->wps->network_key_len < cred->key_len) { + hapd->wps->network_key_len = 0; + os_free(hapd->wps->network_key); + hapd->wps->network_key = os_malloc(cred->key_len); + if (hapd->wps->network_key == NULL) + return -1; + } + hapd->wps->network_key_len = cred->key_len; + os_memcpy(hapd->wps->network_key, cred->key, cred->key_len); + } + hapd->wps->wps_state = WPS_STATE_CONFIGURED; + len = os_strlen(hapd->iface->config_fname) + 5; tmp_fname = os_malloc(len); if (tmp_fname == NULL) @@ -326,15 +348,21 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) else fprintf(nconf, "auth_algs=1\n"); - if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx < 4) { - fprintf(nconf, "wep_default_key=%d\n", cred->key_idx); - fprintf(nconf, "wep_key%d=", cred->key_idx); - if (cred->key_len != 10 && cred->key_len != 26) - fputc('"', nconf); - for (i = 0; i < cred->key_len; i++) - fputc(cred->key[i], nconf); - if (cred->key_len != 10 && cred->key_len != 26) - fputc('"', nconf); + if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) { + int key_idx = cred->key_idx; + if (key_idx) + key_idx--; + fprintf(nconf, "wep_default_key=%d\n", key_idx); + fprintf(nconf, "wep_key%d=", key_idx); + if (cred->key_len == 10 || cred->key_len == 26) { + /* WEP key as a hex string */ + for (i = 0; i < cred->key_len; i++) + fputc(cred->key[i], nconf); + } else { + /* Raw WEP key; convert to hex */ + for (i = 0; i < cred->key_len; i++) + fprintf(nconf, "%02x", cred->key[i]); + } fprintf(nconf, "\n"); } } @@ -620,6 +648,8 @@ int hostapd_init_wps(struct hostapd_data *hapd, cfg.extra_cred_len = conf->extra_cred_len; cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && conf->skip_cred_build; + if (conf->ssid.security_policy == SECURITY_STATIC_WEP) + cfg.static_wep_only = 1; wps->registrar = wps_registrar_init(wps, &cfg); if (wps->registrar == NULL) { @@ -669,7 +699,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd) int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, - const char *pin) + const char *pin, int timeout) { u8 u[UUID_LEN]; int any = 0; @@ -681,7 +711,8 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, else if (uuid_str2bin(uuid, u)) return -1; return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u, - (const u8 *) pin, os_strlen(pin)); + (const u8 *) pin, os_strlen(pin), + timeout); } @@ -864,8 +895,8 @@ static int hostapd_rx_req_put_wlan_response( wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr=" MACSTR, ev_type, MAC2STR(mac_addr)); - wpa_hexdump_ascii(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage", - wpabuf_head(msg), wpabuf_len(msg)); + wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage", + wpabuf_head(msg), wpabuf_len(msg)); if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) { wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected " "PutWLANResponse WLANEventType %d", ev_type); diff --git a/contrib/wpa/hostapd/wps_hostapd.h b/contrib/wpa/hostapd/wps_hostapd.h index 6615c62a..e949bee 100644 --- a/contrib/wpa/hostapd/wps_hostapd.h +++ b/contrib/wpa/hostapd/wps_hostapd.h @@ -21,7 +21,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, struct hostapd_bss_config *conf); void hostapd_deinit_wps(struct hostapd_data *hapd); int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, - const char *pin); + const char *pin, int timeout); int hostapd_wps_button_pushed(struct hostapd_data *hapd); void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr, const u8 *ie, size_t ie_len); |