MFV hostapd & wpa_supplicant 0.6.10.
This commit is contained in:
commit
ce9c8f380b
7
contrib/wpa/hostapd/.gitignore
vendored
7
contrib/wpa/hostapd/.gitignore
vendored
@ -1,7 +0,0 @@
|
||||
*.d
|
||||
.config
|
||||
driver_conf.c
|
||||
hostapd
|
||||
hostapd_cli
|
||||
hlr_auc_gw
|
||||
nt_password_hash
|
@ -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>)
|
||||
|
635
contrib/wpa/hostapd/Makefile
Normal file
635
contrib/wpa/hostapd/Makefile
Normal file
@ -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)
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
4
contrib/wpa/hostapd/doc/.gitignore
vendored
4
contrib/wpa/hostapd/doc/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
html
|
||||
latex
|
||||
hostapd.eps
|
||||
hostapd.png
|
839
contrib/wpa/hostapd/driver_bsd.c
Normal file
839
contrib/wpa/hostapd/driver_bsd.c
Normal file
@ -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,
|
||||
};
|
1279
contrib/wpa/hostapd/driver_hostap.c
Normal file
1279
contrib/wpa/hostapd/driver_hostap.c
Normal file
File diff suppressed because it is too large
Load Diff
372
contrib/wpa/hostapd/driver_wired.c
Normal file
372
contrib/wpa/hostapd/driver_wired.c
Normal file
@ -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,
|
||||
};
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
287
contrib/wpa/hostapd/radiotap.c
Normal file
287
contrib/wpa/hostapd/radiotap.c
Normal file
@ -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;
|
||||
}
|
242
contrib/wpa/hostapd/radiotap.h
Normal file
242
contrib/wpa/hostapd/radiotap.h
Normal file
@ -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 */
|
41
contrib/wpa/hostapd/radiotap_iter.h
Normal file
41
contrib/wpa/hostapd/radiotap_iter.h
Normal file
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/* Add WME Parameter Element to Beacon and Probe Response frames. */
|
||||
u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid)
|
||||
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 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];
|
||||
struct wmm_ac_parameter *ac = &wmm->ac[e];
|
||||
struct hostapd_wmm_ac_params *acp =
|
||||
&hapd->iconf->wmm_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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Convert to 32 microseconds per second unit */
|
||||
tspec->medium_time = host_to_le16(medium_time / 32);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
/* TODO: account for airtime and answer no to tspec setup requests
|
||||
* when none left!! */
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
#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
|
||||
|
||||
/* byte 2 */
|
||||
u8 eCWmin:4,
|
||||
eCWmax:4;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* byte 1 */
|
||||
u8 reserved:1,
|
||||
aci:2,
|
||||
acm:1,
|
||||
aifsn:4;
|
||||
#define WMM_AC_ECWMIN_MASK 0x0f
|
||||
#define WMM_AC_ECWMIN_SHIFT 0
|
||||
#define WMM_AC_ECWMAX_MASK 0xf0
|
||||
#define WMM_AC_ECWMAX_SHIFT 4
|
||||
|
||||
/* byte 2 */
|
||||
u8 eCWmax:4,
|
||||
eCWmin:4;
|
||||
#else
|
||||
#error "Please fix <endian.h>"
|
||||
#endif
|
||||
|
||||
/* bytes 3 & 4 */
|
||||
le16 txopLimit;
|
||||
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 */
|
||||
|
@ -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,6 +288,25 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
|
||||
}
|
||||
|
||||
|
||||
static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
|
||||
{
|
||||
switch (cipher) {
|
||||
case WPA_CIPHER_CCMP:
|
||||
group->GTK_len = 16;
|
||||
break;
|
||||
case WPA_CIPHER_TKIP:
|
||||
group->GTK_len = 32;
|
||||
break;
|
||||
case WPA_CIPHER_WEP104:
|
||||
group->GTK_len = 13;
|
||||
break;
|
||||
case WPA_CIPHER_WEP40:
|
||||
group->GTK_len = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
|
||||
int vlan_id)
|
||||
{
|
||||
@ -300,20 +321,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
|
||||
group->GTKAuthenticator = TRUE;
|
||||
group->vlan_id = vlan_id;
|
||||
|
||||
switch (wpa_auth->conf.wpa_group) {
|
||||
case WPA_CIPHER_CCMP:
|
||||
group->GTK_len = 16;
|
||||
break;
|
||||
case WPA_CIPHER_TKIP:
|
||||
group->GTK_len = 32;
|
||||
break;
|
||||
case WPA_CIPHER_WEP104:
|
||||
group->GTK_len = 13;
|
||||
break;
|
||||
case WPA_CIPHER_WEP40:
|
||||
group->GTK_len = 5;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
1
contrib/wpa/src/common/.gitignore
vendored
1
contrib/wpa/src/common/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.d
|
@ -49,26 +49,33 @@ static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen,
|
||||
elems->wpa_ie = pos;
|
||||
elems->wpa_ie_len = elen;
|
||||
break;
|
||||
case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
|
||||
case WMM_OUI_TYPE:
|
||||
/* WMM information element */
|
||||
if (elen < 5) {
|
||||
wpa_printf(MSG_MSGDUMP, "short WME "
|
||||
wpa_printf(MSG_MSGDUMP, "short WMM "
|
||||
"information element ignored "
|
||||
"(len=%lu)",
|
||||
(unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
switch (pos[4]) {
|
||||
case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
|
||||
case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
|
||||
elems->wme = pos;
|
||||
elems->wme_len = elen;
|
||||
case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
|
||||
case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
|
||||
/*
|
||||
* Share same pointer since only one of these
|
||||
* is used and they start with same data.
|
||||
* Length field can be used to distinguish the
|
||||
* IEs.
|
||||
*/
|
||||
elems->wmm = pos;
|
||||
elems->wmm_len = elen;
|
||||
break;
|
||||
case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
|
||||
elems->wme_tspec = pos;
|
||||
elems->wme_tspec_len = elen;
|
||||
case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
|
||||
elems->wmm_tspec = pos;
|
||||
elems->wmm_tspec_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_MSGDUMP, "unknown WME "
|
||||
wpa_printf(MSG_MSGDUMP, "unknown WMM "
|
||||
"information element ignored "
|
||||
"(subtype=%d len=%lu)",
|
||||
pos[4], (unsigned long) elen);
|
||||
|
@ -41,10 +41,10 @@ struct ieee802_11_elems {
|
||||
u8 wpa_ie_len;
|
||||
u8 *rsn_ie;
|
||||
u8 rsn_ie_len;
|
||||
u8 *wme;
|
||||
u8 wme_len;
|
||||
u8 *wme_tspec;
|
||||
u8 wme_tspec_len;
|
||||
u8 *wmm; /* WMM Information or Parameter Element */
|
||||
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
|
||||
u8 *wmm_tspec;
|
||||
u8 wmm_tspec_len;
|
||||
u8 *wps_ie;
|
||||
u8 wps_ie_len;
|
||||
u8 *power_cap;
|
||||
|
@ -134,10 +134,9 @@
|
||||
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
|
||||
/* IEEE 802.11r */
|
||||
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
|
||||
#define WLAN_STATUS_EXPECTED_RESOURCE_REQ_FT 53
|
||||
#define WLAN_STATUS_INVALID_PMKID 54
|
||||
#define WLAN_STATUS_INVALID_MDIE 55
|
||||
#define WLAN_STATUS_INVALID_FTIE 56
|
||||
#define WLAN_STATUS_INVALID_PMKID 53
|
||||
#define WLAN_STATUS_INVALID_MDIE 54
|
||||
#define WLAN_STATUS_INVALID_FTIE 55
|
||||
|
||||
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
|
||||
#define WLAN_REASON_UNSPECIFIED 1
|
||||
@ -211,16 +210,18 @@
|
||||
#define WLAN_ACTION_QOS 1
|
||||
#define WLAN_ACTION_DLS 2
|
||||
#define WLAN_ACTION_BLOCK_ACK 3
|
||||
#define WLAN_ACTION_PUBLIC 4
|
||||
#define WLAN_ACTION_RADIO_MEASUREMENT 5
|
||||
#define WLAN_ACTION_FT 6
|
||||
#define WLAN_ACTION_HT 7
|
||||
#define WLAN_ACTION_SA_QUERY 8
|
||||
#define WLAN_ACTION_WMM 17
|
||||
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
|
||||
|
||||
/* SA Query Action frame (IEEE 802.11w/D7.0, 7.4.9) */
|
||||
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
|
||||
#define WLAN_SA_QUERY_REQUEST 0
|
||||
#define WLAN_SA_QUERY_RESPONSE 1
|
||||
|
||||
#define WLAN_SA_QUERY_TR_ID_LEN 16
|
||||
#define WLAN_SA_QUERY_TR_ID_LEN 2
|
||||
|
||||
/* Timeout Interval Type */
|
||||
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
|
||||
@ -301,7 +302,7 @@ struct ieee80211_mgmt {
|
||||
u8 dialog_token;
|
||||
u8 status_code;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED wme_action;
|
||||
} STRUCT_PACKED wmm_action;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 element_id;
|
||||
@ -562,23 +563,27 @@ struct mimo_pwr_save_action {
|
||||
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
|
||||
* 00:50:F2 */
|
||||
|
||||
#define WME_OUI_TYPE 2
|
||||
#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0
|
||||
#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1
|
||||
#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2
|
||||
#define WME_VERSION 1
|
||||
#define WMM_OUI_TYPE 2
|
||||
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
|
||||
#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
|
||||
#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
|
||||
#define WMM_VERSION 1
|
||||
|
||||
#define WME_ACTION_CODE_SETUP_REQUEST 0
|
||||
#define WME_ACTION_CODE_SETUP_RESPONSE 1
|
||||
#define WME_ACTION_CODE_TEARDOWN 2
|
||||
#define WMM_ACTION_CODE_ADDTS_REQ 0
|
||||
#define WMM_ACTION_CODE_ADDTS_RESP 1
|
||||
#define WMM_ACTION_CODE_DELTS 2
|
||||
|
||||
#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0
|
||||
#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1
|
||||
#define WME_SETUP_RESPONSE_STATUS_REFUSED 3
|
||||
#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
|
||||
#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
|
||||
/* 2 - Reserved */
|
||||
#define WMM_ADDTS_STATUS_REFUSED 3
|
||||
/* 4-255 - Reserved */
|
||||
|
||||
#define WME_TSPEC_DIRECTION_UPLINK 0
|
||||
#define WME_TSPEC_DIRECTION_DOWNLINK 1
|
||||
#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3
|
||||
/* WMM TSPEC Direction Field Values */
|
||||
#define WMM_TSPEC_DIRECTION_UPLINK 0
|
||||
#define WMM_TSPEC_DIRECTION_DOWNLINK 1
|
||||
/* 2 - Reserved */
|
||||
#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
|
||||
|
||||
|
||||
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
|
||||
|
1434
contrib/wpa/src/common/nl80211_copy.h
Normal file
1434
contrib/wpa/src/common/nl80211_copy.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION_STR "0.6.8"
|
||||
#define VERSION_STR "0.6.10"
|
||||
|
||||
#endif /* VERSION_H */
|
||||
|
1099
contrib/wpa/src/common/wireless_copy.h
Normal file
1099
contrib/wpa/src/common/wireless_copy.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -56,10 +56,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
|
||||
hmac_sha1(key, 16, buf, len, hash);
|
||||
os_memcpy(mic, hash, MD5_MAC_LEN);
|
||||
break;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
|
||||
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
|
||||
return omac1_aes_128(key, buf, len, mic);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
1
contrib/wpa/src/crypto/.gitignore
vendored
1
contrib/wpa/src/crypto/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.d
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* WPA Supplicant / Crypto wrapper for Microsoft CryptoAPI
|
||||
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
|
||||
* Crypto wrapper for Microsoft CryptoAPI
|
||||
* Copyright (c) 2005-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
|
||||
@ -40,12 +40,6 @@ L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
|
||||
* define here whatever extra is needed.
|
||||
*/
|
||||
|
||||
static PCCERT_CONTEXT WINAPI
|
||||
(*CertCreateCertificateContext)(DWORD dwCertEncodingType,
|
||||
const BYTE *pbCertEncoded,
|
||||
DWORD cbCertEncoded)
|
||||
= NULL; /* to be loaded from crypt32.dll */
|
||||
|
||||
static BOOL WINAPI
|
||||
(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
|
||||
PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
|
||||
@ -59,7 +53,7 @@ static int mingw_load_crypto_func(void)
|
||||
/* MinGW does not yet have full CryptoAPI support, so load the needed
|
||||
* function here. */
|
||||
|
||||
if (CertCreateCertificateContext)
|
||||
if (CryptImportPublicKeyInfo)
|
||||
return 0;
|
||||
|
||||
dll = LoadLibrary("crypt32");
|
||||
@ -69,15 +63,6 @@ static int mingw_load_crypto_func(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
CertCreateCertificateContext = (void *) GetProcAddress(
|
||||
dll, "CertCreateCertificateContext");
|
||||
if (CertCreateCertificateContext == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
|
||||
"CertCreateCertificateContext() address from "
|
||||
"crypt32 library");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CryptImportPublicKeyInfo = GetProcAddress(
|
||||
dll, "CryptImportPublicKeyInfo");
|
||||
if (CryptImportPublicKeyInfo == NULL) {
|
||||
|
@ -57,7 +57,6 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
|
||||
}
|
||||
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
gcry_md_hd_t hd;
|
||||
@ -162,7 +161,6 @@ void aes_decrypt_deinit(void *ctx)
|
||||
gcry_cipher_hd_t hd = ctx;
|
||||
gcry_cipher_close(hd);
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
||||
|
||||
int crypto_mod_exp(const u8 *base, size_t base_len,
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "tls/asn1.h"
|
||||
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
#ifdef CONFIG_CRYPTO_INTERNAL
|
||||
|
||||
#ifdef CONFIG_TLS_INTERNAL
|
||||
|
||||
@ -435,6 +435,7 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
|
||||
}
|
||||
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
static struct crypto_private_key *
|
||||
crypto_pkcs8_key_import(const u8 *buf, size_t len)
|
||||
{
|
||||
@ -536,6 +537,7 @@ crypto_pkcs8_key_import(const u8 *buf, size_t len)
|
||||
return (struct crypto_private_key *)
|
||||
crypto_rsa_import_private_key(hdr.payload, hdr.length);
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
||||
|
||||
struct crypto_private_key * crypto_private_key_import(const u8 *key,
|
||||
@ -788,6 +790,7 @@ int crypto_global_init(void)
|
||||
void crypto_global_deinit(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL */
|
||||
|
||||
|
||||
#if defined(EAP_FAST) || defined(CONFIG_WPS)
|
||||
@ -830,6 +833,4 @@ error:
|
||||
#endif /* EAP_FAST || CONFIG_WPS */
|
||||
|
||||
|
||||
#endif /* CONFIG_TLS_INTERNAL */
|
||||
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
#endif /* CONFIG_CRYPTO_INTERNAL */
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "dh_groups.h"
|
||||
|
||||
|
||||
#ifdef ALL_DH_GROUPS
|
||||
|
||||
/* RFC 4306, B.1. Group 1 - 768 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
|
||||
@ -63,6 +65,8 @@ static const u8 dh_group2_prime[128] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
#endif /* ALL_DH_GROUPS */
|
||||
|
||||
/* RFC 3526, 2. Group 5 - 1536 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
|
||||
@ -95,6 +99,8 @@ static const u8 dh_group5_prime[192] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
#ifdef ALL_DH_GROUPS
|
||||
|
||||
/* RFC 3526, 3. Group 14 - 2048 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
|
||||
@ -503,6 +509,8 @@ static const u8 dh_group18_prime[1024] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
#endif /* ALL_DH_GROUPS */
|
||||
|
||||
|
||||
#define DH_GROUP(id) \
|
||||
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
|
||||
@ -510,14 +518,16 @@ dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
|
||||
|
||||
|
||||
static struct dh_group dh_groups[] = {
|
||||
DH_GROUP(5),
|
||||
#ifdef ALL_DH_GROUPS
|
||||
DH_GROUP(1),
|
||||
DH_GROUP(2),
|
||||
DH_GROUP(5),
|
||||
DH_GROUP(14),
|
||||
DH_GROUP(15),
|
||||
DH_GROUP(16),
|
||||
DH_GROUP(17),
|
||||
DH_GROUP(18)
|
||||
#endif /* ALL_DH_GROUPS */
|
||||
};
|
||||
|
||||
#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
|
||||
|
@ -379,7 +379,7 @@ int encrypt_pw_block_with_password_hash(
|
||||
*/
|
||||
pos = &pw_block[2 * 256];
|
||||
WPA_PUT_LE16(pos, password_len * 2);
|
||||
rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
|
||||
rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -68,19 +68,3 @@ void rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
*pos++ ^= S[(S[i] + S[j]) & 0xff];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rc4 - XOR RC4 stream to given data
|
||||
* @buf: data to be XOR'ed with RC4 stream
|
||||
* @len: buf length
|
||||
* @key: RC4 key
|
||||
* @key_len: RC4 key length
|
||||
*
|
||||
* Generate RC4 pseudo random stream for the given key and XOR this with the
|
||||
* data buffer to perform RC4 encryption/decryption.
|
||||
*/
|
||||
void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len)
|
||||
{
|
||||
rc4_skip(key, key_len, 0, buf, len);
|
||||
}
|
||||
|
@ -17,6 +17,5 @@
|
||||
|
||||
void rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
u8 *data, size_t data_len);
|
||||
void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len);
|
||||
|
||||
#endif /* RC4_H */
|
||||
|
@ -606,8 +606,8 @@ static void SHA1Transform(u32 state[5], const unsigned char buffer[64])
|
||||
} CHAR64LONG16;
|
||||
CHAR64LONG16* block;
|
||||
#ifdef SHA1HANDSOFF
|
||||
u32 workspace[16];
|
||||
block = (CHAR64LONG16 *) workspace;
|
||||
CHAR64LONG16 workspace;
|
||||
block = &workspace;
|
||||
os_memcpy(block, buffer, 64);
|
||||
#else
|
||||
block = (CHAR64LONG16 *) buffer;
|
||||
|
@ -122,7 +122,7 @@ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
|
||||
void sha256_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
|
||||
{
|
||||
u16 counter = 0;
|
||||
u16 counter = 1;
|
||||
size_t pos, plen;
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *addr[4];
|
||||
|
@ -34,6 +34,9 @@ struct tls_config {
|
||||
const char *pkcs11_module_path;
|
||||
};
|
||||
|
||||
#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
|
||||
#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
|
||||
|
||||
/**
|
||||
* struct tls_connection_params - Parameters for TLS connection
|
||||
* @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
|
||||
@ -68,6 +71,7 @@ struct tls_config {
|
||||
* @cert_id: the certificate's id when using engine
|
||||
* @ca_cert_id: the CA certificate's id when using engine
|
||||
* @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
|
||||
* @flags: Parameter options (TLS_CONN_*)
|
||||
*
|
||||
* TLS connection parameters to be configured with tls_connection_set_params()
|
||||
* and tls_global_set_params().
|
||||
@ -103,6 +107,8 @@ struct tls_connection_params {
|
||||
const char *key_id;
|
||||
const char *cert_id;
|
||||
const char *ca_cert_id;
|
||||
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
|
||||
|
@ -35,8 +35,12 @@ int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
|
||||
#include "tls.h"
|
||||
|
||||
|
||||
#ifndef TLS_RANDOM_SIZE
|
||||
#define TLS_RANDOM_SIZE 32
|
||||
#endif
|
||||
#ifndef TLS_MASTER_SIZE
|
||||
#define TLS_MASTER_SIZE 48
|
||||
#endif
|
||||
|
||||
|
||||
#if LIBGNUTLS_VERSION_NUMBER < 0x010302
|
||||
@ -591,6 +595,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
|
||||
gnutls_certificate_set_verify_flags(
|
||||
conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
|
||||
}
|
||||
|
||||
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
|
||||
gnutls_certificate_set_verify_flags(
|
||||
conn->xcred,
|
||||
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
|
||||
}
|
||||
}
|
||||
|
||||
if (params->client_cert && params->private_key) {
|
||||
@ -711,6 +726,18 @@ int tls_global_set_params(void *tls_ctx,
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
|
||||
gnutls_certificate_set_verify_flags(
|
||||
global->xcred,
|
||||
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
|
||||
}
|
||||
|
||||
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
|
||||
gnutls_certificate_set_verify_flags(
|
||||
global->xcred,
|
||||
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
|
||||
}
|
||||
}
|
||||
|
||||
if (params->client_cert && params->private_key) {
|
||||
@ -843,7 +870,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
}
|
||||
|
||||
|
||||
static int tls_connection_verify_peer(struct tls_connection *conn)
|
||||
static int tls_connection_verify_peer(struct tls_connection *conn,
|
||||
gnutls_alert_description_t *err)
|
||||
{
|
||||
unsigned int status, num_certs, i;
|
||||
struct os_time now;
|
||||
@ -853,22 +881,39 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
|
||||
if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
|
||||
"certificate chain");
|
||||
*err = GNUTLS_A_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
|
||||
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
|
||||
wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
|
||||
"algorithm");
|
||||
*err = GNUTLS_A_INSUFFICIENT_SECURITY;
|
||||
}
|
||||
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
|
||||
wpa_printf(MSG_INFO, "TLS: Certificate not yet "
|
||||
"activated");
|
||||
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
|
||||
}
|
||||
if (status & GNUTLS_CERT_EXPIRED) {
|
||||
wpa_printf(MSG_INFO, "TLS: Certificate expired");
|
||||
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
|
||||
wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
|
||||
"known issuer");
|
||||
*err = GNUTLS_A_UNKNOWN_CA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status & GNUTLS_CERT_REVOKED) {
|
||||
wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
|
||||
*err = GNUTLS_A_CERTIFICATE_REVOKED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -878,6 +923,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
|
||||
if (certs == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
|
||||
"received");
|
||||
*err = GNUTLS_A_UNKNOWN_CA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -887,6 +933,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
|
||||
if (gnutls_x509_crt_init(&cert) < 0) {
|
||||
wpa_printf(MSG_INFO, "TLS: Certificate initialization "
|
||||
"failed");
|
||||
*err = GNUTLS_A_BAD_CERTIFICATE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -895,6 +942,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
|
||||
wpa_printf(MSG_INFO, "TLS: Could not parse peer "
|
||||
"certificate %d/%d", i + 1, num_certs);
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
*err = GNUTLS_A_BAD_CERTIFICATE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -920,6 +968,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
|
||||
"not valid at this time",
|
||||
i + 1, num_certs);
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -981,19 +1030,24 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
|
||||
}
|
||||
} else {
|
||||
size_t size;
|
||||
gnutls_alert_description_t err;
|
||||
|
||||
if (conn->verify_peer && tls_connection_verify_peer(conn)) {
|
||||
if (conn->verify_peer &&
|
||||
tls_connection_verify_peer(conn, &err)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
|
||||
"failed validation");
|
||||
conn->failed++;
|
||||
return NULL;
|
||||
gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GNUTLS_EXTRA
|
||||
if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
|
||||
wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
|
||||
conn->failed++;
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_GNUTLS_EXTRA */
|
||||
|
||||
if (conn->tls_ia)
|
||||
wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
|
||||
@ -1021,6 +1075,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
out_data = conn->push_buf;
|
||||
*out_len = conn->push_buf_len;
|
||||
conn->push_buf = NULL;
|
||||
|
@ -108,71 +108,9 @@ static void tls_show_errors(int level, const char *func, const char *txt)
|
||||
* MinGW does not yet include all the needed definitions for CryptoAPI, so
|
||||
* define here whatever extra is needed.
|
||||
*/
|
||||
#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)
|
||||
#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
|
||||
#define CERT_STORE_READONLY_FLAG 0x00008000
|
||||
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
|
||||
#define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 0x00000004
|
||||
|
||||
static BOOL WINAPI
|
||||
(*CryptAcquireCertificatePrivateKey)(PCCERT_CONTEXT pCert, DWORD dwFlags,
|
||||
void *pvReserved, HCRYPTPROV *phCryptProv,
|
||||
DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
|
||||
= NULL; /* to be loaded from crypt32.dll */
|
||||
|
||||
#ifdef CONFIG_MINGW32_LOAD_CERTENUM
|
||||
static PCCERT_CONTEXT WINAPI
|
||||
(*CertEnumCertificatesInStore)(HCERTSTORE hCertStore,
|
||||
PCCERT_CONTEXT pPrevCertContext)
|
||||
= NULL; /* to be loaded from crypt32.dll */
|
||||
#endif /* CONFIG_MINGW32_LOAD_CERTENUM */
|
||||
|
||||
static int mingw_load_crypto_func(void)
|
||||
{
|
||||
HINSTANCE dll;
|
||||
|
||||
/* MinGW does not yet have full CryptoAPI support, so load the needed
|
||||
* function here. */
|
||||
|
||||
if (CryptAcquireCertificatePrivateKey)
|
||||
return 0;
|
||||
|
||||
dll = LoadLibrary("crypt32");
|
||||
if (dll == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
|
||||
"library");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CryptAcquireCertificatePrivateKey = GetProcAddress(
|
||||
dll, "CryptAcquireCertificatePrivateKey");
|
||||
if (CryptAcquireCertificatePrivateKey == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
|
||||
"CryptAcquireCertificatePrivateKey() address from "
|
||||
"crypt32 library");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MINGW32_LOAD_CERTENUM
|
||||
CertEnumCertificatesInStore = (void *) GetProcAddress(
|
||||
dll, "CertEnumCertificatesInStore");
|
||||
if (CertEnumCertificatesInStore == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
|
||||
"CertEnumCertificatesInStore() address from "
|
||||
"crypt32 library");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_MINGW32_LOAD_CERTENUM */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* __MINGW32_VERSION */
|
||||
|
||||
static int mingw_load_crypto_func(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __MINGW32_VERSION */
|
||||
|
||||
@ -403,9 +341,6 @@ static int tls_cryptoapi_cert(SSL *ssl, const char *name)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mingw_load_crypto_func())
|
||||
goto err;
|
||||
|
||||
if (!CryptAcquireCertificatePrivateKey(priv->cert,
|
||||
CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
|
||||
NULL, &priv->crypt_prov,
|
||||
@ -476,9 +411,6 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
|
||||
WCHAR *wstore;
|
||||
#endif /* UNICODE */
|
||||
|
||||
if (mingw_load_crypto_func())
|
||||
return -1;
|
||||
|
||||
if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
|
||||
return -1;
|
||||
|
||||
@ -735,11 +667,23 @@ void * tls_init(const struct tls_config *conf)
|
||||
if (tls_openssl_ref_count == 0) {
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
#ifndef OPENSSL_NO_SHA256
|
||||
EVP_add_digest(EVP_sha256());
|
||||
#endif /* OPENSSL_NO_SHA256 */
|
||||
/* TODO: if /dev/urandom is available, PRNG is seeded
|
||||
* automatically. If this is not the case, random data should
|
||||
* be added here. */
|
||||
|
||||
#ifdef PKCS12_FUNCS
|
||||
#ifndef OPENSSL_NO_RC2
|
||||
/*
|
||||
* 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
|
||||
* This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
|
||||
* versions, but it looks like OpenSSL 1.0.0 does not do that
|
||||
* anymore.
|
||||
*/
|
||||
EVP_add_cipher(EVP_rc2_40_cbc());
|
||||
#endif /* OPENSSL_NO_RC2 */
|
||||
PKCS12_PBE_add();
|
||||
#endif /* PKCS12_FUNCS */
|
||||
}
|
||||
@ -2105,9 +2049,18 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
|
||||
if (*appl_data) {
|
||||
res = SSL_read(conn->ssl, *appl_data, in_len);
|
||||
if (res < 0) {
|
||||
tls_show_errors(MSG_INFO, __func__,
|
||||
"Failed to read possible "
|
||||
"Application Data");
|
||||
int err = SSL_get_error(conn->ssl, res);
|
||||
if (err == SSL_ERROR_WANT_READ ||
|
||||
err == SSL_ERROR_WANT_WRITE) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SSL: No Application Data "
|
||||
"included");
|
||||
} else {
|
||||
tls_show_errors(MSG_INFO, __func__,
|
||||
"Failed to read "
|
||||
"possible "
|
||||
"Application Data");
|
||||
}
|
||||
os_free(*appl_data);
|
||||
*appl_data = NULL;
|
||||
} else {
|
||||
|
156
contrib/wpa/src/drivers/Apple80211.h
Normal file
156
contrib/wpa/src/drivers/Apple80211.h
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef APPLE80211_H
|
||||
#define APPLE80211_H
|
||||
|
||||
/*
|
||||
* Apple80211 framework definitions
|
||||
* This is an undocumented interface and the definitions here are based on
|
||||
* information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
|
||||
* whatever related information can be found with google and experiments ;-).
|
||||
*/
|
||||
|
||||
typedef struct __WirelessRef *WirelessRef;
|
||||
typedef SInt32 WirelessError;
|
||||
#define errWirelessNoError 0
|
||||
|
||||
typedef struct WirelessInfo {
|
||||
UInt16 link_qual;
|
||||
UInt16 comms_qual;
|
||||
UInt16 signal;
|
||||
UInt16 noise;
|
||||
UInt16 port_stat;
|
||||
UInt16 client_mode;
|
||||
UInt16 res1;
|
||||
UInt16 power;
|
||||
UInt16 res2;
|
||||
UInt8 bssID[6];
|
||||
UInt8 ssid[34];
|
||||
} WirelessInfo;
|
||||
|
||||
typedef struct WirelessInfo2 {
|
||||
/* TODO - these are probably not in correct order or complete */
|
||||
WirelessInfo info1;
|
||||
UInt8 macAddress[6];
|
||||
} WirelessInfo2;
|
||||
|
||||
typedef struct WirelessNetworkInfo {
|
||||
UInt16 channel;
|
||||
UInt16 noise;
|
||||
UInt16 signal;
|
||||
UInt8 bssid[6];
|
||||
UInt16 beacon_int;
|
||||
UInt16 capability;
|
||||
UInt16 ssid_len;
|
||||
UInt8 ssid[32];
|
||||
} WirelessNetworkInfo;
|
||||
|
||||
typedef int wirelessKeyType; /* TODO */
|
||||
|
||||
int WirelessIsAvailable(void);
|
||||
WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
|
||||
WirelessError WirelessDetach(WirelessRef ref);
|
||||
WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
|
||||
void *out_ptr, int out_bytes);
|
||||
WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
|
||||
WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
|
||||
WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
|
||||
WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
|
||||
WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
|
||||
WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
|
||||
WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
|
||||
UInt32 strip_dups);
|
||||
WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
|
||||
CFArrayRef *ibss_results, UInt32 strip_dups);
|
||||
WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
|
||||
UInt32 strip_dups, CFStringRef ssid);
|
||||
WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
|
||||
UInt32 strip_dups, CFArrayRef *results);
|
||||
WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
|
||||
WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
|
||||
CFStringRef passwd);
|
||||
WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
|
||||
/*
|
||||
* Set WEP key
|
||||
* ref: wireless reference from WirelessAttach()
|
||||
* type: ?
|
||||
* key_idx: 0..3
|
||||
* key_len: 13 for WEP-104 or 0 for clearing the key
|
||||
* key: Pointer to the key or %NULL if key_len = 0
|
||||
*/
|
||||
WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
|
||||
int key_idx, int key_len,
|
||||
const unsigned char *key);
|
||||
/*
|
||||
* Set WPA key (e.g., PMK for 4-way handshake)
|
||||
* ref: wireless reference from WirelessAttach()
|
||||
* type: 0..4; 1 = PMK
|
||||
* key_len: 16, 32, or 0
|
||||
* key: Pointer to the key or %NULL if key_len = 0
|
||||
*/
|
||||
WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
|
||||
int key_len, const unsigned char *key);
|
||||
WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
|
||||
CFStringRef key);
|
||||
WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
|
||||
CFStringRef key);
|
||||
WirelessError WirelessDisassociate(WirelessRef ref);
|
||||
|
||||
/*
|
||||
* Get a copy of scan results for the given SSID
|
||||
* The returned dictionary includes following entries:
|
||||
* beaconInterval: CFNumber(kCFNumberSInt32Type)
|
||||
* SSID: CFData buffer of the SSID
|
||||
* isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
|
||||
* name: Name of the network (SSID string)
|
||||
* BSSID: CFData buffer of the BSSID
|
||||
* channel: CFNumber(kCFNumberSInt32Type)
|
||||
* signal: CFNumber(kCFNumberSInt32Type)
|
||||
* appleIE: CFData
|
||||
* WPSNOPINRequired: CFBoolean
|
||||
* noise: CFNumber(kCFNumberSInt32Type)
|
||||
* capability: CFNumber(kCFNumberSInt32Type)
|
||||
* uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
|
||||
* appleIE_Version: CFNumber(kCFNumberSInt32Type)
|
||||
* appleIE_Robust: CFBoolean
|
||||
* WPSConfigured: CFBoolean
|
||||
* scanWasDirected: CFBoolean
|
||||
* appleIE_Product: CFNumber(kCFNumberSInt32Type)
|
||||
* authModes: CFArray of CFNumber(kCFNumberSInt32Type)
|
||||
* multiCipher: CFNumber(kCFNumberSInt32Type)
|
||||
*/
|
||||
CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
|
||||
|
||||
/*
|
||||
* Get information about the current association
|
||||
* The returned dictionary includes following entries:
|
||||
* keyData: CFData buffer of the key (e.g., 32-octet PSK)
|
||||
* multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
|
||||
* channel: CFNumber(kCFNumberSInt32Type)
|
||||
* isIBSS: CFBoolean
|
||||
* authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
|
||||
* 129 = WPA2-Enterprise
|
||||
* isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
|
||||
* SSID: CFData buffer of the SSID
|
||||
* cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
|
||||
*/
|
||||
CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
|
||||
|
||||
WirelessError WirelessConfigure(WirelessRef ref);
|
||||
|
||||
/*
|
||||
* Get ASP information
|
||||
* The returned dictionary includes following entries:
|
||||
* Version: version number (e.g., 3.0)
|
||||
* Channel: channel (e.g., 1)
|
||||
* Vendor: vendor (e.g., 2)
|
||||
*/
|
||||
CFDictionaryRef WirelessGetInfoASP(void);
|
||||
|
||||
/*
|
||||
* Get a copy of the interface dictionary
|
||||
* The returned dictionary has a key,value pairs for wireless interfaces.
|
||||
* The key is the interface name and the value is the driver identifier, e.g.,
|
||||
* en1: com.apple.driver.AirPort.Atheros
|
||||
*/
|
||||
CFDictionaryRef WirelessCopyInterfaceDict(void);
|
||||
|
||||
#endif /* APPLE80211_H */
|
9
contrib/wpa/src/drivers/Makefile
Normal file
9
contrib/wpa/src/drivers/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
all:
|
||||
@echo Nothing to be made.
|
||||
|
||||
clean:
|
||||
for d in $(SUBDIRS); do make -C $$d clean; done
|
||||
rm -f *~ *.o *.d
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
189
contrib/wpa/src/drivers/MobileApple80211.c
Normal file
189
contrib/wpa/src/drivers/MobileApple80211.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include "includes.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "MobileApple80211.h"
|
||||
|
||||
/*
|
||||
* Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
|
||||
* having to link with full Preferences.framework.
|
||||
*/
|
||||
|
||||
static void *aeropuerto = NULL;
|
||||
|
||||
|
||||
int _Apple80211Initialized(void)
|
||||
{
|
||||
return aeropuerto ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
|
||||
|
||||
int Apple80211Open(Apple80211Ref *ctx)
|
||||
{
|
||||
return __Apple80211Open(ctx);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
|
||||
|
||||
int Apple80211Close(Apple80211Ref ctx)
|
||||
{
|
||||
return __Apple80211Close(ctx);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
|
||||
= NULL;
|
||||
|
||||
int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
|
||||
{
|
||||
return __Apple80211GetIfListCopy(handle, list);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
|
||||
CFStringRef interface) = NULL;
|
||||
|
||||
int Apple80211BindToInterface(Apple80211Ref handle,
|
||||
CFStringRef interface)
|
||||
{
|
||||
return __Apple80211BindToInterface(handle, interface);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
|
||||
CFStringRef *name) = NULL;
|
||||
|
||||
int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
|
||||
CFStringRef *name)
|
||||
{
|
||||
return __Apple80211GetInterfaceNameCopy(handle, name);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
|
||||
CFDictionaryRef *info) = NULL;
|
||||
|
||||
int Apple80211GetInfoCopy(Apple80211Ref handle,
|
||||
CFDictionaryRef *info)
|
||||
{
|
||||
return __Apple80211GetInfoCopy(handle, info);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
|
||||
|
||||
int Apple80211GetPower(Apple80211Ref handle, char *pwr)
|
||||
{
|
||||
return __Apple80211GetPower(handle, pwr);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
|
||||
|
||||
int Apple80211SetPower(Apple80211Ref handle, char pwr)
|
||||
{
|
||||
return __Apple80211SetPower(handle, pwr);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
|
||||
CFDictionaryRef parameters) = NULL;
|
||||
|
||||
int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
|
||||
CFDictionaryRef parameters)
|
||||
{
|
||||
return __Apple80211Scan(handle, list, parameters);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password) = NULL;
|
||||
|
||||
int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password)
|
||||
{
|
||||
return __Apple80211Associate(handle, bss, password);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
|
||||
CFDictionaryRef bss,
|
||||
CFStringRef password,
|
||||
CFDictionaryRef *info) =
|
||||
NULL;
|
||||
|
||||
int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password, CFDictionaryRef *info)
|
||||
{
|
||||
return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
|
||||
CFDictionaryRef arg2, void *value) = NULL;
|
||||
|
||||
int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
|
||||
void *value)
|
||||
{
|
||||
return __Apple80211CopyValue(handle, field, arg2, value);
|
||||
}
|
||||
|
||||
|
||||
#define DLSYM(s) \
|
||||
do { \
|
||||
__ ## s = dlsym(aeropuerto, #s); \
|
||||
if (__ ## s == NULL) { \
|
||||
wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
|
||||
"symbol '" #s "' (%s)", dlerror()); \
|
||||
err = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
__attribute__ ((constructor))
|
||||
void _Apple80211_constructor(void)
|
||||
{
|
||||
const char *fname = "/System/Library/SystemConfiguration/"
|
||||
"Aeropuerto.bundle/Aeropuerto";
|
||||
int err = 0;
|
||||
|
||||
aeropuerto = dlopen(fname, RTLD_LAZY);
|
||||
if (!aeropuerto) {
|
||||
wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
|
||||
"for symbols", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
DLSYM(Apple80211Open);
|
||||
DLSYM(Apple80211Close);
|
||||
DLSYM(Apple80211GetIfListCopy);
|
||||
DLSYM(Apple80211BindToInterface);
|
||||
DLSYM(Apple80211GetInterfaceNameCopy);
|
||||
DLSYM(Apple80211GetInfoCopy);
|
||||
DLSYM(Apple80211GetPower);
|
||||
DLSYM(Apple80211SetPower);
|
||||
DLSYM(Apple80211Scan);
|
||||
DLSYM(Apple80211Associate);
|
||||
DLSYM(Apple80211AssociateAndCopyInfo);
|
||||
DLSYM(Apple80211CopyValue);
|
||||
|
||||
if (err) {
|
||||
dlclose(aeropuerto);
|
||||
aeropuerto = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((destructor))
|
||||
void _Apple80211_destructor(void)
|
||||
{
|
||||
if (aeropuerto) {
|
||||
dlclose(aeropuerto);
|
||||
aeropuerto = NULL;
|
||||
}
|
||||
}
|
43
contrib/wpa/src/drivers/MobileApple80211.h
Normal file
43
contrib/wpa/src/drivers/MobileApple80211.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef MOBILEAPPLE80211_H
|
||||
#define MOBILEAPPLE80211_H
|
||||
|
||||
/*
|
||||
* MobileApple80211 interface for iPhone/iPod touch
|
||||
* These functions are available from Aeropuerto.
|
||||
*/
|
||||
|
||||
struct Apple80211;
|
||||
typedef struct Apple80211 *Apple80211Ref;
|
||||
|
||||
int Apple80211Open(Apple80211Ref *ctx);
|
||||
int Apple80211Close(Apple80211Ref ctx);
|
||||
int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
|
||||
int Apple80211BindToInterface(Apple80211Ref handle,
|
||||
CFStringRef interface);
|
||||
int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
|
||||
CFStringRef *name);
|
||||
int Apple80211GetInfoCopy(Apple80211Ref handle,
|
||||
CFDictionaryRef *info);
|
||||
int Apple80211GetPower(Apple80211Ref handle, char *pwr);
|
||||
int Apple80211SetPower(Apple80211Ref handle, char pwr);
|
||||
|
||||
/* parameters can be NULL; returns scan results in CFArrayRef *list;
|
||||
* caller will need to free with CFRelease() */
|
||||
int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
|
||||
CFDictionaryRef parameters);
|
||||
|
||||
int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password);
|
||||
int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password,
|
||||
CFDictionaryRef *info);
|
||||
|
||||
enum {
|
||||
APPLE80211_VALUE_SSID = 1,
|
||||
APPLE80211_VALUE_BSSID = 9
|
||||
};
|
||||
|
||||
int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
|
||||
void *value);
|
||||
|
||||
#endif /* MOBILEAPPLE80211_H */
|
@ -131,7 +131,7 @@ struct wpa_scan_results {
|
||||
* @ifname: Interface name that can be used with init() or init2()
|
||||
* @desc: Human readable adapter description (e.g., vendor/model) or NULL if
|
||||
* not available
|
||||
* @drv_bame: struct wpa_driver_ops::name (note: unlike other strings, this one
|
||||
* @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one
|
||||
* is not an allocated copy, i.e., get_interfaces() caller will not free
|
||||
* this)
|
||||
*/
|
||||
@ -702,7 +702,7 @@ struct wpa_driver_ops {
|
||||
int (*flush_pmkid)(void *priv);
|
||||
|
||||
/**
|
||||
* flush_pmkid - Flush PMKSA cache
|
||||
* get_capa - Get driver capabilities
|
||||
* @priv: private driver interface data
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
|
506
contrib/wpa/src/drivers/driver_atmel.c
Normal file
506
contrib/wpa/src/drivers/driver_atmel.c
Normal file
@ -0,0 +1,506 @@
|
||||
/*
|
||||
* WPA Supplicant - Driver interaction with Atmel Wireless LAN drivers
|
||||
* Copyright (c) 2000-2005, ATMEL Corporation
|
||||
* Copyright (c) 2004-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.
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
Copyright 2000-2001 ATMEL Corporation.
|
||||
|
||||
WPA Supplicant - driver interaction with Atmel Wireless lan drivers.
|
||||
|
||||
This is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Atmel wireless lan drivers; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "wireless_copy.h"
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wext.h"
|
||||
|
||||
struct wpa_driver_atmel_data {
|
||||
void *wext; /* private data for driver_wext */
|
||||
void *ctx;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int sock;
|
||||
};
|
||||
|
||||
|
||||
#define ATMEL_WPA_IOCTL (SIOCIWFIRSTPRIV + 2)
|
||||
#define ATMEL_WPA_IOCTL_PARAM (SIOCIWFIRSTPRIV + 3)
|
||||
#define ATMEL_WPA_IOCTL_GET_PARAM (SIOCIWFIRSTPRIV + 4)
|
||||
|
||||
|
||||
/* ATMEL_WPA_IOCTL ioctl() cmd: */
|
||||
enum {
|
||||
SET_WPA_ENCRYPTION = 1,
|
||||
SET_CIPHER_SUITES = 2,
|
||||
MLME_STA_DEAUTH = 3,
|
||||
MLME_STA_DISASSOC = 4
|
||||
};
|
||||
|
||||
/* ATMEL_WPA_IOCTL_PARAM ioctl() cmd: */
|
||||
enum {
|
||||
ATMEL_PARAM_WPA = 1,
|
||||
ATMEL_PARAM_PRIVACY_INVOKED = 2,
|
||||
ATMEL_PARAM_WPA_TYPE = 3
|
||||
};
|
||||
|
||||
#define MAX_KEY_LENGTH 40
|
||||
|
||||
struct atmel_param{
|
||||
unsigned char sta_addr[6];
|
||||
int cmd;
|
||||
u8 alg;
|
||||
u8 key_idx;
|
||||
u8 set_tx;
|
||||
u8 seq[8];
|
||||
u8 seq_len;
|
||||
u16 key_len;
|
||||
u8 key[MAX_KEY_LENGTH];
|
||||
struct{
|
||||
int reason_code;
|
||||
u8 state;
|
||||
}mlme;
|
||||
u8 pairwise_suite;
|
||||
u8 group_suite;
|
||||
u8 key_mgmt_suite;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int atmel_ioctl(struct wpa_driver_atmel_data *drv,
|
||||
struct atmel_param *param,
|
||||
int len, int show_err)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.data.pointer = (caddr_t) param;
|
||||
iwr.u.data.length = len;
|
||||
|
||||
if (ioctl(drv->sock, ATMEL_WPA_IOCTL, &iwr) < 0) {
|
||||
int ret;
|
||||
ret = errno;
|
||||
if (show_err)
|
||||
perror("ioctl[ATMEL_WPA_IOCTL]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int atmel2param(struct wpa_driver_atmel_data *drv, int param, int value)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
int *i, ret = 0;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
i = (int *) iwr.u.name;
|
||||
*i++ = param;
|
||||
*i++ = value;
|
||||
|
||||
if (ioctl(drv->sock, ATMEL_WPA_IOCTL_PARAM, &iwr) < 0) {
|
||||
perror("ioctl[ATMEL_WPA_IOCTL_PARAM]");
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int wpa_driver_atmel_set_wpa_ie(struct wpa_driver_atmel_data *drv,
|
||||
const char *wpa_ie, size_t wpa_ie_len)
|
||||
{
|
||||
struct atmel_param *param;
|
||||
int res;
|
||||
size_t blen = ATMEL_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
|
||||
if (blen < sizeof(*param))
|
||||
blen = sizeof(*param);
|
||||
|
||||
param = os_zalloc(blen);
|
||||
if (param == NULL)
|
||||
return -1;
|
||||
|
||||
param->cmd = ATMEL_SET_GENERIC_ELEMENT;
|
||||
param->u.generic_elem.len = wpa_ie_len;
|
||||
os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
|
||||
res = atmel_ioctl(drv, param, blen, 1);
|
||||
|
||||
os_free(param);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
int ret = 0;
|
||||
|
||||
printf("wpa_driver_atmel_set_wpa %s\n", drv->ifname);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
|
||||
#if 0
|
||||
if (!enabled && wpa_driver_atmel_set_wpa_ie(drv, NULL, 0) < 0)
|
||||
ret = -1;
|
||||
#endif
|
||||
if (atmel2param(drv, ATMEL_PARAM_PRIVACY_INVOKED, enabled) < 0)
|
||||
ret = -1;
|
||||
if (atmel2param(drv, ATMEL_PARAM_WPA, enabled) < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx,
|
||||
int set_tx, const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct atmel_param *param;
|
||||
u8 *buf;
|
||||
u8 alg_type;
|
||||
|
||||
size_t blen;
|
||||
char *alg_name;
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_NONE:
|
||||
alg_name = "none";
|
||||
alg_type = 0;
|
||||
break;
|
||||
case WPA_ALG_WEP:
|
||||
alg_name = "WEP";
|
||||
alg_type = 1;
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
alg_name = "TKIP";
|
||||
alg_type = 2;
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
alg_name = "CCMP";
|
||||
alg_type = 3;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
||||
(unsigned long) seq_len, (unsigned long) key_len);
|
||||
|
||||
if (seq_len > 8)
|
||||
return -2;
|
||||
|
||||
blen = sizeof(*param) + key_len;
|
||||
buf = os_zalloc(blen);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
param = (struct atmel_param *) buf;
|
||||
|
||||
param->cmd = SET_WPA_ENCRYPTION;
|
||||
|
||||
if (addr == NULL)
|
||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
||||
else
|
||||
os_memcpy(param->sta_addr, addr, ETH_ALEN);
|
||||
|
||||
param->alg = alg_type;
|
||||
param->key_idx = key_idx;
|
||||
param->set_tx = set_tx;
|
||||
os_memcpy(param->seq, seq, seq_len);
|
||||
param->seq_len = seq_len;
|
||||
param->key_len = key_len;
|
||||
os_memcpy((u8 *)param->key, key, key_len);
|
||||
|
||||
if (atmel_ioctl(drv, param, blen, 1)) {
|
||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
||||
/* TODO: show key error*/
|
||||
ret = -1;
|
||||
}
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_set_countermeasures(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
/* FIX */
|
||||
printf("wpa_driver_atmel_set_countermeasures - not yet "
|
||||
"implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_set_drop_unencrypted(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
/* FIX */
|
||||
printf("wpa_driver_atmel_set_drop_unencrypted - not yet "
|
||||
"implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
struct atmel_param param;
|
||||
int ret;
|
||||
int mgmt_error = 0xaa;
|
||||
|
||||
os_memset(¶m, 0, sizeof(param));
|
||||
os_memcpy(param.sta_addr, addr, ETH_ALEN);
|
||||
param.cmd = cmd;
|
||||
param.mlme.reason_code = reason_code;
|
||||
param.mlme.state = mgmt_error;
|
||||
ret = atmel_ioctl(drv, ¶m, sizeof(param), 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int wpa_driver_atmel_set_suites(struct wpa_driver_atmel_data *drv,
|
||||
u8 pairwise_suite, u8 group_suite,
|
||||
u8 key_mgmt_suite)
|
||||
{
|
||||
struct atmel_param param;
|
||||
int ret;
|
||||
|
||||
os_memset(¶m, 0, sizeof(param));
|
||||
param.cmd = SET_CIPHER_SUITES;
|
||||
param.pairwise_suite = pairwise_suite;
|
||||
param.group_suite = group_suite;
|
||||
param.key_mgmt_suite = key_mgmt_suite;
|
||||
|
||||
ret = atmel_ioctl(drv, ¶m, sizeof(param), 1);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int wpa_driver_atmel_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
printf("wpa_driver_atmel_deauthenticate\n");
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DEAUTH,
|
||||
reason_code);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
printf("wpa_driver_atmel_disassociate\n");
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DISASSOC,
|
||||
reason_code);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* Atmel driver uses specific values for each cipher suite */
|
||||
static int convertSuiteToDriver(wpa_cipher suite)
|
||||
{
|
||||
u8 suite_type;
|
||||
|
||||
switch(suite) {
|
||||
case CIPHER_NONE:
|
||||
suite_type = 0;
|
||||
break;
|
||||
case CIPHER_WEP40:
|
||||
suite_type = 1;
|
||||
break;
|
||||
case CIPHER_TKIP:
|
||||
suite_type = 2;
|
||||
break;
|
||||
case CIPHER_WEP104:
|
||||
suite_type = 5;
|
||||
break;
|
||||
case CIPHER_CCMP:
|
||||
suite_type = 3;
|
||||
break;
|
||||
default:
|
||||
suite_type = 2;
|
||||
}
|
||||
|
||||
return suite_type;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
wpa_driver_atmel_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
int ret = 0;
|
||||
#if 0
|
||||
u8 pairwise_suite_driver;
|
||||
u8 group_suite_driver;
|
||||
u8 key_mgmt_suite_driver;
|
||||
|
||||
pairwise_suite_driver = convertSuiteToDriver(params->pairwise_suite);
|
||||
group_suite_driver = convertSuiteToDriver(params->group_suite);
|
||||
key_mgmt_suite_driver = convertSuiteToDriver(params->key_mgmt_suite);
|
||||
|
||||
if (wpa_driver_atmel_set_suites(drv, pairwise_suite_driver,
|
||||
group_suite_driver,
|
||||
key_mgmt_suite_driver) < 0){
|
||||
printf("wpa_driver_atmel_set_suites.\n");
|
||||
ret = -1;
|
||||
}
|
||||
if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) {
|
||||
printf("wpa_driver_atmel_set_freq.\n");
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
|
||||
< 0) {
|
||||
printf("FAILED : wpa_driver_atmel_set_ssid.\n");
|
||||
ret = -1;
|
||||
}
|
||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) {
|
||||
printf("FAILED : wpa_driver_atmel_set_bssid.\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results * wpa_driver_atmel_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_atmel_set_operstate(void *priv, int state)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
||||
if (drv->wext == NULL) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->sock < 0) {
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_atmel_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_atmel_data *drv = priv;
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
close(drv->sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_atmel_ops = {
|
||||
.name = "atmel",
|
||||
.desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
|
||||
.get_bssid = wpa_driver_atmel_get_bssid,
|
||||
.get_ssid = wpa_driver_atmel_get_ssid,
|
||||
.set_wpa = wpa_driver_atmel_set_wpa,
|
||||
.set_key = wpa_driver_atmel_set_key,
|
||||
.init = wpa_driver_atmel_init,
|
||||
.deinit = wpa_driver_atmel_deinit,
|
||||
.set_countermeasures = wpa_driver_atmel_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_atmel_set_drop_unencrypted,
|
||||
.scan = wpa_driver_atmel_scan,
|
||||
.get_scan_results2 = wpa_driver_atmel_get_scan_results,
|
||||
.deauthenticate = wpa_driver_atmel_deauthenticate,
|
||||
.disassociate = wpa_driver_atmel_disassociate,
|
||||
.associate = wpa_driver_atmel_associate,
|
||||
.set_operstate = wpa_driver_atmel_set_operstate,
|
||||
};
|
604
contrib/wpa/src/drivers/driver_broadcom.c
Normal file
604
contrib/wpa/src/drivers/driver_broadcom.c
Normal file
@ -0,0 +1,604 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with old Broadcom wl.o driver
|
||||
* Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
|
||||
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*
|
||||
* Please note that the newer Broadcom driver ("hybrid Linux driver") supports
|
||||
* Linux wireless extensions and does not need (or even work) with this old
|
||||
* driver wrapper. Use driver_wext.c with that driver.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if 0
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h> /* the L2 protocols */
|
||||
#else
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_ether.h> /* The L2 protocols */
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <typedefs.h>
|
||||
|
||||
/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
|
||||
* WRT54G GPL tarball. */
|
||||
#include <wlioctl.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
|
||||
struct wpa_driver_broadcom_data {
|
||||
void *ctx;
|
||||
int ioctl_sock;
|
||||
int event_sock;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
};
|
||||
|
||||
|
||||
#ifndef WLC_DEAUTHENTICATE
|
||||
#define WLC_DEAUTHENTICATE 143
|
||||
#endif
|
||||
#ifndef WLC_DEAUTHENTICATE_WITH_REASON
|
||||
#define WLC_DEAUTHENTICATE_WITH_REASON 201
|
||||
#endif
|
||||
#ifndef WLC_SET_TKIP_COUNTERMEASURES
|
||||
#define WLC_SET_TKIP_COUNTERMEASURES 202
|
||||
#endif
|
||||
|
||||
#if !defined(PSK_ENABLED) /* NEW driver interface */
|
||||
#define WL_VERSION 360130
|
||||
/* wireless authentication bit vector */
|
||||
#define WPA_ENABLED 1
|
||||
#define PSK_ENABLED 2
|
||||
|
||||
#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
|
||||
#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
|
||||
#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
|
||||
|
||||
#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
|
||||
|
||||
typedef wl_wsec_key_t wsec_key_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32 val;
|
||||
struct ether_addr ea;
|
||||
uint16 res;
|
||||
} wlc_deauth_t;
|
||||
|
||||
|
||||
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx);
|
||||
|
||||
static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
|
||||
void *buf, int len)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
wl_ioctl_t ioc;
|
||||
int ret = 0;
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
|
||||
drv->ifname, cmd, len, buf);
|
||||
/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
|
||||
|
||||
ioc.cmd = cmd;
|
||||
ioc.buf = buf;
|
||||
ioc.len = len;
|
||||
os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
ifr.ifr_data = (caddr_t) &ioc;
|
||||
if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
|
||||
if (cmd != WLC_GET_MAGIC)
|
||||
perror(ifr.ifr_name);
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
|
||||
cmd, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
|
||||
return 0;
|
||||
|
||||
os_memset(bssid, 0, ETH_ALEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_ssid_t s;
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
|
||||
return -1;
|
||||
|
||||
os_memcpy(ssid, s.SSID, s.SSID_len);
|
||||
return s.SSID_len;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
unsigned int wauth, wsec;
|
||||
struct ether_addr ea;
|
||||
|
||||
os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
|
||||
if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
|
||||
-1 ||
|
||||
broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
|
||||
return -1;
|
||||
|
||||
if (enable) {
|
||||
wauth = PSK_ENABLED;
|
||||
wsec = TKIP_ENABLED;
|
||||
} else {
|
||||
wauth = 255;
|
||||
wsec &= ~(TKIP_ENABLED | AES_ENABLED);
|
||||
}
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
|
||||
-1 ||
|
||||
broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
|
||||
return -1;
|
||||
|
||||
/* FIX: magic number / error handling? */
|
||||
broadcom_ioctl(drv, 122, &ea, sizeof(ea));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
int ret;
|
||||
wsec_key_t wkt;
|
||||
|
||||
os_memset(&wkt, 0, sizeof wkt);
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
|
||||
set_tx ? "PRIMARY " : "", key_idx, alg);
|
||||
if (key && key_len > 0)
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_NONE:
|
||||
wkt.algo = CRYPTO_ALGO_OFF;
|
||||
break;
|
||||
case WPA_ALG_WEP:
|
||||
wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
|
||||
* AES_OCB_MSDU, AES_OCB_MPDU? */
|
||||
break;
|
||||
default:
|
||||
wkt.algo = CRYPTO_ALGO_NALG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (seq && seq_len > 0)
|
||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
|
||||
|
||||
if (addr)
|
||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
|
||||
|
||||
wkt.index = key_idx;
|
||||
wkt.len = key_len;
|
||||
if (key && key_len > 0) {
|
||||
os_memcpy(wkt.data, key, key_len);
|
||||
if (key_len == 32) {
|
||||
/* hack hack hack XXX */
|
||||
os_memcpy(&wkt.data[16], &key[24], 8);
|
||||
os_memcpy(&wkt.data[24], &key[16], 8);
|
||||
}
|
||||
}
|
||||
/* wkt.algo = CRYPTO_ALGO_...; */
|
||||
wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
|
||||
if (addr && set_tx)
|
||||
os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
|
||||
ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
|
||||
if (addr && set_tx) {
|
||||
/* FIX: magic number / error handling? */
|
||||
broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
|
||||
void *sock_ctx)
|
||||
{
|
||||
char buf[8192];
|
||||
int left;
|
||||
wl_wpa_header_t *wwh;
|
||||
union wpa_event_data data;
|
||||
|
||||
if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
|
||||
return;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
|
||||
|
||||
if ((size_t) left < sizeof(wl_wpa_header_t))
|
||||
return;
|
||||
|
||||
wwh = (wl_wpa_header_t *) buf;
|
||||
|
||||
if (wwh->snap.type != WL_WPA_ETHER_TYPE)
|
||||
return;
|
||||
if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
|
||||
switch (wwh->type) {
|
||||
case WLC_ASSOC_MSG:
|
||||
left -= WL_WPA_HEADER_LEN;
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
|
||||
left);
|
||||
if (left > 0) {
|
||||
data.assoc_info.resp_ies = os_malloc(left);
|
||||
if (data.assoc_info.resp_ies == NULL)
|
||||
return;
|
||||
os_memcpy(data.assoc_info.resp_ies,
|
||||
buf + WL_WPA_HEADER_LEN, left);
|
||||
data.assoc_info.resp_ies_len = left;
|
||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
|
||||
"into resp_ies",
|
||||
data.assoc_info.resp_ies, left);
|
||||
}
|
||||
/* data.assoc_info.req_ies = NULL; */
|
||||
/* data.assoc_info.req_ies_len = 0; */
|
||||
|
||||
wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
|
||||
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
|
||||
break;
|
||||
case WLC_DISASSOC_MSG:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
|
||||
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
|
||||
break;
|
||||
case WLC_PTK_MIC_MSG:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
|
||||
data.michael_mic_failure.unicast = 1;
|
||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
||||
break;
|
||||
case WLC_GTK_MIC_MSG:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
|
||||
data.michael_mic_failure.unicast = 0;
|
||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
|
||||
wwh->type);
|
||||
break;
|
||||
}
|
||||
os_free(data.assoc_info.resp_ies);
|
||||
}
|
||||
|
||||
static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_ll ll;
|
||||
struct wpa_driver_broadcom_data *drv;
|
||||
struct ifreq ifr;
|
||||
|
||||
/* open socket to kernel */
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
perror("socket");
|
||||
return NULL;
|
||||
}
|
||||
/* do it */
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror(ifr.ifr_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->ioctl_sock = s;
|
||||
|
||||
s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
|
||||
if (s < 0) {
|
||||
perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
|
||||
close(drv->ioctl_sock);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&ll, 0, sizeof(ll));
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_protocol = ntohs(ETH_P_802_2);
|
||||
ll.sll_ifindex = ifr.ifr_ifindex;
|
||||
ll.sll_hatype = 0;
|
||||
ll.sll_pkttype = PACKET_HOST;
|
||||
ll.sll_halen = 0;
|
||||
|
||||
if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
|
||||
perror("bind(netlink)");
|
||||
close(s);
|
||||
close(drv->ioctl_sock);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
|
||||
NULL);
|
||||
drv->event_sock = s;
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
static void wpa_driver_broadcom_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
|
||||
eloop_unregister_read_sock(drv->event_sock);
|
||||
close(drv->event_sock);
|
||||
close(drv->ioctl_sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_countermeasures(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
#if 0
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
/* FIX: ? */
|
||||
return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
|
||||
sizeof(enabled));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
|
||||
int restrict = (enabled ? 1 : 0);
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
|
||||
&restrict, sizeof(restrict)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
|
||||
&restrict, sizeof(restrict)) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
|
||||
size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_ssid_t wst = { 0, "" };
|
||||
|
||||
if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
|
||||
wst.SSID_len = ssid_len;
|
||||
os_memcpy(wst.SSID, ssid, ssid_len);
|
||||
}
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
|
||||
return -1;
|
||||
|
||||
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
|
||||
eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const int frequency_list[] = {
|
||||
2412, 2417, 2422, 2427, 2432, 2437, 2442,
|
||||
2447, 2452, 2457, 2462, 2467, 2472, 2484
|
||||
};
|
||||
|
||||
struct bss_ie_hdr {
|
||||
u8 elem_id;
|
||||
u8 len;
|
||||
u8 oui[3];
|
||||
/* u8 oui_type; */
|
||||
/* u16 version; */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static int
|
||||
wpa_driver_broadcom_get_scan_results(void *priv,
|
||||
struct wpa_scan_result *results,
|
||||
size_t max_size)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
char *buf;
|
||||
wl_scan_results_t *wsr;
|
||||
wl_bss_info_t *wbi;
|
||||
size_t ap_num;
|
||||
|
||||
buf = os_malloc(WLC_IOCTL_MAXLEN);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
wsr = (wl_scan_results_t *) buf;
|
||||
|
||||
wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
|
||||
wsr->version = 107;
|
||||
wsr->count = 0;
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
|
||||
|
||||
for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
|
||||
int left;
|
||||
struct bss_ie_hdr *ie;
|
||||
|
||||
os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
|
||||
os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
|
||||
results[ap_num].ssid_len = wbi->SSID_len;
|
||||
results[ap_num].freq = frequency_list[wbi->channel - 1];
|
||||
/* get ie's */
|
||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
|
||||
(u8 *) wbi + sizeof(*wbi), wbi->ie_length);
|
||||
ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
|
||||
for (left = wbi->ie_length; left > 0;
|
||||
left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
|
||||
((u8 *) ie + 2 + ie->len)) {
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
|
||||
ie->elem_id, ie->len);
|
||||
if (ie->len >= 3)
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"BROADCOM: oui:%02x%02x%02x",
|
||||
ie->oui[0], ie->oui[1], ie->oui[2]);
|
||||
if (ie->elem_id != 0xdd ||
|
||||
ie->len < 6 ||
|
||||
os_memcmp(ie->oui, WPA_OUI, 3) != 0)
|
||||
continue;
|
||||
os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
|
||||
results[ap_num].wpa_ie_len = ie->len + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
|
||||
"BSSes)",
|
||||
wsr->buflen, (unsigned long) ap_num);
|
||||
|
||||
os_free(buf);
|
||||
return ap_num;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_deauth_t wdt;
|
||||
wdt.val = reason_code;
|
||||
os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
|
||||
wdt.res = 0x7fff;
|
||||
return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
|
||||
sizeof(wdt));
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_broadcom_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_ssid_t s;
|
||||
int infra = 1;
|
||||
int auth = 0;
|
||||
int wsec = 4;
|
||||
int dummy;
|
||||
int wpa_auth;
|
||||
|
||||
s.SSID_len = params->ssid_len;
|
||||
os_memcpy(s.SSID, params->ssid, params->ssid_len);
|
||||
|
||||
switch (params->pairwise_suite) {
|
||||
case CIPHER_WEP40:
|
||||
case CIPHER_WEP104:
|
||||
wsec = 1;
|
||||
break;
|
||||
|
||||
case CIPHER_TKIP:
|
||||
wsec = 2;
|
||||
break;
|
||||
|
||||
case CIPHER_CCMP:
|
||||
wsec = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
wsec = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (params->key_mgmt_suite) {
|
||||
case KEY_MGMT_802_1X:
|
||||
wpa_auth = 1;
|
||||
break;
|
||||
|
||||
case KEY_MGMT_PSK:
|
||||
wpa_auth = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_auth = 255;
|
||||
break;
|
||||
}
|
||||
|
||||
/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
|
||||
* group_suite, key_mgmt_suite);
|
||||
* broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
|
||||
* wl join uses wlc_sec_wep here, not wlc_set_wsec */
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
|
||||
sizeof(wpa_auth)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_broadcom_ops = {
|
||||
.name = "broadcom",
|
||||
.desc = "Broadcom wl.o driver",
|
||||
.get_bssid = wpa_driver_broadcom_get_bssid,
|
||||
.get_ssid = wpa_driver_broadcom_get_ssid,
|
||||
.set_wpa = wpa_driver_broadcom_set_wpa,
|
||||
.set_key = wpa_driver_broadcom_set_key,
|
||||
.init = wpa_driver_broadcom_init,
|
||||
.deinit = wpa_driver_broadcom_deinit,
|
||||
.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
|
||||
.scan = wpa_driver_broadcom_scan,
|
||||
.get_scan_results = wpa_driver_broadcom_get_scan_results,
|
||||
.deauthenticate = wpa_driver_broadcom_deauthenticate,
|
||||
.disassociate = wpa_driver_broadcom_disassociate,
|
||||
.associate = wpa_driver_broadcom_associate,
|
||||
};
|
795
contrib/wpa/src/drivers/driver_bsd.c
Normal file
795
contrib/wpa/src/drivers/driver_bsd.c
Normal file
@ -0,0 +1,795 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with BSD net80211 layer
|
||||
* Copyright (c) 2004, Sam Leffler <sam@errno.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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <net/if_ether.h>
|
||||
#define COMPAT_FREEBSD_NET80211
|
||||
#else
|
||||
#include <net/ethernet.h>
|
||||
#endif
|
||||
|
||||
#include <net80211/_ieee80211.h>
|
||||
#include <net80211/ieee80211.h>
|
||||
#include <net80211/ieee80211_crypto.h>
|
||||
#include <net80211/ieee80211_ioctl.h>
|
||||
|
||||
struct wpa_driver_bsd_data {
|
||||
int sock; /* open socket for 802.11 ioctls */
|
||||
int route; /* routing socket for events */
|
||||
char ifname[IFNAMSIZ+1]; /* interface name */
|
||||
unsigned int ifindex; /* interface index */
|
||||
void *ctx;
|
||||
int prev_roaming; /* roaming state to restore on deinit */
|
||||
int prev_privacy; /* privacy state to restore on deinit */
|
||||
int prev_wpa; /* wpa state to restore on deinit */
|
||||
};
|
||||
|
||||
static int
|
||||
set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
|
||||
{
|
||||
struct ieee80211req ireq;
|
||||
|
||||
os_memset(&ireq, 0, sizeof(ireq));
|
||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
||||
ireq.i_type = op;
|
||||
ireq.i_len = arg_len;
|
||||
ireq.i_data = (void *) arg;
|
||||
|
||||
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
|
||||
fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
|
||||
op, arg_len, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
|
||||
{
|
||||
struct ieee80211req ireq;
|
||||
|
||||
os_memset(&ireq, 0, sizeof(ireq));
|
||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
||||
ireq.i_type = op;
|
||||
ireq.i_len = arg_len;
|
||||
ireq.i_data = arg;
|
||||
|
||||
if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
|
||||
fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
|
||||
op, arg_len, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return ireq.i_len;
|
||||
}
|
||||
|
||||
static int
|
||||
set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
|
||||
{
|
||||
struct ieee80211req ireq;
|
||||
|
||||
os_memset(&ireq, 0, sizeof(ireq));
|
||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
||||
ireq.i_type = op;
|
||||
ireq.i_val = arg;
|
||||
|
||||
if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
|
||||
fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
|
||||
op, arg, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get80211param(struct wpa_driver_bsd_data *drv, int op)
|
||||
{
|
||||
struct ieee80211req ireq;
|
||||
|
||||
os_memset(&ireq, 0, sizeof(ireq));
|
||||
os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
|
||||
ireq.i_type = op;
|
||||
|
||||
if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
|
||||
fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
|
||||
op, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return ireq.i_val;
|
||||
}
|
||||
|
||||
static int
|
||||
getifflags(struct wpa_driver_bsd_data *drv, int *flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
|
||||
perror("SIOCGIFFLAGS");
|
||||
return errno;
|
||||
}
|
||||
*flags = ifr.ifr_flags & 0xffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
setifflags(struct wpa_driver_bsd_data *drv, int flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_flags = flags & 0xffff;
|
||||
if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
|
||||
perror("SIOCSIFFLAGS");
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
|
||||
return get80211var(drv, IEEE80211_IOC_BSSID,
|
||||
bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
|
||||
return set80211var(drv, IEEE80211_IOC_BSSID,
|
||||
bssid, IEEE80211_ADDR_LEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
|
||||
return get80211var(drv, IEEE80211_IOC_SSID,
|
||||
ssid, IEEE80211_NWID_LEN);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
|
||||
size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
|
||||
return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
||||
{
|
||||
return set80211var(drv, IEEE80211_IOC_APPIE, wpa_ie, wpa_ie_len);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
int ret = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
|
||||
__FUNCTION__, wpa, privacy);
|
||||
|
||||
if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
|
||||
ret = -1;
|
||||
if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
|
||||
ret = -1;
|
||||
if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
|
||||
return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
|
||||
const unsigned char *addr)
|
||||
{
|
||||
struct ieee80211req_del_key wk;
|
||||
|
||||
os_memset(&wk, 0, sizeof(wk));
|
||||
if (addr != NULL &&
|
||||
bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
|
||||
struct ether_addr ea;
|
||||
|
||||
os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
|
||||
wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
|
||||
__func__, ether_ntoa(&ea), key_idx);
|
||||
os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
|
||||
wk.idk_keyix = key_idx;
|
||||
}
|
||||
return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
|
||||
const unsigned char *addr, int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
struct ieee80211req_key wk;
|
||||
struct ether_addr ea;
|
||||
char *alg_name;
|
||||
u_int8_t cipher;
|
||||
|
||||
if (alg == WPA_ALG_NONE)
|
||||
return wpa_driver_bsd_del_key(drv, key_idx, addr);
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_WEP:
|
||||
alg_name = "WEP";
|
||||
cipher = IEEE80211_CIPHER_WEP;
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
alg_name = "TKIP";
|
||||
cipher = IEEE80211_CIPHER_TKIP;
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
alg_name = "CCMP";
|
||||
cipher = IEEE80211_CIPHER_AES_CCM;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
|
||||
__func__, alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
|
||||
__func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
|
||||
seq_len, key_len);
|
||||
|
||||
if (seq_len > sizeof(u_int64_t)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
|
||||
__func__, seq_len);
|
||||
return -2;
|
||||
}
|
||||
if (key_len > sizeof(wk.ik_keydata)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
|
||||
__func__, key_len);
|
||||
return -3;
|
||||
}
|
||||
|
||||
os_memset(&wk, 0, sizeof(wk));
|
||||
wk.ik_type = cipher;
|
||||
wk.ik_flags = IEEE80211_KEY_RECV;
|
||||
if (set_tx)
|
||||
wk.ik_flags |= IEEE80211_KEY_XMIT;
|
||||
os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
/*
|
||||
* Deduce whether group/global or unicast key by checking
|
||||
* the address (yech). Note also that we can only mark global
|
||||
* keys default; doing this for a unicast key is an error.
|
||||
*/
|
||||
if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
|
||||
wk.ik_flags |= IEEE80211_KEY_GROUP;
|
||||
wk.ik_keyix = key_idx;
|
||||
} else {
|
||||
wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
|
||||
}
|
||||
if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
|
||||
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
|
||||
wk.ik_keylen = key_len;
|
||||
os_memcpy(&wk.ik_keyrsc, seq, seq_len);
|
||||
os_memcpy(wk.ik_keydata, key, key_len);
|
||||
|
||||
return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
||||
return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
||||
return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
struct ieee80211req_mlme mlme;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s", __func__);
|
||||
os_memset(&mlme, 0, sizeof(mlme));
|
||||
mlme.im_op = IEEE80211_MLME_DEAUTH;
|
||||
mlme.im_reason = reason_code;
|
||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
struct ieee80211req_mlme mlme;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s", __func__);
|
||||
os_memset(&mlme, 0, sizeof(mlme));
|
||||
mlme.im_op = IEEE80211_MLME_DISASSOC;
|
||||
mlme.im_reason = reason_code;
|
||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
struct ieee80211req_mlme mlme;
|
||||
int privacy;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
|
||||
, __func__
|
||||
, params->ssid_len, params->ssid
|
||||
, params->wpa_ie_len
|
||||
, params->pairwise_suite
|
||||
, params->group_suite
|
||||
, params->key_mgmt_suite
|
||||
);
|
||||
|
||||
/* XXX error handling is wrong but unclear what to do... */
|
||||
if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
|
||||
return -1;
|
||||
|
||||
privacy = !(params->pairwise_suite == CIPHER_NONE &&
|
||||
params->group_suite == CIPHER_NONE &&
|
||||
params->key_mgmt_suite == KEY_MGMT_NONE &&
|
||||
params->wpa_ie_len == 0);
|
||||
wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
|
||||
|
||||
if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
|
||||
return -1;
|
||||
|
||||
if (params->wpa_ie_len &&
|
||||
set80211param(drv, IEEE80211_IOC_WPA,
|
||||
params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&mlme, 0, sizeof(mlme));
|
||||
mlme.im_op = IEEE80211_MLME_ASSOC;
|
||||
if (params->ssid != NULL)
|
||||
os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
|
||||
mlme.im_ssid_len = params->ssid_len;
|
||||
if (params->bssid != NULL)
|
||||
os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
|
||||
if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
int authmode;
|
||||
|
||||
if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
|
||||
(auth_alg & AUTH_ALG_SHARED_KEY))
|
||||
authmode = IEEE80211_AUTH_AUTO;
|
||||
else if (auth_alg & AUTH_ALG_SHARED_KEY)
|
||||
authmode = IEEE80211_AUTH_SHARED;
|
||||
else
|
||||
authmode = IEEE80211_AUTH_OPEN;
|
||||
|
||||
return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
int flags;
|
||||
|
||||
/* NB: interface must be marked UP to do a scan */
|
||||
if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
|
||||
return -1;
|
||||
|
||||
/* set desired ssid before scan */
|
||||
if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
|
||||
return -1;
|
||||
|
||||
/* NB: net80211 delivers a scan complete event so no need to poll */
|
||||
return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
|
||||
}
|
||||
|
||||
#include <net/route.h>
|
||||
#if __FreeBSD__
|
||||
#include <net80211/ieee80211_freebsd.h>
|
||||
#endif
|
||||
#if __NetBSD__
|
||||
#include <net80211/ieee80211_netbsd.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = sock_ctx;
|
||||
char buf[2048];
|
||||
struct if_announcemsghdr *ifan;
|
||||
struct if_msghdr *ifm;
|
||||
struct rt_msghdr *rtm;
|
||||
union wpa_event_data event;
|
||||
struct ieee80211_michael_event *mic;
|
||||
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;
|
||||
}
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
switch (rtm->rtm_type) {
|
||||
case RTM_IFANNOUNCE:
|
||||
ifan = (struct if_announcemsghdr *) rtm;
|
||||
if (ifan->ifan_index != drv->ifindex)
|
||||
break;
|
||||
strlcpy(event.interface_status.ifname, drv->ifname,
|
||||
sizeof(event.interface_status.ifname));
|
||||
switch (ifan->ifan_what) {
|
||||
case IFAN_DEPARTURE:
|
||||
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
|
||||
event.interface_status.ifname,
|
||||
ifan->ifan_what == IFAN_DEPARTURE ?
|
||||
"removed" : "added");
|
||||
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
|
||||
break;
|
||||
case RTM_IEEE80211:
|
||||
ifan = (struct if_announcemsghdr *) rtm;
|
||||
if (ifan->ifan_index != drv->ifindex)
|
||||
break;
|
||||
switch (ifan->ifan_what) {
|
||||
case RTM_IEEE80211_ASSOC:
|
||||
case RTM_IEEE80211_REASSOC:
|
||||
wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
|
||||
break;
|
||||
case RTM_IEEE80211_DISASSOC:
|
||||
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
|
||||
break;
|
||||
case RTM_IEEE80211_SCAN:
|
||||
wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
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));
|
||||
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.michael_mic_failure.unicast =
|
||||
!IEEE80211_IS_MULTICAST(mic->iev_dst);
|
||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
|
||||
&event);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RTM_IFINFO:
|
||||
ifm = (struct if_msghdr *) rtm;
|
||||
if (ifm->ifm_index != drv->ifindex)
|
||||
break;
|
||||
if ((rtm->rtm_flags & RTF_UP) == 0) {
|
||||
strlcpy(event.interface_status.ifname, drv->ifname,
|
||||
sizeof(event.interface_status.ifname));
|
||||
event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
|
||||
wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
|
||||
event.interface_status.ifname);
|
||||
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare function for sorting scan results. Return >0 if @b is consider
|
||||
* better. */
|
||||
static int
|
||||
wpa_scan_result_compar(const void *a, const void *b)
|
||||
{
|
||||
const struct wpa_scan_result *wa = a;
|
||||
const struct wpa_scan_result *wb = b;
|
||||
|
||||
/* WPA/WPA2 support preferred */
|
||||
if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
|
||||
!(wa->wpa_ie_len || wa->rsn_ie_len))
|
||||
return 1;
|
||||
if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
|
||||
(wa->wpa_ie_len || wa->rsn_ie_len))
|
||||
return -1;
|
||||
|
||||
/* privacy support preferred */
|
||||
if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
|
||||
(wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
|
||||
return 1;
|
||||
if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
|
||||
(wb->caps & IEEE80211_CAPINFO_PRIVACY))
|
||||
return -1;
|
||||
|
||||
/* best/max rate preferred if signal level close enough XXX */
|
||||
if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
|
||||
return wb->maxrate - wa->maxrate;
|
||||
|
||||
/* use freq for channel preference */
|
||||
|
||||
/* all things being equal, use signal level */
|
||||
return wb->level - wa->level;
|
||||
}
|
||||
|
||||
static int
|
||||
getmaxrate(uint8_t rates[15], uint8_t nrates)
|
||||
{
|
||||
int i, maxrate = -1;
|
||||
|
||||
for (i = 0; i < nrates; i++) {
|
||||
int rate = rates[i] & IEEE80211_RATE_VAL;
|
||||
if (rate > maxrate)
|
||||
rate = maxrate;
|
||||
}
|
||||
return maxrate;
|
||||
}
|
||||
|
||||
/* unalligned little endian access */
|
||||
#define LE_READ_4(p) \
|
||||
((u_int32_t) \
|
||||
((((const u_int8_t *)(p))[0] ) | \
|
||||
(((const u_int8_t *)(p))[1] << 8) | \
|
||||
(((const u_int8_t *)(p))[2] << 16) | \
|
||||
(((const u_int8_t *)(p))[3] << 24)))
|
||||
|
||||
static int __inline
|
||||
iswpaoui(const u_int8_t *frm)
|
||||
{
|
||||
return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_get_scan_results(void *priv,
|
||||
struct wpa_scan_result *results,
|
||||
size_t max_size)
|
||||
{
|
||||
#define min(a,b) ((a)>(b)?(b):(a))
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
uint8_t buf[24*1024];
|
||||
uint8_t *cp, *vp;
|
||||
struct ieee80211req_scan_result *sr;
|
||||
struct wpa_scan_result *wsr;
|
||||
int len, ielen;
|
||||
|
||||
os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
|
||||
|
||||
len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
|
||||
if (len < 0)
|
||||
return -1;
|
||||
cp = buf;
|
||||
wsr = results;
|
||||
while (len >= sizeof(struct ieee80211req_scan_result)) {
|
||||
sr = (struct ieee80211req_scan_result *) cp;
|
||||
os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
|
||||
wsr->ssid_len = sr->isr_ssid_len;
|
||||
wsr->freq = sr->isr_freq;
|
||||
wsr->noise = sr->isr_noise;
|
||||
wsr->qual = sr->isr_rssi;
|
||||
wsr->level = 0; /* XXX? */
|
||||
wsr->caps = sr->isr_capinfo;
|
||||
wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
|
||||
vp = (u_int8_t *)(sr+1);
|
||||
os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
|
||||
if (sr->isr_ie_len > 0) {
|
||||
vp += sr->isr_ssid_len;
|
||||
ielen = sr->isr_ie_len;
|
||||
while (ielen > 0) {
|
||||
switch (vp[0]) {
|
||||
case IEEE80211_ELEMID_VENDOR:
|
||||
if (!iswpaoui(vp))
|
||||
break;
|
||||
wsr->wpa_ie_len =
|
||||
min(2+vp[1], SSID_MAX_WPA_IE_LEN);
|
||||
os_memcpy(wsr->wpa_ie, vp,
|
||||
wsr->wpa_ie_len);
|
||||
break;
|
||||
case IEEE80211_ELEMID_RSN:
|
||||
wsr->rsn_ie_len =
|
||||
min(2+vp[1], SSID_MAX_WPA_IE_LEN);
|
||||
os_memcpy(wsr->rsn_ie, vp,
|
||||
wsr->rsn_ie_len);
|
||||
break;
|
||||
}
|
||||
ielen -= 2+vp[1];
|
||||
vp += 2+vp[1];
|
||||
}
|
||||
}
|
||||
|
||||
cp += sr->isr_len, len -= sr->isr_len;
|
||||
wsr++;
|
||||
}
|
||||
qsort(results, wsr - results, sizeof(struct wpa_scan_result),
|
||||
wpa_scan_result_compar);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
|
||||
len, wsr - results);
|
||||
|
||||
return wsr - results;
|
||||
#undef min
|
||||
}
|
||||
|
||||
static void *
|
||||
wpa_driver_bsd_init(void *ctx, const char *ifname)
|
||||
{
|
||||
#define GETPARAM(drv, param, v) \
|
||||
(((v) = get80211param(drv, param)) != -1)
|
||||
struct wpa_driver_bsd_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
/*
|
||||
* NB: We require the interface name be mappable to an index.
|
||||
* This implies we do not support having wpa_supplicant
|
||||
* wait for an interface to appear. This seems ok; that
|
||||
* doesn't belong here; it's really the job of devd.
|
||||
*/
|
||||
drv->ifindex = if_nametoindex(ifname);
|
||||
if (drv->ifindex == 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
|
||||
__func__, ifname);
|
||||
goto fail1;
|
||||
}
|
||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->sock < 0)
|
||||
goto fail1;
|
||||
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
|
||||
if (drv->route < 0)
|
||||
goto fail;
|
||||
eloop_register_read_sock(drv->route,
|
||||
wpa_driver_bsd_event_receive, ctx, drv);
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
|
||||
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
|
||||
__func__, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
|
||||
__func__, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
|
||||
__func__, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
|
||||
"roaming: %s", __func__, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
|
||||
__func__, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return drv;
|
||||
fail:
|
||||
close(drv->sock);
|
||||
fail1:
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
#undef GETPARAM
|
||||
}
|
||||
|
||||
static void
|
||||
wpa_driver_bsd_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_bsd_data *drv = priv;
|
||||
int flags;
|
||||
|
||||
eloop_unregister_read_sock(drv->route);
|
||||
|
||||
/* NB: mark interface down */
|
||||
if (getifflags(drv, &flags) == 0)
|
||||
(void) setifflags(drv, flags &~ IFF_UP);
|
||||
|
||||
wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
|
||||
if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
|
||||
__func__);
|
||||
|
||||
(void) close(drv->route); /* ioctl socket */
|
||||
(void) close(drv->sock); /* event socket */
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_bsd_ops = {
|
||||
.name = "bsd",
|
||||
.desc = "BSD 802.11 support (Atheros, etc.)",
|
||||
.init = wpa_driver_bsd_init,
|
||||
.deinit = wpa_driver_bsd_deinit,
|
||||
.get_bssid = wpa_driver_bsd_get_bssid,
|
||||
.get_ssid = wpa_driver_bsd_get_ssid,
|
||||
.set_wpa = wpa_driver_bsd_set_wpa,
|
||||
.set_key = wpa_driver_bsd_set_key,
|
||||
.set_countermeasures = wpa_driver_bsd_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted,
|
||||
.scan = wpa_driver_bsd_scan,
|
||||
.get_scan_results = wpa_driver_bsd_get_scan_results,
|
||||
.deauthenticate = wpa_driver_bsd_deauthenticate,
|
||||
.disassociate = wpa_driver_bsd_disassociate,
|
||||
.associate = wpa_driver_bsd_associate,
|
||||
.set_auth_alg = wpa_driver_bsd_set_auth_alg,
|
||||
};
|
513
contrib/wpa/src/drivers/driver_hostap.c
Normal file
513
contrib/wpa/src/drivers/driver_hostap.c
Normal file
@ -0,0 +1,513 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with Linux Host AP driver
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "wireless_copy.h"
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wext.h"
|
||||
#include "eloop.h"
|
||||
#include "driver_hostap.h"
|
||||
|
||||
|
||||
struct wpa_driver_hostap_data {
|
||||
void *wext; /* private data for driver_wext */
|
||||
void *ctx;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int sock;
|
||||
int current_mode; /* infra/adhoc */
|
||||
};
|
||||
|
||||
|
||||
static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
|
||||
struct prism2_hostapd_param *param,
|
||||
int len, int show_err)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.data.pointer = (caddr_t) param;
|
||||
iwr.u.data.length = len;
|
||||
|
||||
if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
|
||||
int ret = errno;
|
||||
if (show_err)
|
||||
perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
||||
{
|
||||
struct prism2_hostapd_param *param;
|
||||
int res;
|
||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_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 = wpa_ie_len;
|
||||
os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
|
||||
res = hostapd_ioctl(drv, param, blen, 1);
|
||||
|
||||
os_free(param);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int prism2param(struct wpa_driver_hostap_data *drv, int param,
|
||||
int value)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
int *i, ret = 0;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
i = (int *) iwr.u.name;
|
||||
*i++ = param;
|
||||
*i++ = value;
|
||||
|
||||
if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
|
||||
perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
int ret = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
|
||||
if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
|
||||
ret = -1;
|
||||
if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
|
||||
ret = -1;
|
||||
if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void show_set_key_error(struct prism2_hostapd_param *param)
|
||||
{
|
||||
switch (param->u.crypt.err) {
|
||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
|
||||
wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
|
||||
param->u.crypt.alg);
|
||||
wpa_printf(MSG_INFO, "You may need to load kernel module to "
|
||||
"register that algorithm.");
|
||||
wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
|
||||
"WEP.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
|
||||
wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
|
||||
MAC2STR(param->sta_addr));
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
|
||||
wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
|
||||
wpa_printf(MSG_INFO, "Key setting failed.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
|
||||
wpa_printf(MSG_INFO, "TX key index setting failed.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
|
||||
wpa_printf(MSG_INFO, "Card configuration failed.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx,
|
||||
int set_tx, const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
struct prism2_hostapd_param *param;
|
||||
u8 *buf;
|
||||
size_t blen;
|
||||
int ret = 0;
|
||||
char *alg_name;
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_NONE:
|
||||
alg_name = "none";
|
||||
break;
|
||||
case WPA_ALG_WEP:
|
||||
alg_name = "WEP";
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
alg_name = "TKIP";
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
alg_name = "CCMP";
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
||||
(unsigned long) seq_len, (unsigned long) key_len);
|
||||
|
||||
if (seq_len > 8)
|
||||
return -2;
|
||||
|
||||
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;
|
||||
/* TODO: In theory, STA in client mode can use five keys; four default
|
||||
* keys for receiving (with keyidx 0..3) and one individual key for
|
||||
* both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
|
||||
* keyidx 0 is reserved for this unicast use and default keys can only
|
||||
* use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
|
||||
* This should be fine for more or less all cases, but for completeness
|
||||
* sake, the driver could be enhanced to support the missing key. */
|
||||
#if 0
|
||||
if (addr == NULL)
|
||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
||||
else
|
||||
os_memcpy(param->sta_addr, addr, ETH_ALEN);
|
||||
#else
|
||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
||||
#endif
|
||||
os_strlcpy((char *) param->u.crypt.alg, alg_name,
|
||||
HOSTAP_CRYPT_ALG_NAME_LEN);
|
||||
param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
|
||||
param->u.crypt.idx = key_idx;
|
||||
os_memcpy(param->u.crypt.seq, seq, seq_len);
|
||||
param->u.crypt.key_len = key_len;
|
||||
os_memcpy((u8 *) (param + 1), key, key_len);
|
||||
|
||||
if (hostapd_ioctl(drv, param, blen, 1)) {
|
||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
||||
show_set_key_error(param);
|
||||
ret = -1;
|
||||
}
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
|
||||
int type)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
int *i, ret = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
i = (int *) iwr.u.name;
|
||||
*i++ = type;
|
||||
|
||||
if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
|
||||
perror("ioctl[PRISM2_IOCTL_RESET]");
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
|
||||
const u8 *addr, int cmd, int reason_code)
|
||||
{
|
||||
struct prism2_hostapd_param param;
|
||||
int ret;
|
||||
|
||||
/* There does not seem to be a better way of deauthenticating or
|
||||
* disassociating with Prism2/2.5/3 than sending the management frame
|
||||
* and then resetting the Port0 to make sure both the AP and the STA
|
||||
* end up in disconnected state. */
|
||||
os_memset(¶m, 0, sizeof(param));
|
||||
param.cmd = PRISM2_HOSTAPD_MLME;
|
||||
os_memcpy(param.sta_addr, addr, ETH_ALEN);
|
||||
param.u.mlme.cmd = cmd;
|
||||
param.u.mlme.reason_code = reason_code;
|
||||
ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1);
|
||||
if (ret == 0) {
|
||||
os_sleep(0, 100000);
|
||||
ret = wpa_driver_hostap_reset(drv, 2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
|
||||
reason_code);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
|
||||
reason_code);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
wpa_driver_hostap_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
int ret = 0;
|
||||
int allow_unencrypted_eapol;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
|
||||
if (params->mode != drv->current_mode) {
|
||||
/* At the moment, Host AP driver requires host_roaming=2 for
|
||||
* infrastructure mode and host_roaming=0 for adhoc. */
|
||||
if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
|
||||
params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
|
||||
0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
|
||||
__func__);
|
||||
}
|
||||
drv->current_mode = params->mode;
|
||||
}
|
||||
|
||||
if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
|
||||
params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
|
||||
params->wpa_ie_len) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
|
||||
ret = -1;
|
||||
if (params->freq &&
|
||||
wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
|
||||
< 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
|
||||
ret = -1;
|
||||
|
||||
/* Allow unencrypted EAPOL messages even if pairwise keys are set when
|
||||
* not using WPA. IEEE 802.1X specifies that these frames are not
|
||||
* encrypted, but WPA encrypts them when pairwise keys are in use. */
|
||||
if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
|
||||
params->key_mgmt_suite == KEY_MGMT_PSK)
|
||||
allow_unencrypted_eapol = 0;
|
||||
else
|
||||
allow_unencrypted_eapol = 1;
|
||||
|
||||
if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
|
||||
allow_unencrypted_eapol) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
|
||||
"ieee_802_1x param");
|
||||
/* Ignore this error.. driver_hostap.c can also be used with
|
||||
* other drivers that do not support this prism2_param. */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
struct prism2_hostapd_param param;
|
||||
int ret;
|
||||
|
||||
if (ssid == NULL) {
|
||||
/* Use standard Linux Wireless Extensions ioctl if possible
|
||||
* because some drivers using hostap code in wpa_supplicant
|
||||
* might not support Host AP specific scan request (with SSID
|
||||
* info). */
|
||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
||||
}
|
||||
|
||||
if (ssid_len > 32)
|
||||
ssid_len = 32;
|
||||
|
||||
os_memset(¶m, 0, sizeof(param));
|
||||
param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
|
||||
param.u.scan_req.ssid_len = ssid_len;
|
||||
os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
|
||||
ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1);
|
||||
|
||||
/* Not all drivers generate "scan completed" wireless event, so try to
|
||||
* read results after a timeout. */
|
||||
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
|
||||
drv->ctx);
|
||||
eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
|
||||
drv->ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
int algs = 0;
|
||||
|
||||
if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
|
||||
algs |= 1;
|
||||
if (auth_alg & AUTH_ALG_SHARED_KEY)
|
||||
algs |= 2;
|
||||
if (auth_alg & AUTH_ALG_LEAP)
|
||||
algs |= 4;
|
||||
if (algs == 0)
|
||||
algs = 1; /* at least one algorithm should be set */
|
||||
|
||||
return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_hostap_set_operstate(void *priv, int state)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
||||
if (drv->wext == NULL) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->sock < 0) {
|
||||
perror("socket");
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (os_strncmp(ifname, "wlan", 4) == 0) {
|
||||
/*
|
||||
* Host AP driver may use both wlan# and wifi# interface in
|
||||
* wireless events.
|
||||
*/
|
||||
char ifname2[IFNAMSIZ + 1];
|
||||
os_strlcpy(ifname2, ifname, sizeof(ifname2));
|
||||
os_memcpy(ifname2, "wifi", 4);
|
||||
wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_hostap_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_hostap_data *drv = priv;
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
close(drv->sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_hostap_ops = {
|
||||
.name = "hostap",
|
||||
.desc = "Host AP driver (Intersil Prism2/2.5/3)",
|
||||
.get_bssid = wpa_driver_hostap_get_bssid,
|
||||
.get_ssid = wpa_driver_hostap_get_ssid,
|
||||
.set_wpa = wpa_driver_hostap_set_wpa,
|
||||
.set_key = wpa_driver_hostap_set_key,
|
||||
.set_countermeasures = wpa_driver_hostap_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted,
|
||||
.scan = wpa_driver_hostap_scan,
|
||||
.get_scan_results2 = wpa_driver_hostap_get_scan_results,
|
||||
.deauthenticate = wpa_driver_hostap_deauthenticate,
|
||||
.disassociate = wpa_driver_hostap_disassociate,
|
||||
.associate = wpa_driver_hostap_associate,
|
||||
.set_auth_alg = wpa_driver_hostap_set_auth_alg,
|
||||
.init = wpa_driver_hostap_init,
|
||||
.deinit = wpa_driver_hostap_deinit,
|
||||
.set_operstate = wpa_driver_hostap_set_operstate,
|
||||
};
|
153
contrib/wpa/src/drivers/driver_hostap.h
Normal file
153
contrib/wpa/src/drivers/driver_hostap.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with Linux Host AP driver
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef HOSTAP_DRIVER_H
|
||||
#define HOSTAP_DRIVER_H
|
||||
|
||||
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
|
||||
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
|
||||
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
|
||||
|
||||
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
|
||||
enum {
|
||||
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
|
||||
PRISM2_PARAM_TXRATECTRL = 2,
|
||||
PRISM2_PARAM_BEACON_INT = 3,
|
||||
PRISM2_PARAM_PSEUDO_IBSS = 4,
|
||||
PRISM2_PARAM_ALC = 5,
|
||||
/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
|
||||
PRISM2_PARAM_DUMP = 7,
|
||||
PRISM2_PARAM_OTHER_AP_POLICY = 8,
|
||||
PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
|
||||
PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
|
||||
PRISM2_PARAM_DTIM_PERIOD = 11,
|
||||
PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
|
||||
PRISM2_PARAM_MAX_WDS = 13,
|
||||
PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
|
||||
PRISM2_PARAM_AP_AUTH_ALGS = 15,
|
||||
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
|
||||
PRISM2_PARAM_HOST_ENCRYPT = 17,
|
||||
PRISM2_PARAM_HOST_DECRYPT = 18,
|
||||
PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
|
||||
PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
|
||||
PRISM2_PARAM_HOST_ROAMING = 21,
|
||||
PRISM2_PARAM_BCRX_STA_KEY = 22,
|
||||
PRISM2_PARAM_IEEE_802_1X = 23,
|
||||
PRISM2_PARAM_ANTSEL_TX = 24,
|
||||
PRISM2_PARAM_ANTSEL_RX = 25,
|
||||
PRISM2_PARAM_MONITOR_TYPE = 26,
|
||||
PRISM2_PARAM_WDS_TYPE = 27,
|
||||
PRISM2_PARAM_HOSTSCAN = 28,
|
||||
PRISM2_PARAM_AP_SCAN = 29,
|
||||
PRISM2_PARAM_ENH_SEC = 30,
|
||||
PRISM2_PARAM_IO_DEBUG = 31,
|
||||
PRISM2_PARAM_BASIC_RATES = 32,
|
||||
PRISM2_PARAM_OPER_RATES = 33,
|
||||
PRISM2_PARAM_HOSTAPD = 34,
|
||||
PRISM2_PARAM_HOSTAPD_STA = 35,
|
||||
PRISM2_PARAM_WPA = 36,
|
||||
PRISM2_PARAM_PRIVACY_INVOKED = 37,
|
||||
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
|
||||
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
|
||||
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
|
||||
};
|
||||
|
||||
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
|
||||
enum {
|
||||
PRISM2_HOSTAPD_FLUSH = 1,
|
||||
PRISM2_HOSTAPD_ADD_STA = 2,
|
||||
PRISM2_HOSTAPD_REMOVE_STA = 3,
|
||||
PRISM2_HOSTAPD_GET_INFO_STA = 4,
|
||||
/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
|
||||
PRISM2_SET_ENCRYPTION = 6,
|
||||
PRISM2_GET_ENCRYPTION = 7,
|
||||
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
|
||||
PRISM2_HOSTAPD_GET_RID = 9,
|
||||
PRISM2_HOSTAPD_SET_RID = 10,
|
||||
PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
|
||||
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
|
||||
PRISM2_HOSTAPD_MLME = 13,
|
||||
PRISM2_HOSTAPD_SCAN_REQ = 14,
|
||||
PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
|
||||
};
|
||||
|
||||
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
|
||||
#define PRISM2_HOSTAPD_RID_HDR_LEN \
|
||||
((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
|
||||
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
|
||||
((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
|
||||
|
||||
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
|
||||
*/
|
||||
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
|
||||
|
||||
|
||||
struct prism2_hostapd_param {
|
||||
u32 cmd;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
union {
|
||||
struct {
|
||||
u16 aid;
|
||||
u16 capability;
|
||||
u8 tx_supp_rates;
|
||||
} add_sta;
|
||||
struct {
|
||||
u32 inactive_sec;
|
||||
} get_info_sta;
|
||||
struct {
|
||||
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
|
||||
u32 flags;
|
||||
u32 err;
|
||||
u8 idx;
|
||||
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
|
||||
u16 key_len;
|
||||
u8 key[0];
|
||||
} crypt;
|
||||
struct {
|
||||
u32 flags_and;
|
||||
u32 flags_or;
|
||||
} set_flags_sta;
|
||||
struct {
|
||||
u16 rid;
|
||||
u16 len;
|
||||
u8 data[0];
|
||||
} rid;
|
||||
struct {
|
||||
u8 len;
|
||||
u8 data[0];
|
||||
} generic_elem;
|
||||
struct {
|
||||
#define MLME_STA_DEAUTH 0
|
||||
#define MLME_STA_DISASSOC 1
|
||||
u16 cmd;
|
||||
u16 reason_code;
|
||||
} mlme;
|
||||
struct {
|
||||
u8 ssid_len;
|
||||
u8 ssid[32];
|
||||
} scan_req;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
|
||||
#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
|
||||
|
||||
#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
|
||||
#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
|
||||
#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
|
||||
#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
|
||||
#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
|
||||
#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
|
||||
|
||||
#endif /* HOSTAP_DRIVER_H */
|
466
contrib/wpa/src/drivers/driver_iphone.m
Normal file
466
contrib/wpa/src/drivers/driver_iphone.m
Normal file
@ -0,0 +1,466 @@
|
||||
/*
|
||||
* WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
|
||||
* Copyright (c) 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"
|
||||
#define Boolean __DummyBoolean
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#undef Boolean
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
|
||||
#include "MobileApple80211.h"
|
||||
|
||||
struct wpa_driver_iphone_data {
|
||||
void *ctx;
|
||||
Apple80211Ref wireless_ctx;
|
||||
CFArrayRef scan_results;
|
||||
int ctrl_power;
|
||||
};
|
||||
|
||||
|
||||
static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
|
||||
{
|
||||
const void *res;
|
||||
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
|
||||
kCFStringEncodingMacRoman);
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
res = CFDictionaryGetValue(dict, str);
|
||||
CFRelease(str);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
CFDataRef data;
|
||||
int err, len;
|
||||
|
||||
err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
|
||||
&data);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
|
||||
"failed: %d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = CFDataGetLength(data);
|
||||
if (len > 32) {
|
||||
CFRelease(data);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(ssid, CFDataGetBytePtr(data), len);
|
||||
CFRelease(data);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
CFStringRef data;
|
||||
int err;
|
||||
int a1, a2, a3, a4, a5, a6;
|
||||
|
||||
err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
|
||||
&data);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
|
||||
"failed: %d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
|
||||
"%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
|
||||
bssid[0] = a1;
|
||||
bssid[1] = a2;
|
||||
bssid[2] = a3;
|
||||
bssid[3] = a4;
|
||||
bssid[4] = a5;
|
||||
bssid[5] = a6;
|
||||
|
||||
CFRelease(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
int err;
|
||||
|
||||
if (drv->scan_results) {
|
||||
CFRelease(drv->scan_results);
|
||||
drv->scan_results = NULL;
|
||||
}
|
||||
|
||||
err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
|
||||
err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_scan_results(void *priv,
|
||||
struct wpa_scan_result *results,
|
||||
size_t max_size)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
size_t i, num;
|
||||
|
||||
if (drv->scan_results == NULL)
|
||||
return 0;
|
||||
|
||||
num = CFArrayGetCount(drv->scan_results);
|
||||
if (num > max_size)
|
||||
num = max_size;
|
||||
os_memset(results, 0, num * sizeof(struct wpa_scan_result));
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct wpa_scan_result *res = &results[i];
|
||||
CFDictionaryRef dict =
|
||||
CFArrayGetValueAtIndex(drv->scan_results, i);
|
||||
CFDataRef data;
|
||||
CFStringRef str;
|
||||
CFNumberRef num;
|
||||
int val;
|
||||
|
||||
data = cfdict_get_key_str(dict, "SSID");
|
||||
if (data) {
|
||||
res->ssid_len = CFDataGetLength(data);
|
||||
if (res->ssid_len > 32)
|
||||
res->ssid_len = 32;
|
||||
os_memcpy(res->ssid, CFDataGetBytePtr(data),
|
||||
res->ssid_len);
|
||||
}
|
||||
|
||||
str = cfdict_get_key_str(dict, "BSSID");
|
||||
if (str) {
|
||||
int a1, a2, a3, a4, a5, a6;
|
||||
sscanf(CFStringGetCStringPtr(
|
||||
str, kCFStringEncodingMacRoman),
|
||||
"%x:%x:%x:%x:%x:%x",
|
||||
&a1, &a2, &a3, &a4, &a5, &a6);
|
||||
res->bssid[0] = a1;
|
||||
res->bssid[1] = a2;
|
||||
res->bssid[2] = a3;
|
||||
res->bssid[3] = a4;
|
||||
res->bssid[4] = a5;
|
||||
res->bssid[5] = a6;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "CAPABILITIES");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->caps = val;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "CHANNEL");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->freq = 2407 + val * 5;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "RSSI");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->level = val;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "NOISE");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->noise = val;
|
||||
}
|
||||
|
||||
data = cfdict_get_key_str(dict, "IE");
|
||||
if (data) {
|
||||
u8 *ptr = (u8 *) CFDataGetBytePtr(data);
|
||||
int len = CFDataGetLength(data);
|
||||
u8 *pos = ptr, *end = ptr + len;
|
||||
|
||||
while (pos + 2 < end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
break;
|
||||
if (pos[0] == WLAN_EID_RSN &&
|
||||
pos[1] <= SSID_MAX_WPA_IE_LEN) {
|
||||
os_memcpy(res->rsn_ie, pos,
|
||||
2 + pos[1]);
|
||||
res->rsn_ie_len = 2 + pos[1];
|
||||
}
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
|
||||
pos[1] > 4 && pos[2] == 0x00 &&
|
||||
pos[3] == 0x50 && pos[4] == 0xf2 &&
|
||||
pos[5] == 0x01) {
|
||||
os_memcpy(res->wpa_ie, pos,
|
||||
2 + pos[1]);
|
||||
res->wpa_ie_len = 2 + pos[1];
|
||||
}
|
||||
|
||||
pos = pos + 2 + pos[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = eloop_ctx;
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
|
||||
eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
|
||||
drv, drv->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_associate(
|
||||
void *priv, struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
int i, num, err;
|
||||
size_t ssid_len;
|
||||
CFDictionaryRef bss = NULL;
|
||||
|
||||
/*
|
||||
* TODO: Consider generating parameters instead of just using an entry
|
||||
* from scan results in order to support ap_scan=2.
|
||||
*/
|
||||
|
||||
if (drv->scan_results == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
|
||||
"associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = CFArrayGetCount(drv->scan_results);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
CFDictionaryRef dict =
|
||||
CFArrayGetValueAtIndex(drv->scan_results, i);
|
||||
CFDataRef data;
|
||||
|
||||
data = cfdict_get_key_str(dict, "SSID");
|
||||
if (data == NULL)
|
||||
continue;
|
||||
|
||||
ssid_len = CFDataGetLength(data);
|
||||
if (ssid_len != params->ssid_len ||
|
||||
os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
|
||||
!= 0)
|
||||
continue;
|
||||
|
||||
bss = dict;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bss == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
|
||||
"results - cannot associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
|
||||
"from scan results");
|
||||
|
||||
err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
|
||||
"%d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver is actually already associated; report association from an
|
||||
* eloop callback.
|
||||
*/
|
||||
eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
|
||||
eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
|
||||
drv->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx, const u8 *seq,
|
||||
size_t seq_len, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
/*
|
||||
* TODO: Need to either support configuring PMK for 4-way handshake or
|
||||
* PTK for TKIP/CCMP.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
os_memset(capa, 0, sizeof(*capa));
|
||||
|
||||
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
|
||||
capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
|
||||
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
|
||||
capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
|
||||
WPA_DRIVER_AUTH_LEAP;
|
||||
capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv;
|
||||
int err;
|
||||
char power;
|
||||
CFStringRef name;
|
||||
CFDictionaryRef dict;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
err = Apple80211Open(&drv->wireless_ctx);
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
|
||||
err);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
|
||||
kCFStringEncodingISOLatin1);
|
||||
if (name == NULL) {
|
||||
wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
|
||||
Apple80211Close(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = Apple80211BindToInterface(drv->wireless_ctx, name);
|
||||
CFRelease(name);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
|
||||
"failed: %d", err);
|
||||
Apple80211Close(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = Apple80211GetPower(drv->wireless_ctx, &power);
|
||||
if (err)
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
|
||||
err);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
|
||||
|
||||
if (!power) {
|
||||
drv->ctrl_power = 1;
|
||||
err = Apple80211SetPower(drv->wireless_ctx, 1);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
|
||||
"failed: %d", err);
|
||||
Apple80211Close(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
|
||||
if (err == 0) {
|
||||
CFShow(dict);
|
||||
CFRelease(dict);
|
||||
} else {
|
||||
printf("Apple80211GetInfoCopy: %d\n", err);
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_iphone_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
int err;
|
||||
|
||||
eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
|
||||
eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
|
||||
|
||||
if (drv->ctrl_power) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
|
||||
err = Apple80211SetPower(drv->wireless_ctx, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
|
||||
"failed: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
err = Apple80211Close(drv->wireless_ctx);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
|
||||
err);
|
||||
}
|
||||
|
||||
if (drv->scan_results)
|
||||
CFRelease(drv->scan_results);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_iphone_ops = {
|
||||
.name = "iphone",
|
||||
.desc = "iPhone/iPod touch Apple80211 driver",
|
||||
.get_ssid = wpa_driver_iphone_get_ssid,
|
||||
.get_bssid = wpa_driver_iphone_get_bssid,
|
||||
.init = wpa_driver_iphone_init,
|
||||
.deinit = wpa_driver_iphone_deinit,
|
||||
.scan = wpa_driver_iphone_scan,
|
||||
.get_scan_results = wpa_driver_iphone_get_scan_results,
|
||||
.associate = wpa_driver_iphone_associate,
|
||||
.set_key = wpa_driver_iphone_set_key,
|
||||
.get_capa = wpa_driver_iphone_get_capa,
|
||||
};
|
463
contrib/wpa/src/drivers/driver_ipw.c
Normal file
463
contrib/wpa/src/drivers/driver_ipw.c
Normal file
@ -0,0 +1,463 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
|
||||
* Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com>
|
||||
* Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk>
|
||||
* Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*
|
||||
* Please note that ipw2100/2200 drivers change to use generic Linux wireless
|
||||
* extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
|
||||
* or newer). driver_wext.c should be used in those cases.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "wireless_copy.h"
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wext.h"
|
||||
|
||||
struct wpa_driver_ipw_data {
|
||||
void *wext; /* private data for driver_wext */
|
||||
void *ctx;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int sock;
|
||||
};
|
||||
|
||||
/* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
|
||||
|
||||
#define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
|
||||
|
||||
#define IPW_CMD_SET_WPA_PARAM 1
|
||||
#define IPW_CMD_SET_WPA_IE 2
|
||||
#define IPW_CMD_SET_ENCRYPTION 3
|
||||
#define IPW_CMD_MLME 4
|
||||
|
||||
#define IPW_PARAM_WPA_ENABLED 1
|
||||
#define IPW_PARAM_TKIP_COUNTERMEASURES 2
|
||||
#define IPW_PARAM_DROP_UNENCRYPTED 3
|
||||
#define IPW_PARAM_PRIVACY_INVOKED 4
|
||||
#define IPW_PARAM_AUTH_ALGS 5
|
||||
#define IPW_PARAM_IEEE_802_1X 6
|
||||
|
||||
#define IPW_MLME_STA_DEAUTH 1
|
||||
#define IPW_MLME_STA_DISASSOC 2
|
||||
|
||||
#define IPW_CRYPT_ERR_UNKNOWN_ALG 2
|
||||
#define IPW_CRYPT_ERR_UNKNOWN_ADDR 3
|
||||
#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4
|
||||
#define IPW_CRYPT_ERR_KEY_SET_FAILED 5
|
||||
#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6
|
||||
#define IPW_CRYPT_ERR_CARD_CONF_FAILED 7
|
||||
|
||||
#define IPW_CRYPT_ALG_NAME_LEN 16
|
||||
|
||||
struct ipw_param {
|
||||
u32 cmd;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
union {
|
||||
struct {
|
||||
u8 name;
|
||||
u32 value;
|
||||
} wpa_param;
|
||||
struct {
|
||||
u32 len;
|
||||
u8 reserved[32];
|
||||
u8 data[0];
|
||||
} wpa_ie;
|
||||
struct{
|
||||
u32 command;
|
||||
u32 reason_code;
|
||||
} mlme;
|
||||
struct {
|
||||
u8 alg[IPW_CRYPT_ALG_NAME_LEN];
|
||||
u8 set_tx;
|
||||
u32 err;
|
||||
u8 idx;
|
||||
u8 seq[8];
|
||||
u16 key_len;
|
||||
u8 key[0];
|
||||
} crypt;
|
||||
|
||||
} u;
|
||||
};
|
||||
|
||||
/* end of ipw2100.c and ipw2200.c code */
|
||||
|
||||
static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
|
||||
struct ipw_param *param, int len, int show_err)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.data.pointer = (caddr_t) param;
|
||||
iwr.u.data.length = len;
|
||||
|
||||
if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
|
||||
int ret = errno;
|
||||
if (show_err)
|
||||
perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ipw_show_set_key_error(struct ipw_param *param)
|
||||
{
|
||||
switch (param->u.crypt.err) {
|
||||
case IPW_CRYPT_ERR_UNKNOWN_ALG:
|
||||
wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
|
||||
param->u.crypt.alg);
|
||||
wpa_printf(MSG_INFO, "You may need to load kernel module to "
|
||||
"register that algorithm.");
|
||||
wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
|
||||
" WEP.");
|
||||
break;
|
||||
case IPW_CRYPT_ERR_UNKNOWN_ADDR:
|
||||
wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
|
||||
MAC2STR(param->sta_addr));
|
||||
break;
|
||||
case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
|
||||
wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
|
||||
break;
|
||||
case IPW_CRYPT_ERR_KEY_SET_FAILED:
|
||||
wpa_printf(MSG_INFO, "Key setting failed.");
|
||||
break;
|
||||
case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
|
||||
wpa_printf(MSG_INFO, "TX key index setting failed.");
|
||||
break;
|
||||
case IPW_CRYPT_ERR_CARD_CONF_FAILED:
|
||||
wpa_printf(MSG_INFO, "Card configuration failed.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
||||
{
|
||||
struct ipw_param *param;
|
||||
int ret;
|
||||
size_t blen = sizeof(*param) + wpa_ie_len;
|
||||
|
||||
param = os_zalloc(blen);
|
||||
if (param == NULL)
|
||||
return -1;
|
||||
|
||||
param->cmd = IPW_CMD_SET_WPA_IE;
|
||||
param->u.wpa_ie.len = wpa_ie_len;
|
||||
os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
|
||||
|
||||
ret = ipw_ioctl(drv, param, blen, 1);
|
||||
|
||||
os_free(param);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
|
||||
u32 value)
|
||||
{
|
||||
struct ipw_param param;
|
||||
|
||||
os_memset(¶m, 0, sizeof(param));
|
||||
param.cmd = IPW_CMD_SET_WPA_PARAM;
|
||||
param.u.wpa_param.name = name;
|
||||
param.u.wpa_param.value = value;
|
||||
|
||||
return ipw_ioctl(drv, ¶m, sizeof(param), 1);
|
||||
}
|
||||
|
||||
|
||||
static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
|
||||
int cmd, int reason)
|
||||
{
|
||||
struct ipw_param param;
|
||||
|
||||
os_memset(¶m, 0, sizeof(param));
|
||||
os_memcpy(param.sta_addr, addr, ETH_ALEN);
|
||||
param.cmd = IPW_CMD_MLME;
|
||||
param.u.mlme.command = cmd;
|
||||
param.u.mlme.reason_code = reason;
|
||||
|
||||
return ipw_ioctl(drv, ¶m, sizeof(param), 1);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
int ret = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
|
||||
if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
struct ipw_param *param;
|
||||
u8 *buf;
|
||||
size_t blen;
|
||||
int ret = 0;
|
||||
char *alg_name;
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_NONE:
|
||||
alg_name = "none";
|
||||
break;
|
||||
case WPA_ALG_WEP:
|
||||
alg_name = "WEP";
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
alg_name = "TKIP";
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
alg_name = "CCMP";
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
||||
(unsigned long) seq_len, (unsigned long) key_len);
|
||||
|
||||
if (seq_len > 8)
|
||||
return -2;
|
||||
|
||||
blen = sizeof(*param) + key_len;
|
||||
buf = os_zalloc(blen);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
param = (struct ipw_param *) buf;
|
||||
param->cmd = IPW_CMD_SET_ENCRYPTION;
|
||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
||||
os_strlcpy((char *) param->u.crypt.alg, alg_name,
|
||||
IPW_CRYPT_ALG_NAME_LEN);
|
||||
param->u.crypt.set_tx = set_tx ? 1 : 0;
|
||||
param->u.crypt.idx = key_idx;
|
||||
os_memcpy(param->u.crypt.seq, seq, seq_len);
|
||||
param->u.crypt.key_len = key_len;
|
||||
os_memcpy((u8 *) (param + 1), key, key_len);
|
||||
|
||||
if (ipw_ioctl(drv, param, blen, 1)) {
|
||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
||||
ipw_show_set_key_error(param);
|
||||
ret = -1;
|
||||
}
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
|
||||
enabled);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
|
||||
enabled);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
int ret = 0;
|
||||
int unencrypted_eapol;
|
||||
|
||||
if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
||||
params->ssid_len) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
|
||||
params->key_mgmt_suite == KEY_MGMT_PSK)
|
||||
unencrypted_eapol = 0;
|
||||
else
|
||||
unencrypted_eapol = 1;
|
||||
|
||||
if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
|
||||
unencrypted_eapol) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
|
||||
"ieee_802_1x param");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
int algs = 0;
|
||||
|
||||
if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
|
||||
algs |= 1;
|
||||
if (auth_alg & AUTH_ALG_SHARED_KEY)
|
||||
algs |= 2;
|
||||
if (auth_alg & AUTH_ALG_LEAP)
|
||||
algs |= 4;
|
||||
if (algs == 0)
|
||||
algs = 1; /* at least one algorithm should be set */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
|
||||
return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_ipw_set_operstate(void *priv, int state)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv;
|
||||
int ver;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
||||
if (drv->wext == NULL) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ver = wpa_driver_wext_get_version(drv->wext);
|
||||
if (ver >= 18) {
|
||||
wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
|
||||
"detected.", ver);
|
||||
wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
|
||||
"(-Dwext) instead of driver_ipw.");
|
||||
}
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->sock < 0) {
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_ipw_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_ipw_data *drv = priv;
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
close(drv->sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_ipw_ops = {
|
||||
.name = "ipw",
|
||||
.desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
|
||||
"or newer)",
|
||||
.get_bssid = wpa_driver_ipw_get_bssid,
|
||||
.get_ssid = wpa_driver_ipw_get_ssid,
|
||||
.set_wpa = wpa_driver_ipw_set_wpa,
|
||||
.set_key = wpa_driver_ipw_set_key,
|
||||
.set_countermeasures = wpa_driver_ipw_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
|
||||
.scan = wpa_driver_ipw_scan,
|
||||
.get_scan_results2 = wpa_driver_ipw_get_scan_results,
|
||||
.deauthenticate = wpa_driver_ipw_deauthenticate,
|
||||
.disassociate = wpa_driver_ipw_disassociate,
|
||||
.associate = wpa_driver_ipw_associate,
|
||||
.set_auth_alg = wpa_driver_ipw_set_auth_alg,
|
||||
.init = wpa_driver_ipw_init,
|
||||
.deinit = wpa_driver_ipw_deinit,
|
||||
.set_operstate = wpa_driver_ipw_set_operstate,
|
||||
};
|
601
contrib/wpa/src/drivers/driver_madwifi.c
Normal file
601
contrib/wpa/src/drivers/driver_madwifi.c
Normal file
@ -0,0 +1,601 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with MADWIFI 802.11 driver
|
||||
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
|
||||
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*
|
||||
* Please note that madwifi supports WPA configuration via Linux wireless
|
||||
* extensions and if the kernel includes support for this, driver_wext.c should
|
||||
* be used instead of this driver wrapper.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wext.h"
|
||||
#include "eloop.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "wireless_copy.h"
|
||||
|
||||
/*
|
||||
* Avoid conflicts with wpa_supplicant definitions by undefining a definition.
|
||||
*/
|
||||
#undef WME_OUI_TYPE
|
||||
|
||||
#include <include/compat.h>
|
||||
#include <net80211/ieee80211.h>
|
||||
#ifdef WME_NUM_AC
|
||||
/* Assume this is built against BSD branch of madwifi driver. */
|
||||
#define MADWIFI_BSD
|
||||
#include <net80211/_ieee80211.h>
|
||||
#endif /* WME_NUM_AC */
|
||||
#include <net80211/ieee80211_crypto.h>
|
||||
#include <net80211/ieee80211_ioctl.h>
|
||||
|
||||
|
||||
#ifdef IEEE80211_IOCTL_SETWMMPARAMS
|
||||
/* Assume this is built against madwifi-ng */
|
||||
#define MADWIFI_NG
|
||||
#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
|
||||
|
||||
struct wpa_driver_madwifi_data {
|
||||
void *wext; /* private data for driver_wext */
|
||||
void *ctx;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int sock;
|
||||
};
|
||||
|
||||
static int
|
||||
set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
|
||||
int show_err)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
if (len < IFNAMSIZ &&
|
||||
op != IEEE80211_IOCTL_SET_APPIEBUF) {
|
||||
/*
|
||||
* Argument data fits inline; put it there.
|
||||
*/
|
||||
os_memcpy(iwr.u.name, data, len);
|
||||
} else {
|
||||
/*
|
||||
* Argument data too big for inline transfer; setup a
|
||||
* parameter block instead; the kernel will transfer
|
||||
* the data for the driver.
|
||||
*/
|
||||
iwr.u.data.pointer = data;
|
||||
iwr.u.data.length = len;
|
||||
}
|
||||
|
||||
if (ioctl(drv->sock, op, &iwr) < 0) {
|
||||
if (show_err) {
|
||||
#ifdef MADWIFI_NG
|
||||
int first = IEEE80211_IOCTL_SETPARAM;
|
||||
int last = IEEE80211_IOCTL_KICKMAC;
|
||||
static const char *opnames[] = {
|
||||
"ioctl[IEEE80211_IOCTL_SETPARAM]",
|
||||
"ioctl[IEEE80211_IOCTL_GETPARAM]",
|
||||
"ioctl[IEEE80211_IOCTL_SETMODE]",
|
||||
"ioctl[IEEE80211_IOCTL_GETMODE]",
|
||||
"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
|
||||
"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
|
||||
"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
|
||||
"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
|
||||
"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
|
||||
"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
|
||||
"ioctl[IEEE80211_IOCTL_SETOPTIE]",
|
||||
"ioctl[IEEE80211_IOCTL_GETOPTIE]",
|
||||
"ioctl[IEEE80211_IOCTL_SETMLME]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_SETKEY]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_DELKEY]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_ADDMAC]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_DELMAC]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_WDSMAC]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_KICKMAC]",
|
||||
};
|
||||
#else /* MADWIFI_NG */
|
||||
int first = IEEE80211_IOCTL_SETPARAM;
|
||||
int last = IEEE80211_IOCTL_CHANLIST;
|
||||
static const char *opnames[] = {
|
||||
"ioctl[IEEE80211_IOCTL_SETPARAM]",
|
||||
"ioctl[IEEE80211_IOCTL_GETPARAM]",
|
||||
"ioctl[IEEE80211_IOCTL_SETKEY]",
|
||||
"ioctl[IEEE80211_IOCTL_GETKEY]",
|
||||
"ioctl[IEEE80211_IOCTL_DELKEY]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_SETMLME]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_SETOPTIE]",
|
||||
"ioctl[IEEE80211_IOCTL_GETOPTIE]",
|
||||
"ioctl[IEEE80211_IOCTL_ADDMAC]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_DELMAC]",
|
||||
NULL,
|
||||
"ioctl[IEEE80211_IOCTL_CHANLIST]",
|
||||
};
|
||||
#endif /* MADWIFI_NG */
|
||||
int idx = op - first;
|
||||
if (first <= op && op <= last &&
|
||||
idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
|
||||
&& opnames[idx])
|
||||
perror(opnames[idx]);
|
||||
else
|
||||
perror("ioctl[unknown???]");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
|
||||
int show_err)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.mode = op;
|
||||
os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
|
||||
|
||||
if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
|
||||
if (show_err)
|
||||
perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
/* NB: SETOPTIE is not fixed-size so must not be inlined */
|
||||
iwr.u.data.pointer = (void *) wpa_ie;
|
||||
iwr.u.data.length = wpa_ie_len;
|
||||
|
||||
if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
|
||||
perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ieee80211req_del_key wk;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
|
||||
os_memset(&wk, 0, sizeof(wk));
|
||||
wk.idk_keyix = key_idx;
|
||||
if (addr != NULL)
|
||||
os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
|
||||
return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
struct ieee80211req_key wk;
|
||||
char *alg_name;
|
||||
u_int8_t cipher;
|
||||
|
||||
if (alg == WPA_ALG_NONE)
|
||||
return wpa_driver_madwifi_del_key(drv, key_idx, addr);
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_WEP:
|
||||
if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
|
||||
ETH_ALEN) == 0) {
|
||||
/*
|
||||
* madwifi did not seem to like static WEP key
|
||||
* configuration with IEEE80211_IOCTL_SETKEY, so use
|
||||
* Linux wireless extensions ioctl for this.
|
||||
*/
|
||||
return wpa_driver_wext_set_key(drv->wext, alg, addr,
|
||||
key_idx, set_tx,
|
||||
seq, seq_len,
|
||||
key, key_len);
|
||||
}
|
||||
alg_name = "WEP";
|
||||
cipher = IEEE80211_CIPHER_WEP;
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
alg_name = "TKIP";
|
||||
cipher = IEEE80211_CIPHER_TKIP;
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
alg_name = "CCMP";
|
||||
cipher = IEEE80211_CIPHER_AES_CCM;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
|
||||
__FUNCTION__, alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
||||
(unsigned long) seq_len, (unsigned long) key_len);
|
||||
|
||||
if (seq_len > sizeof(u_int64_t)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
|
||||
__FUNCTION__, (unsigned long) seq_len);
|
||||
return -2;
|
||||
}
|
||||
if (key_len > sizeof(wk.ik_keydata)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
|
||||
__FUNCTION__, (unsigned long) key_len);
|
||||
return -3;
|
||||
}
|
||||
|
||||
os_memset(&wk, 0, sizeof(wk));
|
||||
wk.ik_type = cipher;
|
||||
wk.ik_flags = IEEE80211_KEY_RECV;
|
||||
if (addr == NULL ||
|
||||
os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
|
||||
wk.ik_flags |= IEEE80211_KEY_GROUP;
|
||||
if (set_tx) {
|
||||
wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
|
||||
os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
} else
|
||||
os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
|
||||
wk.ik_keyix = key_idx;
|
||||
wk.ik_keylen = key_len;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define WPA_KEY_RSC_LEN 8
|
||||
{
|
||||
size_t i;
|
||||
u8 tmp[WPA_KEY_RSC_LEN];
|
||||
os_memset(tmp, 0, sizeof(tmp));
|
||||
for (i = 0; i < seq_len; i++)
|
||||
tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
|
||||
os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
|
||||
}
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
os_memcpy(&wk.ik_keyrsc, seq, seq_len);
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
os_memcpy(wk.ik_keydata, key, key_len);
|
||||
|
||||
return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
|
||||
return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
struct ieee80211req_mlme mlme;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
mlme.im_op = IEEE80211_MLME_DEAUTH;
|
||||
mlme.im_reason = reason_code;
|
||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
struct ieee80211req_mlme mlme;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
mlme.im_op = IEEE80211_MLME_DISASSOC;
|
||||
mlme.im_reason = reason_code;
|
||||
os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||
return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
struct ieee80211req_mlme mlme;
|
||||
int ret = 0, privacy = 1;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
|
||||
|
||||
/*
|
||||
* NB: Don't need to set the freq or cipher-related state as
|
||||
* this is implied by the bssid which is used to locate
|
||||
* the scanned node state which holds it. The ssid is
|
||||
* needed to disambiguate an AP that broadcasts multiple
|
||||
* ssid's but uses the same bssid.
|
||||
*/
|
||||
/* XXX error handling is wrong but unclear what to do... */
|
||||
if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
|
||||
params->wpa_ie_len) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (params->pairwise_suite == CIPHER_NONE &&
|
||||
params->group_suite == CIPHER_NONE &&
|
||||
params->key_mgmt_suite == KEY_MGMT_NONE &&
|
||||
params->wpa_ie_len == 0)
|
||||
privacy = 0;
|
||||
|
||||
if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (params->wpa_ie_len &&
|
||||
set80211param(drv, IEEE80211_PARAM_WPA,
|
||||
params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (params->bssid == NULL) {
|
||||
/* ap_scan=2 mode - driver takes care of AP selection and
|
||||
* roaming */
|
||||
/* FIX: this does not seem to work; would probably need to
|
||||
* change something in the driver */
|
||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
||||
params->ssid_len) < 0)
|
||||
ret = -1;
|
||||
} else {
|
||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
||||
params->ssid_len) < 0)
|
||||
ret = -1;
|
||||
os_memset(&mlme, 0, sizeof(mlme));
|
||||
mlme.im_op = IEEE80211_MLME_ASSOC;
|
||||
os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
|
||||
if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
|
||||
sizeof(mlme), 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
|
||||
__func__);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
int authmode;
|
||||
|
||||
if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
|
||||
(auth_alg & AUTH_ALG_SHARED_KEY))
|
||||
authmode = IEEE80211_AUTH_AUTO;
|
||||
else if (auth_alg & AUTH_ALG_SHARED_KEY)
|
||||
authmode = IEEE80211_AUTH_SHARED;
|
||||
else
|
||||
authmode = IEEE80211_AUTH_OPEN;
|
||||
|
||||
return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
struct iwreq iwr;
|
||||
int ret = 0;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
|
||||
/* set desired ssid before scan */
|
||||
/* FIX: scan should not break the current association, so using
|
||||
* set_ssid may not be the best way of doing this.. */
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
|
||||
perror("ioctl[SIOCSIWSCAN]");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* madwifi delivers a scan complete event so no need to poll, but
|
||||
* register a backup timeout anyway to make sure that we recover even
|
||||
* if the driver does not send this event for any reason. This timeout
|
||||
* will only be used if the event is not delivered (event handler will
|
||||
* cancel the timeout).
|
||||
*/
|
||||
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
|
||||
drv->ctx);
|
||||
eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
|
||||
drv->ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results *
|
||||
wpa_driver_madwifi_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_madwifi_set_operstate(void *priv, int state)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
|
||||
size_t ies_len)
|
||||
{
|
||||
struct ieee80211req_getset_appiebuf *probe_req_ie;
|
||||
int ret;
|
||||
|
||||
probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
|
||||
if (probe_req_ie == NULL)
|
||||
return -1;
|
||||
|
||||
probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
|
||||
probe_req_ie->app_buflen = ies_len;
|
||||
os_memcpy(probe_req_ie->app_buf, ies, ies_len);
|
||||
|
||||
ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
|
||||
sizeof(struct ieee80211req_getset_appiebuf) +
|
||||
ies_len, 1);
|
||||
|
||||
os_free(probe_req_ie);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
||||
if (drv->wext == NULL)
|
||||
goto fail;
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->sock < 0)
|
||||
goto fail2;
|
||||
|
||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
|
||||
"roaming", __FUNCTION__);
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
|
||||
__FUNCTION__);
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
return drv;
|
||||
|
||||
fail3:
|
||||
close(drv->sock);
|
||||
fail2:
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
fail:
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_madwifi_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_madwifi_data *drv = priv;
|
||||
|
||||
if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
|
||||
__FUNCTION__);
|
||||
}
|
||||
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
|
||||
"roaming", __FUNCTION__);
|
||||
}
|
||||
if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
|
||||
"flag", __FUNCTION__);
|
||||
}
|
||||
if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
|
||||
close(drv->sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_madwifi_ops = {
|
||||
.name = "madwifi",
|
||||
.desc = "MADWIFI 802.11 support (Atheros, etc.)",
|
||||
.get_bssid = wpa_driver_madwifi_get_bssid,
|
||||
.get_ssid = wpa_driver_madwifi_get_ssid,
|
||||
.set_key = wpa_driver_madwifi_set_key,
|
||||
.init = wpa_driver_madwifi_init,
|
||||
.deinit = wpa_driver_madwifi_deinit,
|
||||
.set_countermeasures = wpa_driver_madwifi_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
|
||||
.scan = wpa_driver_madwifi_scan,
|
||||
.get_scan_results2 = wpa_driver_madwifi_get_scan_results,
|
||||
.deauthenticate = wpa_driver_madwifi_deauthenticate,
|
||||
.disassociate = wpa_driver_madwifi_disassociate,
|
||||
.associate = wpa_driver_madwifi_associate,
|
||||
.set_auth_alg = wpa_driver_madwifi_set_auth_alg,
|
||||
.set_operstate = wpa_driver_madwifi_set_operstate,
|
||||
.set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,
|
||||
};
|
@ -56,9 +56,14 @@ static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
|
||||
static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
|
||||
|
||||
|
||||
static const u8 pae_group_addr[ETH_ALEN] =
|
||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
||||
|
||||
|
||||
/* FIX: to be removed once this can be compiled with the complete NDIS
|
||||
* header files */
|
||||
#ifndef OID_802_11_BSSID
|
||||
#define OID_802_3_MULTICAST_LIST 0x01010103
|
||||
#define OID_802_11_BSSID 0x0d010101
|
||||
#define OID_802_11_SSID 0x0d010102
|
||||
#define OID_802_11_INFRASTRUCTURE_MODE 0x0d010108
|
||||
@ -610,12 +615,7 @@ static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
|
||||
* Report PAE group address as the "BSSID" for wired
|
||||
* connection.
|
||||
*/
|
||||
bssid[0] = 0x01;
|
||||
bssid[1] = 0x80;
|
||||
bssid[2] = 0xc2;
|
||||
bssid[3] = 0x00;
|
||||
bssid[4] = 0x00;
|
||||
bssid[5] = 0x03;
|
||||
os_memcpy(bssid, pae_group_addr, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2704,6 +2704,19 @@ static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
|
||||
}
|
||||
|
||||
|
||||
static int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
|
||||
{
|
||||
if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
|
||||
(const char *) pae_group_addr, ETH_ALEN) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
|
||||
"to the multicast list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_ndis_data *drv;
|
||||
@ -2799,6 +2812,7 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
|
||||
"any wireless capabilities - assume it is "
|
||||
"a wired interface");
|
||||
drv->wired = 1;
|
||||
ndis_add_multicast(drv);
|
||||
}
|
||||
}
|
||||
|
||||
|
105
contrib/wpa/src/drivers/driver_ndis_.c
Normal file
105
contrib/wpa/src/drivers/driver_ndis_.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* WPA Supplicant - Windows/NDIS driver interface - event processing
|
||||
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
|
||||
/* Keep this event processing in a separate file and without WinPcap headers to
|
||||
* avoid conflicts with some of the header files. */
|
||||
struct _ADAPTER;
|
||||
typedef struct _ADAPTER * LPADAPTER;
|
||||
#include "driver_ndis.h"
|
||||
|
||||
|
||||
void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv);
|
||||
void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv);
|
||||
void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
|
||||
const u8 *data, size_t data_len);
|
||||
void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv);
|
||||
void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv);
|
||||
|
||||
|
||||
enum event_types { EVENT_CONNECT, EVENT_DISCONNECT,
|
||||
EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL,
|
||||
EVENT_ADAPTER_REMOVAL };
|
||||
|
||||
/* Event data:
|
||||
* enum event_types (as int, i.e., 4 octets)
|
||||
* data length (2 octets (big endian), optional)
|
||||
* data (variable len, optional)
|
||||
*/
|
||||
|
||||
|
||||
static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv,
|
||||
u8 *buf, size_t len)
|
||||
{
|
||||
u8 *pos, *data = NULL;
|
||||
enum event_types type;
|
||||
size_t data_len = 0;
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len);
|
||||
if (len < sizeof(int))
|
||||
return;
|
||||
type = *((int *) buf);
|
||||
pos = buf + sizeof(int);
|
||||
wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type);
|
||||
|
||||
if (buf + len - pos > 2) {
|
||||
data_len = (int) *pos++ << 8;
|
||||
data_len += *pos++;
|
||||
if (data_len > (size_t) (buf + len - pos)) {
|
||||
wpa_printf(MSG_DEBUG, "NDIS: event data overflow");
|
||||
return;
|
||||
}
|
||||
data = pos;
|
||||
wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case EVENT_CONNECT:
|
||||
wpa_driver_ndis_event_connect(drv);
|
||||
break;
|
||||
case EVENT_DISCONNECT:
|
||||
wpa_driver_ndis_event_disconnect(drv);
|
||||
break;
|
||||
case EVENT_MEDIA_SPECIFIC:
|
||||
wpa_driver_ndis_event_media_specific(drv, data, data_len);
|
||||
break;
|
||||
case EVENT_ADAPTER_ARRIVAL:
|
||||
wpa_driver_ndis_event_adapter_arrival(drv);
|
||||
break;
|
||||
case EVENT_ADAPTER_REMOVAL:
|
||||
wpa_driver_ndis_event_adapter_removal(drv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data)
|
||||
{
|
||||
struct wpa_driver_ndis_data *drv = eloop_data;
|
||||
u8 buf[512];
|
||||
DWORD len;
|
||||
|
||||
ResetEvent(drv->event_avail);
|
||||
if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL))
|
||||
wpa_driver_ndis_event_process(drv, buf, len);
|
||||
else {
|
||||
wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__,
|
||||
(int) GetLastError());
|
||||
}
|
||||
}
|
370
contrib/wpa/src/drivers/driver_ndiswrapper.c
Normal file
370
contrib/wpa/src/drivers/driver_ndiswrapper.c
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with Linux ndiswrapper
|
||||
* Copyright (c) 2004-2006, Giridhar Pemmasani <giri@lmc.cs.sunysb.edu>
|
||||
* Copyright (c) 2004-2006, 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.
|
||||
*
|
||||
* Please note that ndiswrapper supports WPA configuration via Linux wireless
|
||||
* extensions and if the kernel includes support for this, driver_wext.c should
|
||||
* be used instead of this driver wrapper.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "wireless_copy.h"
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wext.h"
|
||||
|
||||
struct wpa_driver_ndiswrapper_data {
|
||||
void *wext; /* private data for driver_wext */
|
||||
void *ctx;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int sock;
|
||||
};
|
||||
|
||||
|
||||
struct wpa_key
|
||||
{
|
||||
wpa_alg alg;
|
||||
const u8 *addr;
|
||||
int key_index;
|
||||
int set_tx;
|
||||
const u8 *seq;
|
||||
size_t seq_len;
|
||||
const u8 *key;
|
||||
size_t key_len;
|
||||
};
|
||||
|
||||
struct wpa_assoc_info
|
||||
{
|
||||
const u8 *bssid;
|
||||
const u8 *ssid;
|
||||
size_t ssid_len;
|
||||
int freq;
|
||||
const u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
wpa_cipher pairwise_suite;
|
||||
wpa_cipher group_suite;
|
||||
wpa_key_mgmt key_mgmt_suite;
|
||||
int auth_alg;
|
||||
int mode;
|
||||
};
|
||||
|
||||
#define PRIV_RESET SIOCIWFIRSTPRIV+0
|
||||
#define WPA_SET_WPA SIOCIWFIRSTPRIV+1
|
||||
#define WPA_SET_KEY SIOCIWFIRSTPRIV+2
|
||||
#define WPA_ASSOCIATE SIOCIWFIRSTPRIV+3
|
||||
#define WPA_DISASSOCIATE SIOCIWFIRSTPRIV+4
|
||||
#define WPA_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+5
|
||||
#define WPA_SET_COUNTERMEASURES SIOCIWFIRSTPRIV+6
|
||||
#define WPA_DEAUTHENTICATE SIOCIWFIRSTPRIV+7
|
||||
#define WPA_SET_AUTH_ALG SIOCIWFIRSTPRIV+8
|
||||
#define WPA_INIT SIOCIWFIRSTPRIV+9
|
||||
#define WPA_DEINIT SIOCIWFIRSTPRIV+10
|
||||
#define WPA_GET_CAPA SIOCIWFIRSTPRIV+11
|
||||
|
||||
static int get_socket(void)
|
||||
{
|
||||
static const int families[] = {
|
||||
AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
|
||||
};
|
||||
unsigned int i;
|
||||
int sock;
|
||||
|
||||
for (i = 0; i < sizeof(families) / sizeof(int); ++i) {
|
||||
sock = socket(families[i], SOCK_DGRAM, 0);
|
||||
if (sock >= 0)
|
||||
return sock;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int iw_set_ext(struct wpa_driver_ndiswrapper_data *drv, int request,
|
||||
struct iwreq *pwrq)
|
||||
{
|
||||
os_strlcpy(pwrq->ifr_name, drv->ifname, IFNAMSIZ);
|
||||
return ioctl(drv->sock, request, pwrq);
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
struct iwreq priv_req;
|
||||
int ret = 0;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
priv_req.u.data.flags = enabled;
|
||||
if (iw_set_ext(drv, WPA_SET_WPA, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
struct wpa_key wpa_key;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
wpa_key.alg = alg;
|
||||
wpa_key.addr = addr;
|
||||
wpa_key.key_index = key_idx;
|
||||
wpa_key.set_tx = set_tx;
|
||||
wpa_key.seq = seq;
|
||||
wpa_key.seq_len = seq_len;
|
||||
wpa_key.key = key;
|
||||
wpa_key.key_len = key_len;
|
||||
|
||||
priv_req.u.data.pointer = (void *)&wpa_key;
|
||||
priv_req.u.data.length = sizeof(wpa_key);
|
||||
|
||||
if (iw_set_ext(drv, WPA_SET_KEY, &priv_req) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (alg == WPA_ALG_NONE) {
|
||||
/*
|
||||
* ndiswrapper did not seem to be clearing keys properly in
|
||||
* some cases with WPA_SET_KEY. For example, roaming from WPA
|
||||
* enabled AP to plaintext one seemed to fail since the driver
|
||||
* did not associate. Try to make sure the keys are cleared so
|
||||
* that plaintext APs can be used in all cases.
|
||||
*/
|
||||
wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx,
|
||||
seq, seq_len, key, key_len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_set_countermeasures(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
priv_req.u.param.value = enabled;
|
||||
if (iw_set_ext(drv, WPA_SET_COUNTERMEASURES, &priv_req) < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_set_drop_unencrypted(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
priv_req.u.param.value = enabled;
|
||||
if (iw_set_ext(drv, WPA_DROP_UNENCRYPTED, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
priv_req.u.param.value = reason_code;
|
||||
os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
|
||||
if (iw_set_ext(drv, WPA_DEAUTHENTICATE, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
|
||||
if (iw_set_ext(drv, WPA_DISASSOCIATE, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_ndiswrapper_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct wpa_assoc_info wpa_assoc_info;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info));
|
||||
|
||||
wpa_assoc_info.bssid = params->bssid;
|
||||
wpa_assoc_info.ssid = params->ssid;
|
||||
wpa_assoc_info.ssid_len = params->ssid_len;
|
||||
wpa_assoc_info.freq = params->freq;
|
||||
wpa_assoc_info.wpa_ie = params->wpa_ie;
|
||||
wpa_assoc_info.wpa_ie_len = params->wpa_ie_len;
|
||||
wpa_assoc_info.pairwise_suite = params->pairwise_suite;
|
||||
wpa_assoc_info.group_suite = params->group_suite;
|
||||
wpa_assoc_info.key_mgmt_suite = params->key_mgmt_suite;
|
||||
wpa_assoc_info.auth_alg = params->auth_alg;
|
||||
wpa_assoc_info.mode = params->mode;
|
||||
|
||||
priv_req.u.data.pointer = (void *)&wpa_assoc_info;
|
||||
priv_req.u.data.length = sizeof(wpa_assoc_info);
|
||||
|
||||
if (iw_set_ext(drv, WPA_ASSOCIATE, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
priv_req.u.param.value = auth_alg;
|
||||
if (iw_set_ext(drv, WPA_SET_AUTH_ALG, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_ndiswrapper_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ndiswrapper_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results * wpa_ndiswrapper_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ndiswrapper_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
int ret = 0;
|
||||
struct iwreq priv_req;
|
||||
|
||||
os_memset(&priv_req, 0, sizeof(priv_req));
|
||||
|
||||
priv_req.u.data.pointer = (void *) capa;
|
||||
priv_req.u.data.length = sizeof(*capa);
|
||||
if (iw_set_ext(drv, WPA_GET_CAPA, &priv_req) < 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ndiswrapper_set_operstate(void *priv, int state)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
||||
if (drv->wext == NULL) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->sock = get_socket();
|
||||
if (drv->sock < 0) {
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_ndiswrapper_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_ndiswrapper_data *drv = priv;
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
close(drv->sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = {
|
||||
.name = "ndiswrapper",
|
||||
.desc = "Linux ndiswrapper (deprecated; use wext)",
|
||||
.set_wpa = wpa_ndiswrapper_set_wpa,
|
||||
.set_key = wpa_ndiswrapper_set_key,
|
||||
.set_countermeasures = wpa_ndiswrapper_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_ndiswrapper_set_drop_unencrypted,
|
||||
.deauthenticate = wpa_ndiswrapper_deauthenticate,
|
||||
.disassociate = wpa_ndiswrapper_disassociate,
|
||||
.associate = wpa_ndiswrapper_associate,
|
||||
.set_auth_alg = wpa_ndiswrapper_set_auth_alg,
|
||||
|
||||
.get_bssid = wpa_ndiswrapper_get_bssid,
|
||||
.get_ssid = wpa_ndiswrapper_get_ssid,
|
||||
.scan = wpa_ndiswrapper_scan,
|
||||
.get_scan_results2 = wpa_ndiswrapper_get_scan_results,
|
||||
.init = wpa_ndiswrapper_init,
|
||||
.deinit = wpa_ndiswrapper_deinit,
|
||||
.get_capa = wpa_ndiswrapper_get_capa,
|
||||
.set_operstate = wpa_ndiswrapper_set_operstate,
|
||||
};
|
2766
contrib/wpa/src/drivers/driver_nl80211.c
Normal file
2766
contrib/wpa/src/drivers/driver_nl80211.c
Normal file
File diff suppressed because it is too large
Load Diff
432
contrib/wpa/src/drivers/driver_osx.m
Normal file
432
contrib/wpa/src/drivers/driver_osx.m
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* WPA Supplicant - Mac OS X Apple80211 driver interface
|
||||
* Copyright (c) 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"
|
||||
#define Boolean __DummyBoolean
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#undef Boolean
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
|
||||
#include "Apple80211.h"
|
||||
|
||||
struct wpa_driver_osx_data {
|
||||
void *ctx;
|
||||
WirelessRef wireless_ctx;
|
||||
CFArrayRef scan_results;
|
||||
};
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
extern int wpa_debug_level;
|
||||
|
||||
static void dump_dict_cb(const void *key, const void *value, void *context)
|
||||
{
|
||||
if (MSG_DEBUG < wpa_debug_level)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Key:");
|
||||
CFShow(key);
|
||||
wpa_printf(MSG_DEBUG, "Value:");
|
||||
CFShow(value);
|
||||
}
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
|
||||
static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
|
||||
{
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
|
||||
title, (unsigned int) CFDictionaryGetCount(dict));
|
||||
CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
WirelessInfo info;
|
||||
int len;
|
||||
|
||||
err = WirelessGetInfo(drv->wireless_ctx, &info);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
|
||||
(int) err);
|
||||
return -1;
|
||||
}
|
||||
if (!info.power) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (len = 0; len < 32; len++)
|
||||
if (info.ssid[len] == 0)
|
||||
break;
|
||||
|
||||
os_memcpy(ssid, info.ssid, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
WirelessInfo info;
|
||||
|
||||
err = WirelessGetInfo(drv->wireless_ctx, &info);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
|
||||
(int) err);
|
||||
return -1;
|
||||
}
|
||||
if (!info.power) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(bssid, info.bssID, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
|
||||
if (drv->scan_results) {
|
||||
CFRelease(drv->scan_results);
|
||||
drv->scan_results = NULL;
|
||||
}
|
||||
|
||||
if (ssid) {
|
||||
CFStringRef data;
|
||||
data = CFStringCreateWithBytes(kCFAllocatorDefault,
|
||||
ssid, ssid_len,
|
||||
kCFStringEncodingISOLatin1,
|
||||
FALSE);
|
||||
if (data == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
|
||||
"failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = WirelessDirectedScan(drv->wireless_ctx,
|
||||
&drv->scan_results, 0, data);
|
||||
CFRelease(data);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
|
||||
"failed: 0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_scan_results(void *priv,
|
||||
struct wpa_scan_result *results,
|
||||
size_t max_size)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
size_t i, num;
|
||||
|
||||
if (drv->scan_results == NULL)
|
||||
return 0;
|
||||
|
||||
num = CFArrayGetCount(drv->scan_results);
|
||||
if (num > max_size)
|
||||
num = max_size;
|
||||
os_memset(results, 0, num * sizeof(struct wpa_scan_result));
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct wpa_scan_result *res = &results[i];
|
||||
WirelessNetworkInfo *info;
|
||||
info = (WirelessNetworkInfo *)
|
||||
CFDataGetBytePtr(CFArrayGetValueAtIndex(
|
||||
drv->scan_results, i));
|
||||
|
||||
os_memcpy(res->bssid, info->bssid, ETH_ALEN);
|
||||
if (info->ssid_len > 32) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
|
||||
"scan results", (int) info->ssid_len);
|
||||
continue;
|
||||
}
|
||||
os_memcpy(res->ssid, info->ssid, info->ssid_len);
|
||||
res->ssid_len = info->ssid_len;
|
||||
res->caps = info->capability;
|
||||
res->freq = 2407 + info->channel * 5;
|
||||
res->level = info->signal;
|
||||
res->noise = info->noise;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = eloop_ctx;
|
||||
u8 bssid[ETH_ALEN];
|
||||
CFDictionaryRef ai;
|
||||
|
||||
if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
|
||||
eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
|
||||
drv, drv->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ai = WirelessGetAssociationInfo(drv->wireless_ctx);
|
||||
if (ai) {
|
||||
wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
|
||||
CFRelease(ai);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
|
||||
}
|
||||
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
CFDataRef ssid;
|
||||
CFStringRef key;
|
||||
int assoc_type;
|
||||
|
||||
ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
|
||||
params->ssid_len);
|
||||
if (ssid == NULL)
|
||||
return -1;
|
||||
|
||||
/* TODO: support for WEP */
|
||||
if (params->key_mgmt_suite == KEY_MGMT_PSK) {
|
||||
if (params->passphrase == NULL)
|
||||
return -1;
|
||||
key = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
params->passphrase,
|
||||
kCFStringEncodingISOLatin1);
|
||||
if (key == NULL) {
|
||||
CFRelease(ssid);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
key = NULL;
|
||||
|
||||
if (params->key_mgmt_suite == KEY_MGMT_NONE)
|
||||
assoc_type = 0;
|
||||
else
|
||||
assoc_type = 4;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
|
||||
assoc_type, key);
|
||||
err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
|
||||
CFRelease(ssid);
|
||||
if (key)
|
||||
CFRelease(key);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver is actually already associated; report association from an
|
||||
* eloop callback.
|
||||
*/
|
||||
eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
|
||||
eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
|
||||
drv->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx, const u8 *seq,
|
||||
size_t seq_len, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
|
||||
if (alg == WPA_ALG_WEP) {
|
||||
err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
|
||||
key);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (alg == WPA_ALG_PMK) {
|
||||
err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
os_memset(capa, 0, sizeof(*capa));
|
||||
|
||||
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
|
||||
capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
|
||||
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
|
||||
capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
|
||||
WPA_DRIVER_AUTH_LEAP;
|
||||
capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_osx_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv;
|
||||
WirelessError err;
|
||||
u8 enabled, power;
|
||||
|
||||
if (!WirelessIsAvailable()) {
|
||||
wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
err = WirelessAttach(&drv->wireless_ctx, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
|
||||
(int) err);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
|
||||
if (err)
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
err = WirelessGetPower(drv->wireless_ctx, &power);
|
||||
if (err)
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
|
||||
|
||||
if (!enabled) {
|
||||
err = WirelessSetEnabled(drv->wireless_ctx, 1);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
|
||||
" 0x%08x", (unsigned int) err);
|
||||
WirelessDetach(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!power) {
|
||||
err = WirelessSetPower(drv->wireless_ctx, 1);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
WirelessDetach(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
|
||||
eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
|
||||
eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
|
||||
|
||||
err = WirelessSetPower(drv->wireless_ctx, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
}
|
||||
|
||||
err = WirelessDetach(drv->wireless_ctx);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
}
|
||||
|
||||
if (drv->scan_results)
|
||||
CFRelease(drv->scan_results);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_osx_ops = {
|
||||
.name = "osx",
|
||||
.desc = "Mac OS X Apple80211 driver",
|
||||
.get_ssid = wpa_driver_osx_get_ssid,
|
||||
.get_bssid = wpa_driver_osx_get_bssid,
|
||||
.init = wpa_driver_osx_init,
|
||||
.deinit = wpa_driver_osx_deinit,
|
||||
.scan = wpa_driver_osx_scan,
|
||||
.get_scan_results = wpa_driver_osx_get_scan_results,
|
||||
.associate = wpa_driver_osx_associate,
|
||||
.set_key = wpa_driver_osx_set_key,
|
||||
.get_capa = wpa_driver_osx_get_capa,
|
||||
};
|
381
contrib/wpa/src/drivers/driver_prism54.c
Normal file
381
contrib/wpa/src/drivers/driver_prism54.c
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* WPA Supplicant - driver interaction with Linux Prism54.org driver
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
|
||||
*
|
||||
* 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 "wireless_copy.h"
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wext.h"
|
||||
#include "driver_hostap.h"
|
||||
|
||||
struct wpa_driver_prism54_data {
|
||||
void *wext; /* private data for driver_wext */
|
||||
void *ctx;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int sock;
|
||||
};
|
||||
|
||||
#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
|
||||
#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
|
||||
#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
|
||||
|
||||
static void show_set_key_error(struct prism2_hostapd_param *);
|
||||
|
||||
static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
|
||||
struct prism2_hostapd_param *param,
|
||||
int len, int show_err)
|
||||
{
|
||||
struct iwreq iwr;
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.data.pointer = (caddr_t) param;
|
||||
iwr.u.data.length = len;
|
||||
|
||||
if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
|
||||
int ret = errno;
|
||||
if (show_err)
|
||||
perror("ioctl[PRISM54_HOSTAPD]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
|
||||
const u8 *wpa_ie,
|
||||
size_t wpa_ie_len)
|
||||
{
|
||||
struct prism2_hostapd_param *param;
|
||||
int res;
|
||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_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 = wpa_ie_len;
|
||||
os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
|
||||
res = hostapd_ioctl_prism54(drv, param, blen, 1);
|
||||
|
||||
os_free(param);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* This is called at wpa_supplicant daemon init time */
|
||||
static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
struct prism2_hostapd_param *param;
|
||||
int res;
|
||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
|
||||
if (blen < sizeof(*param))
|
||||
blen = sizeof(*param);
|
||||
|
||||
param = os_zalloc(blen);
|
||||
if (param == NULL)
|
||||
return -1;
|
||||
|
||||
param->cmd = PRISM54_SET_WPA;
|
||||
param->u.generic_elem.len = 0;
|
||||
res = hostapd_ioctl_prism54(drv, param, blen, 1);
|
||||
|
||||
os_free(param);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
struct prism2_hostapd_param *param;
|
||||
u8 *buf;
|
||||
size_t blen;
|
||||
int ret = 0;
|
||||
char *alg_name;
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_NONE:
|
||||
alg_name = "none";
|
||||
return -1;
|
||||
break;
|
||||
case WPA_ALG_WEP:
|
||||
alg_name = "WEP";
|
||||
return -1;
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
alg_name = "TKIP";
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
alg_name = "CCMP";
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
|
||||
"key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
|
||||
(unsigned long) seq_len, (unsigned long) key_len);
|
||||
|
||||
if (seq_len > 8)
|
||||
return -2;
|
||||
|
||||
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;
|
||||
/* TODO: In theory, STA in client mode can use five keys; four default
|
||||
* keys for receiving (with keyidx 0..3) and one individual key for
|
||||
* both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
|
||||
* keyidx 0 is reserved for this unicast use and default keys can only
|
||||
* use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
|
||||
* This should be fine for more or less all cases, but for completeness
|
||||
* sake, the driver could be enhanced to support the missing key. */
|
||||
#if 0
|
||||
if (addr == NULL)
|
||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
||||
else
|
||||
os_memcpy(param->sta_addr, addr, ETH_ALEN);
|
||||
#else
|
||||
os_memset(param->sta_addr, 0xff, ETH_ALEN);
|
||||
#endif
|
||||
os_strlcpy((char *) param->u.crypt.alg, alg_name,
|
||||
HOSTAP_CRYPT_ALG_NAME_LEN);
|
||||
param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
|
||||
param->u.crypt.idx = key_idx;
|
||||
os_memcpy(param->u.crypt.seq, seq, seq_len);
|
||||
param->u.crypt.key_len = key_len;
|
||||
os_memcpy((u8 *) (param + 1), key, key_len);
|
||||
|
||||
if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
|
||||
wpa_printf(MSG_WARNING, "Failed to set encryption.");
|
||||
show_set_key_error(param);
|
||||
ret = -1;
|
||||
}
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_set_countermeasures(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
/* FIX */
|
||||
printf("wpa_driver_prism54_set_countermeasures - not yet "
|
||||
"implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
struct prism2_hostapd_param *param;
|
||||
int res;
|
||||
size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
|
||||
if (blen < sizeof(*param))
|
||||
blen = sizeof(*param);
|
||||
|
||||
param = os_zalloc(blen);
|
||||
if (param == NULL)
|
||||
return -1;
|
||||
|
||||
param->cmd = PRISM54_DROP_UNENCRYPTED;
|
||||
param->u.generic_elem.len = 0;
|
||||
res = hostapd_ioctl_prism54(drv, param, blen, 1);
|
||||
|
||||
os_free(param);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
/* FIX */
|
||||
printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
/* FIX */
|
||||
printf("wpa_driver_prism54_disassociate - not yet implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
wpa_driver_prism54_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
int ret = 0;
|
||||
|
||||
if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
|
||||
params->wpa_ie_len) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
|
||||
params->ssid_len) < 0)
|
||||
ret = -1;
|
||||
if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void show_set_key_error(struct prism2_hostapd_param *param)
|
||||
{
|
||||
switch (param->u.crypt.err) {
|
||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
|
||||
wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
|
||||
param->u.crypt.alg);
|
||||
wpa_printf(MSG_INFO, "You may need to load kernel module to "
|
||||
"register that algorithm.");
|
||||
wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
|
||||
"WEP.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
|
||||
wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
|
||||
MAC2STR(param->sta_addr));
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
|
||||
wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
|
||||
wpa_printf(MSG_INFO, "Key setting failed.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
|
||||
wpa_printf(MSG_INFO, "TX key index setting failed.");
|
||||
break;
|
||||
case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
|
||||
wpa_printf(MSG_INFO, "Card configuration failed.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
return wpa_driver_wext_get_bssid(drv->wext, bssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
return wpa_driver_wext_get_ssid(drv->wext, ssid);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results *
|
||||
wpa_driver_prism54_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
return wpa_driver_wext_get_scan_results(drv->wext);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_prism54_set_operstate(void *priv, int state)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
return wpa_driver_wext_set_operstate(drv->wext, state);
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->wext = wpa_driver_wext_init(ctx, ifname);
|
||||
if (drv->wext == NULL) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->sock < 0) {
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_prism54_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_prism54_data *drv = priv;
|
||||
wpa_driver_wext_deinit(drv->wext);
|
||||
close(drv->sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_prism54_ops = {
|
||||
.name = "prism54",
|
||||
.desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
|
||||
.get_bssid = wpa_driver_prism54_get_bssid,
|
||||
.get_ssid = wpa_driver_prism54_get_ssid,
|
||||
.set_wpa = wpa_driver_prism54_set_wpa,
|
||||
.set_key = wpa_driver_prism54_set_key,
|
||||
.set_countermeasures = wpa_driver_prism54_set_countermeasures,
|
||||
.set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
|
||||
.scan = wpa_driver_prism54_scan,
|
||||
.get_scan_results2 = wpa_driver_prism54_get_scan_results,
|
||||
.deauthenticate = wpa_driver_prism54_deauthenticate,
|
||||
.disassociate = wpa_driver_prism54_disassociate,
|
||||
.associate = wpa_driver_prism54_associate,
|
||||
.init = wpa_driver_prism54_init,
|
||||
.deinit = wpa_driver_prism54_deinit,
|
||||
.set_operstate = wpa_driver_prism54_set_operstate,
|
||||
};
|
820
contrib/wpa/src/drivers/driver_privsep.c
Normal file
820
contrib/wpa/src/drivers/driver_privsep.c
Normal file
@ -0,0 +1,820 @@
|
||||
/*
|
||||
* WPA Supplicant - privilege separated driver interface
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
#include "privsep_commands.h"
|
||||
|
||||
|
||||
struct wpa_driver_privsep_data {
|
||||
void *ctx;
|
||||
u8 own_addr[ETH_ALEN];
|
||||
int priv_socket;
|
||||
char *own_socket_path;
|
||||
int cmd_socket;
|
||||
char *own_cmd_path;
|
||||
struct sockaddr_un priv_addr;
|
||||
char ifname[16];
|
||||
};
|
||||
|
||||
|
||||
static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
|
||||
(struct sockaddr *) &drv->priv_addr,
|
||||
sizeof(drv->priv_addr));
|
||||
if (res < 0)
|
||||
perror("sendto");
|
||||
return res < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
|
||||
const void *data, size_t data_len,
|
||||
void *reply, size_t *reply_len)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec io[2];
|
||||
|
||||
io[0].iov_base = &cmd;
|
||||
io[0].iov_len = sizeof(cmd);
|
||||
io[1].iov_base = (u8 *) data;
|
||||
io[1].iov_len = data_len;
|
||||
|
||||
os_memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = io;
|
||||
msg.msg_iovlen = data ? 2 : 1;
|
||||
msg.msg_name = &drv->priv_addr;
|
||||
msg.msg_namelen = sizeof(drv->priv_addr);
|
||||
|
||||
if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
|
||||
perror("sendmsg(cmd_socket)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
int res;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(drv->cmd_socket, &rfds);
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
|
||||
if (res < 0 && errno != EINTR) {
|
||||
perror("select");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FD_ISSET(drv->cmd_socket, &rfds)) {
|
||||
res = recv(drv->cmd_socket, reply, *reply_len, 0);
|
||||
if (res < 0) {
|
||||
perror("recv");
|
||||
return -1;
|
||||
}
|
||||
*reply_len = res;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
|
||||
"for reply (cmd=%d)", cmd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_set_wpa(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled,
|
||||
sizeof(enabled), NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
|
||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results *
|
||||
wpa_driver_privsep_get_scan_results2(void *priv)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
int res, num;
|
||||
u8 *buf, *pos, *end;
|
||||
size_t reply_len = 60000;
|
||||
struct wpa_scan_results *results;
|
||||
struct wpa_scan_res *r;
|
||||
|
||||
buf = os_malloc(reply_len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
|
||||
NULL, 0, buf, &reply_len);
|
||||
if (res < 0) {
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
|
||||
(unsigned long) reply_len);
|
||||
if (reply_len < sizeof(int)) {
|
||||
wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
|
||||
(unsigned long) reply_len);
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = buf;
|
||||
end = buf + reply_len;
|
||||
os_memcpy(&num, pos, sizeof(int));
|
||||
if (num < 0 || num > 1000) {
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
pos += sizeof(int);
|
||||
|
||||
results = os_zalloc(sizeof(*results));
|
||||
if (results == NULL) {
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
|
||||
if (results->res == NULL) {
|
||||
os_free(results);
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (results->num < (size_t) num && pos + sizeof(int) < end) {
|
||||
int len;
|
||||
os_memcpy(&len, pos, sizeof(int));
|
||||
pos += sizeof(int);
|
||||
if (len < 0 || len > 10000 || pos + len > end)
|
||||
break;
|
||||
|
||||
r = os_malloc(len);
|
||||
if (r == NULL)
|
||||
break;
|
||||
os_memcpy(r, pos, len);
|
||||
pos += len;
|
||||
if (sizeof(*r) + r->ie_len > (size_t) len) {
|
||||
os_free(r);
|
||||
break;
|
||||
}
|
||||
|
||||
results->res[results->num++] = r;
|
||||
}
|
||||
|
||||
os_free(buf);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
struct privsep_cmd_set_key cmd;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
|
||||
__func__, priv, alg, key_idx, set_tx);
|
||||
|
||||
os_memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.alg = alg;
|
||||
if (addr)
|
||||
os_memcpy(cmd.addr, addr, ETH_ALEN);
|
||||
else
|
||||
os_memset(cmd.addr, 0xff, ETH_ALEN);
|
||||
cmd.key_idx = key_idx;
|
||||
cmd.set_tx = set_tx;
|
||||
if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
|
||||
os_memcpy(cmd.seq, seq, seq_len);
|
||||
cmd.seq_len = seq_len;
|
||||
}
|
||||
if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
|
||||
os_memcpy(cmd.key, key, key_len);
|
||||
cmd.key_len = key_len;
|
||||
}
|
||||
|
||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_associate(
|
||||
void *priv, struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
struct privsep_cmd_associate *data;
|
||||
int res;
|
||||
size_t buflen;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
|
||||
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
|
||||
__func__, priv, params->freq, params->pairwise_suite,
|
||||
params->group_suite, params->key_mgmt_suite,
|
||||
params->auth_alg, params->mode);
|
||||
|
||||
buflen = sizeof(*data) + params->wpa_ie_len;
|
||||
data = os_zalloc(buflen);
|
||||
if (data == NULL)
|
||||
return -1;
|
||||
|
||||
if (params->bssid)
|
||||
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
|
||||
os_memcpy(data->ssid, params->ssid, params->ssid_len);
|
||||
data->ssid_len = params->ssid_len;
|
||||
data->freq = params->freq;
|
||||
data->pairwise_suite = params->pairwise_suite;
|
||||
data->group_suite = params->group_suite;
|
||||
data->key_mgmt_suite = params->key_mgmt_suite;
|
||||
data->auth_alg = params->auth_alg;
|
||||
data->mode = params->mode;
|
||||
data->wpa_ie_len = params->wpa_ie_len;
|
||||
if (params->wpa_ie)
|
||||
os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
|
||||
/* TODO: add support for other assoc parameters */
|
||||
|
||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
|
||||
NULL, NULL);
|
||||
os_free(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
int res;
|
||||
size_t len = ETH_ALEN;
|
||||
|
||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
|
||||
if (res < 0 || len != ETH_ALEN)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
int res, ssid_len;
|
||||
u8 reply[sizeof(int) + 32];
|
||||
size_t len = sizeof(reply);
|
||||
|
||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
|
||||
if (res < 0 || len < sizeof(int))
|
||||
return -1;
|
||||
os_memcpy(&ssid_len, reply, sizeof(int));
|
||||
if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
|
||||
wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
|
||||
return ssid_len;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
//struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
|
||||
__func__, MAC2STR(addr), reason_code);
|
||||
wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
//struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
|
||||
__func__, MAC2STR(addr), reason_code);
|
||||
wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event,
|
||||
u8 *buf, size_t len)
|
||||
{
|
||||
union wpa_event_data data;
|
||||
int inc_data = 0;
|
||||
u8 *pos, *end;
|
||||
int ie_len;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
|
||||
if (end - pos < (int) sizeof(int))
|
||||
return;
|
||||
os_memcpy(&ie_len, pos, sizeof(int));
|
||||
pos += sizeof(int);
|
||||
if (ie_len < 0 || ie_len > end - pos)
|
||||
return;
|
||||
if (ie_len) {
|
||||
data.assoc_info.req_ies = pos;
|
||||
data.assoc_info.req_ies_len = ie_len;
|
||||
pos += ie_len;
|
||||
inc_data = 1;
|
||||
}
|
||||
|
||||
wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
union wpa_event_data data;
|
||||
int ievent;
|
||||
|
||||
if (len < sizeof(int) ||
|
||||
len - sizeof(int) > sizeof(data.interface_status.ifname))
|
||||
return;
|
||||
|
||||
os_memcpy(&ievent, buf, sizeof(int));
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
data.interface_status.ievent = ievent;
|
||||
os_memcpy(data.interface_status.ifname, buf + sizeof(int),
|
||||
len - sizeof(int));
|
||||
wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_michael_mic_failure(
|
||||
void *ctx, u8 *buf, size_t len)
|
||||
{
|
||||
union wpa_event_data data;
|
||||
|
||||
if (len != sizeof(int))
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
|
||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
union wpa_event_data data;
|
||||
|
||||
if (len != sizeof(struct pmkid_candidate))
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
os_memcpy(&data.pmkid_candidate, buf, len);
|
||||
wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
|
||||
{
|
||||
union wpa_event_data data;
|
||||
|
||||
if (len != ETH_ALEN)
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
|
||||
wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
union wpa_event_data data;
|
||||
|
||||
if (len < sizeof(int) + ETH_ALEN)
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
|
||||
os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
|
||||
data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
|
||||
data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
|
||||
wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
|
||||
{
|
||||
if (len < ETH_ALEN)
|
||||
return;
|
||||
|
||||
wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
|
||||
{
|
||||
#ifdef CONFIG_CLIENT_MLME
|
||||
struct ieee80211_rx_status *rx_status;
|
||||
|
||||
if (len < sizeof(*rx_status))
|
||||
return;
|
||||
rx_status = (struct ieee80211_rx_status *) buf;
|
||||
buf += sizeof(*rx_status);
|
||||
len -= sizeof(*rx_status);
|
||||
|
||||
wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
|
||||
#endif /* CONFIG_CLIENT_MLME */
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
|
||||
void *sock_ctx)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = eloop_ctx;
|
||||
u8 *buf, *event_buf;
|
||||
size_t event_len;
|
||||
int res, event;
|
||||
enum privsep_event e;
|
||||
struct sockaddr_un from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
const size_t buflen = 2000;
|
||||
|
||||
buf = os_malloc(buflen);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
res = recvfrom(sock, buf, buflen, 0,
|
||||
(struct sockaddr *) &from, &fromlen);
|
||||
if (res < 0) {
|
||||
perror("recvfrom(priv_socket)");
|
||||
os_free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
|
||||
|
||||
if (res < (int) sizeof(int)) {
|
||||
wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(&event, buf, sizeof(int));
|
||||
event_buf = &buf[sizeof(int)];
|
||||
event_len = res - sizeof(int);
|
||||
wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
|
||||
event, (unsigned long) event_len);
|
||||
|
||||
e = event;
|
||||
switch (e) {
|
||||
case PRIVSEP_EVENT_SCAN_RESULTS:
|
||||
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
break;
|
||||
case PRIVSEP_EVENT_ASSOC:
|
||||
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
|
||||
event_buf, event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_DISASSOC:
|
||||
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
|
||||
break;
|
||||
case PRIVSEP_EVENT_ASSOCINFO:
|
||||
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
|
||||
event_buf, event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
|
||||
wpa_driver_privsep_event_michael_mic_failure(
|
||||
drv->ctx, event_buf, event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_INTERFACE_STATUS:
|
||||
wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
|
||||
event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_PMKID_CANDIDATE:
|
||||
wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
|
||||
event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_STKSTART:
|
||||
wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
|
||||
event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_FT_RESPONSE:
|
||||
wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
|
||||
event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_RX_EAPOL:
|
||||
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
|
||||
event_len);
|
||||
break;
|
||||
case PRIVSEP_EVENT_STA_RX:
|
||||
wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
|
||||
event_len);
|
||||
break;
|
||||
}
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
drv->priv_socket = -1;
|
||||
drv->cmd_socket = -1;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_privsep_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
|
||||
if (drv->priv_socket >= 0) {
|
||||
wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
|
||||
eloop_unregister_read_sock(drv->priv_socket);
|
||||
close(drv->priv_socket);
|
||||
}
|
||||
|
||||
if (drv->own_socket_path) {
|
||||
unlink(drv->own_socket_path);
|
||||
os_free(drv->own_socket_path);
|
||||
}
|
||||
|
||||
if (drv->cmd_socket >= 0) {
|
||||
eloop_unregister_read_sock(drv->cmd_socket);
|
||||
close(drv->cmd_socket);
|
||||
}
|
||||
|
||||
if (drv->own_cmd_path) {
|
||||
unlink(drv->own_cmd_path);
|
||||
os_free(drv->own_cmd_path);
|
||||
}
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_set_param(void *priv, const char *param)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
const char *pos;
|
||||
char *own_dir, *priv_dir;
|
||||
static unsigned int counter = 0;
|
||||
size_t len;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
|
||||
if (param == NULL)
|
||||
pos = NULL;
|
||||
else
|
||||
pos = os_strstr(param, "own_dir=");
|
||||
if (pos) {
|
||||
char *end;
|
||||
own_dir = os_strdup(pos + 8);
|
||||
if (own_dir == NULL)
|
||||
return -1;
|
||||
end = os_strchr(own_dir, ' ');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
} else {
|
||||
own_dir = os_strdup("/tmp");
|
||||
if (own_dir == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (param == NULL)
|
||||
pos = NULL;
|
||||
else
|
||||
pos = os_strstr(param, "priv_dir=");
|
||||
if (pos) {
|
||||
char *end;
|
||||
priv_dir = os_strdup(pos + 9);
|
||||
if (priv_dir == NULL) {
|
||||
os_free(own_dir);
|
||||
return -1;
|
||||
}
|
||||
end = os_strchr(priv_dir, ' ');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
} else {
|
||||
priv_dir = os_strdup("/var/run/wpa_priv");
|
||||
if (priv_dir == NULL) {
|
||||
os_free(own_dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
len = os_strlen(own_dir) + 50;
|
||||
drv->own_socket_path = os_malloc(len);
|
||||
if (drv->own_socket_path == NULL) {
|
||||
os_free(priv_dir);
|
||||
os_free(own_dir);
|
||||
return -1;
|
||||
}
|
||||
os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
|
||||
own_dir, getpid(), counter++);
|
||||
|
||||
len = os_strlen(own_dir) + 50;
|
||||
drv->own_cmd_path = os_malloc(len);
|
||||
if (drv->own_cmd_path == NULL) {
|
||||
os_free(drv->own_socket_path);
|
||||
drv->own_socket_path = NULL;
|
||||
os_free(priv_dir);
|
||||
os_free(own_dir);
|
||||
return -1;
|
||||
}
|
||||
os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
|
||||
own_dir, getpid(), counter++);
|
||||
|
||||
os_free(own_dir);
|
||||
|
||||
drv->priv_addr.sun_family = AF_UNIX;
|
||||
os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
|
||||
"%s/%s", priv_dir, drv->ifname);
|
||||
os_free(priv_dir);
|
||||
|
||||
drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (drv->priv_socket < 0) {
|
||||
perror("socket(PF_UNIX)");
|
||||
os_free(drv->own_socket_path);
|
||||
drv->own_socket_path = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
|
||||
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
|
||||
0) {
|
||||
perror("bind(PF_UNIX)");
|
||||
close(drv->priv_socket);
|
||||
drv->priv_socket = -1;
|
||||
unlink(drv->own_socket_path);
|
||||
os_free(drv->own_socket_path);
|
||||
drv->own_socket_path = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
|
||||
drv, NULL);
|
||||
|
||||
drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (drv->cmd_socket < 0) {
|
||||
perror("socket(PF_UNIX)");
|
||||
os_free(drv->own_cmd_path);
|
||||
drv->own_cmd_path = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
|
||||
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||
{
|
||||
perror("bind(PF_UNIX)");
|
||||
close(drv->cmd_socket);
|
||||
drv->cmd_socket = -1;
|
||||
unlink(drv->own_cmd_path);
|
||||
os_free(drv->own_cmd_path);
|
||||
drv->own_cmd_path = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_get_capa(void *priv,
|
||||
struct wpa_driver_capa *capa)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
int res;
|
||||
size_t len = sizeof(*capa);
|
||||
|
||||
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
|
||||
if (res < 0 || len != sizeof(*capa))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s", __func__);
|
||||
return drv->own_addr;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_set_mode(void *priv, int mode)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
|
||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
|
||||
{
|
||||
struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
|
||||
return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
|
||||
os_strlen(alpha2), NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
struct wpa_driver_ops wpa_driver_privsep_ops = {
|
||||
"privsep",
|
||||
"wpa_supplicant privilege separated driver",
|
||||
wpa_driver_privsep_get_bssid,
|
||||
wpa_driver_privsep_get_ssid,
|
||||
wpa_driver_privsep_set_wpa,
|
||||
wpa_driver_privsep_set_key,
|
||||
wpa_driver_privsep_init,
|
||||
wpa_driver_privsep_deinit,
|
||||
wpa_driver_privsep_set_param,
|
||||
NULL /* set_countermeasures */,
|
||||
NULL /* set_drop_unencrypted */,
|
||||
wpa_driver_privsep_scan,
|
||||
NULL /* get_scan_results */,
|
||||
wpa_driver_privsep_deauthenticate,
|
||||
wpa_driver_privsep_disassociate,
|
||||
wpa_driver_privsep_associate,
|
||||
NULL /* set_auth_alg */,
|
||||
NULL /* add_pmkid */,
|
||||
NULL /* remove_pmkid */,
|
||||
NULL /* flush_pmkid */,
|
||||
wpa_driver_privsep_get_capa,
|
||||
NULL /* poll */,
|
||||
NULL /* get_ifname */,
|
||||
wpa_driver_privsep_get_mac_addr,
|
||||
NULL /* send_eapol */,
|
||||
NULL /* set_operstate */,
|
||||
NULL /* mlme_setprotection */,
|
||||
NULL /* get_hw_feature_data */,
|
||||
NULL /* set_channel */,
|
||||
NULL /* set_ssid */,
|
||||
NULL /* set_bssid */,
|
||||
NULL /* send_mlme */,
|
||||
NULL /* mlme_add_sta */,
|
||||
NULL /* mlme_remove_sta */,
|
||||
NULL /* update_ft_ies */,
|
||||
NULL /* send_ft_action */,
|
||||
wpa_driver_privsep_get_scan_results2,
|
||||
NULL /* set_probe_req_ie */,
|
||||
wpa_driver_privsep_set_mode,
|
||||
wpa_driver_privsep_set_country,
|
||||
NULL /* global_init */,
|
||||
NULL /* global_deinit */,
|
||||
NULL /* init2 */,
|
||||
NULL /* get_interfaces */
|
||||
};
|
||||
|
||||
|
||||
struct wpa_driver_ops *wpa_supplicant_drivers[] =
|
||||
{
|
||||
&wpa_driver_privsep_ops,
|
||||
NULL
|
||||
};
|
186
contrib/wpa/src/drivers/driver_ps3.c
Normal file
186
contrib/wpa/src/drivers/driver_ps3.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* WPA Supplicant - PS3 Linux wireless extension driver interface
|
||||
* Copyright 2007, 2008 Sony Corporation
|
||||
*
|
||||
* 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 "wireless_copy.h"
|
||||
#include "common.h"
|
||||
#include "wpa_common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
#include "driver_wext.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
|
||||
static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
int ret, i;
|
||||
struct iwreq iwr;
|
||||
char *buf, *str;
|
||||
|
||||
if (!params->psk && !params->passphrase) {
|
||||
wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
if (params->psk) {
|
||||
/* includes null */
|
||||
iwr.u.data.length = PMK_LEN * 2 + 1;
|
||||
buf = os_malloc(iwr.u.data.length);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
str = buf;
|
||||
for (i = 0; i < PMK_LEN; i++) {
|
||||
str += snprintf(str, iwr.u.data.length - (str - buf),
|
||||
"%02x", params->psk[i]);
|
||||
}
|
||||
} else if (params->passphrase) {
|
||||
/* including quotations and null */
|
||||
iwr.u.data.length = strlen(params->passphrase) + 3;
|
||||
buf = os_malloc(iwr.u.data.length);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
buf[0] = '"';
|
||||
os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
|
||||
buf[iwr.u.data.length - 2] = '"';
|
||||
buf[iwr.u.data.length - 1] = '\0';
|
||||
} else
|
||||
return -EINVAL;
|
||||
iwr.u.data.pointer = (caddr_t) buf;
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
int ret, i;
|
||||
struct iwreq iwr;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
os_memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.encoding.flags = i + 1;
|
||||
if (params->wep_key_len[i]) {
|
||||
iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
|
||||
iwr.u.encoding.length = params->wep_key_len[i];
|
||||
} else
|
||||
iwr.u.encoding.flags = IW_ENCODE_NOKEY |
|
||||
IW_ENCODE_DISABLED;
|
||||
|
||||
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
|
||||
perror("ioctl[SIOCSIWENCODE]");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_driver_ps3_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_wext_data *drv = priv;
|
||||
int ret, value;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: <-", __func__);
|
||||
|
||||
/* clear BSSID */
|
||||
if (!params->bssid &&
|
||||
wpa_driver_wext_set_bssid(drv, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
|
||||
value = IW_AUTH_WPA_VERSION_DISABLED;
|
||||
else if (params->wpa_ie[0] == WLAN_EID_RSN)
|
||||
value = IW_AUTH_WPA_VERSION_WPA2;
|
||||
else
|
||||
value = IW_AUTH_WPA_VERSION_WPA;
|
||||
if (wpa_driver_wext_set_auth_param(drv,
|
||||
IW_AUTH_WPA_VERSION, value) < 0)
|
||||
ret = -1;
|
||||
value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
|
||||
if (wpa_driver_wext_set_auth_param(drv,
|
||||
IW_AUTH_CIPHER_PAIRWISE, value) < 0)
|
||||
ret = -1;
|
||||
value = wpa_driver_wext_cipher2wext(params->group_suite);
|
||||
if (wpa_driver_wext_set_auth_param(drv,
|
||||
IW_AUTH_CIPHER_GROUP, value) < 0)
|
||||
ret = -1;
|
||||
value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
|
||||
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
|
||||
ret = -1;
|
||||
|
||||
/* set selected BSSID */
|
||||
if (params->bssid &&
|
||||
wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
|
||||
ret = -1;
|
||||
|
||||
switch (params->group_suite) {
|
||||
case CIPHER_NONE:
|
||||
ret = 0;
|
||||
break;
|
||||
case CIPHER_WEP40:
|
||||
case CIPHER_WEP104:
|
||||
ret = wpa_driver_ps3_set_wep_keys(drv, params);
|
||||
break;
|
||||
case CIPHER_TKIP:
|
||||
case CIPHER_CCMP:
|
||||
ret = wpa_driver_ps3_set_wpa_key(drv, params);
|
||||
break;
|
||||
}
|
||||
|
||||
/* start to associate */
|
||||
ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: ->", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
int ret;
|
||||
wpa_printf(MSG_DEBUG, "%s:<-", __func__);
|
||||
|
||||
ret = wpa_driver_wext_get_capa(priv, capa);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_INFO, "%s: base wext returns error %d",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
/* PS3 hypervisor does association and 4way handshake by itself */
|
||||
capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
||||
wpa_printf(MSG_DEBUG, "%s:->", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_ps3_ops = {
|
||||
.name = "ps3",
|
||||
.desc = "PLAYSTATION3 Linux wireless extension driver",
|
||||
.get_bssid = wpa_driver_wext_get_bssid,
|
||||
.get_ssid = wpa_driver_wext_get_ssid,
|
||||
.scan = wpa_driver_wext_scan,
|
||||
.get_scan_results2 = wpa_driver_wext_get_scan_results,
|
||||
.associate = wpa_driver_ps3_associate, /* PS3 */
|
||||
.init = wpa_driver_wext_init,
|
||||
.deinit = wpa_driver_wext_deinit,
|
||||
.get_capa = wpa_driver_ps3_get_capa, /* PS3 */
|
||||
};
|
1505
contrib/wpa/src/drivers/driver_ralink.c
Normal file
1505
contrib/wpa/src/drivers/driver_ralink.c
Normal file
File diff suppressed because it is too large
Load Diff
382
contrib/wpa/src/drivers/driver_ralink.h
Normal file
382
contrib/wpa/src/drivers/driver_ralink.h
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* WPA Supplicant - driver_ralink exported functions
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Ralink defined OIDs
|
||||
#if WIRELESS_EXT <= 11
|
||||
#ifndef SIOCDEVPRIVATE
|
||||
#define SIOCDEVPRIVATE 0x8BE0
|
||||
#endif
|
||||
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
|
||||
#endif
|
||||
|
||||
#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E)
|
||||
#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
|
||||
|
||||
// IEEE 802.11 OIDs & Ralink defined OIDs ******
|
||||
|
||||
// (RaConfig Set/QueryInform) ==>
|
||||
#define OID_GET_SET_TOGGLE 0x8000
|
||||
|
||||
#define OID_802_11_ADD_WEP 0x0112
|
||||
#define OID_802_11_REMOVE_WEP 0x0113
|
||||
#define OID_802_11_DISASSOCIATE 0x0114
|
||||
#define OID_802_11_PRIVACY_FILTER 0x0118
|
||||
#define OID_802_11_ASSOCIATION_INFORMATION 0x011E
|
||||
#define OID_802_11_BSSID_LIST_SCAN 0x0508
|
||||
#define OID_802_11_SSID 0x0509
|
||||
#define OID_802_11_BSSID 0x050A
|
||||
#define OID_802_11_WEP_STATUS 0x0510
|
||||
#define OID_802_11_AUTHENTICATION_MODE 0x0511
|
||||
#define OID_802_11_INFRASTRUCTURE_MODE 0x0512
|
||||
#define OID_802_11_TX_POWER_LEVEL 0x0517
|
||||
#define OID_802_11_REMOVE_KEY 0x0519
|
||||
#define OID_802_11_ADD_KEY 0x0520
|
||||
#define OID_802_11_DEAUTHENTICATION 0x0526
|
||||
#define OID_802_11_DROP_UNENCRYPTED 0x0527
|
||||
#define OID_802_11_BSSID_LIST 0x0609
|
||||
#define OID_802_3_CURRENT_ADDRESS 0x060A
|
||||
#define OID_SET_COUNTERMEASURES 0x0616
|
||||
#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode
|
||||
#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode
|
||||
#define OID_802_11_PMKID 0x0620
|
||||
#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support
|
||||
#define RT_OID_WE_VERSION_COMPILED 0x0622
|
||||
#define RT_OID_NEW_DRIVER 0x0623
|
||||
|
||||
#define PACKED __attribute__ ((packed))
|
||||
|
||||
//wpa_supplicant event flags
|
||||
#define RT_ASSOC_EVENT_FLAG 0x0101
|
||||
#define RT_DISASSOC_EVENT_FLAG 0x0102
|
||||
#define RT_REQIE_EVENT_FLAG 0x0103
|
||||
#define RT_RESPIE_EVENT_FLAG 0x0104
|
||||
#define RT_ASSOCINFO_EVENT_FLAG 0x0105
|
||||
#define RT_PMKIDCAND_FLAG 0x0106
|
||||
#define RT_INTERFACE_DOWN 0x0107
|
||||
#define RT_REPORT_AP_INFO 0x0108
|
||||
|
||||
//
|
||||
// IEEE 802.11 Structures and definitions
|
||||
//
|
||||
// new types for Media Specific Indications
|
||||
|
||||
#ifndef ULONG
|
||||
#define CHAR char
|
||||
#define INT int
|
||||
#define SHORT int
|
||||
#define UINT u32
|
||||
#undef ULONG
|
||||
//#define ULONG u32
|
||||
#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
|
||||
#define USHORT unsigned short
|
||||
#define UCHAR unsigned char
|
||||
|
||||
#define uint32 u32
|
||||
#define uint8 u8
|
||||
|
||||
|
||||
#define BOOLEAN u8
|
||||
//#define LARGE_INTEGER s64
|
||||
#define VOID void
|
||||
#define LONG long
|
||||
#define LONGLONG s64
|
||||
#define ULONGLONG u64
|
||||
typedef VOID *PVOID;
|
||||
typedef CHAR *PCHAR;
|
||||
typedef UCHAR *PUCHAR;
|
||||
typedef USHORT *PUSHORT;
|
||||
typedef LONG *PLONG;
|
||||
typedef ULONG *PULONG;
|
||||
|
||||
typedef union _LARGE_INTEGER {
|
||||
struct {
|
||||
ULONG LowPart;
|
||||
LONG HighPart;
|
||||
}vv;
|
||||
struct {
|
||||
ULONG LowPart;
|
||||
LONG HighPart;
|
||||
} u;
|
||||
s64 QuadPart;
|
||||
} LARGE_INTEGER;
|
||||
|
||||
#endif
|
||||
|
||||
#define NDIS_802_11_LENGTH_SSID 32
|
||||
#define NDIS_802_11_LENGTH_RATES 8
|
||||
#define NDIS_802_11_LENGTH_RATES_EX 16
|
||||
#define MAX_LEN_OF_SSID 32
|
||||
#define MAC_ADDR_LEN 6
|
||||
|
||||
typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
|
||||
|
||||
// mask for authentication/integrity fields
|
||||
#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
|
||||
|
||||
#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
|
||||
#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
|
||||
#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
|
||||
#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
|
||||
|
||||
// Added new types for OFDM 5G and 2.4G
|
||||
typedef enum _NDIS_802_11_NETWORK_TYPE
|
||||
{
|
||||
Ndis802_11FH,
|
||||
Ndis802_11DS,
|
||||
Ndis802_11OFDM5,
|
||||
Ndis802_11OFDM24,
|
||||
Ndis802_11Automode,
|
||||
Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
|
||||
} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
|
||||
|
||||
//
|
||||
// Received Signal Strength Indication
|
||||
//
|
||||
typedef LONG NDIS_802_11_RSSI; // in dBm
|
||||
|
||||
typedef struct _NDIS_802_11_CONFIGURATION_FH
|
||||
{
|
||||
ULONG Length; // Length of structure
|
||||
ULONG HopPattern; // As defined by 802.11, MSB set
|
||||
ULONG HopSet; // to one if non-802.11
|
||||
ULONG DwellTime; // units are Kusec
|
||||
} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
|
||||
|
||||
typedef struct _NDIS_802_11_CONFIGURATION
|
||||
{
|
||||
ULONG Length; // Length of structure
|
||||
ULONG BeaconPeriod; // units are Kusec
|
||||
ULONG ATIMWindow; // units are Kusec
|
||||
ULONG DSConfig; // Frequency, units are kHz
|
||||
NDIS_802_11_CONFIGURATION_FH FHConfig;
|
||||
} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
|
||||
|
||||
typedef ULONG NDIS_802_11_KEY_INDEX;
|
||||
typedef ULONGLONG NDIS_802_11_KEY_RSC;
|
||||
|
||||
// Key mapping keys require a BSSID
|
||||
typedef struct _NDIS_802_11_KEY
|
||||
{
|
||||
UINT Length; // Length of this structure
|
||||
UINT KeyIndex;
|
||||
UINT KeyLength; // length of key in bytes
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
NDIS_802_11_KEY_RSC KeyRSC;
|
||||
UCHAR KeyMaterial[1]; // variable length depending on above field
|
||||
} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
|
||||
|
||||
typedef struct _NDIS_802_11_REMOVE_KEY
|
||||
{
|
||||
UINT Length; // Length of this structure
|
||||
UINT KeyIndex;
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_WEP
|
||||
{
|
||||
UINT Length; // Length of this structure
|
||||
UINT KeyIndex; // 0 is the per-client key, 1-N are the
|
||||
// global keys
|
||||
UINT KeyLength; // length of key in bytes
|
||||
UCHAR KeyMaterial[1];// variable length depending on above field
|
||||
} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
|
||||
|
||||
|
||||
typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
|
||||
{
|
||||
Ndis802_11IBSS,
|
||||
Ndis802_11Infrastructure,
|
||||
Ndis802_11AutoUnknown,
|
||||
Ndis802_11InfrastructureMax // Not a real value, defined as upper bound
|
||||
} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
|
||||
|
||||
// PMKID Structures
|
||||
typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
|
||||
|
||||
typedef struct _BSSID_INFO
|
||||
{
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
NDIS_802_11_PMKID_VALUE PMKID;
|
||||
} BSSID_INFO, *PBSSID_INFO;
|
||||
|
||||
typedef struct _NDIS_802_11_PMKID
|
||||
{
|
||||
ULONG Length;
|
||||
ULONG BSSIDInfoCount;
|
||||
BSSID_INFO BSSIDInfo[1];
|
||||
} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
|
||||
|
||||
//Added new types for PMKID Candidate lists.
|
||||
typedef struct _PMKID_CANDIDATE {
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
ULONG Flags;
|
||||
} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
|
||||
|
||||
typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
|
||||
{
|
||||
ULONG Version; // Version of the structure
|
||||
ULONG NumCandidates; // No. of pmkid candidates
|
||||
PMKID_CANDIDATE CandidateList[1];
|
||||
} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
|
||||
|
||||
//Flags for PMKID Candidate list structure
|
||||
#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
|
||||
|
||||
// Add new authentication modes
|
||||
typedef enum _NDIS_802_11_AUTHENTICATION_MODE
|
||||
{
|
||||
Ndis802_11AuthModeOpen,
|
||||
Ndis802_11AuthModeShared,
|
||||
Ndis802_11AuthModeAutoSwitch,
|
||||
Ndis802_11AuthModeWPA,
|
||||
Ndis802_11AuthModeWPAPSK,
|
||||
Ndis802_11AuthModeWPANone,
|
||||
Ndis802_11AuthModeWPA2,
|
||||
Ndis802_11AuthModeWPA2PSK,
|
||||
Ndis802_11AuthModeMax // Not a real mode, defined as upper bound
|
||||
} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
|
||||
|
||||
typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates
|
||||
typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_SSID
|
||||
{
|
||||
INT SsidLength; // length of SSID field below, in bytes;
|
||||
// this can be zero.
|
||||
UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field
|
||||
} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
|
||||
|
||||
|
||||
typedef struct PACKED _NDIS_WLAN_BSSID
|
||||
{
|
||||
ULONG Length; // Length of this structure
|
||||
NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
|
||||
UCHAR Reserved[2];
|
||||
NDIS_802_11_SSID Ssid; // SSID
|
||||
ULONG Privacy; // WEP encryption requirement
|
||||
NDIS_802_11_RSSI Rssi; // receive signal
|
||||
// strength in dBm
|
||||
NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
|
||||
NDIS_802_11_CONFIGURATION Configuration;
|
||||
NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
|
||||
NDIS_802_11_RATES SupportedRates;
|
||||
} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_BSSID_LIST
|
||||
{
|
||||
UINT NumberOfItems; // in list below, at least 1
|
||||
NDIS_WLAN_BSSID Bssid[1];
|
||||
} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
|
||||
|
||||
// Added Capabilities, IELength and IEs for each BSSID
|
||||
typedef struct PACKED _NDIS_WLAN_BSSID_EX
|
||||
{
|
||||
ULONG Length; // Length of this structure
|
||||
NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
|
||||
UCHAR Reserved[2];
|
||||
NDIS_802_11_SSID Ssid; // SSID
|
||||
UINT Privacy; // WEP encryption requirement
|
||||
NDIS_802_11_RSSI Rssi; // receive signal
|
||||
// strength in dBm
|
||||
NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
|
||||
NDIS_802_11_CONFIGURATION Configuration;
|
||||
NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
|
||||
NDIS_802_11_RATES_EX SupportedRates;
|
||||
ULONG IELength;
|
||||
UCHAR IEs[1];
|
||||
} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
|
||||
{
|
||||
UINT NumberOfItems; // in list below, at least 1
|
||||
NDIS_WLAN_BSSID_EX Bssid[1];
|
||||
} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_FIXED_IEs
|
||||
{
|
||||
UCHAR Timestamp[8];
|
||||
USHORT BeaconInterval;
|
||||
USHORT Capabilities;
|
||||
} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
|
||||
|
||||
// Added new encryption types
|
||||
// Also aliased typedef to new name
|
||||
typedef enum _NDIS_802_11_WEP_STATUS
|
||||
{
|
||||
Ndis802_11WEPEnabled,
|
||||
Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
|
||||
Ndis802_11WEPDisabled,
|
||||
Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
|
||||
Ndis802_11WEPKeyAbsent,
|
||||
Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
|
||||
Ndis802_11WEPNotSupported,
|
||||
Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
|
||||
Ndis802_11Encryption2Enabled,
|
||||
Ndis802_11Encryption2KeyAbsent,
|
||||
Ndis802_11Encryption3Enabled,
|
||||
Ndis802_11Encryption3KeyAbsent
|
||||
} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
|
||||
NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
|
||||
|
||||
typedef enum _NDIS_802_11_RELOAD_DEFAULTS
|
||||
{
|
||||
Ndis802_11ReloadWEPKeys
|
||||
} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
|
||||
|
||||
#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
|
||||
#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
|
||||
#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
|
||||
|
||||
#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
|
||||
#define NDIS_802_11_AI_RESFI_STATUSCODE 2
|
||||
#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
|
||||
|
||||
typedef struct _NDIS_802_11_AI_REQFI
|
||||
{
|
||||
USHORT Capabilities;
|
||||
USHORT ListenInterval;
|
||||
NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
|
||||
} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
|
||||
|
||||
typedef struct _NDIS_802_11_AI_RESFI
|
||||
{
|
||||
USHORT Capabilities;
|
||||
USHORT StatusCode;
|
||||
USHORT AssociationId;
|
||||
} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
|
||||
|
||||
typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
|
||||
{
|
||||
ULONG Length;
|
||||
USHORT AvailableRequestFixedIEs;
|
||||
NDIS_802_11_AI_REQFI RequestFixedIEs;
|
||||
ULONG RequestIELength;
|
||||
ULONG OffsetRequestIEs;
|
||||
USHORT AvailableResponseFixedIEs;
|
||||
NDIS_802_11_AI_RESFI ResponseFixedIEs;
|
||||
ULONG ResponseIELength;
|
||||
ULONG OffsetResponseIEs;
|
||||
} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
|
||||
|
||||
struct ndis_pmkid_entry {
|
||||
struct ndis_pmkid_entry *next;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 pmkid[16];
|
||||
};
|
||||
|
||||
typedef struct _MLME_DEAUTH_REQ_STRUCT {
|
||||
UCHAR Addr[MAC_ADDR_LEN];
|
||||
USHORT Reason;
|
||||
} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
|
476
contrib/wpa/src/drivers/driver_roboswitch.c
Normal file
476
contrib/wpa/src/drivers/driver_roboswitch.c
Normal file
@ -0,0 +1,476 @@
|
||||
/*
|
||||
* WPA Supplicant - roboswitch driver interface
|
||||
* Copyright (c) 2008-2009 Jouke Witteveen
|
||||
*
|
||||
* 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 <linux/if.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/mii.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
|
||||
#ifndef ETH_P_EAPOL
|
||||
#define ETH_P_EAPOL 0x888e
|
||||
#endif
|
||||
|
||||
#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */
|
||||
|
||||
/* MII access registers */
|
||||
#define ROBO_MII_PAGE 0x10 /* MII page register */
|
||||
#define ROBO_MII_ADDR 0x11 /* MII address register */
|
||||
#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */
|
||||
|
||||
#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */
|
||||
#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */
|
||||
#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */
|
||||
#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */
|
||||
#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */
|
||||
|
||||
/* Page numbers */
|
||||
#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */
|
||||
#define ROBO_VLAN_PAGE 0x34 /* VLAN page */
|
||||
|
||||
/* ARL control page registers */
|
||||
#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */
|
||||
#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */
|
||||
#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */
|
||||
#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */
|
||||
#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */
|
||||
|
||||
/* VLAN page registers */
|
||||
#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */
|
||||
#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */
|
||||
#define ROBO_VLAN_READ 0x0c /* VLAN read register */
|
||||
#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */
|
||||
|
||||
|
||||
static const u8 pae_group_addr[ETH_ALEN] =
|
||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
||||
|
||||
|
||||
struct wpa_driver_roboswitch_data {
|
||||
void *ctx;
|
||||
struct l2_packet_data *l2;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
u8 own_addr[ETH_ALEN];
|
||||
struct ifreq ifr;
|
||||
int fd, is_5350;
|
||||
u16 ports;
|
||||
};
|
||||
|
||||
|
||||
/* Copied from the kernel-only part of mii.h. */
|
||||
static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
|
||||
{
|
||||
return (struct mii_ioctl_data *) &rq->ifr_ifru;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RoboSwitch uses 16-bit Big Endian addresses.
|
||||
* The ordering of the words is reversed in the MII registers.
|
||||
*/
|
||||
static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ETH_ALEN; i += 2)
|
||||
be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
|
||||
}
|
||||
|
||||
|
||||
static u16 wpa_driver_roboswitch_mdio_read(
|
||||
struct wpa_driver_roboswitch_data *drv, u8 reg)
|
||||
{
|
||||
struct mii_ioctl_data *mii = if_mii(&drv->ifr);
|
||||
|
||||
mii->phy_id = ROBO_PHY_ADDR;
|
||||
mii->reg_num = reg;
|
||||
|
||||
if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
|
||||
perror("ioctl[SIOCGMIIREG]");
|
||||
return 0x00;
|
||||
}
|
||||
return mii->val_out;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_roboswitch_mdio_write(
|
||||
struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
|
||||
{
|
||||
struct mii_ioctl_data *mii = if_mii(&drv->ifr);
|
||||
|
||||
mii->phy_id = ROBO_PHY_ADDR;
|
||||
mii->reg_num = reg;
|
||||
mii->val_in = val;
|
||||
|
||||
if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
|
||||
perror("ioctl[SIOCSMIIREG");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
|
||||
u8 page, u8 reg, u8 op)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set page number */
|
||||
wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
|
||||
(page << 8) | ROBO_MII_PAGE_ENABLE);
|
||||
/* set register address */
|
||||
wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
|
||||
|
||||
/* check if operation completed */
|
||||
for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
|
||||
if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
|
||||
== 0)
|
||||
return 0;
|
||||
}
|
||||
/* timeout */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
|
||||
u8 page, u8 reg, u16 *val, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len > ROBO_MII_DATA_MAX ||
|
||||
wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
val[i] = wpa_driver_roboswitch_mdio_read(
|
||||
drv, ROBO_MII_DATA_OFFSET + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
|
||||
u8 page, u8 reg, u16 *val, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len > ROBO_MII_DATA_MAX) return -1;
|
||||
for (i = 0; i < len; ++i) {
|
||||
wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
|
||||
val[i]);
|
||||
}
|
||||
return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct wpa_driver_roboswitch_data *drv = priv;
|
||||
|
||||
if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
|
||||
os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) {
|
||||
wpa_supplicant_rx_eapol(drv->ctx, src_addr, buf + 14,
|
||||
len - 14);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
ssid[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
/* Report PAE group address as the "BSSID" for wired connection. */
|
||||
os_memcpy(bssid, pae_group_addr, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
|
||||
{
|
||||
struct wpa_driver_roboswitch_data *drv = priv;
|
||||
char *sep;
|
||||
|
||||
if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
|
||||
sep = drv->ifname + os_strlen(drv->ifname);
|
||||
*sep = '.';
|
||||
drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
|
||||
wpa_driver_roboswitch_receive, drv,
|
||||
1);
|
||||
if (drv->l2 == NULL) {
|
||||
wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
|
||||
__func__, drv->ifname);
|
||||
return -1;
|
||||
}
|
||||
*sep = '\0';
|
||||
l2_packet_get_own_addr(drv->l2, drv->own_addr);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
|
||||
drv->l2 = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char * wpa_driver_roboswitch_get_ifname(void *priv)
|
||||
{
|
||||
struct wpa_driver_roboswitch_data *drv = priv;
|
||||
return drv->ifname;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
|
||||
u16 ports, const u8 *addr)
|
||||
{
|
||||
u16 read1[3], read2[3], addr_be16[3];
|
||||
|
||||
wpa_driver_roboswitch_addr_be16(addr, addr_be16);
|
||||
|
||||
if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_CONF, read1, 1) < 0)
|
||||
return -1;
|
||||
if (!(read1[0] & (1 << 4))) {
|
||||
/* multiport addresses are not yet enabled */
|
||||
read1[0] |= 1 << 4;
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_1, &ports, 1);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_2, &ports, 1);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_CONF, read1, 1);
|
||||
} else {
|
||||
/* if both multiport addresses are the same we can add */
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_1, read1, 3);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_2, read2, 3);
|
||||
if (os_memcmp(read1, read2, 6) != 0)
|
||||
return -1;
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_1, read1, 1);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_2, read2, 1);
|
||||
if (read1[0] != read2[0])
|
||||
return -1;
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_1, &ports, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
|
||||
u16 ports, const u8 *addr)
|
||||
{
|
||||
u16 _read, addr_be16[3], addr_read[3], ports_read;
|
||||
|
||||
wpa_driver_roboswitch_addr_be16(addr, addr_be16);
|
||||
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
|
||||
&_read, 1);
|
||||
/* If ARL control is disabled, there is nothing to leave. */
|
||||
if (!(_read & (1 << 4))) return -1;
|
||||
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_1, addr_read, 3);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
|
||||
&ports_read, 1);
|
||||
/* check if we occupy multiport address 1 */
|
||||
if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_2, addr_read, 3);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_2, &ports_read, 1);
|
||||
/* and multiport address 2 */
|
||||
if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
|
||||
ports_read == ports) {
|
||||
_read &= ~(1 << 4);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_CONF, &_read,
|
||||
1);
|
||||
} else {
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_1,
|
||||
addr_read, 3);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_1,
|
||||
&ports_read, 1);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_2,
|
||||
addr_read, 3);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_2,
|
||||
&ports_read, 1);
|
||||
}
|
||||
} else {
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_2, addr_read, 3);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_2, &ports_read, 1);
|
||||
/* or multiport address 2 */
|
||||
if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
|
||||
ports_read == ports) {
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_ADDR_1,
|
||||
addr_read, 3);
|
||||
wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
|
||||
ROBO_ARLCTRL_VEC_1,
|
||||
&ports_read, 1);
|
||||
} else return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_roboswitch_data *drv;
|
||||
char *sep;
|
||||
u16 vlan = 0, _read[2];
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL) return NULL;
|
||||
drv->ctx = ctx;
|
||||
drv->own_addr[0] = '\0';
|
||||
|
||||
/* copy ifname and take a pointer to the second to last character */
|
||||
sep = drv->ifname +
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
|
||||
/* find the '.' seperating <interface> and <vlan> */
|
||||
while (sep > drv->ifname && *sep != '.') sep--;
|
||||
if (sep <= drv->ifname) {
|
||||
wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
|
||||
"interface name %s", __func__, drv->ifname);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
*sep = '\0';
|
||||
while (*++sep) {
|
||||
if (*sep < '0' || *sep > '9') {
|
||||
wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
|
||||
"in interface name %s", __func__, ifname);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
vlan *= 10;
|
||||
vlan += *sep - '0';
|
||||
if (vlan > ROBO_VLAN_MAX) {
|
||||
wpa_printf(MSG_INFO, "%s: VLAN out of range in "
|
||||
"interface name %s", __func__, ifname);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->fd < 0) {
|
||||
wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&drv->ifr, 0, sizeof(drv->ifr));
|
||||
os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
|
||||
perror("ioctl[SIOCGMIIPHY]");
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
|
||||
wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
|
||||
"RoboSwitch?)", __func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set and read back to see if the register can be used */
|
||||
_read[0] = ROBO_VLAN_MAX;
|
||||
wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
|
||||
_read, 1);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
|
||||
_read + 1, 1);
|
||||
drv->is_5350 = _read[0] == _read[1];
|
||||
|
||||
/* set the read bit */
|
||||
vlan |= 1 << 13;
|
||||
wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
|
||||
drv->is_5350 ? ROBO_VLAN_ACCESS_5350
|
||||
: ROBO_VLAN_ACCESS,
|
||||
&vlan, 1);
|
||||
wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
|
||||
drv->is_5350 ? 2 : 1);
|
||||
if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
|
||||
wpa_printf(MSG_INFO, "%s: Could not get port information for "
|
||||
"VLAN %d", __func__, vlan & ~(1 << 13));
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
drv->ports = _read[0] & 0x001F;
|
||||
/* add the MII port */
|
||||
drv->ports |= 1 << 8;
|
||||
if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
|
||||
wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
|
||||
"RoboSwitch ARL", __func__);
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_roboswitch_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_roboswitch_data *drv = priv;
|
||||
|
||||
if (drv->l2) {
|
||||
l2_packet_deinit(drv->l2);
|
||||
drv->l2 = NULL;
|
||||
}
|
||||
if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
|
||||
__func__);
|
||||
}
|
||||
|
||||
close(drv->fd);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
|
||||
.name = "roboswitch",
|
||||
.desc = "wpa_supplicant roboswitch driver",
|
||||
.get_ssid = wpa_driver_roboswitch_get_ssid,
|
||||
.get_bssid = wpa_driver_roboswitch_get_bssid,
|
||||
.init = wpa_driver_roboswitch_init,
|
||||
.deinit = wpa_driver_roboswitch_deinit,
|
||||
.set_param = wpa_driver_roboswitch_set_param,
|
||||
.get_ifname = wpa_driver_roboswitch_get_ifname,
|
||||
};
|
1230
contrib/wpa/src/drivers/driver_test.c
Normal file
1230
contrib/wpa/src/drivers/driver_test.c
Normal file
File diff suppressed because it is too large
Load Diff
2375
contrib/wpa/src/drivers/driver_wext.c
Normal file
2375
contrib/wpa/src/drivers/driver_wext.c
Normal file
File diff suppressed because it is too large
Load Diff
82
contrib/wpa/src/drivers/driver_wext.h
Normal file
82
contrib/wpa/src/drivers/driver_wext.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* WPA Supplicant - driver_wext exported functions
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_WEXT_H
|
||||
#define DRIVER_WEXT_H
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
struct wpa_driver_wext_data {
|
||||
void *ctx;
|
||||
int event_sock;
|
||||
int ioctl_sock;
|
||||
int mlme_sock;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int ifindex;
|
||||
int ifindex2;
|
||||
int if_removed;
|
||||
u8 *assoc_req_ies;
|
||||
size_t assoc_req_ies_len;
|
||||
u8 *assoc_resp_ies;
|
||||
size_t assoc_resp_ies_len;
|
||||
struct wpa_driver_capa capa;
|
||||
int has_capability;
|
||||
int we_version_compiled;
|
||||
|
||||
/* for set_auth_alg fallback */
|
||||
int use_crypt;
|
||||
int auth_alg_fallback;
|
||||
|
||||
int operstate;
|
||||
|
||||
char mlmedev[IFNAMSIZ + 1];
|
||||
|
||||
int scan_complete_events;
|
||||
};
|
||||
|
||||
int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
|
||||
int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
|
||||
int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
|
||||
int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
|
||||
int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
|
||||
int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
|
||||
int wpa_driver_wext_set_freq(void *priv, int freq);
|
||||
int wpa_driver_wext_set_mode(void *priv, int mode);
|
||||
int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
|
||||
const u8 *addr, int key_idx,
|
||||
int set_tx, const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len);
|
||||
int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len);
|
||||
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
|
||||
|
||||
void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
|
||||
const char *ifname);
|
||||
|
||||
void * wpa_driver_wext_init(void *ctx, const char *ifname);
|
||||
void wpa_driver_wext_deinit(void *priv);
|
||||
|
||||
int wpa_driver_wext_set_operstate(void *priv, int state);
|
||||
int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
|
||||
|
||||
int wpa_driver_wext_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params);
|
||||
int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
|
||||
int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
|
||||
int idx, u32 value);
|
||||
int wpa_driver_wext_cipher2wext(int cipher);
|
||||
int wpa_driver_wext_keymgmt2wext(int keymgmt);
|
||||
|
||||
#endif /* DRIVER_WEXT_H */
|
286
contrib/wpa/src/drivers/driver_wired.c
Normal file
286
contrib/wpa/src/drivers/driver_wired.c
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* WPA Supplicant - wired Ethernet driver interface
|
||||
* Copyright (c) 2005-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>
|
||||
#include <net/if.h>
|
||||
#ifdef __linux__
|
||||
#include <netpacket/packet.h>
|
||||
#endif /* __linux__ */
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <net/if_dl.h>
|
||||
#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
static const u8 pae_group_addr[ETH_ALEN] =
|
||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
||||
|
||||
|
||||
struct wpa_driver_wired_data {
|
||||
void *ctx;
|
||||
int pf_sock;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int membership, multi, iff_allmulti, iff_up;
|
||||
};
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
ssid[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
/* Report PAE group address as the "BSSID" for wired connection. */
|
||||
os_memcpy(bssid, pae_group_addr, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
|
||||
perror("ioctl[SIOCGIFFLAGS]");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
*flags = ifr.ifr_flags & 0xffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
ifr.ifr_flags = flags & 0xffff;
|
||||
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
|
||||
perror("ioctl[SIOCSIFFLAGS]");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
#ifdef __linux__
|
||||
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
||||
os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
|
||||
#endif /* __linux__ */
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
{
|
||||
struct sockaddr_dl *dlp;
|
||||
dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
|
||||
dlp->sdl_len = sizeof(struct sockaddr_dl);
|
||||
dlp->sdl_family = AF_LINK;
|
||||
dlp->sdl_index = 0;
|
||||
dlp->sdl_nlen = 0;
|
||||
dlp->sdl_alen = ETH_ALEN;
|
||||
dlp->sdl_slen = 0;
|
||||
os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
|
||||
}
|
||||
#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||
{
|
||||
struct sockaddr *sap;
|
||||
sap = (struct sockaddr *) &ifr.ifr_addr;
|
||||
sap->sa_len = sizeof(struct sockaddr);
|
||||
sap->sa_family = AF_UNSPEC;
|
||||
os_memcpy(sap->sa_data, addr, ETH_ALEN);
|
||||
}
|
||||
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
|
||||
|
||||
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
|
||||
perror("ioctl[SIOC{ADD/DEL}MULTI]");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
|
||||
const u8 *addr, int add)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct packet_mreq mreq;
|
||||
|
||||
if (drv->pf_sock == -1)
|
||||
return -1;
|
||||
|
||||
os_memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.mr_ifindex = if_nametoindex(drv->ifname);
|
||||
mreq.mr_type = PACKET_MR_MULTICAST;
|
||||
mreq.mr_alen = ETH_ALEN;
|
||||
os_memcpy(mreq.mr_address, addr, ETH_ALEN);
|
||||
|
||||
if (setsockopt(drv->pf_sock, SOL_PACKET,
|
||||
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
|
||||
&mreq, sizeof(mreq)) < 0) {
|
||||
perror("setsockopt");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else /* __linux__ */
|
||||
return -1;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv;
|
||||
int flags;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->ctx = ctx;
|
||||
|
||||
#ifdef __linux__
|
||||
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
|
||||
if (drv->pf_sock < 0)
|
||||
perror("socket(PF_PACKET)");
|
||||
#else /* __linux__ */
|
||||
drv->pf_sock = -1;
|
||||
#endif /* __linux__ */
|
||||
|
||||
if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
|
||||
!(flags & IFF_UP) &&
|
||||
wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
|
||||
drv->iff_up = 1;
|
||||
}
|
||||
|
||||
if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
|
||||
"packet socket", __func__);
|
||||
drv->membership = 1;
|
||||
} else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
|
||||
"SIOCADDMULTI", __func__);
|
||||
drv->multi = 1;
|
||||
} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
|
||||
wpa_printf(MSG_INFO, "%s: Could not get interface "
|
||||
"flags", __func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
} else if (flags & IFF_ALLMULTI) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
|
||||
"for multicast", __func__);
|
||||
} else if (wpa_driver_wired_set_ifflags(ifname,
|
||||
flags | IFF_ALLMULTI) < 0) {
|
||||
wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
|
||||
__func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
|
||||
__func__);
|
||||
drv->iff_allmulti = 1;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_wired_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv = priv;
|
||||
int flags;
|
||||
|
||||
if (drv->membership &&
|
||||
wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
|
||||
"group (PACKET)", __func__);
|
||||
}
|
||||
|
||||
if (drv->multi &&
|
||||
wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
|
||||
"group (SIOCDELMULTI)", __func__);
|
||||
}
|
||||
|
||||
if (drv->iff_allmulti &&
|
||||
(wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
|
||||
wpa_driver_wired_set_ifflags(drv->ifname,
|
||||
flags & ~IFF_ALLMULTI) < 0)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
|
||||
__func__);
|
||||
}
|
||||
|
||||
if (drv->iff_up &&
|
||||
wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
|
||||
(flags & IFF_UP) &&
|
||||
wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
|
||||
__func__);
|
||||
}
|
||||
|
||||
if (drv->pf_sock != -1)
|
||||
close(drv->pf_sock);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_wired_ops = {
|
||||
.name = "wired",
|
||||
.desc = "wpa_supplicant wired Ethernet driver",
|
||||
.get_ssid = wpa_driver_wired_get_ssid,
|
||||
.get_bssid = wpa_driver_wired_get_bssid,
|
||||
.init = wpa_driver_wired_init,
|
||||
.deinit = wpa_driver_wired_deinit,
|
||||
};
|
808
contrib/wpa/src/drivers/ndis_events.c
Normal file
808
contrib/wpa/src/drivers/ndis_events.c
Normal file
@ -0,0 +1,808 @@
|
||||
/*
|
||||
* ndis_events - Receive NdisMIndicateStatus() events using WMI
|
||||
* Copyright (c) 2004-2006, 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.
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0400
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef COBJMACROS
|
||||
#define COBJMACROS
|
||||
#endif /* COBJMACROS */
|
||||
#include <wbemidl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
static int wmi_refcnt = 0;
|
||||
static int wmi_first = 1;
|
||||
|
||||
struct ndis_events_data {
|
||||
IWbemObjectSink sink;
|
||||
IWbemObjectSinkVtbl sink_vtbl;
|
||||
|
||||
IWbemServices *pSvc;
|
||||
IWbemLocator *pLoc;
|
||||
|
||||
HANDLE read_pipe, write_pipe, event_avail;
|
||||
UINT ref;
|
||||
int terminating;
|
||||
char *ifname; /* {GUID..} */
|
||||
WCHAR *adapter_desc;
|
||||
};
|
||||
|
||||
#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
|
||||
#define BstrFree(x) if (x) SysFreeString(x)
|
||||
|
||||
/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
|
||||
* BSTRs */
|
||||
HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
|
||||
IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
|
||||
long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
|
||||
{
|
||||
BSTR bsQueryLanguage, bsQuery;
|
||||
HRESULT hr;
|
||||
|
||||
bsQueryLanguage = BstrAlloc(strQueryLanguage);
|
||||
bsQuery = BstrAlloc(strQuery);
|
||||
|
||||
hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
|
||||
pCtx, ppEnum);
|
||||
|
||||
BstrFree(bsQueryLanguage);
|
||||
BstrFree(bsQuery);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
|
||||
IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
|
||||
long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
|
||||
{
|
||||
BSTR bsQueryLanguage, bsQuery;
|
||||
HRESULT hr;
|
||||
|
||||
bsQueryLanguage = BstrAlloc(strQueryLanguage);
|
||||
bsQuery = BstrAlloc(strQuery);
|
||||
|
||||
hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
|
||||
bsQuery, lFlags, pCtx,
|
||||
pResponseHandler);
|
||||
|
||||
BstrFree(bsQueryLanguage);
|
||||
BstrFree(bsQuery);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
|
||||
IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
|
||||
LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
|
||||
LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
|
||||
{
|
||||
BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
|
||||
HRESULT hr;
|
||||
|
||||
bsNetworkResource = BstrAlloc(strNetworkResource);
|
||||
bsUser = BstrAlloc(strUser);
|
||||
bsPassword = BstrAlloc(strPassword);
|
||||
bsLocale = BstrAlloc(strLocale);
|
||||
bsAuthority = BstrAlloc(strAuthority);
|
||||
|
||||
hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
|
||||
bsPassword, bsLocale, lSecurityFlags,
|
||||
bsAuthority, pCtx, ppNamespace);
|
||||
|
||||
BstrFree(bsNetworkResource);
|
||||
BstrFree(bsUser);
|
||||
BstrFree(bsPassword);
|
||||
BstrFree(bsLocale);
|
||||
BstrFree(bsAuthority);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
|
||||
EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
|
||||
|
||||
static int ndis_events_get_adapter(struct ndis_events_data *events,
|
||||
const char *ifname, const char *desc);
|
||||
|
||||
|
||||
static int ndis_events_constructor(struct ndis_events_data *events)
|
||||
{
|
||||
events->ref = 1;
|
||||
|
||||
if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
|
||||
wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
|
||||
(int) GetLastError());
|
||||
return -1;
|
||||
}
|
||||
events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (events->event_avail == NULL) {
|
||||
wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
|
||||
(int) GetLastError());
|
||||
CloseHandle(events->read_pipe);
|
||||
CloseHandle(events->write_pipe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ndis_events_destructor(struct ndis_events_data *events)
|
||||
{
|
||||
CloseHandle(events->read_pipe);
|
||||
CloseHandle(events->write_pipe);
|
||||
CloseHandle(events->event_avail);
|
||||
IWbemServices_Release(events->pSvc);
|
||||
IWbemLocator_Release(events->pLoc);
|
||||
if (--wmi_refcnt == 0)
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
|
||||
{
|
||||
*obj = NULL;
|
||||
|
||||
if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
IsEqualIID(riid, &IID_IWbemObjectSink)) {
|
||||
*obj = this;
|
||||
IWbemObjectSink_AddRef(this);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
|
||||
{
|
||||
struct ndis_events_data *events = (struct ndis_events_data *) this;
|
||||
return ++events->ref;
|
||||
}
|
||||
|
||||
|
||||
static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
|
||||
{
|
||||
struct ndis_events_data *events = (struct ndis_events_data *) this;
|
||||
|
||||
if (--events->ref != 0)
|
||||
return events->ref;
|
||||
|
||||
ndis_events_destructor(events);
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: terminated");
|
||||
os_free(events->adapter_desc);
|
||||
os_free(events->ifname);
|
||||
os_free(events);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ndis_events_send_event(struct ndis_events_data *events,
|
||||
enum event_types type,
|
||||
char *data, size_t data_len)
|
||||
{
|
||||
char buf[512], *pos, *end;
|
||||
int _type;
|
||||
DWORD written;
|
||||
|
||||
end = buf + sizeof(buf);
|
||||
_type = (int) type;
|
||||
os_memcpy(buf, &_type, sizeof(_type));
|
||||
pos = buf + sizeof(_type);
|
||||
|
||||
if (data) {
|
||||
if (2 + data_len > (size_t) (end - pos)) {
|
||||
wpa_printf(MSG_DEBUG, "Not enough room for send_event "
|
||||
"data (%d)", data_len);
|
||||
return -1;
|
||||
}
|
||||
*pos++ = data_len >> 8;
|
||||
*pos++ = data_len & 0xff;
|
||||
os_memcpy(pos, data, data_len);
|
||||
pos += data_len;
|
||||
}
|
||||
|
||||
if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
|
||||
SetEvent(events->event_avail);
|
||||
return 0;
|
||||
}
|
||||
wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void ndis_events_media_connect(struct ndis_events_data *events)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
|
||||
ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static void ndis_events_media_disconnect(struct ndis_events_data *events)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
|
||||
ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static void ndis_events_media_specific(struct ndis_events_data *events,
|
||||
IWbemClassObject *pObj)
|
||||
{
|
||||
VARIANT vt;
|
||||
HRESULT hr;
|
||||
LONG lower, upper, k;
|
||||
UCHAR ch;
|
||||
char *data, *pos;
|
||||
size_t data_len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
|
||||
|
||||
/* This is the StatusBuffer from NdisMIndicateStatus() call */
|
||||
hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
|
||||
0, &vt, NULL, NULL);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not get "
|
||||
"NdisStatusMediaSpecificIndication from "
|
||||
"the object?!");
|
||||
return;
|
||||
}
|
||||
|
||||
SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
|
||||
SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
|
||||
data_len = upper - lower + 1;
|
||||
data = os_malloc(data_len);
|
||||
if (data == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
|
||||
"data");
|
||||
VariantClear(&vt);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = data;
|
||||
for (k = lower; k <= upper; k++) {
|
||||
SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
|
||||
*pos++ = ch;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
|
||||
|
||||
VariantClear(&vt);
|
||||
|
||||
ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
|
||||
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static void ndis_events_adapter_arrival(struct ndis_events_data *events)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
|
||||
ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static void ndis_events_adapter_removal(struct ndis_events_data *events)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
|
||||
ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
|
||||
IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
|
||||
{
|
||||
struct ndis_events_data *events = (struct ndis_events_data *) this;
|
||||
long i;
|
||||
|
||||
if (events->terminating) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
|
||||
"indication - terminating");
|
||||
return WBEM_NO_ERROR;
|
||||
}
|
||||
/* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
|
||||
lObjectCount); */
|
||||
|
||||
for (i = 0; i < lObjectCount; i++) {
|
||||
IWbemClassObject *pObj = ppObjArray[i];
|
||||
HRESULT hr;
|
||||
VARIANT vtClass, vt;
|
||||
|
||||
hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
|
||||
NULL);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
|
||||
"event.");
|
||||
break;
|
||||
}
|
||||
/* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
|
||||
|
||||
hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
|
||||
NULL);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
|
||||
"from event.");
|
||||
VariantClear(&vtClass);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wcscmp(vtClass.bstrVal,
|
||||
L"MSNdis_NotifyAdapterArrival") == 0) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
|
||||
"update adapter description since it may "
|
||||
"have changed with new adapter instance");
|
||||
ndis_events_get_adapter(events, events->ifname, NULL);
|
||||
}
|
||||
|
||||
if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
|
||||
"indication for foreign adapter: "
|
||||
"InstanceName: '%S' __CLASS: '%S'",
|
||||
vt.bstrVal, vtClass.bstrVal);
|
||||
VariantClear(&vtClass);
|
||||
VariantClear(&vt);
|
||||
continue;
|
||||
}
|
||||
VariantClear(&vt);
|
||||
|
||||
if (wcscmp(vtClass.bstrVal,
|
||||
L"MSNdis_StatusMediaSpecificIndication") == 0) {
|
||||
ndis_events_media_specific(events, pObj);
|
||||
} else if (wcscmp(vtClass.bstrVal,
|
||||
L"MSNdis_StatusMediaConnect") == 0) {
|
||||
ndis_events_media_connect(events);
|
||||
} else if (wcscmp(vtClass.bstrVal,
|
||||
L"MSNdis_StatusMediaDisconnect") == 0) {
|
||||
ndis_events_media_disconnect(events);
|
||||
} else if (wcscmp(vtClass.bstrVal,
|
||||
L"MSNdis_NotifyAdapterArrival") == 0) {
|
||||
ndis_events_adapter_arrival(events);
|
||||
} else if (wcscmp(vtClass.bstrVal,
|
||||
L"MSNdis_NotifyAdapterRemoval") == 0) {
|
||||
ndis_events_adapter_removal(events);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
|
||||
"'%S'", vtClass.bstrVal);
|
||||
}
|
||||
|
||||
VariantClear(&vtClass);
|
||||
}
|
||||
|
||||
return WBEM_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
|
||||
BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
|
||||
{
|
||||
return WBEM_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int notification_query(IWbemObjectSink *pDestSink,
|
||||
IWbemServices *pSvc, const char *class_name)
|
||||
{
|
||||
HRESULT hr;
|
||||
WCHAR query[256];
|
||||
|
||||
_snwprintf(query, 256,
|
||||
L"SELECT * FROM %S", class_name);
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
|
||||
hr = call_IWbemServices_ExecNotificationQueryAsync(
|
||||
pSvc, L"WQL", query, 0, 0, pDestSink);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
|
||||
"failed with hresult of 0x%x",
|
||||
class_name, (int) hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int register_async_notification(IWbemObjectSink *pDestSink,
|
||||
IWbemServices *pSvc)
|
||||
{
|
||||
int i;
|
||||
const char *class_list[] = {
|
||||
"MSNdis_StatusMediaConnect",
|
||||
"MSNdis_StatusMediaDisconnect",
|
||||
"MSNdis_StatusMediaSpecificIndication",
|
||||
"MSNdis_NotifyAdapterArrival",
|
||||
"MSNdis_NotifyAdapterRemoval",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (i = 0; class_list[i]; i++) {
|
||||
if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ndis_events_deinit(struct ndis_events_data *events)
|
||||
{
|
||||
events->terminating = 1;
|
||||
IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
|
||||
IWbemObjectSink_Release(&events->sink);
|
||||
/*
|
||||
* Rest of deinitialization is done in ndis_events_destructor() once
|
||||
* all reference count drops to zero.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static int ndis_events_use_desc(struct ndis_events_data *events,
|
||||
const char *desc)
|
||||
{
|
||||
char *tmp, *pos;
|
||||
size_t len;
|
||||
|
||||
if (desc == NULL) {
|
||||
if (events->adapter_desc == NULL)
|
||||
return -1;
|
||||
/* Continue using old description */
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = os_strdup(desc);
|
||||
if (tmp == NULL)
|
||||
return -1;
|
||||
|
||||
pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
|
||||
if (pos)
|
||||
*pos = '\0';
|
||||
|
||||
len = os_strlen(tmp);
|
||||
events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
|
||||
if (events->adapter_desc == NULL) {
|
||||
os_free(tmp);
|
||||
return -1;
|
||||
}
|
||||
_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
|
||||
os_free(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ndis_events_get_adapter(struct ndis_events_data *events,
|
||||
const char *ifname, const char *desc)
|
||||
{
|
||||
HRESULT hr;
|
||||
IWbemServices *pSvc;
|
||||
#define MAX_QUERY_LEN 256
|
||||
WCHAR query[MAX_QUERY_LEN];
|
||||
IEnumWbemClassObject *pEnumerator;
|
||||
IWbemClassObject *pObj;
|
||||
ULONG uReturned;
|
||||
VARIANT vt;
|
||||
int len, pos;
|
||||
|
||||
/*
|
||||
* Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
|
||||
* to have better probability of matching with InstanceName from
|
||||
* MSNdis events. If this fails, use the provided description.
|
||||
*/
|
||||
|
||||
os_free(events->adapter_desc);
|
||||
events->adapter_desc = NULL;
|
||||
|
||||
hr = call_IWbemLocator_ConnectServer(
|
||||
events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
|
||||
"server (ROOT\\CIMV2) - error 0x%x", (int) hr);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
|
||||
|
||||
_snwprintf(query, MAX_QUERY_LEN,
|
||||
L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
|
||||
L"WHERE SettingID='%S'", ifname);
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
|
||||
|
||||
hr = call_IWbemServices_ExecQuery(
|
||||
pSvc, L"WQL", query,
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
NULL, &pEnumerator);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
|
||||
"GUID from Win32_NetworkAdapterConfiguration: "
|
||||
"0x%x", (int) hr);
|
||||
IWbemServices_Release(pSvc);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
|
||||
uReturned = 0;
|
||||
hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
|
||||
&pObj, &uReturned);
|
||||
if (!SUCCEEDED(hr) || uReturned == 0) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
|
||||
"GUID from Win32_NetworkAdapterConfiguration: "
|
||||
"0x%x", (int) hr);
|
||||
IEnumWbemClassObject_Release(pEnumerator);
|
||||
IWbemServices_Release(pSvc);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
IEnumWbemClassObject_Release(pEnumerator);
|
||||
|
||||
VariantInit(&vt);
|
||||
hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
|
||||
"Win32_NetworkAdapterConfiguration: 0x%x",
|
||||
(int) hr);
|
||||
IWbemServices_Release(pSvc);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
|
||||
_snwprintf(query, MAX_QUERY_LEN,
|
||||
L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
|
||||
L"Index=%d",
|
||||
vt.uintVal);
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
|
||||
VariantClear(&vt);
|
||||
IWbemClassObject_Release(pObj);
|
||||
|
||||
hr = call_IWbemServices_ExecQuery(
|
||||
pSvc, L"WQL", query,
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
NULL, &pEnumerator);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
|
||||
"from Win32_NetworkAdapter: 0x%x", (int) hr);
|
||||
IWbemServices_Release(pSvc);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
|
||||
uReturned = 0;
|
||||
hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
|
||||
&pObj, &uReturned);
|
||||
if (!SUCCEEDED(hr) || uReturned == 0) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
|
||||
"from Win32_NetworkAdapter: 0x%x", (int) hr);
|
||||
IEnumWbemClassObject_Release(pEnumerator);
|
||||
IWbemServices_Release(pSvc);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
IEnumWbemClassObject_Release(pEnumerator);
|
||||
|
||||
hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
|
||||
"Win32_NetworkAdapter: 0x%x", (int) hr);
|
||||
IWbemClassObject_Release(pObj);
|
||||
IWbemServices_Release(pSvc);
|
||||
return ndis_events_use_desc(events, desc);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
|
||||
vt.bstrVal);
|
||||
events->adapter_desc = _wcsdup(vt.bstrVal);
|
||||
VariantClear(&vt);
|
||||
|
||||
/*
|
||||
* Try to get even better candidate for matching with InstanceName
|
||||
* from Win32_PnPEntity. This is needed at least for some USB cards
|
||||
* that can change the InstanceName whenever being unplugged and
|
||||
* plugged again.
|
||||
*/
|
||||
|
||||
hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
|
||||
"from Win32_NetworkAdapter: 0x%x", (int) hr);
|
||||
IWbemClassObject_Release(pObj);
|
||||
IWbemServices_Release(pSvc);
|
||||
if (events->adapter_desc == NULL)
|
||||
return ndis_events_use_desc(events, desc);
|
||||
return 0; /* use Win32_NetworkAdapter::Name */
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
|
||||
"'%S'", vt.bstrVal);
|
||||
|
||||
len = _snwprintf(query, MAX_QUERY_LEN,
|
||||
L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
|
||||
if (len < 0 || len >= MAX_QUERY_LEN - 1) {
|
||||
VariantClear(&vt);
|
||||
IWbemClassObject_Release(pObj);
|
||||
IWbemServices_Release(pSvc);
|
||||
if (events->adapter_desc == NULL)
|
||||
return ndis_events_use_desc(events, desc);
|
||||
return 0; /* use Win32_NetworkAdapter::Name */
|
||||
}
|
||||
|
||||
/* Escape \ as \\ */
|
||||
for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
|
||||
if (vt.bstrVal[pos] == '\\') {
|
||||
if (len >= MAX_QUERY_LEN - 3)
|
||||
break;
|
||||
query[len++] = '\\';
|
||||
}
|
||||
query[len++] = vt.bstrVal[pos];
|
||||
}
|
||||
query[len++] = L'\'';
|
||||
query[len] = L'\0';
|
||||
VariantClear(&vt);
|
||||
IWbemClassObject_Release(pObj);
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
|
||||
|
||||
hr = call_IWbemServices_ExecQuery(
|
||||
pSvc, L"WQL", query,
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
NULL, &pEnumerator);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
|
||||
"Name from Win32_PnPEntity: 0x%x", (int) hr);
|
||||
IWbemServices_Release(pSvc);
|
||||
if (events->adapter_desc == NULL)
|
||||
return ndis_events_use_desc(events, desc);
|
||||
return 0; /* use Win32_NetworkAdapter::Name */
|
||||
}
|
||||
|
||||
uReturned = 0;
|
||||
hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
|
||||
&pObj, &uReturned);
|
||||
if (!SUCCEEDED(hr) || uReturned == 0) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
|
||||
"from Win32_PnPEntity: 0x%x", (int) hr);
|
||||
IEnumWbemClassObject_Release(pEnumerator);
|
||||
IWbemServices_Release(pSvc);
|
||||
if (events->adapter_desc == NULL)
|
||||
return ndis_events_use_desc(events, desc);
|
||||
return 0; /* use Win32_NetworkAdapter::Name */
|
||||
}
|
||||
IEnumWbemClassObject_Release(pEnumerator);
|
||||
|
||||
hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
|
||||
"Win32_PnPEntity: 0x%x", (int) hr);
|
||||
IWbemClassObject_Release(pObj);
|
||||
IWbemServices_Release(pSvc);
|
||||
if (events->adapter_desc == NULL)
|
||||
return ndis_events_use_desc(events, desc);
|
||||
return 0; /* use Win32_NetworkAdapter::Name */
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
|
||||
vt.bstrVal);
|
||||
os_free(events->adapter_desc);
|
||||
events->adapter_desc = _wcsdup(vt.bstrVal);
|
||||
VariantClear(&vt);
|
||||
|
||||
IWbemClassObject_Release(pObj);
|
||||
|
||||
IWbemServices_Release(pSvc);
|
||||
|
||||
if (events->adapter_desc == NULL)
|
||||
return ndis_events_use_desc(events, desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct ndis_events_data *
|
||||
ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
|
||||
const char *ifname, const char *desc)
|
||||
{
|
||||
HRESULT hr;
|
||||
IWbemObjectSink *pSink;
|
||||
struct ndis_events_data *events;
|
||||
|
||||
events = os_zalloc(sizeof(*events));
|
||||
if (events == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
|
||||
return NULL;
|
||||
}
|
||||
events->ifname = os_strdup(ifname);
|
||||
if (events->ifname == NULL) {
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wmi_refcnt++ == 0) {
|
||||
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
|
||||
"returned 0x%x", (int) hr);
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (wmi_first) {
|
||||
/* CoInitializeSecurity() must be called once and only once
|
||||
* per process, so let's use wmi_first flag to protect against
|
||||
* multiple calls. */
|
||||
wmi_first = 0;
|
||||
|
||||
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
|
||||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||
NULL, EOAC_SECURE_REFS, NULL);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
|
||||
"- returned 0x%x", (int) hr);
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
|
||||
&IID_IWbemLocator,
|
||||
(LPVOID *) (void *) &events->pLoc);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
|
||||
"0x%x", (int) hr);
|
||||
CoUninitialize();
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ndis_events_get_adapter(events, ifname, desc) < 0) {
|
||||
CoUninitialize();
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
|
||||
events->adapter_desc);
|
||||
|
||||
hr = call_IWbemLocator_ConnectServer(
|
||||
events->pLoc, L"ROOT\\WMI", NULL, NULL,
|
||||
0, 0, 0, 0, &events->pSvc);
|
||||
if (FAILED(hr)) {
|
||||
wpa_printf(MSG_ERROR, "Could not connect to server - error "
|
||||
"0x%x", (int) hr);
|
||||
CoUninitialize();
|
||||
os_free(events->adapter_desc);
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
|
||||
|
||||
ndis_events_constructor(events);
|
||||
pSink = &events->sink;
|
||||
pSink->lpVtbl = &events->sink_vtbl;
|
||||
events->sink_vtbl.QueryInterface = ndis_events_query_interface;
|
||||
events->sink_vtbl.AddRef = ndis_events_add_ref;
|
||||
events->sink_vtbl.Release = ndis_events_release;
|
||||
events->sink_vtbl.Indicate = ndis_events_indicate;
|
||||
events->sink_vtbl.SetStatus = ndis_events_set_status;
|
||||
|
||||
if (register_async_notification(pSink, events->pSvc) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to register async "
|
||||
"notifications");
|
||||
ndis_events_destructor(events);
|
||||
os_free(events->adapter_desc);
|
||||
os_free(events);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*read_pipe = events->read_pipe;
|
||||
*event_avail = events->event_avail;
|
||||
|
||||
return events;
|
||||
}
|
104
contrib/wpa/src/drivers/priv_netlink.h
Normal file
104
contrib/wpa/src/drivers/priv_netlink.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef PRIV_NETLINK_H
|
||||
#define PRIV_NETLINK_H
|
||||
|
||||
/*
|
||||
* This should be replaced with user space header once one is available with C
|
||||
* library, etc..
|
||||
*/
|
||||
|
||||
#ifndef IFF_LOWER_UP
|
||||
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
|
||||
#endif
|
||||
#ifndef IFF_DORMANT
|
||||
#define IFF_DORMANT 0x20000 /* driver signals dormant */
|
||||
#endif
|
||||
|
||||
#ifndef IFLA_IFNAME
|
||||
#define IFLA_IFNAME 3
|
||||
#endif
|
||||
#ifndef IFLA_WIRELESS
|
||||
#define IFLA_WIRELESS 11
|
||||
#endif
|
||||
#ifndef IFLA_OPERSTATE
|
||||
#define IFLA_OPERSTATE 16
|
||||
#endif
|
||||
#ifndef IFLA_LINKMODE
|
||||
#define IFLA_LINKMODE 17
|
||||
#define IF_OPER_DORMANT 5
|
||||
#define IF_OPER_UP 6
|
||||
#endif
|
||||
|
||||
#define NLM_F_REQUEST 1
|
||||
|
||||
#define NETLINK_ROUTE 0
|
||||
#define RTMGRP_LINK 1
|
||||
#define RTM_BASE 0x10
|
||||
#define RTM_NEWLINK (RTM_BASE + 0)
|
||||
#define RTM_DELLINK (RTM_BASE + 1)
|
||||
#define RTM_SETLINK (RTM_BASE + 3)
|
||||
|
||||
#define NLMSG_ALIGNTO 4
|
||||
#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
|
||||
#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
|
||||
#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
|
||||
|
||||
#define RTA_ALIGNTO 4
|
||||
#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
|
||||
#define RTA_OK(rta,len) \
|
||||
((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
|
||||
(rta)->rta_len <= (len))
|
||||
#define RTA_NEXT(rta,attrlen) \
|
||||
((attrlen) -= RTA_ALIGN((rta)->rta_len), \
|
||||
(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
|
||||
#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
|
||||
#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
|
||||
|
||||
|
||||
struct sockaddr_nl
|
||||
{
|
||||
sa_family_t nl_family;
|
||||
unsigned short nl_pad;
|
||||
u32 nl_pid;
|
||||
u32 nl_groups;
|
||||
};
|
||||
|
||||
struct nlmsghdr
|
||||
{
|
||||
u32 nlmsg_len;
|
||||
u16 nlmsg_type;
|
||||
u16 nlmsg_flags;
|
||||
u32 nlmsg_seq;
|
||||
u32 nlmsg_pid;
|
||||
};
|
||||
|
||||
struct ifinfomsg
|
||||
{
|
||||
unsigned char ifi_family;
|
||||
unsigned char __ifi_pad;
|
||||
unsigned short ifi_type;
|
||||
int ifi_index;
|
||||
unsigned ifi_flags;
|
||||
unsigned ifi_change;
|
||||
};
|
||||
|
||||
struct rtattr
|
||||
{
|
||||
unsigned short rta_len;
|
||||
unsigned short rta_type;
|
||||
};
|
||||
|
||||
#endif /* PRIV_NETLINK_H */
|
287
contrib/wpa/src/drivers/radiotap.c
Normal file
287
contrib/wpa/src/drivers/radiotap.c
Normal file
@ -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;
|
||||
}
|
242
contrib/wpa/src/drivers/radiotap.h
Normal file
242
contrib/wpa/src/drivers/radiotap.h
Normal file
@ -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 */
|
41
contrib/wpa/src/drivers/radiotap_iter.h
Normal file
41
contrib/wpa/src/drivers/radiotap_iter.h
Normal file
@ -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 */
|
1
contrib/wpa/src/eap_common/.gitignore
vendored
1
contrib/wpa/src/eap_common/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.d
|
@ -67,7 +67,7 @@ typedef enum {
|
||||
EAP_TYPE_SAKE = 48 /* RFC 4763 */,
|
||||
EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
|
||||
EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
|
||||
EAP_TYPE_GPSK = 51 /* draft-ietf-emu-eap-gpsk-17.txt */,
|
||||
EAP_TYPE_GPSK = 51 /* RFC 5433 */,
|
||||
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
|
||||
} EapType;
|
||||
|
||||
|
@ -24,8 +24,7 @@
|
||||
#define TLS_EXT_PAC_OPAQUE 35
|
||||
|
||||
/*
|
||||
* draft-cam-winget-eap-fast-provisioning-04.txt:
|
||||
* Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
|
||||
* RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
|
||||
* Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
|
||||
* in the general PAC TLV format (Section 4.2).
|
||||
*/
|
||||
@ -59,10 +58,7 @@ struct pac_tlv_hdr {
|
||||
|
||||
#define EAP_FAST_PAC_KEY_LEN 32
|
||||
|
||||
/* draft-cam-winget-eap-fast-provisioning-04.txt: 4.2.6 PAC-Type TLV
|
||||
* Note: Machine Authentication PAC and User Authorization PAC were removed in
|
||||
* draft-cam-winget-eap-fast-provisioning-03.txt
|
||||
*/
|
||||
/* RFC 5422: 4.2.6 PAC-Type TLV */
|
||||
#define PAC_TYPE_TUNNEL_PAC 1
|
||||
/* Application Specific Short Lived PACs (only in volatile storage) */
|
||||
/* User Authorization PAC */
|
||||
@ -73,8 +69,8 @@ struct pac_tlv_hdr {
|
||||
|
||||
|
||||
/*
|
||||
* draft-cam-winget-eap-fast-provisioning-04.txt:
|
||||
* Section 3.4 - Key Derivations Used in the EAP-FAST Provisioning Exchange
|
||||
* RFC 5422:
|
||||
* Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange
|
||||
*/
|
||||
struct eap_fast_key_block_provisioning {
|
||||
/* Extra key material after TLS key_block */
|
||||
|
@ -24,8 +24,7 @@
|
||||
#define EAP_TLV_URI_TLV 8
|
||||
#define EAP_TLV_EAP_PAYLOAD_TLV 9
|
||||
#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
|
||||
#define EAP_TLV_PAC_TLV 11 /* draft-cam-winget-eap-fast-provisioning-04.txt,
|
||||
* Section 4.2 */
|
||||
#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */
|
||||
#define EAP_TLV_CRYPTO_BINDING_TLV 12
|
||||
#define EAP_TLV_CALLING_STATION_ID_TLV 13
|
||||
#define EAP_TLV_CALLED_STATION_ID_TLV 14
|
||||
@ -99,7 +98,7 @@ struct eap_tlv_request_action_tlv {
|
||||
be16 action;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.2.6 - PAC-Type TLV */
|
||||
/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
|
||||
struct eap_tlv_pac_type_tlv {
|
||||
be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
|
||||
be16 length;
|
||||
|
1
contrib/wpa/src/eap_peer/.gitignore
vendored
1
contrib/wpa/src/eap_peer/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.d
|
@ -918,10 +918,7 @@ static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type,
|
||||
entry->a_id_info_len = len;
|
||||
break;
|
||||
case PAC_TYPE_PAC_TYPE:
|
||||
/*
|
||||
* draft-cam-winget-eap-fast-provisioning-04.txt,
|
||||
* Section 4.2.6 - PAC-Type TLV
|
||||
*/
|
||||
/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type "
|
||||
"length %lu (expected 2)",
|
||||
@ -961,7 +958,7 @@ static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
|
||||
size_t left, len;
|
||||
int type;
|
||||
|
||||
/* draft-cam-winget-eap-fast-provisioning-04.txt, Section 4.2.4 */
|
||||
/* RFC 5422, Section 4.2.4 */
|
||||
|
||||
/* PAC-Type defaults to Tunnel PAC (Type 1) */
|
||||
entry->pac_type = PAC_TYPE_TUNNEL_PAC;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-08.txt)
|
||||
* EAP peer method: EAP-GPSK (RFC 5433)
|
||||
* Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -62,6 +62,11 @@ static inline void eap_peer_unregister_methods(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline char ** eap_get_names_as_string_array(size_t *num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* IEEE8021X_EAPOL */
|
||||
|
||||
|
||||
|
@ -468,8 +468,6 @@ static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
|
||||
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
|
||||
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
|
||||
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
|
||||
wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
|
||||
eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0);
|
||||
if (k_aut && data->reauth) {
|
||||
wpa_printf(MSG_DEBUG, " AT_IV");
|
||||
wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
|
||||
|
@ -45,6 +45,18 @@ static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_params_flags(struct tls_connection_params *params,
|
||||
const char *txt)
|
||||
{
|
||||
if (txt == NULL)
|
||||
return;
|
||||
if (os_strstr(txt, "tls_allow_md5=1"))
|
||||
params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
|
||||
if (os_strstr(txt, "tls_disable_time_checks=1"))
|
||||
params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_params_from_conf1(struct tls_connection_params *params,
|
||||
struct eap_peer_config *config)
|
||||
{
|
||||
@ -62,6 +74,7 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
|
||||
params->key_id = config->key_id;
|
||||
params->cert_id = config->cert_id;
|
||||
params->ca_cert_id = config->ca_cert_id;
|
||||
eap_tls_params_flags(params, config->phase1);
|
||||
}
|
||||
|
||||
|
||||
@ -82,6 +95,7 @@ static void eap_tls_params_from_conf2(struct tls_connection_params *params,
|
||||
params->key_id = config->key2_id;
|
||||
params->cert_id = config->cert2_id;
|
||||
params->ca_cert_id = config->ca_cert2_id;
|
||||
eap_tls_params_flags(params, config->phase2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -295,7 +295,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
|
||||
wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
|
||||
"start flag in the first message");
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tncc_init_connection(data->tncc);
|
||||
@ -308,7 +308,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
|
||||
wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
|
||||
"flag again");
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = tncc_process_if_tnccs(data->tncc,
|
||||
@ -317,7 +317,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
|
||||
switch (res) {
|
||||
case TNCCS_PROCESS_ERROR:
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
goto fail;
|
||||
case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
|
||||
case TNCCS_RECOMMENDATION_ERROR:
|
||||
wpa_printf(MSG_DEBUG, "EAP-TNC: No "
|
||||
@ -404,6 +404,11 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
|
||||
data->out_buf = resp;
|
||||
data->state = PROC_MSG;
|
||||
return eap_tnc_build_msg(data, ret, id);
|
||||
|
||||
fail:
|
||||
if (data->in_buf == &tmpbuf)
|
||||
data->in_buf = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user