MFV hostapd & wpa_supplicant 0.6.10.

This commit is contained in:
Rui Paulo 2010-06-14 15:37:48 +00:00
commit 3157ba2193
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=209158
192 changed files with 31845 additions and 896 deletions

View File

@ -1,7 +0,0 @@
*.d
.config
driver_conf.c
hostapd
hostapd_cli
hlr_auc_gw
nt_password_hash

View File

@ -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>)

View 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)

View File

@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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);
}

View File

@ -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,

View File

@ -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);

View File

@ -1,4 +0,0 @@
html
latex
hostapd.eps
hostapd.png

View 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,
};

File diff suppressed because it is too large Load Diff

View 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,
};

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View 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;
}

View 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 */

View 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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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 {

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -1 +0,0 @@
*.d

View File

@ -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);

View File

@ -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;

View File

@ -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) */

File diff suppressed because it is too large Load Diff

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -1 +0,0 @@
*.d

View File

@ -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) {

View File

@ -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,

View File

@ -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 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
#endif /* EAP_FAST || CONFIG_WPS */
#endif /* CONFIG_TLS_INTERNAL */
#endif /* EAP_TLS_FUNCS */
#endif /* CONFIG_CRYPTO_INTERNAL */

View File

@ -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]))

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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];

View File

@ -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;
};

View File

@ -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;

View File

@ -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 {

View 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 */

View 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.

View 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;
}
}

View 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 */

View File

@ -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

View 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(&param, 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, &param, 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(&param, 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, &param, 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,
};

View 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,
};

View 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,
};

View 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(&param, 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, &param, 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(&param, 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, &param, 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,
};

View 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 */

View 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,
};

View 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(&param, 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, &param, 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(&param, 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, &param, 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,
};

View 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,
};

View File

@ -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);
}
}

View 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());
}
}

View 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,
};

File diff suppressed because it is too large Load Diff

View 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,
};

View 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,
};

View 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
};

View 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 */
};

File diff suppressed because it is too large Load Diff

View 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;

View 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,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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 */

View 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,
};

View 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;
}

View 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 */

View 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;
}

View 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 */

View 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 */

View File

@ -1 +0,0 @@
*.d

View File

@ -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;

View File

@ -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 */

View File

@ -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;

View File

@ -1 +0,0 @@
*.d

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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");

View File

@ -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);
}

View File

@ -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