Re-initialize hostapd/wpa_supplicant git repository based on 0.6.3 release
commit
6fc6879bd5
@ -0,0 +1,181 @@
|
||||
Host AP driver - Frequently Asked Questions
|
||||
===========================================
|
||||
|
||||
1. What does "GetNextTuple: No more items" mean in hostap_cs initialization?
|
||||
2. Why RX does not work?
|
||||
What does "NETDEV WATCHDOG: wlan0: transmit timed out" mean?
|
||||
(interrupt delivery problems)
|
||||
3. What is wrong with Host AP mode in secondary (station) firmware v1.4.2?
|
||||
4. What is causing 'Unresolved symbols' in depmod/modprobe?
|
||||
5. How can I upgrade Prism2/2.5/3 firmware?
|
||||
6. Why did I get two network interfaces (wlan0 and wifi0) even when I have
|
||||
only one wireless card?
|
||||
7. Why does my D-Link DWL-650 rev. P1 or D-Link DWL-520 rev. E1 (or any other
|
||||
card with small flash) card fail?
|
||||
8. Does Host AP driver support IEEE 802.11a and 802.11g? Does it support
|
||||
chipsets other than Prism 2/2.5/3?
|
||||
|
||||
|
||||
|
||||
1. What does "GetNextTuple: No more items" mean in hostap_cs initialization?
|
||||
|
||||
This is one of the most often reported problems in getting the
|
||||
hostap_cs.o driver working. It is usually reported for D-Link DWL-650
|
||||
PC Card, e.g., on ISA-to-PCMCIA adapter. Later versions of the driver
|
||||
report this also with "Vcc mismatch - skipping this entry".
|
||||
|
||||
Most common reason for getting this is a mismatch in voltage
|
||||
configuration. The driver tries to make sure that the voltage (Vcc)
|
||||
configuration in CIS and the slot match each other. It refuses to
|
||||
initialize the card if the card CIS does not include a CFTABLE entry
|
||||
with a matching Vcc value. This seems to be a problem for some cases
|
||||
since the CIS is invalid or the reported voltage is incorrect.
|
||||
|
||||
As a workaround, the driver supports a module parameter ignore_cis_vcc
|
||||
that can be used to skip this verification. This can be enabled by
|
||||
setting ignore_cis_vcc=1 in /etc/pcmcia/hostap_cs.conf (commented
|
||||
example line in the end of file). This can also be tested by manually
|
||||
loading the module with 'modprobe hostap_cs ignore_cis_vcc=1' before
|
||||
inserting the card).
|
||||
|
||||
|
||||
|
||||
2. Why RX does not work?
|
||||
What does "NETDEV WATCHDOG: wlan0: transmit timed out" mean?
|
||||
(interrupt delivery problems)
|
||||
|
||||
If the driver does not seem to receive any packets or sending packets
|
||||
results in "NETDEV WATCHDOG: wlan0: transmit timed out", the reason is
|
||||
probably in interrupt delivery problems. This is quite common with
|
||||
PCI-to-PCMCIA adapters. Newer than 2002-05-19 of the driver have a
|
||||
test that will report this after the initialization ("wlan: Possible
|
||||
interrupt delivery problem"). Another method for checking this is to
|
||||
observer whether interrupt counters in /proc/interrupts increase for
|
||||
hostap_cs/wlan0 entry.
|
||||
|
||||
Adding suitable irq_mode=# setting in PCIC_OPTS line of
|
||||
pcmcia-configuration is the most common fix for this. pcmcia-cs HOWTO
|
||||
has more information on how to debug and fix interrupt delivery
|
||||
problems at
|
||||
http://pcmcia-cs.sourceforge.net/ftp/doc/PCMCIA-HOWTO-5.html#irqmode
|
||||
|
||||
|
||||
|
||||
3. What is wrong with Host AP mode in secondary (station) firmware v1.4.2?
|
||||
|
||||
It looks like secondary firmware v1.4.2 sends beacon frames properly,
|
||||
but does not respond to probe requests. With most station cards, this
|
||||
prevents authentication and association and thus, in practice, no data
|
||||
frames can be sent. It has been reported that at least some Cisco
|
||||
Aironet 350 cards can associate with Host AP mode even with firmware
|
||||
v1.4.2 (i.e., without receiving probe response), but Prism2 and
|
||||
Lucent/ORiNOCO/Agere seem to require probe response and they do not
|
||||
thus associate with AP using v1.4.2 firmware.
|
||||
|
||||
This is fixed in later secondary firmware versions; probably already
|
||||
in 1.4.3, but at least 1.4.9 has been tested to work. In other words,
|
||||
this problem can be fixed by upgrading card firmware.
|
||||
|
||||
|
||||
|
||||
4. What is causing 'Unresolved symbols' in depmod/modprobe?
|
||||
|
||||
Installation of Host AP driver (e.g, 'make install_pccard') may report
|
||||
unresolved symbols when running depmod. These are usually caused with
|
||||
mismatch in kernel configuration for modversions.
|
||||
|
||||
Example:
|
||||
|
||||
depmod reports unresolved symbol 'eth_type_trans' (this is without
|
||||
modversions):
|
||||
depmod: eth_type_trans
|
||||
|
||||
but kernel was really configured with CONFIG_MODVERSIONS:
|
||||
|
||||
# grep eth_type_trans /proc/ksyms
|
||||
c01b66c0 eth_type_trans_Rdb9cd26f
|
||||
|
||||
(notice the _R... postfix)
|
||||
|
||||
This happens if the kernel configuration given to Host AP driver's
|
||||
Makefile (.config in KERNEL_PATH) has not CONFIG_MODVERSIONS, but the
|
||||
running kernel is compiled with it.
|
||||
If the kernel were configured without modversions, /proc/ksyms would
|
||||
show the symbols with _R... postfix:
|
||||
|
||||
|
||||
Mismatches in kernel configuration can be fixed by using the same
|
||||
configuration (i.e., Linux kernel .config) for both the kernel and the
|
||||
driver. If you are using a kernel from a distribution installation
|
||||
(i.e., you have not compiled it yourself), you will need to create a
|
||||
matching .config file somehow. This depends on the distribution you
|
||||
are using, but 'make oldconfig' in kernel source directory might work
|
||||
with some distributions. If you compile the kernel yourself, it will
|
||||
be easier, since you already have to have created the correct .config
|
||||
file.
|
||||
|
||||
|
||||
|
||||
5. How can I upgrade Prism2/2.5/3 firmware?
|
||||
|
||||
Prism2/2.5/3 cards and Host AP driver support two different mechanism
|
||||
of upgrading the card firmware. Firmware images (primary and station)
|
||||
can be downloaded either into volatile memory (RAM download) or
|
||||
non-volatile memory (flash upgrade). Firmware images downloaded into
|
||||
volatile memory are lost when the card is resetted, so they are quite
|
||||
safe. Flash upgrade with incorrect images may cause permanent problems
|
||||
(i.e., render the card useless), so certain amount of caution is
|
||||
always recommended for this.
|
||||
|
||||
Note! Some of the older versions of Host AP driver or prism2_srec had
|
||||
fatal bugs in flash upgrade. Only versions 0.1.0 or newer should be
|
||||
used when performing non-volatile flash upgrade!
|
||||
|
||||
utils/prism2_srec (run 'make' in utils directory to build this) is a
|
||||
tool that can be instructed Host AP driver to download firmware image
|
||||
into the wlan card. Brief usage information is available by running
|
||||
this program without any command line parameters. Please note, that
|
||||
the downloading support is disabled in the default Host AP driver
|
||||
build. You will need to change this by defining
|
||||
PRISM2_DOWNLOAD_SUPPORT (and PRISM2_NON_VOLATILE_DOWNLOAD if you want
|
||||
to update flash); see driver/modules/hostap_config.h for more details.
|
||||
|
||||
Jun Sun has written a mini-howto on flashing Intersil Prism
|
||||
Chipsets. This is available at http://linux.junsun.net/intersil-prism/.
|
||||
|
||||
|
||||
|
||||
6. Why did I get two network interfaces (wlan0 and wifi0) even when I have
|
||||
only one wireless card?
|
||||
|
||||
Host AP driver supports multiple virtual interfaces per wireless
|
||||
card. wifi0 is the master radio interface and wlan0 is the first
|
||||
virtual interface for this radio. Other virtual interfaces are wlan0ap
|
||||
(for hostapd), and one interface per WDS link.
|
||||
|
||||
In most cases, one should ignore wifi0 interface and just use wlan0
|
||||
interface. In other words, assign IP address to wlan0, not wifi0 and
|
||||
in general, just ignore the wifi0 interface.
|
||||
|
||||
|
||||
|
||||
7. Why does my D-Link DWL-650 rev. P1 or D-Link DWL-520 rev. E1 (or any other
|
||||
card with small flash) card fail?
|
||||
|
||||
Some of the new Prism3-based cards use a smaller flash chip that does
|
||||
not include full firmware for the card. For example, D-Link DWL-650
|
||||
rev. P1 and D-Link DWL-520 rev. E1 are such cards. These cards require
|
||||
that the firmware is downloaded to the card during initialization. See
|
||||
utils/hostap_fw_load for example commands on doing this.
|
||||
|
||||
|
||||
|
||||
8. Does Host AP driver support IEEE 802.11a and 802.11g? Does it support
|
||||
chipsets other than Prism 2/2.5/3?
|
||||
|
||||
Host AP driver supports only Intersil Prism chipsets, versions 2, 2.5,
|
||||
and 3. Those chipsets support IEEE 802.11b only; other chipsets are
|
||||
not supported. All utilities distributed with Host AP driver except
|
||||
wpa_supplicant work only with Host AP driver, so they are limited to
|
||||
the same hardware. wpa_supplicant works with other drivers, including
|
||||
those that support 802.11a and 802.11g.
|
@ -0,0 +1,19 @@
|
||||
wpa_supplicant and hostapd v0.6.x
|
||||
---------------------------------
|
||||
|
||||
Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These program is dual-licensed under both the GPL version 2 and BSD
|
||||
license. Either license may be used at your option.
|
||||
|
||||
|
||||
This package may include either wpa_supplicant, hostapd, or both. See
|
||||
README file respective subdirectories (wpa_supplicant/README or
|
||||
hostapd/README) for more details.
|
||||
|
||||
Source code files have been moved around in v0.6.x releases and
|
||||
compared to earlier releases, the programs are now build by first
|
||||
going to a subdirectory (wpa_supplicant or hostapd) and creating
|
||||
build configuration (.config) and running 'make' there (for
|
||||
Linux/BSD/cygwin builds).
|
@ -0,0 +1,143 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Path to the Windows cross compiler (mingw)
|
||||
WINCROSS=/opt/xmingw/bin
|
||||
WINLOCAL=/home/jm/H-win/local
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "build_release <version> [nobin]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMP=tmp.build_release
|
||||
RELDIR=`pwd`/Release
|
||||
VER=$1
|
||||
NOW=`date +%Y-%m-%d`
|
||||
|
||||
echo "Version: $VER - $NOW"
|
||||
|
||||
DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
|
||||
DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
|
||||
|
||||
if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
|
||||
echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
|
||||
fi
|
||||
|
||||
if [ -r $TMP ]; then
|
||||
echo "Temporary directory '$TMP' exists. Remove it before running this."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir $TMP
|
||||
mkdir -p $RELDIR
|
||||
|
||||
git-archive --format=tar --prefix=wpa-$VER/ HEAD \
|
||||
README COPYING patches src wpa_supplicant hostapd |
|
||||
gzip > $RELDIR/wpa-$VER.tar.gz
|
||||
git-archive --format=tar --prefix=hostapd-$VER/ HEAD \
|
||||
README COPYING patches src hostapd |
|
||||
gzip > $RELDIR/hostapd-$VER.tar.gz
|
||||
git-archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
|
||||
README COPYING patches src wpa_supplicant |
|
||||
tar --directory=$TMP -xf -
|
||||
|
||||
cd $TMP
|
||||
make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
|
||||
rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
|
||||
tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
|
||||
cd ..
|
||||
rm -r $TMP
|
||||
|
||||
if [ "$2" == "nobin" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -d $WINCROSS ]; then
|
||||
pushd $RELDIR
|
||||
|
||||
PDIR=wpa_supplicant-$VER
|
||||
WDIR=wpa_supplicant-windows-bin-$VER
|
||||
tar xzf $PDIR.tar.gz
|
||||
mkdir "$WDIR"
|
||||
cd "$PDIR/wpa_supplicant"
|
||||
cat > .config <<EOF
|
||||
CONFIG_DRIVER_NDIS=y
|
||||
CONFIG_NATIVE_WINDOWS=y
|
||||
|
||||
CFLAGS += -I/opt/xmingw/i386-mingw32msvc/include/ddk
|
||||
CC=i386-mingw32msvc-gcc
|
||||
STRIP=i386-mingw32msvc-strip
|
||||
PLATFORMSDKLIB=$WINLOCAL/lib
|
||||
CONFIG_NDIS_EVENTS_INTEGRATED=y
|
||||
|
||||
CFLAGS += -I$WINLOCAL/include
|
||||
LIBS += -L$WINLOCAL/lib
|
||||
LIBS_w += -L$WINLOCAL/lib
|
||||
LIBS_p += -L$WINLOCAL/lib
|
||||
|
||||
CONFIG_EAP_SIM=y
|
||||
CONFIG_EAP_AKA=y
|
||||
CONFIG_EAP_LEAP=y
|
||||
CONFIG_EAP_FAST=y
|
||||
CONFIG_EAP_TLS=y
|
||||
|
||||
CONFIG_CTRL_IFACE=y
|
||||
CONFIG_EAP_FAST=y
|
||||
CONFIG_EAP_MSCHAPV2=y
|
||||
CONFIG_EAP_TTLS=y
|
||||
CONFIG_EAP_PEAP=y
|
||||
CONFIG_EAP_MD5=y
|
||||
CONFIG_EAP_GTC=y
|
||||
CONFIG_EAP_OTP=y
|
||||
CONFIG_EAP_PAX=y
|
||||
CONFIG_EAP_SAKE=y
|
||||
CONFIG_EAP_PSK=y
|
||||
CONFIG_EAP_TNC=y
|
||||
CONFIG_PKCS12=y
|
||||
CONFIG_PCSC=y
|
||||
|
||||
CONFIG_L2_PACKET=winpcap
|
||||
CONFIG_MAIN=main_winsvc
|
||||
CONFIG_BACKEND=winreg
|
||||
CONFIG_ELOOP=eloop_win
|
||||
CFLAGS += -DCONFIG_DEBUG_FILE
|
||||
EOF
|
||||
|
||||
# First, build the Windows service & registry version and rename it
|
||||
PATH=$PATH:$WINCROSS make windows-bin
|
||||
mv wpa_supplicant.exe wpasvc.exe
|
||||
|
||||
# Then, build "the standard" wpa_supplicant.exe
|
||||
cat >> .config <<EOF
|
||||
CONFIG_MAIN=main
|
||||
CONFIG_BACKEND=file
|
||||
EOF
|
||||
|
||||
PATH=$PATH:$WINCROSS make windows-bin
|
||||
|
||||
for i in COPYING; do
|
||||
unix2dos < ../$i > ../../"$WDIR"/$i
|
||||
done
|
||||
for i in README README-Windows.txt wpa_supplicant.conf; do
|
||||
unix2dos < $i > ../../"$WDIR"/$i
|
||||
done
|
||||
mv *.exe ../../"$WDIR"
|
||||
cp win_example.reg ../../"$WDIR"
|
||||
|
||||
cd wpa_gui-qt4
|
||||
PATH=$PATH:$WINCROSS ./setup-mingw-cross-compiling
|
||||
PATH=$PATH:$WINCROSS make
|
||||
cp release/wpa_gui.exe ../../../"$WDIR"
|
||||
cd ../../..
|
||||
rm -rf "$PDIR"
|
||||
zip "$WDIR.zip" "$WDIR"/*
|
||||
rm -rf "$WDIR"
|
||||
|
||||
popd
|
||||
fi
|
||||
|
||||
ls -l $RELDIR/*$VER*
|
||||
|
||||
exit 0
|
@ -0,0 +1,3 @@
|
||||
*.d
|
||||
eap_example
|
||||
libeap.so
|
@ -0,0 +1,179 @@
|
||||
ALL=eap_example
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
|
||||
CONFIG_TLS=openssl
|
||||
#CONFIG_TLS=internal
|
||||
#CONFIG_INTERNAL_LIBTOMMATH=y
|
||||
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../src
|
||||
CFLAGS += -I../src/crypto
|
||||
CFLAGS += -I../src/utils
|
||||
CFLAGS += -I../src/common
|
||||
|
||||
# at least for now, need to include config_ssid.h and config_blob.h from
|
||||
# wpa_supplicant directory
|
||||
CFLAGS += -I../wpa_supplicant
|
||||
|
||||
|
||||
OBJS_both += ../src/utils/common.o
|
||||
OBJS_both += ../src/utils/os_unix.o
|
||||
OBJS_both += ../src/utils/wpa_debug.o
|
||||
OBJS_both += ../src/utils/base64.o
|
||||
OBJS_both += ../src/utils/wpabuf.o
|
||||
OBJS_both += ../src/crypto/md5.o
|
||||
OBJS_both += ../src/crypto/rc4.o
|
||||
OBJS_both += ../src/crypto/md4.o
|
||||
OBJS_both += ../src/crypto/sha1.o
|
||||
OBJS_both += ../src/crypto/des.o
|
||||
OBJS_both += ../src/crypto/aes_wrap.o
|
||||
OBJS_both += ../src/crypto/aes.o
|
||||
OBJS_both += ../src/crypto/ms_funcs.o
|
||||
OBJS_both += ../src/crypto/sha256.o
|
||||
|
||||
|
||||
OBJS_both += ../src/eap_common/eap_psk_common.o
|
||||
OBJS_both += ../src/eap_common/eap_pax_common.o
|
||||
OBJS_both += ../src/eap_common/eap_sake_common.o
|
||||
OBJS_both += ../src/eap_common/eap_gpsk_common.o
|
||||
OBJS_both += ../src/eap_common/chap.o
|
||||
|
||||
OBJS_peer += ../src/eap_peer/eap_tls.o
|
||||
OBJS_peer += ../src/eap_peer/eap_peap.o
|
||||
OBJS_peer += ../src/eap_peer/eap_ttls.o
|
||||
OBJS_peer += ../src/eap_peer/eap_md5.o
|
||||
OBJS_peer += ../src/eap_peer/eap_mschapv2.o
|
||||
OBJS_peer += ../src/eap_peer/mschapv2.o
|
||||
OBJS_peer += ../src/eap_peer/eap_otp.o
|
||||
OBJS_peer += ../src/eap_peer/eap_gtc.o
|
||||
OBJS_peer += ../src/eap_peer/eap_leap.o
|
||||
OBJS_peer += ../src/eap_peer/eap_psk.o
|
||||
OBJS_peer += ../src/eap_peer/eap_tlv.o
|
||||
OBJS_peer += ../src/eap_peer/eap_pax.o
|
||||
OBJS_peer += ../src/eap_peer/eap_sake.o
|
||||
OBJS_peer += ../src/eap_peer/eap_gpsk.o
|
||||
OBJS_peer += ../src/eap_peer/eap.o
|
||||
OBJS_peer += ../src/eap_common/eap_common.o
|
||||
OBJS_peer += ../src/eap_peer/eap_methods.o
|
||||
OBJS_peer += ../src/eap_peer/eap_tls_common.o
|
||||
|
||||
CFLAGS += -DEAP_TLS
|
||||
CFLAGS += -DEAP_PEAP
|
||||
CFLAGS += -DEAP_TTLS
|
||||
CFLAGS += -DEAP_MD5
|
||||
CFLAGS += -DEAP_MSCHAPv2
|
||||
CFLAGS += -DEAP_GTC
|
||||
CFLAGS += -DEAP_OTP
|
||||
CFLAGS += -DEAP_LEAP
|
||||
CFLAGS += -DEAP_PSK
|
||||
CFLAGS += -DEAP_TLV
|
||||
CFLAGS += -DEAP_PAX
|
||||
CFLAGS += -DEAP_SAKE
|
||||
CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
|
||||
CFLAGS += -DEAP_TLS_FUNCS
|
||||
|
||||
CFLAGS += -DIEEE8021X_EAPOL
|
||||
|
||||
ifeq ($(CONFIG_TLS), openssl)
|
||||
CFLAGS += -DEAP_TLS_OPENSSL
|
||||
OBJS_both += ../src/crypto/tls_openssl.o
|
||||
OBJS_both += ../src/crypto/crypto_openssl.o
|
||||
LIBS += -lssl -lcrypto
|
||||
CFLAGS += -DINTERNAL_SHA256
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_TLS), internal)
|
||||
OBJS_both += ../src/crypto/tls_internal.o
|
||||
OBJS_both += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
|
||||
OBJS_both += ../src/tls/tlsv1_cred.o
|
||||
OBJS_both += ../src/tls/asn1.o ../src/tls/x509v3.o
|
||||
OBJS_both += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
|
||||
|
||||
OBJS_peer += ../src/tls/tlsv1_client.o
|
||||
OBJS_peer += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_read.o
|
||||
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
|
||||
|
||||
OBJS_server += ../src/tls/tlsv1_server.o
|
||||
OBJS_server += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
|
||||
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
|
||||
|
||||
CFLAGS += -DCONFIG_TLS_INTERNAL
|
||||
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
|
||||
CFLAGS += -DCONFIG_INTERNAL_X509
|
||||
CFLAGS += -DINTERNAL_AES
|
||||
CFLAGS += -DINTERNAL_SHA1
|
||||
CFLAGS += -DINTERNAL_SHA256
|
||||
CFLAGS += -DINTERNAL_MD5
|
||||
CFLAGS += -DINTERNAL_MD4
|
||||
CFLAGS += -DINTERNAL_DES
|
||||
ifdef CONFIG_INTERNAL_LIBTOMMATH
|
||||
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
|
||||
else
|
||||
LIBS += -ltommath
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
|
||||
# Optional components to add EAP server support
|
||||
OBJS_server += ../src/eap_server/eap_tls.o
|
||||
OBJS_server += ../src/eap_server/eap_peap.o
|
||||
OBJS_server += ../src/eap_server/eap_ttls.o
|
||||
OBJS_server += ../src/eap_server/eap_md5.o
|
||||
OBJS_server += ../src/eap_server/eap_mschapv2.o
|
||||
OBJS_server += ../src/eap_server/eap_gtc.o
|
||||
OBJS_server += ../src/eap_server/eap_psk.o
|
||||
OBJS_server += ../src/eap_server/eap_tlv.o
|
||||
OBJS_server += ../src/eap_server/eap_pax.o
|
||||
OBJS_server += ../src/eap_server/eap_sake.o
|
||||
OBJS_server += ../src/eap_server/eap_gpsk.o
|
||||
OBJS_server += ../src/eap_server/eap.o
|
||||
OBJS_server += ../src/eap_server/eap_identity.o
|
||||
OBJS_server += ../src/eap_server/eap_methods.o
|
||||
OBJS_server += ../src/eap_server/eap_tls_common.o
|
||||
CFLAGS += -DEAP_SERVER
|
||||
|
||||
|
||||
ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
|
||||
OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
|
||||
|
||||
OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
|
||||
|
||||
ifneq ($(CONFIG_SOLIB), yes)
|
||||
LIBEAP = libeap.a
|
||||
libeap.a: $(OBJS_lib)
|
||||
ar rc libeap.a $(OBJS_lib)
|
||||
ranlib libeap.a
|
||||
|
||||
else
|
||||
CFLAGS += -fPIC -DPIC
|
||||
LDFLAGS += -shared
|
||||
|
||||
LIBEAP = libeap.so
|
||||
libeap.so: $(OBJS_lib)
|
||||
$(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
|
||||
|
||||
endif
|
||||
|
||||
eap_example: $(OBJS_ex) $(LIBEAP)
|
||||
$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
|
||||
|
||||
clean:
|
||||
$(MAKE) -C ../src clean
|
||||
rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
@ -0,0 +1,46 @@
|
||||
EAP peer/server library and example program
|
||||
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.
|
||||
|
||||
|
||||
The interfaces of the EAP server/peer implementation are based on RFC
|
||||
4137 (EAP State Machines). This RFC is coordinated with the state
|
||||
machines defined in IEEE 802.1X-2004. hostapd and wpa_supplicant
|
||||
include implementation of the IEEE 802.1X EAPOL state machines and the
|
||||
interface between them and EAP. However, the EAP implementation can be
|
||||
used with other protocols, too, by providing a compatible interface
|
||||
which maps the EAPOL<->EAP variables to another protocol.
|
||||
|
||||
This directory contains an example showing how EAP peer and server
|
||||
code from wpa_supplicant and hostapd can be used as a library. The
|
||||
example program initializes both an EAP server and an EAP peer
|
||||
entities and then runs through an EAP-PEAP/MSCHAPv2 authentication.
|
||||
|
||||
eap_example_peer.c shows the initialization and glue code needed to
|
||||
control the EAP peer implementation. eap_example_server.c does the
|
||||
same for EAP server. eap_example.c is an example that ties in both the
|
||||
EAP server and client parts to allow an EAP authentication to be
|
||||
shown.
|
||||
|
||||
In this example, the EAP messages are passed between the server and
|
||||
the peer are passed by direct function calls within the same process.
|
||||
In practice, server and peer functionalities would likely reside in
|
||||
separate devices and the EAP messages would be transmitted between the
|
||||
devices based on an external protocol. For example, in IEEE 802.11
|
||||
uses IEEE 802.1X EAPOL state machines to control the transmission of
|
||||
EAP messages and WiMax supports optional PMK EAP authentication
|
||||
mechanism that transmits EAP messages as defined in IEEE 802.16e.
|
||||
|
||||
|
||||
The EAP library links in number of helper functions from src/utils and
|
||||
src/crypto directories. Most of these are suitable as-is, but it may
|
||||
be desirable to replace the debug output code in src/utils/wpa_debug.c
|
||||
by dropping this file from the library and re-implementing the
|
||||
functions there in a way that better fits in with the main
|
||||
application.
|
@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDBzCCAnCgAwIBAgIJAIb4NS4TdLXUMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
|
||||
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
|
||||
A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
|
||||
MTIwOTAzMTQzN1oXDTE3MTIwNjAzMTQzN1owYTELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCkNhbGlmb3JuaWExDjAMBgNVBAoTBXcxLmZpMRAwDgYDVQQDEwdUZXN0IENB
|
||||
MRswGQYJKoZIhvcNAQkBFgx0ZXN0Y2FAdzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQAD
|
||||
gY0AMIGJAoGBAO6GoecRclnILh9FTvqnY/yUZmeJDgC+3/PQiicpMDhAzCkWAmi+
|
||||
a1LSnqakNN/GdCy3q053TFLFEzhEHkhhRwY/zzj2vZIcFZESoUhr67CzCpcPmTGa
|
||||
AfOzsGPjaH6xYcaOR4RZMfXd/EKfAauHxj3LuCusLL5hK/FwxWhQJNJrAgMBAAGj
|
||||
gcYwgcMwHQYDVR0OBBYEFKhJuSLJ6JhcB/dRgB8j0h9mOlpKMIGTBgNVHSMEgYsw
|
||||
gYiAFKhJuSLJ6JhcB/dRgB8j0h9mOlpKoWWkYzBhMQswCQYDVQQGEwJVUzETMBEG
|
||||
A1UECBMKQ2FsaWZvcm5pYTEOMAwGA1UEChMFdzEuZmkxEDAOBgNVBAMTB1Rlc3Qg
|
||||
Q0ExGzAZBgkqhkiG9w0BCQEWDHRlc3RjYUB3MS5maYIJAIb4NS4TdLXUMAwGA1Ud
|
||||
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAuU+5Uerq+n8WgiIsiANT3wUoGe2Y
|
||||
cnoQi2nVjUHrivgMDufH0tgh1AVfc3wVNNREdGC136qr1KBNqalQx2rKZ76xeNqW
|
||||
sQa2LIC2wE7Q7LJsltUcUjPyZHGUhBqWjKsCvlonfNB6JHkEayTEvVvyupgzTsxW
|
||||
QuuRdZ0sNv/S8VI=
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Example application showing how EAP peer and server code from
|
||||
* wpa_supplicant/hostapd can be used as a library. This example program
|
||||
* initializes both an EAP server and an EAP peer entities and then runs
|
||||
* through an EAP-PEAP/MSCHAPv2 authentication.
|
||||
* 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"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
int eap_example_peer_init(void);
|
||||
void eap_example_peer_deinit(void);
|
||||
int eap_example_peer_step(void);
|
||||
|
||||
int eap_example_server_init(void);
|
||||
void eap_example_server_deinit(void);
|
||||
int eap_example_server_step(void);
|
||||
|
||||
|
||||
extern int wpa_debug_level;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int res_s, res_p;
|
||||
|
||||
wpa_debug_level = 0;
|
||||
|
||||
if (eap_example_peer_init() < 0 ||
|
||||
eap_example_server_init() < 0)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
printf("---[ server ]--------------------------------\n");
|
||||
res_s = eap_example_server_step();
|
||||
printf("---[ peer ]----------------------------------\n");
|
||||
res_p = eap_example_peer_step();
|
||||
} while (res_s || res_p);
|
||||
|
||||
eap_example_peer_deinit();
|
||||
eap_example_server_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Example application showing how EAP peer code from wpa_supplicant can be
|
||||
* used as a library.
|
||||
* 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"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_peer/eap.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "wpabuf.h"
|
||||
|
||||
void eap_example_server_rx(const u8 *data, size_t data_len);
|
||||
|
||||
|
||||
struct eap_peer_ctx {
|
||||
Boolean eapSuccess;
|
||||
Boolean eapRestart;
|
||||
Boolean eapFail;
|
||||
Boolean eapResp;
|
||||
Boolean eapNoResp;
|
||||
Boolean eapReq;
|
||||
Boolean portEnabled;
|
||||
Boolean altAccept; /* for EAP */
|
||||
Boolean altReject; /* for EAP */
|
||||
|
||||
struct wpabuf *eapReqData; /* for EAP */
|
||||
|
||||
unsigned int idleWhile; /* for EAP state machine */
|
||||
|
||||
struct eap_peer_config eap_config;
|
||||
struct eap_sm *eap;
|
||||
};
|
||||
|
||||
|
||||
static struct eap_peer_ctx eap_ctx;
|
||||
|
||||
|
||||
static struct eap_peer_config * peer_get_config(void *ctx)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
return &peer->eap_config;
|
||||
}
|
||||
|
||||
|
||||
static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return FALSE;
|
||||
switch (variable) {
|
||||
case EAPOL_eapSuccess:
|
||||
return peer->eapSuccess;
|
||||
case EAPOL_eapRestart:
|
||||
return peer->eapRestart;
|
||||
case EAPOL_eapFail:
|
||||
return peer->eapFail;
|
||||
case EAPOL_eapResp:
|
||||
return peer->eapResp;
|
||||
case EAPOL_eapNoResp:
|
||||
return peer->eapNoResp;
|
||||
case EAPOL_eapReq:
|
||||
return peer->eapReq;
|
||||
case EAPOL_portEnabled:
|
||||
return peer->portEnabled;
|
||||
case EAPOL_altAccept:
|
||||
return peer->altAccept;
|
||||
case EAPOL_altReject:
|
||||
return peer->altReject;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
|
||||
Boolean value)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return;
|
||||
switch (variable) {
|
||||
case EAPOL_eapSuccess:
|
||||
peer->eapSuccess = value;
|
||||
break;
|
||||
case EAPOL_eapRestart:
|
||||
peer->eapRestart = value;
|
||||
break;
|
||||
case EAPOL_eapFail:
|
||||
peer->eapFail = value;
|
||||
break;
|
||||
case EAPOL_eapResp:
|
||||
peer->eapResp = value;
|
||||
break;
|
||||
case EAPOL_eapNoResp:
|
||||
peer->eapNoResp = value;
|
||||
break;
|
||||
case EAPOL_eapReq:
|
||||
peer->eapReq = value;
|
||||
break;
|
||||
case EAPOL_portEnabled:
|
||||
peer->portEnabled = value;
|
||||
break;
|
||||
case EAPOL_altAccept:
|
||||
peer->altAccept = value;
|
||||
break;
|
||||
case EAPOL_altReject:
|
||||
peer->altReject = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return 0;
|
||||
switch (variable) {
|
||||
case EAPOL_idleWhile:
|
||||
return peer->idleWhile;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_int(void *ctx, enum eapol_int_var variable,
|
||||
unsigned int value)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return;
|
||||
switch (variable) {
|
||||
case EAPOL_idleWhile:
|
||||
peer->idleWhile = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * peer_get_eapReqData(void *ctx)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL || peer->eapReqData == NULL)
|
||||
return NULL;
|
||||
|
||||
return peer->eapReqData;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob)
|
||||
{
|
||||
printf("TODO: %s\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static const struct wpa_config_blob *
|
||||
peer_get_config_blob(void *ctx, const char *name)
|
||||
{
|
||||
printf("TODO: %s\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void peer_notify_pending(void *ctx)
|
||||
{
|
||||
printf("TODO: %s\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static struct eapol_callbacks eap_cb;
|
||||
static struct eap_config eap_conf;
|
||||
|
||||
int eap_example_peer_init(void)
|
||||
{
|
||||
if (eap_peer_register_methods() < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&eap_ctx, 0, sizeof(eap_ctx));
|
||||
|
||||
eap_ctx.eap_config.identity = (u8 *) os_strdup("user");
|
||||
eap_ctx.eap_config.identity_len = 4;
|
||||
eap_ctx.eap_config.password = (u8 *) os_strdup("password");
|
||||
eap_ctx.eap_config.password_len = 8;
|
||||
eap_ctx.eap_config.ca_cert = (u8 *) os_strdup("ca.pem");
|
||||
eap_ctx.eap_config.fragment_size = 1398;
|
||||
|
||||
os_memset(&eap_cb, 0, sizeof(eap_cb));
|
||||
eap_cb.get_config = peer_get_config;
|
||||
eap_cb.get_bool = peer_get_bool;
|
||||
eap_cb.set_bool = peer_set_bool;
|
||||
eap_cb.get_int = peer_get_int;
|
||||
eap_cb.set_int = peer_set_int;
|
||||
eap_cb.get_eapReqData = peer_get_eapReqData;
|
||||
eap_cb.set_config_blob = peer_set_config_blob;
|
||||
eap_cb.get_config_blob = peer_get_config_blob;
|
||||
eap_cb.notify_pending = peer_notify_pending;
|
||||
|
||||
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||
eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf);
|
||||
if (eap_ctx.eap == NULL)
|
||||
return -1;
|
||||
|
||||
/* Enable "port" to allow authentication */
|
||||
eap_ctx.portEnabled = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_peer_deinit(void)
|
||||
{
|
||||
eap_peer_sm_deinit(eap_ctx.eap);
|
||||
eap_peer_unregister_methods();
|
||||
wpabuf_free(eap_ctx.eapReqData);
|
||||
os_free(eap_ctx.eap_config.identity);
|
||||
os_free(eap_ctx.eap_config.password);
|
||||
os_free(eap_ctx.eap_config.ca_cert);
|
||||
}
|
||||
|
||||
|
||||
int eap_example_peer_step(void)
|
||||
{
|
||||
int res;
|
||||
res = eap_peer_sm_step(eap_ctx.eap);
|
||||
|
||||
if (eap_ctx.eapResp) {
|
||||
struct wpabuf *resp;
|
||||
printf("==> Response\n");
|
||||
eap_ctx.eapResp = FALSE;
|
||||
resp = eap_get_eapRespData(eap_ctx.eap);
|
||||
if (resp) {
|
||||
/* Send EAP response to the server */
|
||||
eap_example_server_rx(wpabuf_head(resp),
|
||||
wpabuf_len(resp));
|
||||
wpabuf_free(resp);
|
||||
}
|
||||
}
|
||||
|
||||
if (eap_ctx.eapSuccess) {
|
||||
res = 0;
|
||||
if (eap_key_available(eap_ctx.eap)) {
|
||||
const u8 *key;
|
||||
size_t key_len;
|
||||
key = eap_get_eapKeyData(eap_ctx.eap, &key_len);
|
||||
wpa_hexdump(MSG_DEBUG, "EAP keying material",
|
||||
key, key_len);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_peer_rx(const u8 *data, size_t data_len)
|
||||
{
|
||||
/* Make received EAP message available to the EAP library */
|
||||
eap_ctx.eapReq = TRUE;
|
||||
wpabuf_free(eap_ctx.eapReqData);
|
||||
eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Example application showing how EAP server code from hostapd can be used as
|
||||
* a library.
|
||||
* 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"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "tls.h"
|
||||
#include "wpabuf.h"
|
||||
|
||||
void eap_example_peer_rx(const u8 *data, size_t data_len);
|
||||
|
||||
|
||||
struct eap_server_ctx {
|
||||
struct eap_eapol_interface *eap_if;
|
||||
struct eap_sm *eap;
|
||||
void *tls_ctx;
|
||||
};
|
||||
|
||||
static struct eap_server_ctx eap_ctx;
|
||||
|
||||
|
||||
static int server_get_eap_user(void *ctx, const u8 *identity,
|
||||
size_t identity_len, int phase2,
|
||||
struct eap_user *user)
|
||||
{
|
||||
os_memset(user, 0, sizeof(*user));
|
||||
|
||||
if (!phase2) {
|
||||
/* Only allow EAP-PEAP as the Phase 1 method */
|
||||
user->methods[0].vendor = EAP_VENDOR_IETF;
|
||||
user->methods[0].method = EAP_TYPE_PEAP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (identity_len != 4 || identity == NULL ||
|
||||
os_memcmp(identity, "user", 4) != 0) {
|
||||
printf("Unknown user\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Only allow EAP-MSCHAPv2 as the Phase 2 method */
|
||||
user->methods[0].vendor = EAP_VENDOR_IETF;
|
||||
user->methods[0].method = EAP_TYPE_MSCHAPV2;
|
||||
user->password = (u8 *) os_strdup("password");
|
||||
user->password_len = 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
|
||||
{
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct eapol_callbacks eap_cb;
|
||||
static struct eap_config eap_conf;
|
||||
|
||||
static int eap_example_server_init_tls(void)
|
||||
{
|
||||
struct tls_config tconf;
|
||||
struct tls_connection_params tparams;
|
||||
|
||||
os_memset(&tconf, 0, sizeof(tconf));
|
||||
eap_ctx.tls_ctx = tls_init(&tconf);
|
||||
if (eap_ctx.tls_ctx == NULL)
|
||||
return -1;
|
||||
|
||||
os_memset(&tparams, 0, sizeof(tparams));
|
||||
tparams.ca_cert = "ca.pem";
|
||||
tparams.client_cert = "server.pem";
|
||||
tparams.private_key = "server.key";
|
||||
tparams.private_key_passwd = "whatever";
|
||||
|
||||
if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
|
||||
printf("Failed to set TLS parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls_global_set_verify(eap_ctx.tls_ctx, 0)) {
|
||||
printf("Failed to set check_crl\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_example_server_init(void)
|
||||
{
|
||||
if (eap_server_register_methods() < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&eap_ctx, 0, sizeof(eap_ctx));
|
||||
|
||||
if (eap_example_server_init_tls() < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&eap_cb, 0, sizeof(eap_cb));
|
||||
eap_cb.get_eap_user = server_get_eap_user;
|
||||
eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
|
||||
|
||||
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||
eap_conf.eap_server = 1;
|
||||
eap_conf.ssl_ctx = eap_ctx.tls_ctx;
|
||||
|
||||
eap_ctx.eap = eap_server_sm_init(&eap_ctx, &eap_cb, &eap_conf);
|
||||
if (eap_ctx.eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
|
||||
|
||||
/* Enable "port" and request EAP to start authentication. */
|
||||
eap_ctx.eap_if->portEnabled = TRUE;
|
||||
eap_ctx.eap_if->eapRestart = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_server_deinit(void)
|
||||
{
|
||||
eap_server_sm_deinit(eap_ctx.eap);
|
||||
eap_server_unregister_methods();
|
||||
tls_deinit(eap_ctx.tls_ctx);
|
||||
}
|
||||
|
||||
|
||||
int eap_example_server_step(void)
|
||||
{
|
||||
int res, process = 0;
|
||||
|
||||
res = eap_server_sm_step(eap_ctx.eap);
|
||||
|
||||
if (eap_ctx.eap_if->eapReq) {
|
||||
printf("==> Request\n");
|
||||
process = 1;
|
||||
eap_ctx.eap_if->eapReq = 0;
|
||||
}
|
||||
|
||||
if (eap_ctx.eap_if->eapSuccess) {
|
||||
printf("==> Success\n");
|
||||
process = 1;
|
||||
res = 0;
|
||||
eap_ctx.eap_if->eapSuccess = 0;
|
||||
|
||||
if (eap_ctx.eap_if->eapKeyAvailable) {
|
||||
wpa_hexdump(MSG_DEBUG, "EAP keying material",
|
||||
eap_ctx.eap_if->eapKeyData,
|
||||
eap_ctx.eap_if->eapKeyDataLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (eap_ctx.eap_if->eapFail) {
|
||||
printf("==> Fail\n");
|
||||
process = 1;
|
||||
eap_ctx.eap_if->eapFail = 0;
|
||||
}
|
||||
|
||||
if (process && eap_ctx.eap_if->eapReqData) {
|
||||
/* Send EAP response to the server */
|
||||
eap_example_peer_rx(wpabuf_head(eap_ctx.eap_if->eapReqData),
|
||||
wpabuf_len(eap_ctx.eap_if->eapReqData));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void eap_example_server_rx(const u8 *data, size_t data_len)
|
||||
{
|
||||
/* Make received EAP message available to the EAP library */
|
||||
wpabuf_free(eap_ctx.eap_if->eapRespData);
|
||||
eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
|
||||
if (eap_ctx.eap_if->eapRespData)
|
||||
eap_ctx.eap_if->eapResp = TRUE;
|
||||
}
|
Binary file not shown.
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC0zCCAjygAwIBAgIJAIb4NS4TdLXVMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
|
||||
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
|
||||
A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
|
||||
MTIwOTAzMTUwOFoXDTE3MTIwNjAzMTUwOFoweTELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDjAMBgNVBAoT
|
||||
BXcxLmZpMRAwDgYDVQQDEwdUZXN0IEFTMRswGQYJKoZIhvcNAQkBFgx0ZXN0YXNA
|
||||
dzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOhi4M+aMRa778CPRFV
|
||||
ZNJvTuxfp0CQ+etNpSNkAbkCGNGolbPMPnSQWZUqL5HsaBLm2UbMtS2iR3CO5JQC
|
||||
bPy0xfAjCZV5LQeW4UNVKL3hdtVFzMT6fKgOKCDVEbLLWZze3lEbzhu81q2r3w5x
|
||||
4lqDieCHwvwjiTWpMtEyXIEnAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
|
||||
QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRb
|
||||
xGTC3mPimgyGb5vYLLV5wyc9ITAfBgNVHSMEGDAWgBSoSbkiyeiYXAf3UYAfI9If
|
||||
ZjpaSjANBgkqhkiG9w0BAQUFAAOBgQA9wVGtroz/rsx1EeALJejW01SAr4kpTxoS
|
||||
WP6zuWFb+J/lJd7DeVM6/QBYAwZb0fB6nwSpJJCj6XDRZtN/yLeaTd/rCZrfom4Z
|
||||
8gbkWMTXDn2Cea2VnCe5W0gK+4dIj5DD5CpPvgt4lYqlwN0WAih6twd7Q4x/tiiJ
|
||||
ejNQzlTHOg==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,7 @@
|
||||
*.d
|
||||
.config
|
||||
driver_conf.c
|
||||
hostapd
|
||||
hostapd_cli
|
||||
hlr_auc_gw
|
||||
nt_password_hash
|
@ -0,0 +1,477 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2008-02-22 - v0.6.3
|
||||
* fixed Reassociation Response callback processing when using internal
|
||||
MLME (driver_{hostap,nl80211,test}.c)
|
||||
* updated FT support to use the latest draft, IEEE 802.11r/D9.0
|
||||
* copy optional Proxy-State attributes into RADIUS response when acting
|
||||
as a RADIUS authentication server
|
||||
* fixed EAPOL state machine to handle a case in which no response is
|
||||
received from the RADIUS authentication server; previous version
|
||||
could have triggered a crash in some cases after a timeout
|
||||
* fixed EAP-SIM/AKA realm processing to allow decorated usernames to
|
||||
be used
|
||||
* added a workaround for EAP-SIM/AKA peers that include incorrect null
|
||||
termination in the username
|
||||
* fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
|
||||
attribute in notification messages only when using fast
|
||||
reauthentication
|
||||
* fixed EAP-SIM Start response processing for fast reauthentication
|
||||
case
|
||||
* added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
|
||||
phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
|
||||
|
||||
2008-01-01 - v0.6.2
|
||||
* fixed EAP-SIM and EAP-AKA message parser to validate attribute
|
||||
lengths properly to avoid potential crash caused by invalid messages
|
||||
* added data structure for storing allocated buffers (struct wpabuf);
|
||||
this does not affect hostapd usage, but many of the APIs changed
|
||||
and various interfaces (e.g., EAP) is not compatible with old
|
||||
versions
|
||||
* added support for protecting EAP-AKA/Identity messages with
|
||||
AT_CHECKCODE (optional feature in RFC 4187)
|
||||
* added support for protected result indication with AT_RESULT_IND for
|
||||
EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
|
||||
* added support for configuring EAP-TTLS phase 2 non-EAP methods in
|
||||
EAP server configuration; previously all four were enabled for every
|
||||
phase 2 user, now all four are disabled by default and need to be
|
||||
enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
|
||||
TTLS-MSCHAPV2
|
||||
* removed old debug printing mechanism and the related 'debug'
|
||||
parameter in the configuration file; debug verbosity is now set with
|
||||
-d (or -dd) command line arguments
|
||||
* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
|
||||
only shared key/password authentication is supported in this version
|
||||
|
||||
2007-11-24 - v0.6.1
|
||||
* added experimental, integrated TLSv1 server implementation with the
|
||||
needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
|
||||
setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
|
||||
.config); this can be useful, e.g., if the target system does not
|
||||
have a suitable TLS library and a minimal code size is required
|
||||
* added support for EAP-FAST server method to the integrated EAP
|
||||
server
|
||||
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
|
||||
draft (draft-ietf-emu-eap-gpsk-07.txt)
|
||||
* added a new configuration parameter, rsn_pairwise, to allow different
|
||||
pairwise cipher suites to be enabled for WPA and RSN/WPA2
|
||||
(note: if wpa_pairwise differs from rsn_pairwise, the driver will
|
||||
either need to support this or will have to use the WPA/RSN IEs from
|
||||
hostapd; currently, the included madwifi and bsd driver interfaces do
|
||||
not have support for this)
|
||||
* updated FT support to use the latest draft, IEEE 802.11r/D8.0
|
||||
|
||||
2007-05-28 - v0.6.0
|
||||
* added experimental IEEE 802.11r/D6.0 support
|
||||
* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
|
||||
* updated EAP-PSK to use the IANA-allocated EAP type 47
|
||||
* fixed EAP-PSK bit ordering of the Flags field
|
||||
* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
|
||||
by reading wpa_psk_file [Bug 181]
|
||||
* fixed EAP-TTLS AVP parser processing for too short AVP lengths
|
||||
* fixed IPv6 connection to RADIUS accounting server
|
||||
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
|
||||
draft (draft-ietf-emu-eap-gpsk-04.txt)
|
||||
* hlr_auc_gw: read GSM triplet file into memory and rotate through the
|
||||
entries instead of only using the same three triplets every time
|
||||
(this does not work properly with tests using multiple clients, but
|
||||
provides bit better triplet data for testing a single client; anyway,
|
||||
if a better quality triplets are needed, GSM-Milenage should be used
|
||||
instead of hardcoded triplet file)
|
||||
* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
|
||||
in Success Request [Bug 203]
|
||||
* added support for sending EAP-AKA Notifications in error cases
|
||||
* updated to use IEEE 802.11w/D2.0 for management frame protection
|
||||
(still experimental)
|
||||
* RADIUS server: added support for processing duplicate messages
|
||||
(retransmissions from RADIUS client) by replying with the previous
|
||||
reply
|
||||
|
||||
2006-11-24 - v0.5.6
|
||||
* added support for configuring and controlling multiple BSSes per
|
||||
radio interface (bss=<ifname> in hostapd.conf); this is only
|
||||
available with Devicescape and test driver interfaces
|
||||
* fixed PMKSA cache update in the end of successful RSN
|
||||
pre-authentication
|
||||
* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
|
||||
for each STA based on RADIUS Access-Accept attributes); this requires
|
||||
VLAN support from the kernel driver/802.11 stack and this is
|
||||
currently only available with Devicescape and test driver interfaces
|
||||
* driver_madwifi: fixed configuration of unencrypted modes (plaintext
|
||||
and IEEE 802.1X without WEP)
|
||||
* removed STAKey handshake since PeerKey handshake has replaced it in
|
||||
IEEE 802.11ma and there are no known deployments of STAKey
|
||||
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
|
||||
draft (draft-ietf-emu-eap-gpsk-01.txt)
|
||||
* added preliminary implementation of IEEE 802.11w/D1.0 (management
|
||||
frame protection)
|
||||
(Note: this requires driver support to work properly.)
|
||||
(Note2: IEEE 802.11w is an unapproved draft and subject to change.)
|
||||
* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
|
||||
* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
|
||||
parameters from a text file to make it possible to implement proper
|
||||
GSM/UMTS authentication server for multiple SIM/USIM cards using
|
||||
EAP-SIM/EAP-AKA
|
||||
* fixed session timeout processing with drivers that do not use
|
||||
ieee802_11.c (e.g., madwifi)
|
||||
|
||||
2006-08-27 - v0.5.5
|
||||
* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
|
||||
hostapd (e.g., to initialize wired network authentication based on an
|
||||
external signal)
|
||||
* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
|
||||
using WPA2 even if PMKSA caching is not used
|
||||
* added -P<pid file> argument for hostapd to write the current process
|
||||
id into a file
|
||||
* added support for RADIUS Authentication Server MIB (RFC 2619)
|
||||
|
||||
2006-06-20 - v0.5.4
|
||||
* fixed nt_password_hash build [Bug 144]
|
||||
* added PeerKey handshake implementation for IEEE 802.11e
|
||||
direct link setup (DLS) to replace STAKey handshake
|
||||
* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
|
||||
draft-clancy-emu-eap-shared-secret-00.txt)
|
||||
* fixed a segmentation fault when RSN pre-authentication was completed
|
||||
successfully [Bug 152]
|
||||
|
||||
2006-04-27 - v0.5.3
|
||||
* do not build nt_password_hash and hlr_auc_gw by default to avoid
|
||||
requiring a TLS library for a successful build; these programs can be
|
||||
build with 'make nt_password_hash' and 'make hlr_auc_gw'
|
||||
* added a new configuration option, eapol_version, that can be used to
|
||||
set EAPOL version to 1 (default is 2) to work around broken client
|
||||
implementations that drop EAPOL frames which use version number 2
|
||||
[Bug 89]
|
||||
* added support for EAP-SAKE (no EAP method number allocated yet, so
|
||||
this is using the same experimental type 255 as EAP-PSK)
|
||||
* fixed EAP-MSCHAPv2 message length validation
|
||||
|
||||
2006-03-19 - v0.5.2
|
||||
* fixed stdarg use in hostapd_logger(): if both stdout and syslog
|
||||
logging was enabled, hostapd could trigger a segmentation fault in
|
||||
vsyslog on some CPU -- C library combinations
|
||||
* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
|
||||
program to make it easier to use for implementing real SS7 gateway;
|
||||
eap_sim_db is not anymore used as a file name for GSM authentication
|
||||
triplets; instead, it is path to UNIX domain socket that will be used
|
||||
to communicate with the external gateway program (e.g., hlr_auc_gw)
|
||||
* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
|
||||
local information (GSM authentication triplets from a text file and
|
||||
hardcoded AKA authentication data); this can be used to test EAP-SIM
|
||||
and EAP-AKA
|
||||
* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
|
||||
to make it possible to test EAP-AKA with real USIM cards (this is
|
||||
disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
|
||||
to enable this)
|
||||
* driver_madwifi: added support for getting station RSN IE from
|
||||
madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
|
||||
broken with earlier change (r1357) in the driver
|
||||
* changed EAP method registration to use a dynamic list of methods
|
||||
instead of a static list generated at build time
|
||||
* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
|
||||
[Bug 125]
|
||||
* added ap_max_inactivity configuration parameter
|
||||
|
||||
2006-01-29 - v0.5.1
|
||||
* driver_test: added better support for multiple APs and STAs by using
|
||||
a directory with sockets that include MAC address for each device in
|
||||
the name (test_socket=DIR:/tmp/test)
|
||||
* added support for EAP expanded type (vendor specific EAP methods)
|
||||
|
||||
2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
|
||||
* added experimental STAKey handshake implementation for IEEE 802.11e
|
||||
direct link setup (DLS); note: this is disabled by default in both
|
||||
build and runtime configuration (can be enabled with CONFIG_STAKEY=y
|
||||
and stakey=1)
|
||||
* added support for EAP methods to use callbacks to external programs
|
||||
by buffering a pending request and processing it after the EAP method
|
||||
is ready to continue
|
||||
* improved EAP-SIM database interface to allow external request to GSM
|
||||
HLR/AuC without blocking hostapd process
|
||||
* added support for using EAP-SIM pseudonyms and fast re-authentication
|
||||
* added support for EAP-AKA in the integrated EAP authenticator
|
||||
* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
|
||||
user database to allow EAP-SIM/AKA selection without extra roundtrip
|
||||
for EAP-Nak negotiation
|
||||
* added support for storing EAP user password as NtPasswordHash instead
|
||||
of plaintext password when using MSCHAP or MSCHAPv2 for
|
||||
authentication (hash:<16-octet hex value>); added nt_password_hash
|
||||
tool for hashing password to generate NtPasswordHash
|
||||
|
||||
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
|
||||
* driver_wired: fixed EAPOL sending to optionally use PAE group address
|
||||
as the destination instead of supplicant MAC address; this is
|
||||
disabled by default, but should be enabled with use_pae_group_addr=1
|
||||
in configuration file if the wired interface is used by only one
|
||||
device at the time (common switch configuration)
|
||||
* driver_madwifi: configure driver to use TKIP countermeasures in order
|
||||
to get correct behavior (IEEE 802.11 association failing; previously,
|
||||
association succeeded, but hostpad forced disassociation immediately)
|
||||
* driver_madwifi: added support for madwifi-ng
|
||||
|
||||
2005-10-27 - v0.4.6
|
||||
* added support for replacing user identity from EAP with RADIUS
|
||||
User-Name attribute from Access-Accept message, if that is included,
|
||||
for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
|
||||
tunneled identity into accounting messages when the RADIUS server
|
||||
does not support better way of doing this with Class attribute)
|
||||
* driver_madwifi: fixed EAPOL packet receive for configuration where
|
||||
ath# is part of a bridge interface
|
||||
* added a configuration file and log analyzer script for logwatch
|
||||
* fixed EAPOL state machine step function to process all state
|
||||
transitions before processing new events; this resolves a race
|
||||
condition in which EAPOL-Start message could trigger hostapd to send
|
||||
two EAP-Response/Identity frames to the authentication server
|
||||
|
||||
2005-09-25 - v0.4.5
|
||||
* added client CA list to the TLS certificate request in order to make
|
||||
it easier for the client to select which certificate to use
|
||||
* added experimental support for EAP-PSK
|
||||
* added support for WE-19 (hostap, madwifi)
|
||||
|
||||
2005-08-21 - v0.4.4
|
||||
* fixed build without CONFIG_RSN_PREAUTH
|
||||
* fixed FreeBSD build
|
||||
|
||||
2005-06-26 - v0.4.3
|
||||
* fixed PMKSA caching to copy User-Name and Class attributes so that
|
||||
RADIUS accounting gets correct information
|
||||
* start RADIUS accounting only after successful completion of WPA
|
||||
4-Way Handshake if WPA-PSK is used
|
||||
* fixed PMKSA caching for the case where STA (re)associates without
|
||||
first disassociating
|
||||
|
||||
2005-06-12 - v0.4.2
|
||||
* EAP-PAX is now registered as EAP type 46
|
||||
* fixed EAP-PAX MAC calculation
|
||||
* fixed EAP-PAX CK and ICK key derivation
|
||||
* renamed eap_authenticator configuration variable to eap_server to
|
||||
better match with RFC 3748 (EAP) terminology
|
||||
* driver_test: added support for testing hostapd with wpa_supplicant
|
||||
by using test driver interface without any kernel drivers or network
|
||||
cards
|
||||
|
||||
2005-05-22 - v0.4.1
|
||||
* fixed RADIUS server initialization when only auth or acct server
|
||||
is configured and the other one is left empty
|
||||
* driver_madwifi: added support for RADIUS accounting
|
||||
* driver_madwifi: added preliminary support for compiling against 'BSD'
|
||||
branch of madwifi CVS tree
|
||||
* driver_madwifi: fixed pairwise key removal to allow WPA reauth
|
||||
without disassociation
|
||||
* added support for reading additional certificates from PKCS#12 files
|
||||
and adding them to the certificate chain
|
||||
* fixed RADIUS Class attribute processing to only use Access-Accept
|
||||
packets to update Class; previously, other RADIUS authentication
|
||||
packets could have cleared Class attribute
|
||||
* added support for more than one Class attribute in RADIUS packets
|
||||
* added support for verifying certificate revocation list (CRL) when
|
||||
using integrated EAP authenticator for EAP-TLS; new hostapd.conf
|
||||
options 'check_crl'; CRL must be included in the ca_cert file for now
|
||||
|
||||
2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
|
||||
* added support for including network information into
|
||||
EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
|
||||
(e.g., to implement draft-adrange-eap-network-discovery-07.txt)
|
||||
* fixed a bug which caused some RSN pre-authentication cases to use
|
||||
freed memory and potentially crash hostapd
|
||||
* fixed private key loading for cases where passphrase is not set
|
||||
* added support for sending TLS alerts and aborting authentication
|
||||
when receiving a TLS alert
|
||||
* fixed WPA2 to add PMKSA cache entry when using integrated EAP
|
||||
authenticator
|
||||
* fixed PMKSA caching (EAP authentication was not skipped correctly
|
||||
with the new state machine changes from IEEE 802.1X draft)
|
||||
* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
|
||||
and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
|
||||
to be added to .config to include IPv6 support); for RADIUS server,
|
||||
radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
|
||||
in RADIUS clients file can then use IPv6 format
|
||||
* added experimental support for EAP-PAX
|
||||
* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
|
||||
the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
|
||||
|
||||
2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
|
||||
|
||||
2005-01-23 - v0.3.5
|
||||
* added support for configuring a forced PEAP version based on the
|
||||
Phase 1 identity
|
||||
* fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
|
||||
to terminate authentication
|
||||
* fixed EAP identifier duplicate processing with the new IEEE 802.1X
|
||||
draft
|
||||
* clear accounting data in the driver when starting a new accounting
|
||||
session
|
||||
* driver_madwifi: filter wireless events based on ifindex to allow more
|
||||
than one network interface to be used
|
||||
* fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
|
||||
setting if the packet does not pass MIC verification (e.g., due to
|
||||
incorrect PSK); previously, message 1/4 was not tried again if an
|
||||
invalid message 2/4 was received
|
||||
* fixed reconfiguration of RADIUS client retransmission timer when
|
||||
adding a new message to the pending list; previously, timer was not
|
||||
updated at this point and if there was a pending message with long
|
||||
time for the next retry, the new message needed to wait that long for
|
||||
its first retry, too
|
||||
|
||||
2005-01-09 - v0.3.4
|
||||
* added support for configuring multiple allowed EAP types for Phase 2
|
||||
authentication (EAP-PEAP, EAP-TTLS)
|
||||
* fixed EAPOL-Start processing to trigger WPA reauthentication
|
||||
(previously, only EAPOL authentication was done)
|
||||
|
||||
2005-01-02 - v0.3.3
|
||||
* added support for EAP-PEAP in the integrated EAP authenticator
|
||||
* added support for EAP-GTC in the integrated EAP authenticator
|
||||
* added support for configuring list of EAP methods for Phase 1 so that
|
||||
the integrated EAP authenticator can, e.g., use the wildcard entry
|
||||
for EAP-TLS and EAP-PEAP
|
||||
* added support for EAP-TTLS in the integrated EAP authenticator
|
||||
* added support for EAP-SIM in the integrated EAP authenticator
|
||||
* added support for using hostapd as a RADIUS authentication server
|
||||
with the integrated EAP authenticator taking care of EAP
|
||||
authentication (new hostapd.conf options: radius_server_clients and
|
||||
radius_server_auth_port); this is not included in default build; use
|
||||
CONFIG_RADIUS_SERVER=y in .config to include
|
||||
|
||||
2004-12-19 - v0.3.2
|
||||
* removed 'daemonize' configuration file option since it has not really
|
||||
been used at all for more than year
|
||||
* driver_madwifi: fixed group key setup and added get_ssid method
|
||||
* added support for EAP-MSCHAPv2 in the integrated EAP authenticator
|
||||
|
||||
2004-12-12 - v0.3.1
|
||||
* added support for integrated EAP-TLS authentication (new hostapd.conf
|
||||
variables: ca_cert, server_cert, private_key, private_key_passwd);
|
||||
this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
|
||||
external RADIUS server
|
||||
* added support for reading PKCS#12 (PFX) files (as a replacement for
|
||||
PEM/DER) to get certificate and private key (CONFIG_PKCS12)
|
||||
|
||||
2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
|
||||
* added support for Acct-{Input,Output}-Gigawords
|
||||
* added support for Event-Timestamp (in RADIUS Accounting-Requests)
|
||||
* added support for RADIUS Authentication Client MIB (RFC2618)
|
||||
* added support for RADIUS Accounting Client MIB (RFC2620)
|
||||
* made EAP re-authentication period configurable (eap_reauth_period)
|
||||
* fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
|
||||
* fixed EAPOL state machine to stop if STA is removed during
|
||||
eapol_sm_step(); this fixes at least one segfault triggering bug with
|
||||
IEEE 802.11i pre-authentication
|
||||
* added support for multiple WPA pre-shared keys (e.g., one for each
|
||||
client MAC address or keys shared by a group of clients);
|
||||
new hostapd.conf field wpa_psk_file for setting path to a text file
|
||||
containing PSKs, see hostapd.wpa_psk for an example
|
||||
* added support for multiple driver interfaces to allow hostapd to be
|
||||
used with other drivers
|
||||
* added wired authenticator driver interface (driver=wired in
|
||||
hostapd.conf, see wired.conf for example configuration)
|
||||
* added madwifi driver interface (driver=madwifi in hostapd.conf, see
|
||||
madwifi.conf for example configuration; Note: include files from
|
||||
madwifi project is needed for building and a configuration file,
|
||||
.config, needs to be created in hostapd directory with
|
||||
CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
|
||||
build)
|
||||
* fixed an alignment issue that could cause SHA-1 to fail on some
|
||||
platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
|
||||
align variables)
|
||||
* fixed RADIUS reconnection after an error in sending interim
|
||||
accounting packets
|
||||
* added hostapd control interface for external programs and an example
|
||||
CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
|
||||
* started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
|
||||
'hostapd_cli sta <addr>')
|
||||
* finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
|
||||
* added support for strict GTK rekeying (wpa_strict_rekey in
|
||||
hostapd.conf)
|
||||
* updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
|
||||
(instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
|
||||
IEEE 802.11F-2003)
|
||||
* added Prism54 driver interface (driver=prism54 in hostapd.conf;
|
||||
note: .config needs to be created in hostapd directory with
|
||||
CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
|
||||
build)
|
||||
* dual-licensed hostapd (GPLv2 and BSD licenses)
|
||||
* fixed RADIUS accounting to generate a new session id for cases where
|
||||
a station reassociates without first being complete deauthenticated
|
||||
* fixed STA disassociation handler to mark next timeout state to
|
||||
deauthenticate the station, i.e., skip long wait for inactivity poll
|
||||
and extra disassociation, if the STA disassociates without
|
||||
deauthenticating
|
||||
* added integrated EAP authenticator that can be used instead of
|
||||
external RADIUS authentication server; currently, only EAP-MD5 is
|
||||
supported, so this cannot yet be used for key distribution; the EAP
|
||||
method interface is generic, though, so adding new EAP methods should
|
||||
be straightforward; new hostapd.conf variables: 'eap_authenticator'
|
||||
and 'eap_user_file'; this obsoletes "minimal authentication server"
|
||||
('minimal_eap' in hostapd.conf) which is now removed
|
||||
* added support for FreeBSD and driver interface for the BSD net80211
|
||||
layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
|
||||
.config); please note that some of the required kernel mods have not
|
||||
yet been committed
|
||||
|
||||
2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
|
||||
* fixed some accounting cases where Accounting-Start was sent when
|
||||
IEEE 802.1X port was being deauthorized
|
||||
|
||||
2004-06-20 - v0.2.3
|
||||
* modified RADIUS client to re-connect the socket in case of certain
|
||||
error codes that are generated when a network interface state is
|
||||
changes (e.g., when IP address changes or the interface is set UP)
|
||||
* fixed couple of cases where EAPOL state for a station was freed
|
||||
twice causing a segfault for hostapd
|
||||
* fixed couple of bugs in processing WPA deauthentication (freed data
|
||||
was used)
|
||||
|
||||
2004-05-31 - v0.2.2
|
||||
* fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
|
||||
* fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
|
||||
cases where STAs dropped multicast frames as replay attacks
|
||||
* added support for copying RADIUS Attribute 'Class' from
|
||||
authentication messages into accounting messages
|
||||
* send canned EAP failure if RADIUS server sends Access-Reject without
|
||||
EAP message (previously, Supplicant was not notified in this case)
|
||||
* fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
|
||||
not start EAPOL state machines if the STA selected to use WPA-PSK)
|
||||
|
||||
2004-05-06 - v0.2.1
|
||||
* added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
|
||||
- based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
|
||||
(i.e., IEEE 802.11i/D3.0)
|
||||
- supports WPA-only, RSN-only, and mixed WPA/RSN mode
|
||||
- both WPA-PSK and WPA-RADIUS/EAP are supported
|
||||
- PMKSA caching and pre-authentication
|
||||
- new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
|
||||
wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
|
||||
rsn_preauth, rsn_preauth_interfaces
|
||||
* fixed interim accounting to remove any pending accounting messages
|
||||
to the STA before sending a new one
|
||||
|
||||
2004-02-15 - v0.2.0
|
||||
* added support for Acct-Interim-Interval:
|
||||
- draft-ietf-radius-acct-interim-01.txt
|
||||
- use Acct-Interim-Interval attribute from Access-Accept if local
|
||||
'radius_acct_interim_interval' is not set
|
||||
- allow different update intervals for each STA
|
||||
* fixed event loop to call signal handlers only after returning from
|
||||
the real signal handler
|
||||
* reset sta->timeout_next after successful association to make sure
|
||||
that the previously registered inactivity timer will not remove the
|
||||
STA immediately (e.g., if STA deauthenticates and re-associates
|
||||
before the timer is triggered).
|
||||
* added new hostapd.conf variable, nas_identifier, that can be used to
|
||||
add an optional RADIUS Attribute, NAS-Identifier, into authentication
|
||||
and accounting messages
|
||||
* added support for Accounting-On and Accounting-Off messages
|
||||
* fixed accounting session handling to send Accounting-Start only once
|
||||
per session and not to send Accounting-Stop if the session was not
|
||||
initialized properly
|
||||
* fixed Accounting-Stop statistics in cases where the message was
|
||||
previously sent after the kernel entry for the STA (and/or IEEE
|
||||
802.1X data) was removed
|
||||
|
||||
|
||||
Note:
|
||||
|
||||
Older changes up to and including v0.1.0 are included in the ChangeLog
|
||||
of the Host AP driver.
|
@ -0,0 +1,534 @@
|
||||
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 reconfig.o \
|
||||
mlme.o vlan_init.o ieee802_11h.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/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_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_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
|
||||
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_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
|
||||
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
|
||||
TLS_FUNCS=y
|
||||
CONFIG_EAP_TLV=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
|
||||
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_TLV
|
||||
CFLAGS += -DEAP_TLV
|
||||
OBJS += ../src/eap_server/eap_tlv.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EAP_FAST
|
||||
CFLAGS += -DEAP_FAST
|
||||
OBJS += ../src/eap_server/eap_fast.o
|
||||
TLS_FUNCS=y
|
||||
NEED_T_PRF=y
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
endif
|
||||
|
||||
ifndef NEED_FIPS186_2_PRF
|
||||
CFLAGS += -DCONFIG_NO_FIPS186_2_PRF
|
||||
endif
|
||||
|
||||
ifndef NEED_T_PRF
|
||||
CFLAGS += -DCONFIG_NO_T_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_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
|
||||
|
||||
ALL=hostapd hostapd_cli
|
||||
|
||||
all: verify_config $(ALL)
|
||||
|
||||
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
|
||||
doxygen doc/doxygen.full
|
||||
$(MAKE) -C doc/latex
|
||||
cp doc/latex/refman.pdf hostapd-devel.pdf
|
||||
|
||||
docs-fast: docs-pics
|
||||
doxygen doc/doxygen.fast
|
||||
|
||||
clean-docs:
|
||||
rm -rf doc/latex doc/html
|
||||
rm -f doc/hosta.d{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
|
||||
|
||||
hostapd-sparse: $(OBJS)
|
||||
@echo Sparse run completed
|
||||
|
||||
run-sparse:
|
||||
CC="sparse -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -D__INT_MAX__=2147483647 -D__SHRT_MAX__=32767 -D__LONG_MAX__=2147483647 -D__SCHAR_MAX__=127 -Wbitwise" $(MAKE) hostapd-sparse
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
@ -0,0 +1,386 @@
|
||||
hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
|
||||
Authenticator and RADIUS authentication server
|
||||
================================================================
|
||||
|
||||
Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is dual-licensed under both the GPL version 2 and BSD
|
||||
license. Either license may be used at your option.
|
||||
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
GPL v2:
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
(this copy of the license is in COPYING file)
|
||||
|
||||
|
||||
Alternatively, this software may be distributed, used, and modified
|
||||
under the terms of BSD license:
|
||||
|
||||
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. Neither the name(s) of the above-listed copyright holder(s) nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
||||
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Originally, hostapd was an optional user space component for Host AP
|
||||
driver. It adds more features to the basic IEEE 802.11 management
|
||||
included in the kernel driver: using external RADIUS authentication
|
||||
server for MAC address based access control, IEEE 802.1X Authenticator
|
||||
and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
|
||||
Authenticator and dynamic TKIP/CCMP keying.
|
||||
|
||||
The current version includes support for other drivers, an integrated
|
||||
EAP server (i.e., allow full authentication without requiring
|
||||
an external RADIUS authentication server), and RADIUS authentication
|
||||
server for EAP authentication.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Current hardware/software requirements:
|
||||
- drivers:
|
||||
Host AP driver for Prism2/2.5/3.
|
||||
(http://hostap.epitest.fi/)
|
||||
Please note that station firmware version needs to be 1.7.0 or newer
|
||||
to work in WPA mode.
|
||||
|
||||
madwifi driver for cards based on Atheros chip set (ar521x)
|
||||
(http://sourceforge.net/projects/madwifi/)
|
||||
Please note that you will need to add the correct path for
|
||||
madwifi driver root directory in .config (see defconfig file for
|
||||
an example: CFLAGS += -I<path>)
|
||||
|
||||
Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
|
||||
(http://www.prism54.org/)
|
||||
|
||||
Any wired Ethernet driver for wired IEEE 802.1X authentication
|
||||
(experimental code)
|
||||
|
||||
FreeBSD -current (with some kernel mods that have not yet been
|
||||
committed when hostapd v0.3.0 was released)
|
||||
BSD net80211 layer (e.g., Atheros driver)
|
||||
|
||||
|
||||
Build configuration
|
||||
-------------------
|
||||
|
||||
In order to be able to build hostapd, you will need to create a build
|
||||
time configuration file, .config that selects which optional
|
||||
components are included. See defconfig file for example configuration
|
||||
and list of available options.
|
||||
|
||||
|
||||
|
||||
IEEE 802.1X
|
||||
===========
|
||||
|
||||
IEEE Std 802.1X-2001 is a standard for port-based network access
|
||||
control. In case of IEEE 802.11 networks, a "virtual port" is used
|
||||
between each associated station and the AP. IEEE 802.11 specifies
|
||||
minimal authentication mechanism for stations, whereas IEEE 802.1X
|
||||
introduces a extensible mechanism for authenticating and authorizing
|
||||
users.
|
||||
|
||||
IEEE 802.1X uses elements called Supplicant, Authenticator, Port
|
||||
Access Entity, and Authentication Server. Supplicant is a component in
|
||||
a station and it performs the authentication with the Authentication
|
||||
Server. An access point includes an Authenticator that relays the packets
|
||||
between a Supplicant and an Authentication Server. In addition, it has a
|
||||
Port Access Entity (PAE) with Authenticator functionality for
|
||||
controlling the virtual port authorization, i.e., whether to accept
|
||||
packets from or to the station.
|
||||
|
||||
IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
|
||||
between a Supplicant and an Authenticator are sent using EAP over LAN
|
||||
(EAPOL) and the Authenticator relays these frames to the Authentication
|
||||
Server (and similarly, relays the messages from the Authentication
|
||||
Server to the Supplicant). The Authentication Server can be colocated with the
|
||||
Authenticator, in which case there is no need for additional protocol
|
||||
for EAP frame transmission. However, a more common configuration is to
|
||||
use an external Authentication Server and encapsulate EAP frame in the
|
||||
frames used by that server. RADIUS is suitable for this, but IEEE
|
||||
802.1X would also allow other mechanisms.
|
||||
|
||||
Host AP driver includes PAE functionality in the kernel driver. It
|
||||
is a relatively simple mechanism for denying normal frames going to
|
||||
or coming from an unauthorized port. PAE allows IEEE 802.1X related
|
||||
frames to be passed between the Supplicant and the Authenticator even
|
||||
on an unauthorized port.
|
||||
|
||||
User space daemon, hostapd, includes Authenticator functionality. It
|
||||
receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
|
||||
device that is also used with IEEE 802.11 management frames. The
|
||||
frames to the Supplicant are sent using the same device.
|
||||
|
||||
The normal configuration of the Authenticator would use an external
|
||||
Authentication Server. hostapd supports RADIUS encapsulation of EAP
|
||||
packets, so the Authentication Server should be a RADIUS server, like
|
||||
FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
|
||||
relays the frames between the Supplicant and the Authentication
|
||||
Server. It also controls the PAE functionality in the kernel driver by
|
||||
controlling virtual port authorization, i.e., station-AP
|
||||
connection, based on the IEEE 802.1X state.
|
||||
|
||||
When a station would like to use the services of an access point, it
|
||||
will first perform IEEE 802.11 authentication. This is normally done
|
||||
with open systems authentication, so there is no security. After
|
||||
this, IEEE 802.11 association is performed. If IEEE 802.1X is
|
||||
configured to be used, the virtual port for the station is set in
|
||||
Unauthorized state and only IEEE 802.1X frames are accepted at this
|
||||
point. The Authenticator will then ask the Supplicant to authenticate
|
||||
with the Authentication Server. After this is completed successfully,
|
||||
the virtual port is set to Authorized state and frames from and to the
|
||||
station are accepted.
|
||||
|
||||
Host AP configuration for IEEE 802.1X
|
||||
-------------------------------------
|
||||
|
||||
The user space daemon has its own configuration file that can be used to
|
||||
define AP options. Distribution package contains an example
|
||||
configuration file (hostapd/hostapd.conf) that can be used as a basis
|
||||
for configuration. It includes examples of all supported configuration
|
||||
options and short description of each option. hostapd should be started
|
||||
with full path to the configuration file as the command line argument,
|
||||
e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
|
||||
LAN card, you can use one hostapd process for multiple interfaces by
|
||||
giving a list of configuration files (one per interface) in the command
|
||||
line.
|
||||
|
||||
hostapd includes a minimal co-located IEEE 802.1X server which can be
|
||||
used to test IEEE 802.1X authentication. However, it should not be
|
||||
used in normal use since it does not provide any security. This can be
|
||||
configured by setting ieee8021x and minimal_eap options in the
|
||||
configuration file.
|
||||
|
||||
An external Authentication Server (RADIUS) is configured with
|
||||
auth_server_{addr,port,shared_secret} options. In addition,
|
||||
ieee8021x and own_ip_addr must be set for this mode. With such
|
||||
configuration, the co-located Authentication Server is not used and EAP
|
||||
frames will be relayed using EAPOL between the Supplicant and the
|
||||
Authenticator and RADIUS encapsulation between the Authenticator and
|
||||
the Authentication Server. Other than this, the functionality is similar
|
||||
to the case with the co-located Authentication Server.
|
||||
|
||||
Authentication Server and Supplicant
|
||||
------------------------------------
|
||||
|
||||
Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
|
||||
Authentication Server with hostapd Authenticator. FreeRADIUS
|
||||
(http://www.freeradius.org/) has been successfully tested with hostapd
|
||||
Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
|
||||
XP Supplicants. EAP/TLS was used with Xsupplicant and
|
||||
EAP/MD5-Challenge with Windows XP.
|
||||
|
||||
http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
|
||||
about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
|
||||
Cisco access point with Host AP driver, hostapd daemon, and a Prism2
|
||||
card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
|
||||
about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
|
||||
configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
|
||||
EAP/TLS use with WinXP Supplicant.
|
||||
|
||||
Automatic WEP key configuration
|
||||
-------------------------------
|
||||
|
||||
EAP/TLS generates a session key that can be used to send WEP keys from
|
||||
an AP to authenticated stations. The Authenticator in hostapd can be
|
||||
configured to automatically select a random default/broadcast key
|
||||
(shared by all authenticated stations) with wep_key_len_broadcast
|
||||
option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
|
||||
wep_key_len_unicast option can be used to configure individual unicast
|
||||
keys for stations. This requires support for individual keys in the
|
||||
station driver.
|
||||
|
||||
WEP keys can be automatically updated by configuring rekeying. This
|
||||
will improve security of the network since same WEP key will only be
|
||||
used for a limited period of time. wep_rekey_period option sets the
|
||||
interval for rekeying in seconds.
|
||||
|
||||
|
||||
WPA/WPA2
|
||||
========
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Supported WPA/IEEE 802.11i features:
|
||||
- WPA-PSK ("WPA-Personal")
|
||||
- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
|
||||
- key management for CCMP, TKIP, WEP104, WEP40
|
||||
- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
|
||||
|
||||
WPA
|
||||
---
|
||||
|
||||
The original security mechanism of IEEE 802.11 standard was not
|
||||
designed to be strong and has proved to be insufficient for most
|
||||
networks that require some kind of security. Task group I (Security)
|
||||
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
|
||||
to address the flaws of the base standard and has in practice
|
||||
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
|
||||
802.11 standard was approved in June 2004 and this amendment is likely
|
||||
to be published in July 2004.
|
||||
|
||||
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
|
||||
IEEE 802.11i work (draft 3.0) to define a subset of the security
|
||||
enhancements that can be implemented with existing wlan hardware. This
|
||||
is called Wi-Fi Protected Access<TM> (WPA). This has now become a
|
||||
mandatory component of interoperability testing and certification done
|
||||
by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
|
||||
site (http://www.wi-fi.org/OpenSection/protected_access.asp).
|
||||
|
||||
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
|
||||
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
|
||||
24-bit initialization vector (IV), and CRC32 to protect against packet
|
||||
forgery. All these choices have proven to be insufficient: key space is
|
||||
too small against current attacks, RC4 key scheduling is insufficient
|
||||
(beginning of the pseudorandom stream should be skipped), IV space is
|
||||
too small and IV reuse makes attacks easier, there is no replay
|
||||
protection, and non-keyed authentication does not protect against bit
|
||||
flipping packet data.
|
||||
|
||||
WPA is an intermediate solution for the security issues. It uses
|
||||
Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
|
||||
compromise on strong security and possibility to use existing
|
||||
hardware. It still uses RC4 for the encryption like WEP, but with
|
||||
per-packet RC4 keys. In addition, it implements replay protection,
|
||||
keyed packet authentication mechanism (Michael MIC).
|
||||
|
||||
Keys can be managed using two different mechanisms. WPA can either use
|
||||
an external authentication server (e.g., RADIUS) and EAP just like
|
||||
IEEE 802.1X is using or pre-shared keys without need for additional
|
||||
servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
|
||||
respectively. Both mechanisms will generate a master session key for
|
||||
the Authenticator (AP) and Supplicant (client station).
|
||||
|
||||
WPA implements a new key handshake (4-Way Handshake and Group Key
|
||||
Handshake) for generating and exchanging data encryption keys between
|
||||
the Authenticator and Supplicant. This handshake is also used to
|
||||
verify that both Authenticator and Supplicant know the master session
|
||||
key. These handshakes are identical regardless of the selected key
|
||||
management mechanism (only the method for generating master session
|
||||
key changes).
|
||||
|
||||
|
||||
IEEE 802.11i / WPA2
|
||||
-------------------
|
||||
|
||||
The design for parts of IEEE 802.11i that were not included in WPA has
|
||||
finished (May 2004) and this amendment to IEEE 802.11 was approved in
|
||||
June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
|
||||
version of WPA called WPA2. This includes, e.g., support for more
|
||||
robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
|
||||
to replace TKIP and optimizations for handoff (reduced number of
|
||||
messages in initial key handshake, pre-authentication, and PMKSA caching).
|
||||
|
||||
Some wireless LAN vendors are already providing support for CCMP in
|
||||
their WPA products. There is no "official" interoperability
|
||||
certification for CCMP and/or mixed modes using both TKIP and CCMP, so
|
||||
some interoperability issues can be expected even though many
|
||||
combinations seem to be working with equipment from different vendors.
|
||||
Testing for WPA2 is likely to start during the second half of 2004.
|
||||
|
||||
hostapd configuration for WPA/WPA2
|
||||
----------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
# Enable WPA. Setting this variable configures the AP to require WPA (either
|
||||
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
|
||||
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
|
||||
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
|
||||
# RADIUS authentication server must be configured, and WPA-EAP must be included
|
||||
# in wpa_key_mgmt.
|
||||
# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
|
||||
# and/or WPA2 (full IEEE 802.11i/RSN):
|
||||
# bit0 = WPA
|
||||
# bit1 = IEEE 802.11i/RSN (WPA2)
|
||||
#wpa=1
|
||||
|
||||
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
|
||||
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
|
||||
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
#wpa_passphrase=secret passphrase
|
||||
|
||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||
# entries are separated with a space.
|
||||
#wpa_key_mgmt=WPA-PSK WPA-EAP
|
||||
|
||||
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
|
||||
# (unicast packets). This is a space separated list of algorithms:
|
||||
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
|
||||
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
|
||||
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
|
||||
# is automatically selected based on this configuration. If only CCMP is
|
||||
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
|
||||
# TKIP will be used as the group cipher.
|
||||
#wpa_pairwise=TKIP CCMP
|
||||
|
||||
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
|
||||
# seconds.
|
||||
#wpa_group_rekey=600
|
||||
|
||||
# Time interval for rekeying GMK (master key used internally to generate GTKs
|
||||
# (in seconds).
|
||||
#wpa_gmk_rekey=86400
|
||||
|
||||
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
|
||||
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
|
||||
# authentication and key handshake before actually associating with a new AP.
|
||||
#rsn_preauth=1
|
||||
#
|
||||
# Space separated list of interfaces from which pre-authentication frames are
|
||||
# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
|
||||
# interface that are used for connections to other APs. This could include
|
||||
# wired interfaces and WDS links. The normal wireless data interface towards
|
||||
# associated stations (e.g., wlan0) should not be added, since
|
||||
# pre-authentication is only used with APs other than the currently associated
|
||||
# one.
|
||||
#rsn_preauth_interfaces=eth0
|
@ -0,0 +1,466 @@
|
||||
/*
|
||||
* hostapd / RADIUS Accounting
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "eloop.h"
|
||||
#include "accounting.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
/* Default interval in seconds for polling TX/RX octets from the driver if
|
||||
* STA is not using interim accounting. This detects wrap arounds for
|
||||
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
|
||||
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
|
||||
|
||||
/* from ieee802_1x.c */
|
||||
const char *radius_mode_txt(struct hostapd_data *hapd);
|
||||
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
|
||||
static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
int status_type)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
char buf[128];
|
||||
u8 *val;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
|
||||
radius_client_get_id(hapd->radius));
|
||||
if (msg == NULL) {
|
||||
printf("Could not create net RADIUS packet\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
|
||||
|
||||
os_snprintf(buf, sizeof(buf), "%08X-%08X",
|
||||
sta->acct_session_id_hi, sta->acct_session_id_lo);
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
printf("Could not add Acct-Session-Id\n");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
|
||||
status_type)) {
|
||||
printf("Could not add Acct-Status-Type\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
|
||||
hapd->conf->ieee802_1x ?
|
||||
RADIUS_ACCT_AUTHENTIC_RADIUS :
|
||||
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
|
||||
printf("Could not add Acct-Authentic\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
|
||||
if (!val) {
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
|
||||
MAC2STR(sta->addr));
|
||||
val = (u8 *) buf;
|
||||
len = os_strlen(buf);
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
|
||||
len)) {
|
||||
printf("Could not add User-Name\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||
printf("Could not add NAS-IP-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||
printf("Could not add NAS-IPv6-Address\n");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (hapd->conf->nas_identifier &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||
(u8 *) hapd->conf->nas_identifier,
|
||||
os_strlen(hapd->conf->nas_identifier))) {
|
||||
printf("Could not add NAS-Identifier\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sta &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
|
||||
printf("Could not add NAS-Port\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
|
||||
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
printf("Could not add Called-Station-Id\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
|
||||
MAC2STR(sta->addr));
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
printf("Could not add Calling-Station-Id\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(
|
||||
msg, RADIUS_ATTR_NAS_PORT_TYPE,
|
||||
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
|
||||
printf("Could not add NAS-Port-Type\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
|
||||
radius_sta_rate(hapd, sta) / 2,
|
||||
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
|
||||
radius_mode_txt(hapd));
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
printf("Could not add Connect-Info\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
|
||||
i);
|
||||
if (val == NULL)
|
||||
break;
|
||||
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
|
||||
val, len)) {
|
||||
printf("Could not add Class\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
||||
fail:
|
||||
radius_msg_free(msg);
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int accounting_sta_update_stats(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct hostap_sta_driver_data *data)
|
||||
{
|
||||
if (hostapd_read_sta_data(hapd, data, sta->addr))
|
||||
return -1;
|
||||
|
||||
if (sta->last_rx_bytes > data->rx_bytes)
|
||||
sta->acct_input_gigawords++;
|
||||
if (sta->last_tx_bytes > data->tx_bytes)
|
||||
sta->acct_output_gigawords++;
|
||||
sta->last_rx_bytes = data->rx_bytes;
|
||||
sta->last_tx_bytes = data->tx_bytes;
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
|
||||
"Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
|
||||
"Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
|
||||
sta->last_rx_bytes, sta->acct_input_gigawords,
|
||||
sta->last_tx_bytes, sta->acct_output_gigawords);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
int interval;
|
||||
|
||||
if (sta->acct_interim_interval) {
|
||||
accounting_sta_interim(hapd, sta);
|
||||
interval = sta->acct_interim_interval;
|
||||
} else {
|
||||
struct hostap_sta_driver_data data;
|
||||
accounting_sta_update_stats(hapd, sta, &data);
|
||||
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
|
||||
}
|
||||
|
||||
eloop_register_timeout(interval, 0, accounting_interim_update,
|
||||
hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
int interval;
|
||||
|
||||
if (sta->acct_session_started)
|
||||
return;
|
||||
|
||||
time(&sta->acct_session_start);
|
||||
sta->last_rx_bytes = sta->last_tx_bytes = 0;
|
||||
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
|
||||
hostapd_sta_clear_stats(hapd, sta->addr);
|
||||
|
||||
if (!hapd->conf->radius->acct_server)
|
||||
return;
|
||||
|
||||
if (sta->acct_interim_interval)
|
||||
interval = sta->acct_interim_interval;
|
||||
else
|
||||
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
|
||||
eloop_register_timeout(interval, 0, accounting_interim_update,
|
||||
hapd, sta);
|
||||
|
||||
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
|
||||
if (msg)
|
||||
radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
|
||||
|
||||
sta->acct_session_started = 1;
|
||||
}
|
||||
|
||||
|
||||
void accounting_sta_report(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int stop)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
int cause = sta->acct_terminate_cause;
|
||||
struct hostap_sta_driver_data data;
|
||||
u32 gigawords;
|
||||
|
||||
if (!hapd->conf->radius->acct_server)
|
||||
return;
|
||||
|
||||
msg = accounting_msg(hapd, sta,
|
||||
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
|
||||
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
|
||||
if (!msg) {
|
||||
printf("Could not create RADIUS Accounting message\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
|
||||
time(NULL) - sta->acct_session_start)) {
|
||||
printf("Could not add Acct-Session-Time\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_INPUT_PACKETS,
|
||||
data.rx_packets)) {
|
||||
printf("Could not add Acct-Input-Packets\n");
|
||||
goto fail;
|
||||
}
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
|
||||
data.tx_packets)) {
|
||||
printf("Could not add Acct-Output-Packets\n");
|
||||
goto fail;
|
||||
}
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_INPUT_OCTETS,
|
||||
data.rx_bytes)) {
|
||||
printf("Could not add Acct-Input-Octets\n");
|
||||
goto fail;
|
||||
}
|
||||
gigawords = sta->acct_input_gigawords;
|
||||
#if __WORDSIZE == 64
|
||||
gigawords += data.rx_bytes >> 32;
|
||||
#endif
|
||||
if (gigawords &&
|
||||
!radius_msg_add_attr_int32(
|
||||
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
|
||||
gigawords)) {
|
||||
printf("Could not add Acct-Input-Gigawords\n");
|
||||
goto fail;
|
||||
}
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
|
||||
data.tx_bytes)) {
|
||||
printf("Could not add Acct-Output-Octets\n");
|
||||
goto fail;
|
||||
}
|
||||
gigawords = sta->acct_output_gigawords;
|
||||
#if __WORDSIZE == 64
|
||||
gigawords += data.tx_bytes >> 32;
|
||||
#endif
|
||||
if (gigawords &&
|
||||
!radius_msg_add_attr_int32(
|
||||
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
|
||||
gigawords)) {
|
||||
printf("Could not add Acct-Output-Gigawords\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
|
||||
time(NULL))) {
|
||||
printf("Could not add Event-Timestamp\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (eloop_terminated())
|
||||
cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
|
||||
|
||||
if (stop && cause &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
|
||||
cause)) {
|
||||
printf("Could not add Acct-Terminate-Cause\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
radius_client_send(hapd->radius, msg,
|
||||
stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
|
||||
sta->addr);
|
||||
return;
|
||||
|
||||
fail:
|
||||
radius_msg_free(msg);
|
||||
os_free(msg);
|
||||
}
|
||||
|
||||
|
||||
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
if (sta->acct_session_started)
|
||||
accounting_sta_report(hapd, sta, 0);
|
||||
}
|
||||
|
||||
|
||||
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
if (sta->acct_session_started) {
|
||||
accounting_sta_report(hapd, sta, 1);
|
||||
eloop_cancel_timeout(accounting_interim_update, hapd, sta);
|
||||
sta->acct_session_started = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
|
||||
if (hapd->acct_session_id_lo == 0) {
|
||||
hapd->acct_session_id_hi++;
|
||||
}
|
||||
sta->acct_session_id_hi = hapd->acct_session_id_hi;
|
||||
}
|
||||
|
||||
|
||||
/* Process the RADIUS frames from Accounting Server */
|
||||
static RadiusRxResult
|
||||
accounting_receive(struct radius_msg *msg, struct radius_msg *req,
|
||||
u8 *shared_secret, size_t shared_secret_len, void *data)
|
||||
{
|
||||
if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
|
||||
printf("Unknown RADIUS message code\n");
|
||||
return RADIUS_RX_UNKNOWN;
|
||||
}
|
||||
|
||||
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||
printf("Incoming RADIUS packet did not have correct "
|
||||
"Authenticator - dropped\n");
|
||||
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||
}
|
||||
|
||||
return RADIUS_RX_PROCESSED;
|
||||
}
|
||||
|
||||
|
||||
static void accounting_report_state(struct hostapd_data *hapd, int on)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
|
||||
if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
|
||||
return;
|
||||
|
||||
/* Inform RADIUS server that accounting will start/stop so that the
|
||||
* server can close old accounting sessions. */
|
||||
msg = accounting_msg(hapd, NULL,
|
||||
on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
|
||||
RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
|
||||
{
|
||||
printf("Could not add Acct-Terminate-Cause\n");
|
||||
radius_msg_free(msg);
|
||||
os_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
|
||||
}
|
||||
|
||||
|
||||
int accounting_init(struct hostapd_data *hapd)
|
||||
{
|
||||
/* Acct-Session-Id should be unique over reboots. If reliable clock is
|
||||
* not available, this could be replaced with reboot counter, etc. */
|
||||
hapd->acct_session_id_hi = time(NULL);
|
||||
|
||||
if (radius_client_register(hapd->radius, RADIUS_ACCT,
|
||||
accounting_receive, hapd))
|
||||
return -1;
|
||||
|
||||
accounting_report_state(hapd, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void accounting_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
accounting_report_state(hapd, 0);
|
||||
}
|
||||
|
||||
|
||||
int accounting_reconfig(struct hostapd_data *hapd,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
if (!hapd->radius_client_reconfigured)
|
||||
return 0;
|
||||
|
||||
accounting_deinit(hapd);
|
||||
return accounting_init(hapd);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* hostapd / RADIUS Accounting
|
||||
* Copyright (c) 2002-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 ACCOUNTING_H
|
||||
#define ACCOUNTING_H
|
||||
|
||||
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int accounting_init(struct hostapd_data *hapd);
|
||||
void accounting_deinit(struct hostapd_data *hapd);
|
||||
int accounting_reconfig(struct hostapd_data *hapd,
|
||||
struct hostapd_config *oldconf);
|
||||
|
||||
#endif /* ACCOUNTING_H */
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* hostapd / Station table data structures
|
||||
* Copyright (c) 2002-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.
|
||||
*/
|
||||
|
||||
#ifndef AP_H
|
||||
#define AP_H
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
#define WLAN_STA_ASSOC BIT(1)
|
||||
#define WLAN_STA_PS BIT(2)
|
||||
#define WLAN_STA_TIM BIT(3)
|
||||
#define WLAN_STA_PERM BIT(4)
|
||||
#define WLAN_STA_AUTHORIZED BIT(5)
|
||||
#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_NONERP BIT(31)
|
||||
|
||||
/* Maximum number of supported rates (from both Supported Rates and Extended
|
||||
* Supported Rates IEs). */
|
||||
#define WLAN_SUPP_RATES_MAX 32
|
||||
|
||||
|
||||
struct sta_info {
|
||||
struct sta_info *next; /* next entry in sta list */
|
||||
struct sta_info *hnext; /* next entry in hash table list */
|
||||
u8 addr[6];
|
||||
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
|
||||
u32 flags;
|
||||
u16 capability;
|
||||
u16 listen_interval; /* or beacon_int for APs */
|
||||
u8 supported_rates[WLAN_SUPP_RATES_MAX];
|
||||
int supported_rates_len;
|
||||
|
||||
unsigned int nonerp_set:1;
|
||||
unsigned int no_short_slot_time_set:1;
|
||||
unsigned int no_short_preamble_set:1;
|
||||
|
||||
u16 auth_alg;
|
||||
u8 previous_ap[6];
|
||||
|
||||
enum {
|
||||
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
|
||||
} timeout_next;
|
||||
|
||||
/* IEEE 802.1X related data */
|
||||
struct eapol_state_machine *eapol_sm;
|
||||
|
||||
/* IEEE 802.11f (IAPP) related data */
|
||||
struct ieee80211_mgmt *last_assoc_req;
|
||||
|
||||
u32 acct_session_id_hi;
|
||||
u32 acct_session_id_lo;
|
||||
time_t acct_session_start;
|
||||
int acct_session_started;
|
||||
int acct_terminate_cause; /* Acct-Terminate-Cause */
|
||||
int acct_interim_interval; /* Acct-Interim-Interval */
|
||||
|
||||
unsigned long last_rx_bytes;
|
||||
unsigned long last_tx_bytes;
|
||||
u32 acct_input_gigawords; /* Acct-Input-Gigawords */
|
||||
u32 acct_output_gigawords; /* Acct-Output-Gigawords */
|
||||
|
||||
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
|
||||
|
||||
struct wpa_state_machine *wpa_sm;
|
||||
struct rsn_preauth_interface *preauth_iface;
|
||||
|
||||
struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
|
||||
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
|
||||
|
||||
int vlan_id;
|
||||
};
|
||||
|
||||
|
||||
/* Maximum number of AIDs to use for STAs; must be 2007 or lower
|
||||
* (8802.11 limitation) */
|
||||
#define MAX_AID_TABLE_SIZE 128
|
||||
|
||||
#define STA_HASH_SIZE 256
|
||||
#define STA_HASH(sta) (sta[5])
|
||||
|
||||
|
||||
/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
|
||||
* passed since last received frame from the station, a nullfunc data frame is
|
||||
* sent to the station. If this frame is not acknowledged and no other frames
|
||||
* have been received, the station will be disassociated after
|
||||
* AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
|
||||
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
|
||||
#define AP_MAX_INACTIVITY (5 * 60)
|
||||
#define AP_DISASSOC_DELAY (1)
|
||||
#define AP_DEAUTH_DELAY (1)
|
||||
/* Number of seconds to keep STA entry with Authenticated flag after it has
|
||||
* been disassociated. */
|
||||
#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
|
||||
/* Number of seconds to keep STA entry after it has been deauthenticated. */
|
||||
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
|
||||
|
||||
#endif /* AP_H */
|
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* hostapd / AP table
|
||||
* Copyright 2002-2003, Jouni Malinen <j@w1.fi>
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2006, Devicescape Software, 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 "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "eloop.h"
|
||||
#include "ap_list.h"
|
||||
#include "hw_features.h"
|
||||
#include "beacon.h"
|
||||
|
||||
|
||||
struct ieee80211_frame_info {
|
||||
u32 version;
|
||||
u32 length;
|
||||
u64 mactime;
|
||||
u64 hosttime;
|
||||
u32 phytype;
|
||||
u32 channel;
|
||||
u32 datarate;
|
||||
u32 antenna;
|
||||
u32 priority;
|
||||
u32 ssi_type;
|
||||
u32 ssi_signal;
|
||||
u32 ssi_noise;
|
||||
u32 preamble;
|
||||
u32 encoding;
|
||||
|
||||
/* Note: this structure is otherwise identical to capture format used
|
||||
* in linux-wlan-ng, but this additional field is used to provide meta
|
||||
* data about the frame to hostapd. This was the easiest method for
|
||||
* providing this information, but this might change in the future. */
|
||||
u32 msg_type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
enum ieee80211_phytype {
|
||||
ieee80211_phytype_fhss_dot11_97 = 1,
|
||||
ieee80211_phytype_dsss_dot11_97 = 2,
|
||||
ieee80211_phytype_irbaseband = 3,
|
||||
ieee80211_phytype_dsss_dot11_b = 4,
|
||||
ieee80211_phytype_pbcc_dot11_b = 5,
|
||||
ieee80211_phytype_ofdm_dot11_g = 6,
|
||||
ieee80211_phytype_pbcc_dot11_g = 7,
|
||||
ieee80211_phytype_ofdm_dot11_a = 8,
|
||||
ieee80211_phytype_dsss_dot11_turbog = 255,
|
||||
ieee80211_phytype_dsss_dot11_turbo = 256,
|
||||
};
|
||||
|
||||
|
||||
/* AP list is a double linked list with head->prev pointing to the end of the
|
||||
* list and tail->next = NULL. Entries are moved to the head of the list
|
||||
* whenever a beacon has been received from the AP in question. The tail entry
|
||||
* in this link will thus be the least recently used entry. */
|
||||
|
||||
|
||||
static void ap_list_new_ap(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "New AP detected: " MACSTR, MAC2STR(ap->addr));
|
||||
|
||||
/* TODO: could send a notification message to an external program that
|
||||
* would then determine whether a rogue AP has been detected */
|
||||
}
|
||||
|
||||
|
||||
static void ap_list_expired_ap(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "AP info expired: " MACSTR, MAC2STR(ap->addr));
|
||||
|
||||
/* TODO: could send a notification message to an external program */
|
||||
}
|
||||
|
||||
|
||||
static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
|
||||
ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
|
||||
iface->conf->channel != ap->channel)
|
||||
return 0;
|
||||
|
||||
if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
|
||||
int rate = (ap->supported_rates[i] & 0x7f) * 5;
|
||||
if (rate == 60 || rate == 90 || rate > 110)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
|
||||
{
|
||||
struct ap_info *s;
|
||||
|
||||
s = iface->ap_hash[STA_HASH(ap)];
|
||||
while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
|
||||
s = s->hnext;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
if (iface->ap_list) {
|
||||
ap->prev = iface->ap_list->prev;
|
||||
iface->ap_list->prev = ap;
|
||||
} else
|
||||
ap->prev = ap;
|
||||
ap->next = iface->ap_list;
|
||||
iface->ap_list = ap;
|
||||
}
|
||||
|
||||
|
||||
static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
if (iface->ap_list == ap)
|
||||
iface->ap_list = ap->next;
|
||||
else
|
||||
ap->prev->next = ap->next;
|
||||
|
||||
if (ap->next)
|
||||
ap->next->prev = ap->prev;
|
||||
else if (iface->ap_list)
|
||||
iface->ap_list->prev = ap->prev;
|
||||
}
|
||||
|
||||
|
||||
static void ap_ap_iter_list_add(struct hostapd_iface *iface,
|
||||
struct ap_info *ap)
|
||||
{
|
||||
if (iface->ap_iter_list) {
|
||||
ap->iter_prev = iface->ap_iter_list->iter_prev;
|
||||
iface->ap_iter_list->iter_prev = ap;
|
||||
} else
|
||||
ap->iter_prev = ap;
|
||||
ap->iter_next = iface->ap_iter_list;
|
||||
iface->ap_iter_list = ap;
|
||||
}
|
||||
|
||||
|
||||
static void ap_ap_iter_list_del(struct hostapd_iface *iface,
|
||||
struct ap_info *ap)
|
||||
{
|
||||
if (iface->ap_iter_list == ap)
|
||||
iface->ap_iter_list = ap->iter_next;
|
||||
else
|
||||
ap->iter_prev->iter_next = ap->iter_next;
|
||||
|
||||
if (ap->iter_next)
|
||||
ap->iter_next->iter_prev = ap->iter_prev;
|
||||
else if (iface->ap_iter_list)
|
||||
iface->ap_iter_list->iter_prev = ap->iter_prev;
|
||||
}
|
||||
|
||||
|
||||
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
|
||||
iface->ap_hash[STA_HASH(ap->addr)] = ap;
|
||||
}
|
||||
|
||||
|
||||
static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
struct ap_info *s;
|
||||
|
||||
s = iface->ap_hash[STA_HASH(ap->addr)];
|
||||
if (s == NULL) return;
|
||||
if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
|
||||
iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
|
||||
return;
|
||||
}
|
||||
|
||||
while (s->hnext != NULL &&
|
||||
os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
|
||||
s = s->hnext;
|
||||
if (s->hnext != NULL)
|
||||
s->hnext = s->hnext->hnext;
|
||||
else
|
||||
printf("AP: could not remove AP " MACSTR " from hash table\n",
|
||||
MAC2STR(ap->addr));
|
||||
}
|
||||
|
||||
|
||||
static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
|
||||
{
|
||||
ap_ap_hash_del(iface, ap);
|
||||
ap_ap_list_del(iface, ap);
|
||||
ap_ap_iter_list_del(iface, ap);
|
||||
|
||||
iface->num_ap--;
|
||||
os_free(ap);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_free_aps(struct hostapd_iface *iface)
|
||||
{
|
||||
struct ap_info *ap, *prev;
|
||||
|
||||
ap = iface->ap_list;
|
||||
|
||||
while (ap) {
|
||||
prev = ap;
|
||||
ap = ap->next;
|
||||
ap_free_ap(iface, prev);
|
||||
}
|
||||
|
||||
iface->ap_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
int ap_ap_for_each(struct hostapd_iface *iface,
|
||||
int (*func)(struct ap_info *s, void *data), void *data)
|
||||
{
|
||||
struct ap_info *s;
|
||||
int ret = 0;
|
||||
|
||||
s = iface->ap_list;
|
||||
|
||||
while (s) {
|
||||
ret = func(s, data);
|
||||
if (ret)
|
||||
break;
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
|
||||
{
|
||||
struct ap_info *ap;
|
||||
|
||||
ap = os_zalloc(sizeof(struct ap_info));
|
||||
if (ap == NULL)
|
||||
return NULL;
|
||||
|
||||
/* initialize AP info data */
|
||||
os_memcpy(ap->addr, addr, ETH_ALEN);
|
||||
ap_ap_list_add(iface, ap);
|
||||
iface->num_ap++;
|
||||
ap_ap_hash_add(iface, ap);
|
||||
ap_ap_iter_list_add(iface, ap);
|
||||
|
||||
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
|
||||
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
|
||||
MACSTR " from AP table", MAC2STR(ap->prev->addr));
|
||||
if (iface->conf->passive_scan_interval > 0)
|
||||
ap_list_expired_ap(iface, ap->prev);
|
||||
ap_free_ap(iface, ap->prev);
|
||||
}
|
||||
|
||||
return ap;
|
||||
}
|
||||
|
||||
|
||||
void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct hostapd_frame_info *fi)
|
||||
{
|
||||
struct ap_info *ap;
|
||||
int new_ap = 0;
|
||||
size_t len;
|
||||
|
||||
if (iface->conf->ap_table_max_size < 1)
|
||||
return;
|
||||
|
||||
ap = ap_get_ap(iface, mgmt->bssid);
|
||||
if (!ap) {
|
||||
ap = ap_ap_add(iface, mgmt->bssid);
|
||||
if (!ap) {
|
||||
printf("Failed to allocate AP information entry\n");
|
||||
return;
|
||||
}
|
||||
new_ap = 1;
|
||||
}
|
||||
|
||||
ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
|
||||
ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
|
||||
|
||||
if (elems->ssid) {
|
||||
len = elems->ssid_len;
|
||||
if (len >= sizeof(ap->ssid))
|
||||
len = sizeof(ap->ssid) - 1;
|
||||
os_memcpy(ap->ssid, elems->ssid, len);
|
||||
ap->ssid[len] = '\0';
|
||||
ap->ssid_len = len;
|
||||
}
|
||||
|
||||
os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
|
||||
len = 0;
|
||||
if (elems->supp_rates) {
|
||||
len = elems->supp_rates_len;
|
||||
if (len > WLAN_SUPP_RATES_MAX)
|
||||
len = WLAN_SUPP_RATES_MAX;
|
||||
os_memcpy(ap->supported_rates, elems->supp_rates, len);
|
||||
}
|
||||
if (elems->ext_supp_rates) {
|
||||
int len2;
|
||||
if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
|
||||
len2 = WLAN_SUPP_RATES_MAX - len;
|
||||
else
|
||||
len2 = elems->ext_supp_rates_len;
|
||||
os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
|
||||
len2);
|
||||
}
|
||||
|
||||
ap->wpa = elems->wpa_ie != NULL;
|
||||
|
||||
if (elems->erp_info && elems->erp_info_len == 1)
|
||||
ap->erp = elems->erp_info[0];
|
||||
else
|
||||
ap->erp = -1;
|
||||
|
||||
if (elems->ds_params && elems->ds_params_len == 1)
|
||||
ap->channel = elems->ds_params[0];
|
||||
else if (fi)
|
||||
ap->channel = fi->channel;
|
||||
|
||||
ap->num_beacons++;
|
||||
time(&ap->last_beacon);
|
||||
if (fi) {
|
||||
ap->phytype = fi->phytype;
|
||||
ap->ssi_signal = fi->ssi_signal;
|
||||
ap->datarate = fi->datarate;
|
||||
}
|
||||
|
||||
if (new_ap) {
|
||||
if (iface->conf->passive_scan_interval > 0)
|
||||
ap_list_new_ap(iface, ap);
|
||||
} else if (ap != iface->ap_list) {
|
||||
/* move AP entry into the beginning of the list so that the
|
||||
* oldest entry is always in the end of the list */
|
||||
ap_ap_list_del(iface, ap);
|
||||
ap_ap_list_add(iface, ap);
|
||||
}
|
||||
|
||||
if (!iface->olbc &&
|
||||
ap_list_beacon_olbc(iface, ap)) {
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
iface->olbc = 1;
|
||||
wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
|
||||
"protection", MAC2STR(ap->addr));
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_ctx;
|
||||
time_t now;
|
||||
struct ap_info *ap;
|
||||
|
||||
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
|
||||
|
||||
if (!iface->ap_list)
|
||||
return;
|
||||
|
||||
time(&now);
|
||||
|
||||
/* FIX: it looks like jkm-Purina ended up in busy loop in this
|
||||
* function. Apparently, something can still cause a loop in the AP
|
||||
* list.. */
|
||||
|
||||
while (iface->ap_list) {
|
||||
ap = iface->ap_list->prev;
|
||||
if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
|
||||
now)
|
||||
break;
|
||||
|
||||
if (iface->conf->passive_scan_interval > 0)
|
||||
ap_list_expired_ap(iface, ap);
|
||||
ap_free_ap(iface, ap);
|
||||
}
|
||||
|
||||
if (iface->olbc) {
|
||||
int olbc = 0;
|
||||
ap = iface->ap_list;
|
||||
while (ap) {
|
||||
if (ap_list_beacon_olbc(iface, ap)) {
|
||||
olbc = 1;
|
||||
break;
|
||||
}
|
||||
ap = ap->next;
|
||||
}
|
||||
if (!olbc) {
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
|
||||
iface->olbc = 0;
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ap_list_init(struct hostapd_iface *iface)
|
||||
{
|
||||
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ap_list_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
eloop_cancel_timeout(ap_list_timer, iface, NULL);
|
||||
hostapd_free_aps(iface);
|
||||
}
|
||||
|
||||
|
||||
int ap_list_reconfig(struct hostapd_iface *iface,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
time_t now;
|
||||
struct ap_info *ap;
|
||||
|
||||
if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
|
||||
iface->conf->ap_table_expiration_time ==
|
||||
oldconf->ap_table_expiration_time)
|
||||
return 0;
|
||||
|
||||
time(&now);
|
||||
|
||||
while (iface->ap_list) {
|
||||
ap = iface->ap_list->prev;
|
||||
if (iface->num_ap <= iface->conf->ap_table_max_size &&
|
||||
ap->last_beacon + iface->conf->ap_table_expiration_time >=
|
||||
now)
|
||||
break;
|
||||
|
||||
if (iface->conf->passive_scan_interval > 0)
|
||||
ap_list_expired_ap(iface, iface->ap_list->prev);
|
||||
ap_free_ap(iface, iface->ap_list->prev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* hostapd / AP table
|
||||
* Copyright 2002-2003, Jouni Malinen <j@w1.fi>
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2006, Devicescape Software, 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.
|
||||
*/
|
||||
|
||||
#ifndef AP_LIST_H
|
||||
#define AP_LIST_H
|
||||
|
||||
struct ap_info {
|
||||
/* Note: next/prev pointers are updated whenever a new beacon is
|
||||
* received because these are used to find the least recently used
|
||||
* entries. iter_next/iter_prev are updated only when adding new BSSes
|
||||
* and when removing old ones. These should be used when iterating
|
||||
* through the table in a manner that allows beacons to be received
|
||||
* during the iteration. */
|
||||
struct ap_info *next; /* next entry in AP list */
|
||||
struct ap_info *prev; /* previous entry in AP list */
|
||||
struct ap_info *hnext; /* next entry in hash table list */
|
||||
struct ap_info *iter_next; /* next entry in AP iteration list */
|
||||
struct ap_info *iter_prev; /* previous entry in AP iteration list */
|
||||
u8 addr[6];
|
||||
u16 beacon_int;
|
||||
u16 capability;
|
||||
u8 supported_rates[WLAN_SUPP_RATES_MAX];
|
||||
u8 ssid[33];
|
||||
size_t ssid_len;
|
||||
int wpa;
|
||||
int erp; /* ERP Info or -1 if ERP info element not present */
|
||||
|
||||
int phytype; /* .11a / .11b / .11g / Atheros Turbo */
|
||||
int channel;
|
||||
int datarate; /* in 100 kbps */
|
||||
int ssi_signal;
|
||||
|
||||
unsigned int num_beacons; /* number of beacon frames received */
|
||||
time_t last_beacon;
|
||||
|
||||
int already_seen; /* whether API call AP-NEW has already fetched
|
||||
* information about this AP */
|
||||
};
|
||||
|
||||
struct ieee802_11_elems;
|
||||
struct hostapd_frame_info;
|
||||
|
||||
struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta);
|
||||
int ap_ap_for_each(struct hostapd_iface *iface,
|
||||
int (*func)(struct ap_info *s, void *data), void *data);
|
||||
void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct hostapd_frame_info *fi);
|
||||
int ap_list_init(struct hostapd_iface *iface);
|
||||
void ap_list_deinit(struct hostapd_iface *iface);
|
||||
int ap_list_reconfig(struct hostapd_iface *iface,
|
||||
struct hostapd_config *oldconf);
|
||||
|
||||
#endif /* AP_LIST_H */
|
@ -0,0 +1,418 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
|
||||
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2008, 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"
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "wpa.h"
|
||||
#include "wme.h"
|
||||
#include "beacon.h"
|
||||
#include "hw_features.h"
|
||||
#include "driver.h"
|
||||
#include "sta_info.h"
|
||||
#include "ieee802_11h.h"
|
||||
|
||||
|
||||
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
|
||||
{
|
||||
u8 erp = 0;
|
||||
|
||||
if (hapd->iface->current_mode == NULL ||
|
||||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
|
||||
return 0;
|
||||
|
||||
switch (hapd->iconf->cts_protection_type) {
|
||||
case CTS_PROTECTION_FORCE_ENABLED:
|
||||
erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
|
||||
break;
|
||||
case CTS_PROTECTION_FORCE_DISABLED:
|
||||
erp = 0;
|
||||
break;
|
||||
case CTS_PROTECTION_AUTOMATIC:
|
||||
if (hapd->iface->olbc)
|
||||
erp |= ERP_INFO_USE_PROTECTION;
|
||||
/* continue */
|
||||
case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
|
||||
if (hapd->iface->num_sta_non_erp > 0) {
|
||||
erp |= ERP_INFO_NON_ERP_PRESENT |
|
||||
ERP_INFO_USE_PROTECTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (hapd->iface->num_sta_no_short_preamble > 0)
|
||||
erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
|
||||
|
||||
return erp;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
*eid++ = WLAN_EID_DS_PARAMS;
|
||||
*eid++ = 1;
|
||||
*eid++ = hapd->iconf->channel;
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
if (hapd->iface->current_mode == NULL ||
|
||||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
|
||||
return eid;
|
||||
|
||||
/* Set NonERP_present and use_protection bits if there
|
||||
* are any associated NonERP stations. */
|
||||
/* TODO: use_protection bit can be set to zero even if
|
||||
* there are NonERP stations present. This optimization
|
||||
* might be useful if NonERP stations are "quiet".
|
||||
* See 802.11g/D6 E-1 for recommended practice.
|
||||
* In addition, Non ERP present might be set, if AP detects Non ERP
|
||||
* operation on other APs. */
|
||||
|
||||
/* Add ERP Information element */
|
||||
*eid++ = WLAN_EID_ERP_INFO;
|
||||
*eid++ = 1;
|
||||
*eid++ = ieee802_11_erp_info(hapd);
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
|
||||
int max_len)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
|
||||
if ((!hapd->iconf->ieee80211d && !hapd->iface->dfs_enable) ||
|
||||
max_len < 6)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_COUNTRY;
|
||||
pos++; /* length will be set later */
|
||||
os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
|
||||
pos += 3;
|
||||
|
||||
if ((pos - eid) & 1)
|
||||
*pos++ = 0; /* pad for 16-bit alignment */
|
||||
|
||||
eid[1] = (pos - eid) - 2;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_power_constraint(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
{
|
||||
if (!hapd->iface->dfs_enable)
|
||||
return eid;
|
||||
*eid++ = WLAN_EID_PWR_CONSTRAINT;
|
||||
*eid++ = 1;
|
||||
*eid++ = hapd->iface->pwr_const;
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_tpc_report(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
{
|
||||
if (!hapd->iface->dfs_enable)
|
||||
return eid;
|
||||
*eid++ = WLAN_EID_TPC_REPORT;
|
||||
*eid++ = 2;
|
||||
*eid++ = hapd->iface->tx_power; /* TX POWER */
|
||||
*eid++ = 0; /* Link Margin */
|
||||
return eid;
|
||||
}
|
||||
|
||||
static u8 * hostapd_eid_channel_switch(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
{
|
||||
if (!hapd->iface->dfs_enable || !hapd->iface->channel_switch)
|
||||
return eid;
|
||||
*eid++ = WLAN_EID_CHANNEL_SWITCH;
|
||||
*eid++ = 3;
|
||||
*eid++ = CHAN_SWITCH_MODE_QUIET;
|
||||
*eid++ = hapd->iface->channel_switch; /* New channel */
|
||||
/* 0 - very soon; 1 - before next TBTT; num - after num beacons */
|
||||
*eid++ = 0;
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
|
||||
ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
|
||||
if (ie == NULL || ielen > len)
|
||||
return eid;
|
||||
|
||||
os_memcpy(eid, ie, ielen);
|
||||
return eid + ielen;
|
||||
}
|
||||
|
||||
|
||||
void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_mgmt *resp;
|
||||
struct ieee802_11_elems elems;
|
||||
char *ssid;
|
||||
u8 *pos, *epos, *ie;
|
||||
size_t ssid_len, ie_len;
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
ie = mgmt->u.probe_req.variable;
|
||||
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
|
||||
|
||||
if (!hapd->iconf->send_probe_response)
|
||||
return;
|
||||
|
||||
if (ieee802_11_parse_elems(hapd, ie, ie_len, &elems, 0) == ParseFailed)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
|
||||
MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
ssid = NULL;
|
||||
ssid_len = 0;
|
||||
|
||||
if ((!elems.ssid || !elems.supp_rates)) {
|
||||
wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
|
||||
"without SSID or supported rates element",
|
||||
MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
|
||||
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
|
||||
"broadcast SSID ignored", MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
|
||||
if (elems.ssid_len == 0 ||
|
||||
(elems.ssid_len == hapd->conf->ssid.ssid_len &&
|
||||
os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
|
||||
0)) {
|
||||
ssid = hapd->conf->ssid.ssid;
|
||||
ssid_len = hapd->conf->ssid.ssid_len;
|
||||
if (sta)
|
||||
sta->ssid_probe = &hapd->conf->ssid;
|
||||
}
|
||||
|
||||
if (!ssid) {
|
||||
if (!(mgmt->da[0] & 0x01)) {
|
||||
char ssid_txt[33];
|
||||
ieee802_11_print_ssid(ssid_txt, elems.ssid,
|
||||
elems.ssid_len);
|
||||
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
|
||||
" for foreign SSID '%s'",
|
||||
MAC2STR(mgmt->sa), ssid_txt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: verify that supp_rates contains at least one matching rate
|
||||
* with AP configuration */
|
||||
#define MAX_PROBERESP_LEN 768
|
||||
resp = os_zalloc(MAX_PROBERESP_LEN);
|
||||
if (resp == NULL)
|
||||
return;
|
||||
epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
|
||||
|
||||
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_PROBE_RESP);
|
||||
os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
|
||||
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
|
||||
|
||||
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
|
||||
resp->u.probe_resp.beacon_int =
|
||||
host_to_le16(hapd->iconf->beacon_int);
|
||||
|
||||
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||
resp->u.probe_resp.capab_info =
|
||||
host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
|
||||
|
||||
pos = resp->u.probe_resp.variable;
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = ssid_len;
|
||||
os_memcpy(pos, ssid, ssid_len);
|
||||
pos += ssid_len;
|
||||
|
||||
/* Supported rates */
|
||||
pos = hostapd_eid_supp_rates(hapd, pos);
|
||||
|
||||
/* DS Params */
|
||||
pos = hostapd_eid_ds_params(hapd, pos);
|
||||
|
||||
pos = hostapd_eid_country(hapd, pos, epos - pos);
|
||||
|
||||
pos = hostapd_eid_power_constraint(hapd, pos);
|
||||
pos = hostapd_eid_tpc_report(hapd, pos);
|
||||
|
||||
/* ERP Information element */
|
||||
pos = hostapd_eid_erp_info(hapd, pos);
|
||||
|
||||
/* Extended supported rates */
|
||||
pos = hostapd_eid_ext_supp_rates(hapd, pos);
|
||||
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
|
||||
|
||||
/* Wi-Fi Wireless Multimedia Extensions */
|
||||
if (hapd->conf->wme_enabled)
|
||||
pos = hostapd_eid_wme(hapd, pos);
|
||||
|
||||
if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0)
|
||||
perror("handle_probe_req: send");
|
||||
|
||||
os_free(resp);
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
|
||||
"SSID", MAC2STR(mgmt->sa),
|
||||
elems.ssid_len == 0 ? "broadcast" : "our");
|
||||
}
|
||||
|
||||
|
||||
void ieee802_11_set_beacon(struct hostapd_data *hapd)
|
||||
{
|
||||
struct ieee80211_mgmt *head;
|
||||
u8 *pos, *tail, *tailpos;
|
||||
int preamble;
|
||||
u16 capab_info;
|
||||
size_t head_len, tail_len;
|
||||
int cts_protection = ((ieee802_11_erp_info(hapd) &
|
||||
ERP_INFO_USE_PROTECTION) ? 1 : 0);
|
||||
|
||||
#define BEACON_HEAD_BUF_SIZE 256
|
||||
#define BEACON_TAIL_BUF_SIZE 512
|
||||
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
|
||||
tailpos = tail = os_malloc(BEACON_TAIL_BUF_SIZE);
|
||||
if (head == NULL || tail == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set beacon data");
|
||||
os_free(head);
|
||||
os_free(tail);
|
||||
return;
|
||||
}
|
||||
|
||||
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_BEACON);
|
||||
head->duration = host_to_le16(0);
|
||||
os_memset(head->da, 0xff, ETH_ALEN);
|
||||
|
||||
os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
|
||||
head->u.beacon.beacon_int =
|
||||
host_to_le16(hapd->iconf->beacon_int);
|
||||
|
||||
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||
capab_info = hostapd_own_capab_info(hapd, NULL, 0);
|
||||
head->u.beacon.capab_info = host_to_le16(capab_info);
|
||||
pos = &head->u.beacon.variable[0];
|
||||
|
||||
/* SSID */
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
if (hapd->conf->ignore_broadcast_ssid == 2) {
|
||||
/* clear the data, but keep the correct length of the SSID */
|
||||
*pos++ = hapd->conf->ssid.ssid_len;
|
||||
os_memset(pos, 0, hapd->conf->ssid.ssid_len);
|
||||
pos += hapd->conf->ssid.ssid_len;
|
||||
} else if (hapd->conf->ignore_broadcast_ssid) {
|
||||
*pos++ = 0; /* empty SSID */
|
||||
} else {
|
||||
*pos++ = hapd->conf->ssid.ssid_len;
|
||||
os_memcpy(pos, hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len);
|
||||
pos += hapd->conf->ssid.ssid_len;
|
||||
}
|
||||
|
||||
/* Supported rates */
|
||||
pos = hostapd_eid_supp_rates(hapd, pos);
|
||||
|
||||
/* DS Params */
|
||||
pos = hostapd_eid_ds_params(hapd, pos);
|
||||
|
||||
head_len = pos - (u8 *) head;
|
||||
|
||||
tailpos = hostapd_eid_country(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE - tailpos);
|
||||
|
||||
tailpos = hostapd_eid_power_constraint(hapd, tailpos);
|
||||
tailpos = hostapd_eid_channel_switch(hapd, tailpos);
|
||||
tailpos = hostapd_eid_tpc_report(hapd, tailpos);
|
||||
|
||||
/* ERP Information element */
|
||||
tailpos = hostapd_eid_erp_info(hapd, tailpos);
|
||||
|
||||
/* Extended supported rates */
|
||||
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
|
||||
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos, NULL);
|
||||
|
||||
/* Wi-Fi Wireless Multimedia Extensions */
|
||||
if (hapd->conf->wme_enabled)
|
||||
tailpos = hostapd_eid_wme(hapd, tailpos);
|
||||
|
||||
tail_len = tailpos > tail ? tailpos - tail : 0;
|
||||
|
||||
if (hostapd_set_beacon(hapd->conf->iface, hapd, (u8 *) head, head_len,
|
||||
tail, tail_len))
|
||||
wpa_printf(MSG_ERROR, "Failed to set beacon head/tail");
|
||||
|
||||
os_free(tail);
|
||||
os_free(head);
|
||||
|
||||
if (hostapd_set_cts_protect(hapd, cts_protection))
|
||||
wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
|
||||
"driver");
|
||||
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
|
||||
hostapd_set_short_slot_time(hapd,
|
||||
hapd->iface->num_sta_no_short_slot_time
|
||||
> 0 ? 0 : 1))
|
||||
wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
|
||||
"in kernel driver");
|
||||
|
||||
if (hapd->iface->num_sta_no_short_preamble == 0 &&
|
||||
hapd->iconf->preamble == SHORT_PREAMBLE)
|
||||
preamble = SHORT_PREAMBLE;
|
||||
else
|
||||
preamble = LONG_PREAMBLE;
|
||||
if (hostapd_set_preamble(hapd, preamble))
|
||||
wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
|
||||
"driver");
|
||||
}
|
||||
|
||||
|
||||
void ieee802_11_set_beacons(struct hostapd_iface *iface)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
ieee802_11_set_beacon(iface->bss[i]);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
|
||||
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||
* Copyright (c) 2005-2006, Devicescape Software, 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.
|
||||
*/
|
||||
|
||||
#ifndef BEACON_H
|
||||
#define BEACON_H
|
||||
|
||||
void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
|
||||
size_t len);
|
||||
void ieee802_11_set_beacon(struct hostapd_data *hapd);
|
||||
void ieee802_11_set_beacons(struct hostapd_iface *iface);
|
||||
|
||||
#endif /* BEACON_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* hostapd / Configuration file
|
||||
* Copyright (c) 2003-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.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include "defs.h"
|
||||
#include "ip_addr.h"
|
||||
#include "wpa_common.h"
|
||||
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
|
||||
typedef u8 macaddr[ETH_ALEN];
|
||||
|
||||
struct hostapd_radius_servers;
|
||||
struct ft_remote_r0kh;
|
||||
struct ft_remote_r1kh;
|
||||
|
||||
#define HOSTAPD_MAX_SSID_LEN 32
|
||||
|
||||
#define NUM_WEP_KEYS 4
|
||||
struct hostapd_wep_keys {
|
||||
u8 idx;
|
||||
u8 *key[NUM_WEP_KEYS];
|
||||
size_t len[NUM_WEP_KEYS];
|
||||
int keys_set;
|
||||
size_t default_len; /* key length used for dynamic key generation */
|
||||
};
|
||||
|
||||
typedef enum hostap_security_policy {
|
||||
SECURITY_PLAINTEXT = 0,
|
||||
SECURITY_STATIC_WEP = 1,
|
||||
SECURITY_IEEE_802_1X = 2,
|
||||
SECURITY_WPA_PSK = 3,
|
||||
SECURITY_WPA = 4
|
||||
} secpolicy;
|
||||
|
||||
struct hostapd_ssid {
|
||||
char ssid[HOSTAPD_MAX_SSID_LEN + 1];
|
||||
size_t ssid_len;
|
||||
int ssid_set;
|
||||
|
||||
char vlan[IFNAMSIZ + 1];
|
||||
secpolicy security_policy;
|
||||
|
||||
struct hostapd_wpa_psk *wpa_psk;
|
||||
char *wpa_passphrase;
|
||||
char *wpa_psk_file;
|
||||
|
||||
struct hostapd_wep_keys wep;
|
||||
|
||||
#define DYNAMIC_VLAN_DISABLED 0
|
||||
#define DYNAMIC_VLAN_OPTIONAL 1
|
||||
#define DYNAMIC_VLAN_REQUIRED 2
|
||||
int dynamic_vlan;
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
char *vlan_tagged_interface;
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
struct hostapd_wep_keys **dyn_vlan_keys;
|
||||
size_t max_dyn_vlan_keys;
|
||||
};
|
||||
|
||||
|
||||
#define VLAN_ID_WILDCARD -1
|
||||
|
||||
struct hostapd_vlan {
|
||||
struct hostapd_vlan *next;
|
||||
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int dynamic_vlan;
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
|
||||
#define DVLAN_CLEAN_BR 0x1
|
||||
#define DVLAN_CLEAN_VLAN 0x2
|
||||
#define DVLAN_CLEAN_VLAN_PORT 0x4
|
||||
#define DVLAN_CLEAN_WLAN_PORT 0x8
|
||||
int clean;
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
};
|
||||
|
||||
#define PMK_LEN 32
|
||||
struct hostapd_wpa_psk {
|
||||
struct hostapd_wpa_psk *next;
|
||||
int group;
|
||||
u8 psk[PMK_LEN];
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
#define EAP_USER_MAX_METHODS 8
|
||||
struct hostapd_eap_user {
|
||||
struct hostapd_eap_user *next;
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
struct {
|
||||
int vendor;
|
||||
u32 method;
|
||||
} methods[EAP_USER_MAX_METHODS];
|
||||
u8 *password;
|
||||
size_t password_len;
|
||||
int phase2;
|
||||
int force_version;
|
||||
unsigned int wildcard_prefix:1;
|
||||
unsigned int password_hash:1; /* whether password is hashed with
|
||||
* nt_password_hash() */
|
||||
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
||||
};
|
||||
|
||||
|
||||
#define NUM_TX_QUEUES 8
|
||||
|
||||
struct hostapd_tx_queue_params {
|
||||
int aifs;
|
||||
int cwmin;
|
||||
int cwmax;
|
||||
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
|
||||
int configured;
|
||||
};
|
||||
|
||||
struct hostapd_wme_ac_params {
|
||||
int cwmin;
|
||||
int cwmax;
|
||||
int aifs;
|
||||
int txopLimit; /* in units of 32us */
|
||||
int admission_control_mandatory;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct hostapd_bss_config - Per-BSS configuration
|
||||
*/
|
||||
struct hostapd_bss_config {
|
||||
char iface[IFNAMSIZ + 1];
|
||||
char bridge[IFNAMSIZ + 1];
|
||||
|
||||
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
|
||||
|
||||
unsigned int logger_syslog; /* module bitfield */
|
||||
unsigned int logger_stdout; /* module bitfield */
|
||||
|
||||
char *dump_log_name; /* file name for state dump (SIGUSR1) */
|
||||
|
||||
int max_num_sta; /* maximum number of STAs in station table */
|
||||
|
||||
int dtim_period;
|
||||
|
||||
int ieee802_1x; /* use IEEE 802.1X */
|
||||
int eapol_version;
|
||||
int eap_server; /* Use internal EAP server instead of external
|
||||
* RADIUS server */
|
||||
struct hostapd_eap_user *eap_user;
|
||||
char *eap_sim_db;
|
||||
struct hostapd_ip_addr own_ip_addr;
|
||||
char *nas_identifier;
|
||||
struct hostapd_radius_servers *radius;
|
||||
|
||||
struct hostapd_ssid ssid;
|
||||
|
||||
char *eap_req_id_text; /* optional displayable message sent with
|
||||
* EAP Request-Identity */
|
||||
size_t eap_req_id_text_len;
|
||||
int eapol_key_index_workaround;
|
||||
|
||||
size_t default_wep_key_len;
|
||||
int individual_wep_key_len;
|
||||
int wep_rekeying_period;
|
||||
int broadcast_key_idx_min, broadcast_key_idx_max;
|
||||
int eap_reauth_period;
|
||||
|
||||
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
|
||||
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
|
||||
* frames */
|
||||
|
||||
u8 assoc_ap_addr[ETH_ALEN];
|
||||
int assoc_ap; /* whether assoc_ap_addr is set */
|
||||
|
||||
enum {
|
||||
ACCEPT_UNLESS_DENIED = 0,
|
||||
DENY_UNLESS_ACCEPTED = 1,
|
||||
USE_EXTERNAL_RADIUS_AUTH = 2
|
||||
} macaddr_acl;
|
||||
macaddr *accept_mac;
|
||||
int num_accept_mac;
|
||||
macaddr *deny_mac;
|
||||
int num_deny_mac;
|
||||
|
||||
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
|
||||
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
|
||||
|
||||
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
|
||||
int wpa_key_mgmt;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
enum {
|
||||
NO_IEEE80211W = 0,
|
||||
IEEE80211W_OPTIONAL = 1,
|
||||
IEEE80211W_REQUIRED = 2
|
||||
} ieee80211w;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
int wpa_pairwise;
|
||||
int wpa_group;
|
||||
int wpa_group_rekey;
|
||||
int wpa_strict_rekey;
|
||||
int wpa_gmk_rekey;
|
||||
int rsn_pairwise;
|
||||
int rsn_preauth;
|
||||
char *rsn_preauth_interfaces;
|
||||
int peerkey;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
/* IEEE 802.11r - Fast BSS Transition */
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 r1_key_holder[FT_R1KH_ID_LEN];
|
||||
u32 r0_key_lifetime;
|
||||
u32 reassociation_deadline;
|
||||
struct ft_remote_r0kh *r0kh_list;
|
||||
struct ft_remote_r1kh *r1kh_list;
|
||||
int pmk_r1_push;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||
gid_t ctrl_interface_gid;
|
||||
int ctrl_interface_gid_set;
|
||||
|
||||
char *ca_cert;
|
||||
char *server_cert;
|
||||
char *private_key;
|
||||
char *private_key_passwd;
|
||||
int check_crl;
|
||||
char *dh_file;
|
||||
u8 *pac_opaque_encr_key;
|
||||
char *eap_fast_a_id;
|
||||
int eap_sim_aka_result_ind;
|
||||
|
||||
char *radius_server_clients;
|
||||
int radius_server_auth_port;
|
||||
int radius_server_ipv6;
|
||||
|
||||
char *test_socket; /* UNIX domain socket path for driver_test */
|
||||
|
||||
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
|
||||
* address instead of individual address
|
||||
* (for driver_wired.c).
|
||||
*/
|
||||
|
||||
int ap_max_inactivity;
|
||||
int ignore_broadcast_ssid;
|
||||
|
||||
int wme_enabled;
|
||||
|
||||
struct hostapd_vlan *vlan, *vlan_tail;
|
||||
|
||||
macaddr bssid;
|
||||
};
|
||||
|
||||
|
||||
typedef enum {
|
||||
HOSTAPD_MODE_IEEE80211B,
|
||||
HOSTAPD_MODE_IEEE80211G,
|
||||
HOSTAPD_MODE_IEEE80211A,
|
||||
NUM_HOSTAPD_MODES
|
||||
} hostapd_hw_mode;
|
||||
|
||||
|
||||
/**
|
||||
* struct hostapd_config - Per-radio interface configuration
|
||||
*/
|
||||
struct hostapd_config {
|
||||
struct hostapd_bss_config *bss, *last_bss;
|
||||
struct hostapd_radius_servers *radius;
|
||||
size_t num_bss;
|
||||
|
||||
u16 beacon_int;
|
||||
int rts_threshold;
|
||||
int fragm_threshold;
|
||||
u8 send_probe_response;
|
||||
u8 channel;
|
||||
hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||
enum {
|
||||
LONG_PREAMBLE = 0,
|
||||
SHORT_PREAMBLE = 1
|
||||
} preamble;
|
||||
enum {
|
||||
CTS_PROTECTION_AUTOMATIC = 0,
|
||||
CTS_PROTECTION_FORCE_ENABLED = 1,
|
||||
CTS_PROTECTION_FORCE_DISABLED = 2,
|
||||
CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
|
||||
} cts_protection_type;
|
||||
|
||||
int *supported_rates;
|
||||
int *basic_rates;
|
||||
|
||||
const struct wpa_driver_ops *driver;
|
||||
|
||||
int passive_scan_interval; /* seconds, 0 = disabled */
|
||||
int passive_scan_listen; /* usec */
|
||||
int passive_scan_mode;
|
||||
int ap_table_max_size;
|
||||
int ap_table_expiration_time;
|
||||
|
||||
char country[3]; /* first two octets: country code as described in
|
||||
* ISO/IEC 3166-1. Third octet:
|
||||
* ' ' (ascii 32): all environments
|
||||
* 'O': Outdoor environemnt only
|
||||
* 'I': Indoor environment only
|
||||
*/
|
||||
|
||||
int ieee80211d;
|
||||
unsigned int ieee80211h; /* Enable/Disable 80211h */
|
||||
|
||||
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
|
||||
|
||||
/*
|
||||
* WME 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];
|
||||
|
||||
enum {
|
||||
INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
|
||||
INTERNAL_BRIDGE_DISABLED = 0,
|
||||
INTERNAL_BRIDGE_ENABLED = 1
|
||||
} bridge_packets;
|
||||
};
|
||||
|
||||
|
||||
int hostapd_mac_comp(const void *a, const void *b);
|
||||
int hostapd_mac_comp_empty(const void *a);
|
||||
struct hostapd_config * hostapd_config_read(const char *fname);
|
||||
void hostapd_config_free(struct hostapd_config *conf);
|
||||
int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr);
|
||||
int hostapd_rate_found(int *list, int rate);
|
||||
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
|
||||
struct hostapd_wep_keys *b);
|
||||
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
const u8 *addr, const u8 *prev_psk);
|
||||
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
|
||||
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
|
||||
int vlan_id);
|
||||
const struct hostapd_eap_user *
|
||||
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
|
||||
size_t identity_len, int phase2);
|
||||
|
||||
#endif /* CONFIG_H */
|
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* hostapd / UNIX domain socket -based control interface
|
||||
* Copyright (c) 2004-2008, 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"
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "eloop.h"
|
||||
#include "config.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "wpa.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "ctrl_iface.h"
|
||||
#include "sta_info.h"
|
||||
#include "accounting.h"
|
||||
|
||||
|
||||
struct wpa_ctrl_dst {
|
||||
struct wpa_ctrl_dst *next;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
int debug_level;
|
||||
int errors;
|
||||
};
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
|
||||
struct sockaddr_un *from,
|
||||
socklen_t fromlen)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst;
|
||||
|
||||
dst = os_zalloc(sizeof(*dst));
|
||||
if (dst == NULL)
|
||||
return -1;
|
||||
os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
|
||||
dst->addrlen = fromlen;
|
||||
dst->debug_level = MSG_INFO;
|
||||
dst->next = hapd->ctrl_dst;
|
||||
hapd->ctrl_dst = dst;
|
||||
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
|
||||
(u8 *) from->sun_path, fromlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
|
||||
struct sockaddr_un *from,
|
||||
socklen_t fromlen)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst, *prev = NULL;
|
||||
|
||||
dst = hapd->ctrl_dst;
|
||||
while (dst) {
|
||||
if (fromlen == dst->addrlen &&
|
||||
os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
prev = dst;
|
||||
dst = dst->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
|
||||
struct sockaddr_un *from,
|
||||
socklen_t fromlen,
|
||||
char *level)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
|
||||
|
||||
dst = hapd->ctrl_dst;
|
||||
while (dst) {
|
||||
if (fromlen == dst->addrlen &&
|
||||
os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
|
||||
0) {
|
||||
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
|
||||
"level", (u8 *) from->sun_path, fromlen);
|
||||
dst->debug_level = atoi(level);
|
||||
return 0;
|
||||
}
|
||||
dst = dst->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
int len, res, ret;
|
||||
|
||||
if (sta == NULL) {
|
||||
ret = os_snprintf(buf, buflen, "FAIL\n");
|
||||
if (ret < 0 || (size_t) ret >= buflen)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
|
||||
MAC2STR(sta->addr));
|
||||
if (ret < 0 || (size_t) ret >= buflen - len)
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
|
||||
const char *txtaddr,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
int ret;
|
||||
|
||||
if (hwaddr_aton(txtaddr, addr)) {
|
||||
ret = os_snprintf(buf, buflen, "FAIL\n");
|
||||
if (ret < 0 || (size_t) ret >= buflen)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
|
||||
buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
|
||||
const char *txtaddr,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
if (hwaddr_aton(txtaddr, addr) ||
|
||||
(sta = ap_get_sta(hapd, addr)) == NULL) {
|
||||
ret = os_snprintf(buf, buflen, "FAIL\n");
|
||||
if (ret < 0 || (size_t) ret >= buflen)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
|
||||
const char *txtaddr)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
|
||||
|
||||
if (hwaddr_aton(txtaddr, addr))
|
||||
return -1;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
|
||||
"notification", MAC2STR(addr));
|
||||
sta = ap_sta_add(hapd, addr);
|
||||
if (sta == NULL)
|
||||
return -1;
|
||||
|
||||
hostapd_new_assoc_sta(hapd, sta, 0);
|
||||
accounting_sta_get_id(hapd, sta);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||
void *sock_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
char buf[256];
|
||||
int res;
|
||||
struct sockaddr_un from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
char *reply;
|
||||
const int reply_size = 4096;
|
||||
int reply_len;
|
||||
|
||||
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
|
||||
(struct sockaddr *) &from, &fromlen);
|
||||
if (res < 0) {
|
||||
perror("recvfrom(ctrl_iface)");
|
||||
return;
|
||||
}
|
||||
buf[res] = '\0';
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
|
||||
|
||||
reply = os_malloc(reply_size);
|
||||
if (reply == NULL) {
|
||||
sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
|
||||
fromlen);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(reply, "OK\n", 3);
|
||||
reply_len = 3;
|
||||
|
||||
if (os_strcmp(buf, "PING") == 0) {
|
||||
os_memcpy(reply, "PONG\n", 5);
|
||||
reply_len = 5;
|
||||
} else if (os_strcmp(buf, "MIB") == 0) {
|
||||
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
|
||||
if (reply_len >= 0) {
|
||||
res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
|
||||
reply_size - reply_len);
|
||||
if (res < 0)
|
||||
reply_len = -1;
|
||||
else
|
||||
reply_len += res;
|
||||
}
|
||||
if (reply_len >= 0) {
|
||||
res = ieee802_1x_get_mib(hapd, reply + reply_len,
|
||||
reply_size - reply_len);
|
||||
if (res < 0)
|
||||
reply_len = -1;
|
||||
else
|
||||
reply_len += res;
|
||||
}
|
||||
if (reply_len >= 0) {
|
||||
res = radius_client_get_mib(hapd->radius,
|
||||
reply + reply_len,
|
||||
reply_size - reply_len);
|
||||
if (res < 0)
|
||||
reply_len = -1;
|
||||
else
|
||||
reply_len += res;
|
||||
}
|
||||
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
|
||||
reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
|
||||
reply_size);
|
||||
} else if (os_strncmp(buf, "STA ", 4) == 0) {
|
||||
reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
|
||||
reply_size);
|
||||
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
|
||||
reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
|
||||
reply_size);
|
||||
} else if (os_strcmp(buf, "ATTACH") == 0) {
|
||||
if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "DETACH") == 0) {
|
||||
if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
|
||||
if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
|
||||
buf + 6))
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
|
||||
if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
|
||||
reply_len = -1;
|
||||
} else {
|
||||
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
||||
reply_len = 16;
|
||||
}
|
||||
|
||||
if (reply_len < 0) {
|
||||
os_memcpy(reply, "FAIL\n", 5);
|
||||
reply_len = 5;
|
||||
}
|
||||
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
|
||||
os_free(reply);
|
||||
}
|
||||
|
||||
|
||||
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
|
||||
{
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
if (hapd->conf->ctrl_interface == NULL)
|
||||
return NULL;
|
||||
|
||||
len = os_strlen(hapd->conf->ctrl_interface) +
|
||||
os_strlen(hapd->conf->iface) + 2;
|
||||
buf = os_malloc(len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
os_snprintf(buf, len, "%s/%s",
|
||||
hapd->conf->ctrl_interface, hapd->conf->iface);
|
||||
buf[len - 1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int s = -1;
|
||||
char *fname = NULL;
|
||||
|
||||
hapd->ctrl_sock = -1;
|
||||
|
||||
if (hapd->conf->ctrl_interface == NULL)
|
||||
return 0;
|
||||
|
||||
if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
wpa_printf(MSG_DEBUG, "Using existing control "
|
||||
"interface directory.");
|
||||
} else {
|
||||
perror("mkdir[ctrl_interface]");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (hapd->conf->ctrl_interface_gid_set &&
|
||||
chown(hapd->conf->ctrl_interface, 0,
|
||||
hapd->conf->ctrl_interface_gid) < 0) {
|
||||
perror("chown[ctrl_interface]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
|
||||
os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
|
||||
goto fail;
|
||||
|
||||
s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket(PF_UNIX)");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
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;
|
||||
}
|
||||
|
||||
if (hapd->conf->ctrl_interface_gid_set &&
|
||||
chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
|
||||
perror("chown[ctrl_interface/ifname]");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
|
||||
perror("chmod[ctrl_interface/ifname]");
|
||||
goto fail;
|
||||
}
|
||||
os_free(fname);
|
||||
|
||||
hapd->ctrl_sock = s;
|
||||
eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (s >= 0)
|
||||
close(s);
|
||||
if (fname) {
|
||||
unlink(fname);
|
||||
os_free(fname);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst, *prev;
|
||||
|
||||
if (hapd->ctrl_sock > -1) {
|
||||
char *fname;
|
||||
eloop_unregister_read_sock(hapd->ctrl_sock);
|
||||
close(hapd->ctrl_sock);
|
||||
hapd->ctrl_sock = -1;
|
||||
fname = hostapd_ctrl_iface_path(hapd);
|
||||
if (fname)
|
||||
unlink(fname);
|
||||
os_free(fname);
|
||||
|
||||
if (hapd->conf->ctrl_interface &&
|
||||
rmdir(hapd->conf->ctrl_interface) < 0) {
|
||||
if (errno == ENOTEMPTY) {
|
||||
wpa_printf(MSG_DEBUG, "Control interface "
|
||||
"directory not empty - leaving it "
|
||||
"behind");
|
||||
} else {
|
||||
perror("rmdir[ctrl_interface]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst = hapd->ctrl_dst;
|
||||
while (dst) {
|
||||
prev = dst;
|
||||
dst = dst->next;
|
||||
os_free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst, *next;
|
||||
struct msghdr msg;
|
||||
int idx;
|
||||
struct iovec io[2];
|
||||
char levelstr[10];
|
||||
|
||||
dst = hapd->ctrl_dst;
|
||||
if (hapd->ctrl_sock < 0 || dst == NULL)
|
||||
return;
|
||||
|
||||
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
|
||||
io[0].iov_base = levelstr;
|
||||
io[0].iov_len = os_strlen(levelstr);
|
||||
io[1].iov_base = buf;
|
||||
io[1].iov_len = len;
|
||||
os_memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = io;
|
||||
msg.msg_iovlen = 2;
|
||||
|
||||
idx = 0;
|
||||
while (dst) {
|
||||
next = dst->next;
|
||||
if (level >= dst->debug_level) {
|
||||
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
|
||||
(u8 *) dst->addr.sun_path, dst->addrlen);
|
||||
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");
|
||||
dst->errors++;
|
||||
if (dst->errors > 10) {
|
||||
hostapd_ctrl_iface_detach(
|
||||
hapd, &dst->addr,
|
||||
dst->addrlen);
|
||||
}
|
||||
} else
|
||||
dst->errors = 0;
|
||||
}
|
||||
idx++;
|
||||
dst = next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* hostapd / UNIX domain socket -based control interface
|
||||
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef CTRL_IFACE_H
|
||||
#define CTRL_IFACE_H
|
||||
|
||||
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
|
||||
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
|
||||
char *buf, size_t len);
|
||||
|
||||
#endif /* CTRL_IFACE_H */
|
@ -0,0 +1,119 @@
|
||||
# Example hostapd build time configuration
|
||||
#
|
||||
# This file lists the configuration options that are used when building the
|
||||
# hostapd binary. All lines starting with # are ignored. Configuration option
|
||||
# lines must be commented out complete, if they are not to be included, i.e.,
|
||||
# just setting VARIABLE=n is not disabling that variable.
|
||||
#
|
||||
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
|
||||
# be modified from here. In most cass, these lines should use += in order not
|
||||
# to override previous values of the variables.
|
||||
|
||||
# Driver interface for Host AP driver
|
||||
CONFIG_DRIVER_HOSTAP=y
|
||||
|
||||
# Driver interface for wired authenticator
|
||||
#CONFIG_DRIVER_WIRED=y
|
||||
|
||||
# Driver interface for madwifi driver
|
||||
#CONFIG_DRIVER_MADWIFI=y
|
||||
#CFLAGS += -I../head # change to reflect local setup; directory for madwifi src
|
||||
|
||||
# Driver interface for Prism54 driver
|
||||
#CONFIG_DRIVER_PRISM54=y
|
||||
|
||||
# Driver interface for drivers using the nl80211 kernel interface
|
||||
#CONFIG_DRIVER_NL80211=y
|
||||
# driver_nl80211.c requires a rather new libnl, probably not
|
||||
# shipped with your distribution yet
|
||||
#LIBNL=/usr/src/libnl
|
||||
#CFLAGS += -I$(LIBNL)/include
|
||||
#LIBS += -L$(LIBNL)/lib
|
||||
|
||||
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
|
||||
#CONFIG_DRIVER_BSD=y
|
||||
#CFLAGS += -I/usr/local/include
|
||||
#LIBS += -L/usr/local/lib
|
||||
|
||||
# IEEE 802.11F/IAPP
|
||||
CONFIG_IAPP=y
|
||||
|
||||
# WPA2/IEEE 802.11i RSN pre-authentication
|
||||
CONFIG_RSN_PREAUTH=y
|
||||
|
||||
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
|
||||
CONFIG_PEERKEY=y
|
||||
|
||||
# IEEE 802.11w (management frame protection)
|
||||
# This version is an experimental implementation based on IEEE 802.11w/D1.0
|
||||
# draft and is subject to change since the standard has not yet been finalized.
|
||||
# Driver support is also needed for IEEE 802.11w.
|
||||
#CONFIG_IEEE80211W=y
|
||||
|
||||
# Integrated EAP server
|
||||
CONFIG_EAP=y
|
||||
|
||||
# EAP-MD5 for the integrated EAP server
|
||||
CONFIG_EAP_MD5=y
|
||||
|
||||
# EAP-TLS for the integrated EAP server
|
||||
CONFIG_EAP_TLS=y
|
||||
|
||||
# EAP-MSCHAPv2 for the integrated EAP server
|
||||
CONFIG_EAP_MSCHAPV2=y
|
||||
|
||||
# EAP-PEAP for the integrated EAP server
|
||||
CONFIG_EAP_PEAP=y
|
||||
|
||||
# EAP-GTC for the integrated EAP server
|
||||
CONFIG_EAP_GTC=y
|
||||
|
||||
# EAP-TTLS for the integrated EAP server
|
||||
CONFIG_EAP_TTLS=y
|
||||
|
||||
# EAP-SIM for the integrated EAP server
|
||||
#CONFIG_EAP_SIM=y
|
||||
|
||||
# EAP-AKA for the integrated EAP server
|
||||
#CONFIG_EAP_AKA=y
|
||||
|
||||
# EAP-PAX for the integrated EAP server
|
||||
#CONFIG_EAP_PAX=y
|
||||
|
||||
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
|
||||
#CONFIG_EAP_PSK=y
|
||||
|
||||
# EAP-SAKE for the integrated EAP server
|
||||
#CONFIG_EAP_SAKE=y
|
||||
|
||||
# EAP-GPSK for the integrated EAP server
|
||||
#CONFIG_EAP_GPSK=y
|
||||
# Include support for optional SHA256 cipher suite in EAP-GPSK
|
||||
#CONFIG_EAP_GPSK_SHA256=y
|
||||
|
||||
# EAP-FAST for the integrated EAP server
|
||||
# Note: Default OpenSSL package does not include support for all the
|
||||
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
|
||||
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
|
||||
# to add the needed functions.
|
||||
#CONFIG_EAP_FAST=y
|
||||
|
||||
# EAP-IKEv2
|
||||
#CONFIG_EAP_IKEV2=y
|
||||
|
||||
# PKCS#12 (PFX) support (used to read private key and certificate file from
|
||||
# a file that usually has extension .p12 or .pfx)
|
||||
CONFIG_PKCS12=y
|
||||
|
||||
# RADIUS authentication server. This provides access to the integrated EAP
|
||||
# server from external hosts using RADIUS.
|
||||
#CONFIG_RADIUS_SERVER=y
|
||||
|
||||
# Build IPv6 support for RADIUS operations
|
||||
CONFIG_IPV6=y
|
||||
|
||||
# IEEE 802.11r/D4.1 (Fast BSS Transition)
|
||||
# This enables an experimental implementation of a draft version of
|
||||
# IEEE 802.11r. This draft is still subject to change, so it should be noted
|
||||
# that this version may not comply with the final standard.
|
||||
#CONFIG_IEEE80211R=y
|
@ -0,0 +1,219 @@
|
||||
Developer notes for hostapd
|
||||
===========================
|
||||
|
||||
hostapd daemon setup, operations, and shutdown
|
||||
----------------------------------------------
|
||||
|
||||
Files: hostapd.[ch]
|
||||
|
||||
Externally called functions:
|
||||
hostapd_new_assoc_sta() is called when a station associates with the AP
|
||||
|
||||
Event loop functions:
|
||||
handle_term() is called on SIGINT and SIGTERM to terminate hostapd process
|
||||
handle_reload() is called on SIGHUP to reload configuration
|
||||
handle_dump_state() is called on SIGUSR1 to dump station state data to a
|
||||
text file
|
||||
hostapd_rotate_wep() is called to periodically change WEP keys
|
||||
|
||||
|
||||
Configuration parsing
|
||||
---------------------
|
||||
|
||||
Configuration file parsing and data structure definition.
|
||||
|
||||
Files: config.[ch]
|
||||
|
||||
Externally called functions:
|
||||
hostapd_config_read() is called to read and parse a configuration file;
|
||||
allocates and returns configuration data structure
|
||||
hostapd_config_free() is called to free configuration data structure
|
||||
hostapd_maclist_found() is called to check whether a given address is found
|
||||
in a list of MAC addresses
|
||||
|
||||
|
||||
Kernel driver access
|
||||
--------------------
|
||||
|
||||
Helper functions for configuring the Host AP kernel driver and
|
||||
accessing data from it.
|
||||
|
||||
Files: driver.[ch]
|
||||
|
||||
|
||||
IEEE 802.11 frame handling (netdevice wlan#ap)
|
||||
----------------------------------------------
|
||||
|
||||
Receive all incoming IEEE 802.11 frames from the kernel driver via
|
||||
wlan#ap interface.
|
||||
|
||||
Files: receive.c
|
||||
|
||||
Externally called functions:
|
||||
hostapd_init_sockets() is called to initialize sockets for receiving and
|
||||
sending IEEE 802.11 frames via wlan#ap interface
|
||||
|
||||
Event loop functions:
|
||||
handle_read() is called for each incoming packet from wlan#ap net device
|
||||
|
||||
|
||||
Station table
|
||||
-------------
|
||||
|
||||
Files: sta_info.[ch], ap.h
|
||||
|
||||
Event loop functions:
|
||||
ap_handle_timer() is called to check station activity and to remove
|
||||
inactive stations
|
||||
|
||||
|
||||
IEEE 802.11 management
|
||||
----------------------
|
||||
|
||||
IEEE 802.11 management frame sending and processing (mainly,
|
||||
authentication and association). IEEE 802.11 station functionality
|
||||
(authenticate and associate with another AP as an station).
|
||||
|
||||
Files: ieee802_11.[ch]
|
||||
|
||||
Externally called functions:
|
||||
ieee802_11_mgmt() is called for each received IEEE 802.11 management frame
|
||||
(from handle_frame() in hostapd.c)
|
||||
ieee802_11_mgmt_cb() is called for each received TX callback of IEEE 802.11
|
||||
management frame (from handle_tx_callback() in hostapd.c)
|
||||
ieee802_11_send_deauth() is called to send deauthentication frame
|
||||
ieee802_11_send_disassoc() is called to send disassociation frame
|
||||
ieee802_11_parse_elems() is used to parse information elements in
|
||||
IEEE 802.11 management frames
|
||||
|
||||
Event loop functions:
|
||||
ieee802_11_sta_authenticate() called to retry authentication (with another
|
||||
AP)
|
||||
ieee802_11_sta_associate() called to retry association (with another AP)
|
||||
|
||||
|
||||
IEEE 802.11 authentication
|
||||
--------------------------
|
||||
|
||||
Access control list for IEEE 802.11 authentication. Uses staticly
|
||||
configured ACL from configuration files or an external RADIUS
|
||||
server. Results from external RADIUS queries are cached to allow
|
||||
faster authentication frame processing.
|
||||
|
||||
Files: ieee802_11_auth.[ch]
|
||||
|
||||
Externally called functions:
|
||||
hostapd_acl_init() called once during hostapd startup
|
||||
hostapd_acl_deinit() called once during hostapd shutdown
|
||||
hostapd_acl_recv_radius() called by IEEE 802.1X code for incoming RADIUS
|
||||
Authentication messages (returns 0 if message was processed)
|
||||
hostapd_allowed_address() called to check whether a specified station can be
|
||||
authenticated
|
||||
|
||||
Event loop functions:
|
||||
hostapd_acl_expire() is called to expire ACL cache entries
|
||||
|
||||
|
||||
IEEE 802.1X Authenticator
|
||||
-------------------------
|
||||
|
||||
Files: ieee802_1x.[ch]
|
||||
|
||||
|
||||
Externally called functions:
|
||||
ieee802_1x_receive() is called for each incoming EAPOL frame from the
|
||||
wireless interface
|
||||
ieee802_1x_new_station() is called to start IEEE 802.1X authentication when
|
||||
a new station completes IEEE 802.11 association
|
||||
|
||||
Event loop functions:
|
||||
ieee802_1x_receive_auth() called for each incoming RADIUS Authentication
|
||||
message
|
||||
|
||||
|
||||
EAPOL state machine
|
||||
-------------------
|
||||
|
||||
IEEE 802.1X state machine for EAPOL.
|
||||
|
||||
Files: eapol_sm.[ch]
|
||||
|
||||
Externally called functions:
|
||||
eapol_sm_step() is called to advance EAPOL state machines after any change
|
||||
that could affect their state
|
||||
|
||||
Event loop functions:
|
||||
eapol_port_timers_tick() called once per second to advance Port Timers state
|
||||
machine
|
||||
|
||||
|
||||
IEEE 802.11f (IAPP)
|
||||
-------------------
|
||||
|
||||
Files: iapp.[ch]
|
||||
|
||||
Externally called functions:
|
||||
iapp_new_station() is called to start accounting session when a new station
|
||||
completes IEEE 802.11 association or IEEE 802.1X authentication
|
||||
|
||||
Event loop functions:
|
||||
iapp_receive_udp() is called for incoming IAPP frames over UDP
|
||||
|
||||
|
||||
Per station accounting
|
||||
----------------------
|
||||
|
||||
Send RADIUS Accounting start and stop messages to a RADIUS Accounting
|
||||
server. Process incoming RADIUS Accounting messages.
|
||||
|
||||
Files: accounting.[ch]
|
||||
|
||||
Externally called functions:
|
||||
accounting_init() called once during hostapd startup
|
||||
accounting_deinit() called once during hostapd shutdown
|
||||
accounting_sta_start() called when a station starts new session
|
||||
accounting_sta_stop() called when a station session is terminated
|
||||
|
||||
Event loop functions:
|
||||
accounting_receive() called for each incoming RADIUS Accounting message
|
||||
accounting_list_timer() called to retransmit accounting messages and to
|
||||
remove expired entries
|
||||
|
||||
|
||||
RADIUS messages
|
||||
---------------
|
||||
|
||||
RADIUS message generation and parsing functions.
|
||||
|
||||
Files: radius.[ch]
|
||||
|
||||
|
||||
Event loop
|
||||
----------
|
||||
|
||||
Event loop for registering timeout calls, signal handlers, and socket
|
||||
read events.
|
||||
|
||||
Files: eloop.[ch]
|
||||
|
||||
|
||||
RC4
|
||||
---
|
||||
|
||||
RC4 encryption
|
||||
|
||||
Files: rc4.[ch]
|
||||
|
||||
|
||||
MD5
|
||||
---
|
||||
|
||||
MD5 hash and HMAC-MD5.
|
||||
|
||||
Files: md5.[ch]
|
||||
|
||||
|
||||
Miscellaneous helper functions
|
||||
------------------------------
|
||||
|
||||
Files: common.[ch]
|
@ -0,0 +1,4 @@
|
||||
html
|
||||
latex
|
||||
hostapd.eps
|
||||
hostapd.png
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
\page code_structure Structure of the source code
|
||||
|
||||
|
||||
*/
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
\page ctrl_iface_page Control interface
|
||||
|
||||
hostapd implements a control interface that can be used by
|
||||
external programs to control the operations of the hostapd
|
||||
daemon and to get status information and event notifications. There is
|
||||
a small C library, in a form of a single C file, wpa_ctrl.c, that
|
||||
provides helper functions to facilitate the use of the control
|
||||
interface. External programs can link this file into them and then use
|
||||
the library functions documented in wpa_ctrl.h to interact with
|
||||
%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
|
||||
is an example program using this library.
|
||||
|
||||
There are multiple mechanisms for inter-process communication. For
|
||||
example, Linux version of hostapd is using UNIX domain sockets for the
|
||||
control interface. The use of the functions defined in wpa_ctrl.h can
|
||||
be used to hide the details of the used IPC from external programs.
|
||||
|
||||
|
||||
\section using_ctrl_iface Using the control interface
|
||||
|
||||
External programs, e.g., a GUI or a configuration utility, that need to
|
||||
communicate with hostapd should link in wpa_ctrl.c. This
|
||||
allows them to use helper functions to open connection to the control
|
||||
interface with wpa_ctrl_open() and to send commands with
|
||||
wpa_ctrl_request().
|
||||
|
||||
hostapd uses the control interface for two types of communication:
|
||||
commands and unsolicited event messages. Commands are a pair of
|
||||
messages, a request from the external program and a response from
|
||||
hostapd. These can be executed using wpa_ctrl_request().
|
||||
Unsolicited event messages are sent by hostapd to the control
|
||||
interface connection without specific request from the external program
|
||||
for receiving each message. However, the external program needs to
|
||||
attach to the control interface with wpa_ctrl_attach() to receive these
|
||||
unsolicited messages.
|
||||
|
||||
If the control interface connection is used both for commands and
|
||||
unsolicited event messages, there is potential for receiving an
|
||||
unsolicited message between the command request and response.
|
||||
wpa_ctrl_request() caller will need to supply a callback, msg_cb,
|
||||
for processing these messages. Often it is easier to open two
|
||||
control interface connections by calling wpa_ctrl_open() twice and
|
||||
then use one of the connections for commands and the other one for
|
||||
unsolicited messages. This way command request/response pairs will
|
||||
not be broken by unsolicited messages. wpa_cli is an example of how
|
||||
to use only one connection for both purposes and wpa_gui demonstrates
|
||||
how to use two separate connections.
|
||||
|
||||
Once the control interface connection is not needed anymore, it should
|
||||
be closed by calling wpa_ctrl_close(). If the connection was used for
|
||||
unsolicited event messages, it should be first detached by calling
|
||||
wpa_ctrl_detach().
|
||||
|
||||
|
||||
\section ctrl_iface_cmds Control interface commands
|
||||
|
||||
Following commands can be used with wpa_ctrl_request():
|
||||
|
||||
\subsection ctrl_iface_PING PING
|
||||
|
||||
This command can be used to test whether hostapd is replying
|
||||
to the control interface commands. The expected reply is \c PONG if the
|
||||
connection is open and hostapd is processing commands.
|
||||
|
||||
*/
|
@ -0,0 +1,233 @@
|
||||
# Doxyfile 1.4.4
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = hostapd
|
||||
PROJECT_NUMBER = 0.5.x
|
||||
OUTPUT_DIRECTORY = doc
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = . \
|
||||
../wpa_supplicant/eap_sim_common.c \
|
||||
../wpa_supplicant/eap_sim_common.h
|
||||
FILE_PATTERNS = *.c *.h *.doxygen
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH = doc
|
||||
INPUT_FILTER = doc/kerneldoc2doxygen.pl
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 3
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
@ -0,0 +1,230 @@
|
||||
# Doxyfile 1.4.1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = hostapd
|
||||
PROJECT_NUMBER = 0.5.x
|
||||
OUTPUT_DIRECTORY = doc
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
FILE_PATTERNS = *.c *.h *.doxygen
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH = doc
|
||||
INPUT_FILTER = kerneldoc2doxygen.pl
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 3
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = YES
|
@ -0,0 +1,20 @@
|
||||
/**
|
||||
\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
|
||||
|
||||
All hardware and driver dependent functionality is in separate C files
|
||||
that implement defined wrapper functions. Other parts
|
||||
of the hostapd are designed to be hardware, driver, and operating
|
||||
system independent.
|
||||
|
||||
Driver wrappers need to implement whatever calls are used in the
|
||||
target operating system/driver for controlling wireless LAN
|
||||
devices. As an example, in case of Linux, these are mostly some glue
|
||||
code and ioctl() calls and netlink message parsing for Linux Wireless
|
||||
Extensions (WE). Since features required for WPA were added only recently to
|
||||
Linux Wireless Extensions (in version 18), some driver specific code is used
|
||||
in number of driver interface implementations. These driver dependent parts
|
||||
can be replaced with generic code in driver_wext.c once the target driver
|
||||
includes full support for WE-18. After that, all Linux drivers, at
|
||||
least in theory, could use the same driver wrapper code.
|
||||
|
||||
*/
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
\page eap_module EAP server implementation
|
||||
|
||||
Extensible Authentication Protocol (EAP) is an authentication framework
|
||||
defined in RFC 3748. hostapd uses a separate code module for EAP server
|
||||
implementation. This module was designed to use only a minimal set of
|
||||
direct function calls (mainly, to debug/event functions) in order for
|
||||
it to be usable in other programs. The design of the EAP
|
||||
implementation is based loosely on RFC 4137. The state machine is
|
||||
defined in this RFC and so is the interface between the server state
|
||||
machine and methods. As such, this RFC provides useful information for
|
||||
understanding the EAP server implementation in hostapd.
|
||||
|
||||
Some of the terminology used in EAP state machine is referring to
|
||||
EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
|
||||
layer being IEEE 802.1X if EAP module is built for other programs than
|
||||
%wpa_supplicant. These terms should be understood to refer to the
|
||||
lower layer as defined in RFC 4137.
|
||||
|
||||
|
||||
\section adding_eap_methods Adding EAP methods
|
||||
|
||||
Each EAP method is implemented as a separate module, usually as one C
|
||||
file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
|
||||
methods use the same interface between the server state machine and
|
||||
method specific functions. This allows new EAP methods to be added
|
||||
without modifying the core EAP state machine implementation.
|
||||
|
||||
New EAP methods need to be registered by adding them into the build
|
||||
(Makefile) and the EAP method registration list in the
|
||||
eap_server_register_methods() function of eap_methods.c. Each EAP
|
||||
method should use a build-time configuration option, e.g., EAP_TLS, in
|
||||
order to make it possible to select which of the methods are included
|
||||
in the build.
|
||||
|
||||
EAP methods must implement the interface defined in eap_i.h. struct
|
||||
eap_method defines the needed function pointers that each EAP method
|
||||
must provide. In addition, the EAP type and name are registered using
|
||||
this structure. This interface is based on section 4.4 of RFC 4137.
|
||||
|
||||
It is recommended that the EAP methods would use generic helper
|
||||
functions, eap_msg_alloc() and eap_hdr_validate() when processing
|
||||
messages. This allows code sharing and can avoid missing some of the
|
||||
needed validation steps for received packets. In addition, these
|
||||
functions make it easier to change between expanded and legacy EAP
|
||||
header, if needed.
|
||||
|
||||
When adding an EAP method that uses a vendor specific EAP type
|
||||
(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
|
||||
must be registered by passing vendor id instead of EAP_VENDOR_IETF to
|
||||
eap_server_method_alloc(). These methods must not try to emulate
|
||||
expanded types by registering a legacy EAP method for type 254. See
|
||||
eap_vendor_test.c for an example of an EAP method implementation that
|
||||
is implemented as an expanded type.
|
||||
|
||||
*/
|
@ -0,0 +1,264 @@
|
||||
#FIG 3.2
|
||||
Landscape
|
||||
Center
|
||||
Inches
|
||||
Letter
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
6 1875 4050 2925 4350
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
|
||||
-6
|
||||
6 4725 1200 5925 1500
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
|
||||
-6
|
||||
6 6000 2700 7200 3225
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
|
||||
-6
|
||||
6 6000 4950 7200 5475
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
|
||||
-6
|
||||
6 4350 3900 5025 4425
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
|
||||
4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
|
||||
-6
|
||||
6 4275 2550 5100 2850
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
|
||||
-6
|
||||
6 6000 3900 7200 4425
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
|
||||
-6
|
||||
6 2775 3150 4050 3450
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
|
||||
-6
|
||||
6 3450 1200 4575 1500
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
|
||||
-6
|
||||
6 3525 7800 5775 8100
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
|
||||
-6
|
||||
6 4275 6000 5100 6300
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
|
||||
-6
|
||||
6 8175 4725 9225 5025
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
|
||||
-6
|
||||
6 9300 4725 10350 5025
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
|
||||
-6
|
||||
6 8175 5100 9225 5400
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
|
||||
-6
|
||||
6 9300 5100 10350 5400
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
|
||||
-6
|
||||
6 8175 5475 9225 5775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
|
||||
-6
|
||||
6 8175 5850 9225 6150
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
|
||||
-6
|
||||
6 8175 6225 9225 6525
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
|
||||
-6
|
||||
6 9300 5850 10350 6150
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
|
||||
-6
|
||||
6 9300 5475 10350 5775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
|
||||
-6
|
||||
6 8175 6600 9675 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
|
||||
-6
|
||||
6 8700 3450 9375 3750
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
|
||||
4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
|
||||
-6
|
||||
6 9600 3450 10275 3750
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
|
||||
-6
|
||||
6 6000 5775 7200 6300
|
||||
6 6000 5775 7200 6300
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
|
||||
-6
|
||||
4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
|
||||
-6
|
||||
6 8100 2250 8925 2775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
|
||||
-6
|
||||
6 3150 5475 4425 5775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
|
||||
-6
|
||||
6 1950 5550 2625 6075
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
|
||||
-6
|
||||
6 1875 4725 2925 5250
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
|
||||
-6
|
||||
2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
||||
1275 4200 1875 4200
|
||||
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||
4500 2550 3900 1500
|
||||
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||
4800 2550 5400 1500
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
2925 4200 4350 4200
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5025 3900 6000 3000
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5025 4200 6000 4200
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4650 6000 4650 4425
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6600 4425 6600 4950
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6600 3225 6600 3900
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7200 5250 8100 5250
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9075 4425 9075 3750
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7200 3000 8700 3525
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4650 3900 4650 2850
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7200 4125 8700 3675
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6000 4350 5025 6000
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6000 3150 4875 6000
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
|
||||
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9900 4425 9900 3750
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
|
||||
4350 3900
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4350 3900 4050 3450
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4350 4425 4050 5475
|
||||
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||
2250 7200 4200 7800
|
||||
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||
7200 7200 5100 7800
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
|
||||
2250 6900 2250 6600 7200 6600 7200 6900
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
3225 6900 3225 6600
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4200 6900 4200 6600
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5175 6900 5175 6600
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6150 6900 6150 6600
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
4650 6600 4650 6300
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
6600 5475 6600 5775
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5025 4425 6000 5775
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||
4800 3900 5925 2550 8100 2550
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7200 3900 8475 2775
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
8925 2475 9450 2475
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
2325 5550 2325 5250
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
2925 4950 4350 4275
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||
2850 4725 5775 2400 8100 2400
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
|
||||
4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
|
@ -0,0 +1,129 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
##########################################################################
|
||||
# Convert kernel-doc style comments to Doxygen comments.
|
||||
##########################################################################
|
||||
#
|
||||
# This script reads a C source file from stdin, and writes
|
||||
# to stdout. Normal usage:
|
||||
#
|
||||
# $ mv file.c file.c.gtkdoc
|
||||
# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
|
||||
#
|
||||
# Or to do the same thing with multiple files:
|
||||
# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
|
||||
#
|
||||
# This script may also be suitable for use as a Doxygen input filter,
|
||||
# but that has not been tested.
|
||||
#
|
||||
# Back up your source files before using this script!!
|
||||
#
|
||||
##########################################################################
|
||||
# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
|
||||
# Copyright (C) 2005 Jouni Malinen <j@w1.fi>
|
||||
# (modified for kerneldoc format used in wpa_supplicant)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# or look at http://www.gnu.org/licenses/gpl.html
|
||||
##########################################################################
|
||||
|
||||
|
||||
##########################################################################
|
||||
#
|
||||
# This function converts a single comment from gtk-doc to Doxygen format.
|
||||
# The parameter does not include the opening or closing lines
|
||||
# (i.e. given a comment like this:
|
||||
# "/**\n"
|
||||
# " * FunctionName:\n"
|
||||
# " * @foo: This describes the foo parameter\n"
|
||||
# " * @bar: This describes the bar parameter\n"
|
||||
# " * @Returns: This describes the return value\n"
|
||||
# " *\n"
|
||||
# " * This describes the function.\n"
|
||||
# " */\n"
|
||||
# This function gets:
|
||||
# " * FunctionName:\n"
|
||||
# " * @foo: This describes the foo parameter\n"
|
||||
# " * @bar: This describes the bar parameter\n"
|
||||
# " * @Returns: This describes the return value\n"
|
||||
# " *\n"
|
||||
# " * This describes the function.\n"
|
||||
# And it returns:
|
||||
# " * This describes the function.\n"
|
||||
# " *\n"
|
||||
# " * @param foo This describes the foo parameter\n"
|
||||
# " * @param bar This describes the bar parameter\n"
|
||||
# " * @return This describes the return value\n"
|
||||
# )
|
||||
#
|
||||
sub fixcomment {
|
||||
$t = $_[0];
|
||||
|
||||
# " * func: foo" --> "\brief foo\n"
|
||||
# " * struct bar: foo" --> "\brief foo\n"
|
||||
# If this fails, not a kernel-doc comment ==> return unmodified.
|
||||
($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
|
||||
or return $t;
|
||||
|
||||
# " * Returns: foo" --> "\return foo"
|
||||
$t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
|
||||
|
||||
# " * @foo: bar" --> "\param foo bar"
|
||||
# Handle two common typos: No ":", or "," instead of ":".
|
||||
$t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# Start of main code
|
||||
|
||||
# Read entire stdin into memory - one multi-line string.
|
||||
$_ = do { local $/; <> };
|
||||
|
||||
s{^/\*\n \*}{/\*\* \\file\n\\brief};
|
||||
s{ \* Copyright}{\\par Copyright\nCopyright};
|
||||
|
||||
# Fix any comments like "/*************" so they don't match.
|
||||
# "/***" ===> "/* *"
|
||||
s{/\*\*\*}{/\* \*}gs;
|
||||
|
||||
# The main comment-detection code.
|
||||
s{
|
||||
( # $1 = Open comment
|
||||
/\*\* # Open comment
|
||||
(?!\*) # Do not match /*** (redundant due to fixup above).
|
||||
[\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
|
||||
)
|
||||
(.*?) # $2 = Body of comment (multi-line)
|
||||
( # $3 = Close comment
|
||||
( # If possible, match the whitespace before the close-comment
|
||||
(?<=\n) # This part only matches after a newline
|
||||
[\t ]* # Eat whitespace
|
||||
)?
|
||||
\*/ # Close comment
|
||||
)
|
||||
}
|
||||
{
|
||||
$1 . fixcomment($2) . $3
|
||||
}gesx;
|
||||
# ^^^^ Modes: g - Global, match all occurances.
|
||||
# e - Evaluate the replacement as an expression.
|
||||
# s - Single-line - allows the pattern to match across newlines.
|
||||
# x - eXtended pattern, ignore embedded whitespace
|
||||
# and allow comments.
|
||||
|
||||
# Write results to stdout
|
||||
print $_;
|
||||
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
\mainpage Developers' documentation for hostapd
|
||||
|
||||
hostapd includes IEEE 802.11 access point management (authentication /
|
||||
association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
|
||||
RADIUS authentication server functionality. It can be build with
|
||||
various configuration option, e.g., a standalone AP management
|
||||
solution or a RADIUS authentication server with support for number of
|
||||
EAP methods.
|
||||
|
||||
The goal of this documentation and comments in the source code is to
|
||||
give enough information for other developers to understand how hostapd
|
||||
has been implemented, how it can be modified, how new drivers can be
|
||||
supported, and how hostapd can be ported to other operating
|
||||
systems. If any information is missing, feel free to contact Jouni
|
||||
Malinen <j@w1.fi> for more information. Contributions as
|
||||
patch files are also very welcome at the same address. Please note
|
||||
that hostapd is licensed under dual license, GPLv2 or BSD at user's
|
||||
choice. All contributions to hostapd are expected to use compatible
|
||||
licensing terms.
|
||||
|
||||
The source code and read-only access to hostapd CVS repository
|
||||
is available from the project home page at
|
||||
http://hostap.epitest.fi/hostapd/. This developers' documentation
|
||||
is also available as a PDF file from
|
||||
http://hostap.epitest.fi/hostapd/hostapd-devel.pdf .
|
||||
|
||||
The design goal for hostapd was to use hardware, driver, and
|
||||
OS independent, portable C code for all WPA functionality. The source
|
||||
code is divided into separate C files as shown on the \ref
|
||||
code_structure "code structure page". All hardware/driver specific
|
||||
functionality is in separate files that implement a \ref
|
||||
driver_wrapper "well-defined driver API". Information about porting
|
||||
to different target boards and operating systems is available on
|
||||
the \ref porting "porting page".
|
||||
|
||||
EAPOL (IEEE 802.1X) state machines are implemented as a separate
|
||||
module that interacts with \ref eap_module "EAP server implementation".
|
||||
Similarly, RADIUS authentication server is in its own separate module.
|
||||
Both IEEE 802.1X and RADIUS authentication server can use EAP server
|
||||
functionality.
|
||||
|
||||
hostapd implements a \ref ctrl_iface_page "control interface" that can
|
||||
be used by external programs to control the operations of the hostapdt
|
||||
daemon and to get status information and event notifications. There is
|
||||
a small C library that provides helper functions to facilitate the use
|
||||
of the control interface. This library can also be used with C++.
|
||||
|
||||
\image html hostapd.png "hostapd modules"
|
||||
\image latex hostapd.eps "hostapd modules" width=15cm
|
||||
|
||||
*/
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
\page porting Porting to different target boards and operating systems
|
||||
|
||||
|
||||
*/
|
@ -0,0 +1,681 @@
|
||||
/*
|
||||
* hostapd - driver interface definition
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
enum hostapd_driver_if_type {
|
||||
HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
|
||||
};
|
||||
|
||||
struct wpa_driver_ops {
|
||||
const char *name; /* as appears in the config file */
|
||||
|
||||
void * (*init)(struct hostapd_data *hapd);
|
||||
void * (*init_bssid)(struct hostapd_data *hapd, const u8 *bssid);
|
||||
void (*deinit)(void *priv);
|
||||
|
||||
int (*wireless_event_init)(void *priv);
|
||||
void (*wireless_event_deinit)(void *priv);
|
||||
|
||||
/**
|
||||
* set_8021x - enable/disable IEEE 802.1X support
|
||||
* @ifname: Interface name (for multi-SSID/VLAN support)
|
||||
* @priv: driver private data
|
||||
* @enabled: 1 = enable, 0 = disable
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Configure the kernel driver to enable/disable 802.1X support.
|
||||
* This may be an empty function if 802.1X support is always enabled.
|
||||
*/
|
||||
int (*set_ieee8021x)(const char *ifname, void *priv, int enabled);
|
||||
|
||||
/**
|
||||
* set_privacy - enable/disable privacy
|
||||
* @priv: driver private data
|
||||
* @enabled: 1 = privacy enabled, 0 = disabled
|
||||
*
|
||||
* Return: 0 on success, -1 on failure
|
||||
*
|
||||
* Configure privacy.
|
||||
*/
|
||||
int (*set_privacy)(const char *ifname, void *priv, int enabled);
|
||||
|
||||
int (*set_encryption)(const char *ifname, void *priv, const char *alg,
|
||||
const u8 *addr, int idx,
|
||||
const u8 *key, size_t key_len, int txkey);
|
||||
int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
|
||||
int idx, u8 *seq);
|
||||
int (*get_seqnum_igtk)(const char *ifname, void *priv, const u8 *addr,
|
||||
int idx, u8 *seq);
|
||||
int (*flush)(void *priv);
|
||||
int (*set_generic_elem)(const char *ifname, void *priv, const u8 *elem,
|
||||
size_t elem_len);
|
||||
|
||||
int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
|
||||
const u8 *addr);
|
||||
int (*send_eapol)(void *priv, const u8 *addr, const u8 *data,
|
||||
size_t data_len, int encrypt, const u8 *own_addr);
|
||||
int (*sta_deauth)(void *priv, const u8 *addr, int reason);
|
||||
int (*sta_disassoc)(void *priv, const u8 *addr, int reason);
|
||||
int (*sta_remove)(void *priv, const u8 *addr);
|
||||
int (*get_ssid)(const char *ifname, void *priv, u8 *buf, int len);
|
||||
int (*set_ssid)(const char *ifname, void *priv, const u8 *buf,
|
||||
int len);
|
||||
int (*set_countermeasures)(void *priv, int enabled);
|
||||
int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
|
||||
int flags);
|
||||
int (*set_assoc_ap)(void *priv, const u8 *addr);
|
||||
int (*sta_add)(const char *ifname, void *priv, const u8 *addr, u16 aid,
|
||||
u16 capability, u8 *supp_rates, size_t supp_rates_len,
|
||||
int flags);
|
||||
int (*get_inact_sec)(void *priv, const u8 *addr);
|
||||
int (*sta_clear_stats)(void *priv, const u8 *addr);
|
||||
|
||||
int (*set_freq)(void *priv, int mode, int freq);
|
||||
int (*set_rts)(void *priv, int rts);
|
||||
int (*get_rts)(void *priv, int *rts);
|
||||
int (*set_frag)(void *priv, int frag);
|
||||
int (*get_frag)(void *priv, int *frag);
|
||||
int (*set_retry)(void *priv, int short_retry, int long_retry);
|
||||
int (*get_retry)(void *priv, int *short_retry, int *long_retry);
|
||||
|
||||
int (*sta_set_flags)(void *priv, const u8 *addr,
|
||||
int total_flags, int flags_or, int flags_and);
|
||||
int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
|
||||
int mode);
|
||||
int (*set_channel_flag)(void *priv, int mode, int chan, int flag,
|
||||
unsigned char power_level,
|
||||
unsigned char antenna_max);
|
||||
int (*set_regulatory_domain)(void *priv, unsigned int rd);
|
||||
int (*set_country)(void *priv, const char *country);
|
||||
int (*set_ieee80211d)(void *priv, int enabled);
|
||||
int (*set_beacon)(const char *ifname, void *priv,
|
||||
u8 *head, size_t head_len,
|
||||
u8 *tail, size_t tail_len);
|
||||
|
||||
/* Configure internal bridge:
|
||||
* 0 = disabled, i.e., client separation is enabled (no bridging of
|
||||
* packets between associated STAs
|
||||
* 1 = enabled, i.e., bridge packets between associated STAs (default)
|
||||
*/
|
||||
int (*set_internal_bridge)(void *priv, int value);
|
||||
int (*set_beacon_int)(void *priv, int value);
|
||||
int (*set_dtim_period)(const char *ifname, void *priv, int value);
|
||||
/* Configure broadcast SSID mode:
|
||||
* 0 = include SSID in Beacon frames and reply to Probe Request frames
|
||||
* that use broadcast SSID
|
||||
* 1 = hide SSID from Beacon frames and ignore Probe Request frames for
|
||||
* broadcast SSID
|
||||
*/
|
||||
int (*set_broadcast_ssid)(void *priv, int value);
|
||||
int (*set_cts_protect)(void *priv, int value);
|
||||
int (*set_key_tx_rx_threshold)(void *priv, int value);
|
||||
int (*set_preamble)(void *priv, int value);
|
||||
int (*set_short_slot_time)(void *priv, int value);
|
||||
int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
|
||||
int cw_max, int burst_time);
|
||||
int (*bss_add)(void *priv, const char *ifname, const u8 *bssid);
|
||||
int (*bss_remove)(void *priv, const char *ifname);
|
||||
int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
|
||||
int (*passive_scan)(void *priv, int now, int our_mode_only,
|
||||
int interval, int _listen, int *channel,
|
||||
int *last_rx);
|
||||
struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
|
||||
u16 *num_modes,
|
||||
u16 *flags);
|
||||
int (*if_add)(const char *iface, void *priv,
|
||||
enum hostapd_driver_if_type type, char *ifname,
|
||||
const u8 *addr);
|
||||
int (*if_update)(void *priv, enum hostapd_driver_if_type type,
|
||||
char *ifname, const u8 *addr);
|
||||
int (*if_remove)(void *priv, enum hostapd_driver_if_type type,
|
||||
const char *ifname, const u8 *addr);
|
||||
int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
|
||||
int vlan_id);
|
||||
/**
|
||||
* commit - Optional commit changes handler
|
||||
* @priv: driver private data
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This optional handler function can be registered if the driver
|
||||
* interface implementation needs to commit changes (e.g., by setting
|
||||
* network interface up) at the end of initial configuration. If set,
|
||||
* this handler will be called after initial setup has been completed.
|
||||
*/
|
||||
int (*commit)(void *priv);
|
||||
|
||||
int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
|
||||
const u8 *data, size_t data_len);
|
||||
};
|
||||
|
||||
static inline void *
|
||||
hostapd_driver_init(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->init == NULL)
|
||||
return NULL;
|
||||
return hapd->driver->init(hapd);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hostapd_driver_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->init_bssid == NULL)
|
||||
return NULL;
|
||||
return hapd->driver->init_bssid(hapd, bssid);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_driver_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->deinit == NULL)
|
||||
return;
|
||||
hapd->driver->deinit(hapd->drv_priv);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_wireless_event_init(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->wireless_event_init == NULL)
|
||||
return 0;
|
||||
return hapd->driver->wireless_event_init(hapd->drv_priv);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_wireless_event_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->wireless_event_deinit == NULL)
|
||||
return;
|
||||
hapd->driver->wireless_event_deinit(hapd->drv_priv);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_ieee8021x(const char *ifname, struct hostapd_data *hapd,
|
||||
int enabled)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_ieee8021x(ifname, hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_privacy(hapd->conf->iface, hapd->drv_priv,
|
||||
enabled);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_encryption(const char *ifname, struct hostapd_data *hapd,
|
||||
const char *alg, const u8 *addr, int idx,
|
||||
u8 *key, size_t key_len, int txkey)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_encryption(ifname, hapd->drv_priv, alg, addr,
|
||||
idx, key, key_len, txkey);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
|
||||
const u8 *addr, int idx, u8 *seq)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
|
||||
seq);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_seqnum_igtk(const char *ifname, struct hostapd_data *hapd,
|
||||
const u8 *addr, int idx, u8 *seq)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_seqnum_igtk == NULL)
|
||||
return -1;
|
||||
return hapd->driver->get_seqnum_igtk(ifname, hapd->drv_priv, addr, idx,
|
||||
seq);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->flush == NULL)
|
||||
return 0;
|
||||
return hapd->driver->flush(hapd->drv_priv);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
||||
size_t elem_len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_generic_elem(hapd->conf->iface,
|
||||
hapd->drv_priv, elem, elem_len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_read_sta_data(struct hostapd_data *hapd,
|
||||
struct hostap_sta_driver_data *data, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
|
||||
return -1;
|
||||
return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data,
|
||||
size_t data_len, int encrypt)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_eapol == NULL)
|
||||
return 0;
|
||||
return hapd->driver->send_eapol(hapd->drv_priv, addr, data, data_len,
|
||||
encrypt, hapd->own_addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_deauth(hapd->drv_priv, addr, reason);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_disassoc(hapd->drv_priv, addr, reason);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_remove(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_ssid(hapd->conf->iface, hapd->drv_priv, buf,
|
||||
len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_ssid(hapd->conf->iface, hapd->drv_priv, buf,
|
||||
len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, size_t len,
|
||||
int flags)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_mgmt_frame == NULL)
|
||||
return 0;
|
||||
return hapd->driver->send_mgmt_frame(hapd->drv_priv, msg, len, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_assoc_ap(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_assoc_ap(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_countermeasures(hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_add(const char *ifname, struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 aid, u16 capability, u8 *supp_rates, size_t supp_rates_len,
|
||||
int flags)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_add == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_add(ifname, hapd->drv_priv, addr, aid,
|
||||
capability, supp_rates, supp_rates_len,
|
||||
flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_freq == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_freq(hapd->drv_priv, mode, freq);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_rts(struct hostapd_data *hapd, int rts)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_rts(hapd->drv_priv, rts);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_rts(struct hostapd_data *hapd, int *rts)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_rts == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_rts(hapd->drv_priv, rts);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_frag(struct hostapd_data *hapd, int frag)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_frag(hapd->drv_priv, frag);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_frag(struct hostapd_data *hapd, int *frag)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_frag == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_frag(hapd->drv_priv, frag);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_retry(struct hostapd_data *hapd, int short_retry, int long_retry)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_retry == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_retry(hapd->drv_priv, short_retry,
|
||||
long_retry);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_get_retry(struct hostapd_data *hapd, int *short_retry, int *long_retry)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_retry == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_retry(hapd->drv_priv, short_retry,
|
||||
long_retry);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
|
||||
int total_flags, int flags_or, int flags_and)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
|
||||
flags_or, flags_and);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
|
||||
int *basic_rates, int mode)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
|
||||
basic_rates, mode);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_channel_flag(struct hostapd_data *hapd, int mode, int chan,
|
||||
int flag, unsigned char power_level,
|
||||
unsigned char antenna_max)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_channel_flag == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_channel_flag(hapd->drv_priv, mode, chan, flag,
|
||||
power_level, antenna_max);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->set_regulatory_domain == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_regulatory_domain(hapd->drv_priv, rd);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_country(struct hostapd_data *hapd, const char *country)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->set_country == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_country(hapd->drv_priv, country);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->set_ieee80211d == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_ieee80211d(hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_beacon(const char *ifname, struct hostapd_data *hapd,
|
||||
u8 *head, size_t head_len,
|
||||
u8 *tail, size_t tail_len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_beacon(ifname, hapd->drv_priv, head, head_len,
|
||||
tail, tail_len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_internal_bridge(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_internal_bridge == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_internal_bridge(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_beacon_int(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_beacon_int == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_beacon_int(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_dtim_period(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_dtim_period == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_dtim_period(hapd->conf->iface, hapd->drv_priv,
|
||||
value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_broadcast_ssid(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_broadcast_ssid == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_broadcast_ssid(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_cts_protect(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_key_tx_rx_threshold(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->set_key_tx_rx_threshold == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_key_tx_rx_threshold(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_preamble(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_preamble(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
|
||||
cw_min, cw_max, burst_time);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_bss_add(struct hostapd_data *hapd, const char *ifname, const u8 *bssid)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->bss_add == NULL)
|
||||
return 0;
|
||||
return hapd->driver->bss_add(hapd->drv_priv, ifname, bssid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_bss_remove(struct hostapd_data *hapd, const char *ifname)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->bss_remove == NULL)
|
||||
return 0;
|
||||
return hapd->driver->bss_remove(hapd->drv_priv, ifname);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *mask)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
|
||||
return 1;
|
||||
return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_if_add(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
|
||||
char *ifname, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
|
||||
return -1;
|
||||
return hapd->driver->if_add(hapd->conf->iface, hapd->drv_priv, type,
|
||||
ifname, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_if_update(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
|
||||
char *ifname, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->if_update == NULL)
|
||||
return -1;
|
||||
return hapd->driver->if_update(hapd->drv_priv, type, ifname, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_if_remove(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
|
||||
char *ifname, const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
|
||||
return -1;
|
||||
return hapd->driver->if_remove(hapd->drv_priv, type, ifname, addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_passive_scan(struct hostapd_data *hapd, int now, int our_mode_only,
|
||||
int interval, int _listen, int *channel,
|
||||
int *last_rx)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->passive_scan == NULL)
|
||||
return -1;
|
||||
return hapd->driver->passive_scan(hapd->drv_priv, now, our_mode_only,
|
||||
interval, _listen, channel, last_rx);
|
||||
}
|
||||
|
||||
static inline struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_hw_feature_data == NULL)
|
||||
return NULL;
|
||||
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
|
||||
flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
|
||||
const u8 *addr, int vlan_id)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname, vlan_id);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_driver_commit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->commit == NULL)
|
||||
return 0;
|
||||
return hapd->driver->commit(hapd->drv_priv);
|
||||
}
|
||||
|
||||
#endif /* DRIVER_H */
|
@ -0,0 +1,838 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* 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);
|
||||
accounting_sta_get_id(hapd, sta);
|
||||
} 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,
|
||||
};
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* hostapd / driver interface list
|
||||
* 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"
|
||||
|
||||
|
||||
#ifdef CONFIG_DRIVER_HOSTAP
|
||||
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
|
||||
#endif /* CONFIG_DRIVER_HOSTAP */
|
||||
#ifdef CONFIG_DRIVER_NL80211
|
||||
extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
|
||||
#endif /* CONFIG_DRIVER_NL80211 */
|
||||
#ifdef CONFIG_DRIVER_PRISM54
|
||||
extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */
|
||||
#endif /* CONFIG_DRIVER_PRISM54 */
|
||||
#ifdef CONFIG_DRIVER_MADWIFI
|
||||
extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
|
||||
#endif /* CONFIG_DRIVER_MADWIFI */
|
||||
#ifdef CONFIG_DRIVER_BSD
|
||||
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
|
||||
#endif /* CONFIG_DRIVER_BSD */
|
||||
#ifdef CONFIG_DRIVER_WIRED
|
||||
extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
|
||||
#endif /* CONFIG_DRIVER_WIRED */
|
||||
#ifdef CONFIG_DRIVER_TEST
|
||||
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
|
||||
#endif /* CONFIG_DRIVER_TEST */
|
||||
|
||||
|
||||
struct wpa_driver_ops *hostapd_drivers[] =
|
||||
{
|
||||
#ifdef CONFIG_DRIVER_HOSTAP
|
||||
&wpa_driver_hostap_ops,
|
||||
#endif /* CONFIG_DRIVER_HOSTAP */
|
||||
#ifdef CONFIG_DRIVER_NL80211
|
||||
&wpa_driver_nl80211_ops,
|
||||
#endif /* CONFIG_DRIVER_NL80211 */
|
||||
#ifdef CONFIG_DRIVER_PRISM54
|
||||
&wpa_driver_prism54_ops,
|
||||
#endif /* CONFIG_DRIVER_PRISM54 */
|
||||
#ifdef CONFIG_DRIVER_MADWIFI
|
||||
&wpa_driver_madwifi_ops,
|
||||
#endif /* CONFIG_DRIVER_MADWIFI */
|
||||
#ifdef CONFIG_DRIVER_BSD
|
||||
&wpa_driver_bsd_ops,
|
||||
#endif /* CONFIG_DRIVER_BSD */
|
||||
#ifdef CONFIG_DRIVER_WIRED
|
||||
&wpa_driver_wired_ops,
|
||||
#endif /* CONFIG_DRIVER_WIRED */
|
||||
#ifdef CONFIG_DRIVER_TEST
|
||||
&wpa_driver_test_ops,
|
||||
#endif /* CONFIG_DRIVER_TEST */
|
||||
NULL
|
||||
};
|
@ -0,0 +1,74 @@
|
||||
Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication
|
||||
|
||||
Test matrix
|
||||
|
||||
+) tested successfully
|
||||
F) failed
|
||||
-) peer did not support
|
||||
?) not tested
|
||||
|
||||
XSupplicant --------------------------------.
|
||||
Intel PROSet ---------------------------. |
|
||||
Windows XP -------------------------. | |
|
||||
Mac OS X 10.4 ------------------. | | |
|
||||
Nokia S60 ------------------. | | | |
|
||||
wpa_supplicant ---------. | | | | |
|
||||
| | | | | |
|
||||
|
||||
EAP-MD5 + - ? ? -
|
||||
EAP-GTC + - ? - -
|
||||
EAP-MSCHAPv2 + - ? - -
|
||||
EAP-TLS + + +1 + +
|
||||
EAP-PEAPv0/MSCHAPv2 + + + + + +
|
||||
EAP-PEAPv0/GTC + + + - +
|
||||
EAP-PEAPv0/MD5 + - + - -
|
||||
EAP-PEAPv0/TLS + F - + +
|
||||
EAP-PEAPv0/SIM + + - - -
|
||||
EAP-PEAPv0/AKA + + - - -
|
||||
EAP-PEAPv0/PSK + - - - -
|
||||
EAP-PEAPv0/PAX + - - - -
|
||||
EAP-PEAPv0/SAKE + - - - -
|
||||
EAP-PEAPv0/GPSK + - - - -
|
||||
EAP-PEAPv1/MSCHAPv2 + + + - + +
|
||||
EAP-PEAPv1/GTC + + + - +
|
||||
EAP-PEAPv1/MD5 + - + - -
|
||||
EAP-PEAPv1/TLS + F - - +
|
||||
EAP-PEAPv1/SIM + + - - -
|
||||
EAP-PEAPv1/AKA + + - - -
|
||||
EAP-PEAPv1/PSK + - - - -
|
||||
EAP-PEAPv1/PAX + - - - -
|
||||
EAP-PEAPv1/SAKE + - - - -
|
||||
EAP-PEAPv1/GPSK + - - - -
|
||||
EAP-TTLS/CHAP + - + - + +
|
||||
EAP-TTLS/MSCHAP + - + - + +
|
||||
EAP-TTLS/MSCHAPv2 + + + - + +
|
||||
EAP-TTLS/PAP + - + - + +
|
||||
EAP-TTLS/EAP-MD5 + - - - - +
|
||||
EAP-TTLS/EAP-GTC + + - - -
|
||||
EAP-TTLS/EAP-MSCHAPv2 + + - - -
|
||||
EAP-TTLS/EAP-TLS + F - - -
|
||||
EAP-TTLS/EAP-SIM + + - - -
|
||||
EAP-TTLS/EAP-AKA + + - - -
|
||||
EAP-SIM + + - - +
|
||||
EAP-AKA + + - - -
|
||||
EAP-PAX + - - - -
|
||||
EAP-SAKE + - - - -
|
||||
EAP-GPSK + - - - -
|
||||
EAP-FAST/MSCHAPv2(prov) + - F - F
|
||||
EAP-FAST/GTC(auth) + - + - +
|
||||
EAP-FAST/MSCHAPv2(aprov)+ - F - F
|
||||
EAP-FAST/GTC(aprov) + - F - F
|
||||
EAP-FAST/MD5(aprov) + - - - -
|
||||
EAP-FAST/TLS(aprov) + - - - -
|
||||
EAP-FAST/SIM(aprov) + - - - -
|
||||
EAP-FAST/AKA(aprov) + - - - -
|
||||
EAP-FAST/MSCHAPv2(auth) + - + - +
|
||||
EAP-FAST/MD5(auth) + - + - -
|
||||
EAP-FAST/TLS(auth) + - - - -
|
||||
EAP-FAST/SIM(auth) + - - - -
|
||||
EAP-FAST/AKA(auth) + - - - -
|
||||
EAP-IKEv2 + - - - -
|
||||
|
||||
1) EAP-TLS itself worked, but peer certificate validation failed at
|
||||
least when using the internal TLS server (peer included incorrect
|
||||
certificates in the chain?)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAPOL_SM_H
|
||||
#define EAPOL_SM_H
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/* IEEE Std 802.1X-2004, Ch. 8.2 */
|
||||
|
||||
typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
|
||||
PortTypes;
|
||||
typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
|
||||
typedef enum { Both = 0, In = 1 } ControlledDirection;
|
||||
typedef unsigned int Counter;
|
||||
|
||||
struct eap_sm;
|
||||
|
||||
struct radius_attr_data {
|
||||
u8 *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct radius_class_data {
|
||||
struct radius_attr_data *attr;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
|
||||
struct eapol_auth_config {
|
||||
int eap_reauth_period;
|
||||
int wpa;
|
||||
int individual_wep_key_len;
|
||||
int eap_server;
|
||||
void *ssl_ctx;
|
||||
void *eap_sim_db_priv;
|
||||
char *eap_req_id_text; /* a copy of this will be allocated */
|
||||
size_t eap_req_id_text_len;
|
||||
u8 *pac_opaque_encr_key;
|
||||
char *eap_fast_a_id;
|
||||
int eap_sim_aka_result_ind;
|
||||
|
||||
/*
|
||||
* Pointer to hostapd data. This is a temporary workaround for
|
||||
* transition phase and will be removed once IEEE 802.1X/EAPOL code is
|
||||
* separated more cleanly from rest of hostapd.
|
||||
*/
|
||||
struct hostapd_data *hapd;
|
||||
};
|
||||
|
||||
struct eap_user;
|
||||
|
||||
typedef enum {
|
||||
EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
|
||||
} eapol_logger_level;
|
||||
|
||||
struct eapol_auth_cb {
|
||||
void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data,
|
||||
size_t datalen);
|
||||
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
|
||||
size_t datalen);
|
||||
void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
|
||||
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
|
||||
int phase2, struct eap_user *user);
|
||||
int (*sta_entry_alive)(void *ctx, const u8 *addr);
|
||||
void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level,
|
||||
const char *txt);
|
||||
void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized);
|
||||
void (*abort_auth)(void *ctx, void *sta_ctx);
|
||||
void (*tx_key)(void *ctx, void *sta_ctx);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct eapol_authenticator - Global EAPOL authenticator data
|
||||
*/
|
||||
struct eapol_authenticator {
|
||||
struct eapol_auth_config conf;
|
||||
struct eapol_auth_cb cb;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct eapol_state_machine - Per-Supplicant Authenticator state machines
|
||||
*/
|
||||
struct eapol_state_machine {
|
||||
/* timers */
|
||||
int aWhile;
|
||||
int quietWhile;
|
||||
int reAuthWhen;
|
||||
|
||||
/* global variables */
|
||||
Boolean authAbort;
|
||||
Boolean authFail;
|
||||
PortState authPortStatus;
|
||||
Boolean authStart;
|
||||
Boolean authTimeout;
|
||||
Boolean authSuccess;
|
||||
Boolean eapolEap;
|
||||
Boolean initialize;
|
||||
Boolean keyDone;
|
||||
Boolean keyRun;
|
||||
Boolean keyTxEnabled;
|
||||
PortTypes portControl;
|
||||
Boolean portValid;
|
||||
Boolean reAuthenticate;
|
||||
|
||||
/* Port Timers state machine */
|
||||
/* 'Boolean tick' implicitly handled as registered timeout */
|
||||
|
||||
/* Authenticator PAE state machine */
|
||||
enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
|
||||
AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
|
||||
AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
|
||||
AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
|
||||
/* variables */
|
||||
Boolean eapolLogoff;
|
||||
Boolean eapolStart;
|
||||
PortTypes portMode;
|
||||
unsigned int reAuthCount;
|
||||
/* constants */
|
||||
unsigned int quietPeriod; /* default 60; 0..65535 */
|
||||
#define AUTH_PAE_DEFAULT_quietPeriod 60
|
||||
unsigned int reAuthMax; /* default 2 */
|
||||
#define AUTH_PAE_DEFAULT_reAuthMax 2
|
||||
/* counters */
|
||||
Counter authEntersConnecting;
|
||||
Counter authEapLogoffsWhileConnecting;
|
||||
Counter authEntersAuthenticating;
|
||||
Counter authAuthSuccessesWhileAuthenticating;
|
||||
Counter authAuthTimeoutsWhileAuthenticating;
|
||||
Counter authAuthFailWhileAuthenticating;
|
||||
Counter authAuthEapStartsWhileAuthenticating;
|
||||
Counter authAuthEapLogoffWhileAuthenticating;
|
||||
Counter authAuthReauthsWhileAuthenticated;
|
||||
Counter authAuthEapStartsWhileAuthenticated;
|
||||
Counter authAuthEapLogoffWhileAuthenticated;
|
||||
|
||||
/* Backend Authentication state machine */
|
||||
enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
|
||||
BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
|
||||
BE_AUTH_IGNORE
|
||||
} be_auth_state;
|
||||
/* constants */
|
||||
unsigned int serverTimeout; /* default 30; 1..X */
|
||||
#define BE_AUTH_DEFAULT_serverTimeout 30
|
||||
/* counters */
|
||||
Counter backendResponses;
|
||||
Counter backendAccessChallenges;
|
||||
Counter backendOtherRequestsToSupplicant;
|
||||
Counter backendAuthSuccesses;
|
||||
Counter backendAuthFails;
|
||||
|
||||
/* Reauthentication Timer state machine */
|
||||
enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE
|
||||
} reauth_timer_state;
|
||||
/* constants */
|
||||
unsigned int reAuthPeriod; /* default 3600 s */
|
||||
Boolean reAuthEnabled;
|
||||
|
||||
/* Authenticator Key Transmit state machine */
|
||||
enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
|
||||
} auth_key_tx_state;
|
||||
|
||||
/* Key Receive state machine */
|
||||
enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
|
||||
/* variables */
|
||||
Boolean rxKey;
|
||||
|
||||
/* Controlled Directions state machine */
|
||||
enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
|
||||
/* variables */
|
||||
ControlledDirection adminControlledDirections;
|
||||
ControlledDirection operControlledDirections;
|
||||
Boolean operEdge;
|
||||
|
||||
/* Authenticator Statistics Table */
|
||||
Counter dot1xAuthEapolFramesRx;
|
||||
Counter dot1xAuthEapolFramesTx;
|
||||
Counter dot1xAuthEapolStartFramesRx;
|
||||
Counter dot1xAuthEapolLogoffFramesRx;
|
||||
Counter dot1xAuthEapolRespIdFramesRx;
|
||||
Counter dot1xAuthEapolRespFramesRx;
|
||||
Counter dot1xAuthEapolReqIdFramesTx;
|
||||
Counter dot1xAuthEapolReqFramesTx;
|
||||
Counter dot1xAuthInvalidEapolFramesRx;
|
||||
Counter dot1xAuthEapLengthErrorFramesRx;
|
||||
Counter dot1xAuthLastEapolFrameVersion;
|
||||
|
||||
/* Other variables - not defined in IEEE 802.1X */
|
||||
u8 addr[ETH_ALEN]; /* Supplicant address */
|
||||
#define EAPOL_SM_PREAUTH BIT(0)
|
||||
#define EAPOL_SM_WAIT_START BIT(1)
|
||||
int flags; /* EAPOL_SM_* */
|
||||
|
||||
/* EAPOL/AAA <-> EAP full authenticator interface */
|
||||
struct eap_eapol_interface *eap_if;
|
||||
|
||||
int radius_identifier;
|
||||
/* TODO: check when the last messages can be released */
|
||||
struct radius_msg *last_recv_radius;
|
||||
u8 last_eap_id; /* last used EAP Identifier */
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
u8 eap_type_authsrv; /* EAP type of the last EAP packet from
|
||||
* Authentication server */
|
||||
u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
|
||||
struct radius_class_data radius_class;
|
||||
|
||||
/* Keys for encrypting and signing EAPOL-Key frames */
|
||||
u8 *eapol_key_sign;
|
||||
size_t eapol_key_sign_len;
|
||||
u8 *eapol_key_crypt;
|
||||
size_t eapol_key_crypt_len;
|
||||
|
||||
struct eap_sm *eap;
|
||||
|
||||
Boolean initializing; /* in process of initializing state machines */
|
||||
Boolean changed;
|
||||
|
||||
struct eapol_authenticator *eapol;
|
||||
|
||||
/* Somewhat nasty pointers to global hostapd and STA data to avoid
|
||||
* passing these to every function */
|
||||
struct hostapd_data *hapd;
|
||||
struct sta_info *sta;
|
||||
};
|
||||
|
||||
|
||||
struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
|
||||
struct eapol_auth_cb *cb);
|
||||
void eapol_auth_deinit(struct eapol_authenticator *eapol);
|
||||
struct eapol_state_machine *
|
||||
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
|
||||
int preauth, struct sta_info *sta);
|
||||
void eapol_auth_free(struct eapol_state_machine *sm);
|
||||
void eapol_auth_step(struct eapol_state_machine *sm);
|
||||
void eapol_auth_initialize(struct eapol_state_machine *sm);
|
||||
void eapol_auth_dump_state(FILE *f, const char *prefix,
|
||||
struct eapol_state_machine *sm);
|
||||
int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
|
||||
|
||||
#endif /* EAPOL_SM_H */
|
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* hostapd / Kernel driver communication with Linux Host AP driver
|
||||
* Copyright (c) 2002-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.
|
||||
*/
|
||||
|
||||
#ifndef HOSTAP_COMMON_H
|
||||
#define HOSTAP_COMMON_H
|
||||
|
||||
/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
|
||||
|
||||
/* New wireless extensions API - SET/GET convention (even ioctl numbers are
|
||||
* root only)
|
||||
*/
|
||||
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
|
||||
#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
|
||||
#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
|
||||
#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
|
||||
#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
|
||||
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
|
||||
#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
|
||||
#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
|
||||
#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
|
||||
#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
|
||||
#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
|
||||
#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
|
||||
#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
|
||||
#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
|
||||
|
||||
/* following are not in SIOCGIWPRIV list; check permission in the driver code
|
||||
*/
|
||||
#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
|
||||
#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,
|
||||
};
|
||||
|
||||
enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
|
||||
HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
|
||||
|
||||
|
||||
/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
|
||||
enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
|
||||
AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
|
||||
AP_MAC_CMD_KICKALL = 4 };
|
||||
|
||||
|
||||
/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
|
||||
enum {
|
||||
PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
|
||||
/* Note! Old versions of prism2_srec have a fatal error in CRC-16
|
||||
* calculation, which will corrupt all non-volatile downloads.
|
||||
* PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
|
||||
* prevent use of old versions of prism2_srec for non-volatile
|
||||
* download. */
|
||||
PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
|
||||
PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
|
||||
/* Persistent versions of volatile download commands (keep firmware
|
||||
* data in memory and automatically re-download after hw_reset */
|
||||
PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
|
||||
PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
|
||||
};
|
||||
|
||||
struct prism2_download_param {
|
||||
u32 dl_cmd;
|
||||
u32 start_addr;
|
||||
u32 num_areas;
|
||||
struct prism2_download_area {
|
||||
u32 addr; /* wlan card address */
|
||||
u32 len;
|
||||
caddr_t ptr; /* pointer to data in user space */
|
||||
} data[0];
|
||||
};
|
||||
|
||||
#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
|
||||
#define PRISM2_MAX_DOWNLOAD_LEN 262144
|
||||
|
||||
|
||||
/* 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 \
|
||||
((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
|
||||
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
|
||||
((int) (&((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 BIT(0)
|
||||
#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
|
||||
|
||||
#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_COMMON_H */
|
@ -0,0 +1,59 @@
|
||||
.TH HOSTAPD 8 "April 7, 2005" hostapd hostapd
|
||||
.SH NAME
|
||||
hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
|
||||
.SH SYNOPSIS
|
||||
.B hostapd
|
||||
[-hdBKtv] [-P <PID file>] <configuration file(s)>
|
||||
.SH DESCRIPTION
|
||||
This manual page documents briefly the
|
||||
.B hostapd
|
||||
daemon.
|
||||
.PP
|
||||
.B hostapd
|
||||
is a user space daemon for access point and authentication servers.
|
||||
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
|
||||
The current version supports Linux (Host AP, madwifi, Prism54 drivers) and FreeBSD (net80211).
|
||||
|
||||
.B hostapd
|
||||
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
|
||||
.B hostapd
|
||||
supports separate frontend programs and an example text-based frontend,
|
||||
.BR hostapd_cli ,
|
||||
is included with
|
||||
.BR hostapd .
|
||||
.SH OPTIONS
|
||||
A summary of options is included below.
|
||||
For a complete description, run
|
||||
.BR hostapd
|
||||
from the command line.
|
||||
.TP
|
||||
.B \-h
|
||||
Show usage.
|
||||
.TP
|
||||
.B \-d
|
||||
Show more debug messages.
|
||||
.TP
|
||||
.B \-dd
|
||||
Show even more debug messages.
|
||||
.TP
|
||||
.B \-B
|
||||
Run daemon in the background.
|
||||
.TP
|
||||
.B \-P <PID file>
|
||||
Path to PID file.
|
||||
.TP
|
||||
.B \-K
|
||||
Include key data in debug messages.
|
||||
.TP
|
||||
.B \-t
|
||||
Include timestamps in some debug messages.
|
||||
.TP
|
||||
.B \-v
|
||||
Show hostapd version.
|
||||
.SH SEE ALSO
|
||||
.BR hostapd_cli (1).
|
||||
.SH AUTHOR
|
||||
hostapd was written by Jouni Malinen <j@w1.fi>.
|
||||
.PP
|
||||
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
|
||||
for the Debian project (but may be used by others).
|
@ -0,0 +1,5 @@
|
||||
# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
|
||||
# with the AP.
|
||||
00:11:22:33:44:55
|
||||
00:66:77:88:99:aa
|
||||
00:00:22:33:44:55
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,792 @@
|
||||
##### hostapd configuration file ##############################################
|
||||
# Empty lines and lines starting with # are ignored
|
||||
|
||||
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
|
||||
# management frames); ath0 for madwifi
|
||||
interface=wlan0
|
||||
|
||||
# In case of madwifi driver, an additional configuration parameter, bridge,
|
||||
# must be used to notify hostapd if the interface is included in a bridge. This
|
||||
# parameter is not used with Host AP driver.
|
||||
#bridge=br0
|
||||
|
||||
# Driver interface type (hostap/wired/madwifi/prism54/test/nl80211/bsd);
|
||||
# default: hostap)
|
||||
# Use driver=test if building hostapd as a standalone RADIUS server that does
|
||||
# not control any wireless/wired driver.
|
||||
# driver=hostap
|
||||
|
||||
# hostapd event logger configuration
|
||||
#
|
||||
# Two output method: syslog and stdout (only usable if not forking to
|
||||
# background).
|
||||
#
|
||||
# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
|
||||
# modules):
|
||||
# bit 0 (1) = IEEE 802.11
|
||||
# bit 1 (2) = IEEE 802.1X
|
||||
# bit 2 (4) = RADIUS
|
||||
# bit 3 (8) = WPA
|
||||
# bit 4 (16) = driver interface
|
||||
# bit 5 (32) = IAPP
|
||||
# bit 6 (64) = MLME
|
||||
#
|
||||
# Levels (minimum value for logged events):
|
||||
# 0 = verbose debugging
|
||||
# 1 = debugging
|
||||
# 2 = informational messages
|
||||
# 3 = notification
|
||||
# 4 = warning
|
||||
#
|
||||
logger_syslog=-1
|
||||
logger_syslog_level=2
|
||||
logger_stdout=-1
|
||||
logger_stdout_level=2
|
||||
|
||||
# Dump file for state information (on SIGUSR1)
|
||||
dump_file=/tmp/hostapd.dump
|
||||
|
||||
# Interface for separate control program. If this is specified, hostapd
|
||||
# will create this directory and a UNIX domain socket for listening to requests
|
||||
# from external programs (CLI/GUI, etc.) for status information and
|
||||
# configuration. The socket file will be named based on the interface name, so
|
||||
# multiple hostapd processes/interfaces can be run at the same time if more
|
||||
# than one interface is used.
|
||||
# /var/run/hostapd is the recommended directory for sockets and by default,
|
||||
# hostapd_cli will use it when trying to connect with hostapd.
|
||||
ctrl_interface=/var/run/hostapd
|
||||
|
||||
# Access control for the control interface can be configured by setting the
|
||||
# directory to allow only members of a group to use sockets. This way, it is
|
||||
# possible to run hostapd as root (since it needs to change network
|
||||
# configuration and open raw sockets) and still allow GUI/CLI components to be
|
||||
# run as non-root users. However, since the control interface can be used to
|
||||
# change the network configuration, this access needs to be protected in many
|
||||
# cases. By default, hostapd is configured to use gid 0 (root). If you
|
||||
# want to allow non-root users to use the contron interface, add a new group
|
||||
# and change this value to match with that group. Add users that should have
|
||||
# control interface access to this group.
|
||||
#
|
||||
# This variable can be a group name or gid.
|
||||
#ctrl_interface_group=wheel
|
||||
ctrl_interface_group=0
|
||||
|
||||
|
||||
##### IEEE 802.11 related configuration #######################################
|
||||
|
||||
# SSID to be used in IEEE 802.11 management frames
|
||||
ssid=test
|
||||
|
||||
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
|
||||
# Modify as needed to indicate country in which device is operating.
|
||||
# This can limit available channels and transmit power.
|
||||
# (default: US)
|
||||
#country_code=US
|
||||
|
||||
# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
|
||||
# channels and transmit power levels based on the regulatory limits. The
|
||||
# country_code setting must be configured with the correct country for
|
||||
# IEEE 802.11d functions.
|
||||
# (default: 0 = disabled)
|
||||
#ieee80211d=1
|
||||
|
||||
# Enable IEEE 802.11h. This enables the TPC and DFS services when operating
|
||||
# in a regulatory domain which requires them. Once enabled it will be
|
||||
# operational only when working in hw_mode a and in countries where it is
|
||||
# required. The end user should not be allowed to disable this.
|
||||
# The country_code setting must be configured with the correct country for
|
||||
# IEEE 802.11h to function.
|
||||
# When IEEE 802.11h is operational, the channel_policy and configured channel
|
||||
# settings will be ignored but will behave as though the channel_policy is
|
||||
# set to "3" (automatic channel selection). When IEEE 802.11h is enabled but
|
||||
# not operational (for example, if the radio mode is changed from "a" to "b")
|
||||
# the channel_policy and channel settings take effect again.
|
||||
# (default: 1 = enabled)
|
||||
#ieee80211h=1
|
||||
|
||||
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
|
||||
# Default: IEEE 802.11b
|
||||
hw_mode=a
|
||||
|
||||
# Channel number (IEEE 802.11)
|
||||
# (default: 0, i.e., not set, used with channel_policy=2)
|
||||
channel=60
|
||||
|
||||
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
||||
beacon_int=100
|
||||
|
||||
# DTIM (delivery trafic information message) period (range 1..255):
|
||||
# number of beacons between DTIMs (1 = every beacon includes DTIM element)
|
||||
# (default: 2)
|
||||
dtim_period=2
|
||||
|
||||
# Maximum number of stations allowed in station table. New stations will be
|
||||
# rejected after the station table is full. IEEE 802.11 has a limit of 2007
|
||||
# different association IDs, so this number should not be larger than that.
|
||||
# (default: 2007)
|
||||
max_num_sta=255
|
||||
|
||||
# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
|
||||
# If this field is not included in hostapd.conf, hostapd will not control
|
||||
# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
|
||||
rts_threshold=2347
|
||||
|
||||
# Fragmentation threshold; 2346 = disabled (default); range 256..2346
|
||||
# If this field is not included in hostapd.conf, hostapd will not control
|
||||
# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
|
||||
# it.
|
||||
fragm_threshold=2346
|
||||
|
||||
# Rate configuration
|
||||
# Default is to enable all rates supported by the hardware. This configuration
|
||||
# item allows this list be filtered so that only the listed rates will be left
|
||||
# in the list. If the list is empty, all rates are used. This list can have
|
||||
# entries that are not in the list of rates the hardware supports (such entries
|
||||
# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
|
||||
# If this item is present, at least one rate have to be matching with the rates
|
||||
# hardware supports.
|
||||
# default: use the most common supported rate setting for the selected
|
||||
# hw_mode (i.e., this line can be removed from configuration file in most
|
||||
# cases)
|
||||
#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
|
||||
|
||||
# Basic rate set configuration
|
||||
# List of rates (in 100 kbps) that are included in the basic rate set.
|
||||
# If this item is not included, usually reasonable default set is used.
|
||||
#basic_rates=10 20
|
||||
#basic_rates=10 20 55 110
|
||||
#basic_rates=60 120 240
|
||||
|
||||
# Station MAC address -based authentication
|
||||
# Please note that this kind of access control requires a driver that uses
|
||||
# hostapd to take care of management frame processing and as such, this can be
|
||||
# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
|
||||
# 0 = accept unless in deny list
|
||||
# 1 = deny unless in accept list
|
||||
# 2 = use external RADIUS server (accept/deny lists are searched first)
|
||||
macaddr_acl=0
|
||||
|
||||
# Accept/deny lists are read from separate files (containing list of
|
||||
# MAC addresses, one per line). Use absolute path name to make sure that the
|
||||
# files can be read on SIGHUP configuration reloads.
|
||||
#accept_mac_file=/etc/hostapd.accept
|
||||
#deny_mac_file=/etc/hostapd.deny
|
||||
|
||||
# IEEE 802.11 specifies two authentication algorithms. hostapd can be
|
||||
# configured to allow both of these or only one. Open system authentication
|
||||
# should be used with IEEE 802.1X.
|
||||
# Bit fields of allowed authentication algorithms:
|
||||
# bit 0 = Open System Authentication
|
||||
# bit 1 = Shared Key Authentication (requires WEP)
|
||||
auth_algs=3
|
||||
|
||||
# Send empty SSID in beacons and ignore probe request frames that do not
|
||||
# specify full SSID, i.e., require stations to know SSID.
|
||||
# default: disabled (0)
|
||||
# 1 = send empty (length=0) SSID in beacon and ignore probe request for
|
||||
# broadcast SSID
|
||||
# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
|
||||
# with some clients that do not support empty SSID) and ignore probe
|
||||
# requests for broadcast SSID
|
||||
ignore_broadcast_ssid=0
|
||||
|
||||
# TX queue parameters (EDCF / bursting)
|
||||
# default for all these fields: not set, use hardware defaults
|
||||
# tx_queue_<queue name>_<param>
|
||||
# queues: data0, data1, data2, data3, after_beacon, beacon
|
||||
# (data0 is the highest priority queue)
|
||||
# parameters:
|
||||
# aifs: AIFS (default 2)
|
||||
# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
|
||||
# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
|
||||
# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
|
||||
# bursting
|
||||
#
|
||||
# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
|
||||
# These parameters are used by the access point when transmitting frames
|
||||
# to the clients.
|
||||
#
|
||||
# Low priority / AC_BK = background
|
||||
#tx_queue_data3_aifs=7
|
||||
#tx_queue_data3_cwmin=15
|
||||
#tx_queue_data3_cwmax=1023
|
||||
#tx_queue_data3_burst=0
|
||||
# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
|
||||
#
|
||||
# Normal priority / AC_BE = best effort
|
||||
#tx_queue_data2_aifs=3
|
||||
#tx_queue_data2_cwmin=15
|
||||
#tx_queue_data2_cwmax=63
|
||||
#tx_queue_data2_burst=0
|
||||
# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
|
||||
#
|
||||
# High priority / AC_VI = video
|
||||
#tx_queue_data1_aifs=1
|
||||
#tx_queue_data1_cwmin=7
|
||||
#tx_queue_data1_cwmax=15
|
||||
#tx_queue_data1_burst=3.0
|
||||
# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
|
||||
#
|
||||
# Highest priority / AC_VO = voice
|
||||
#tx_queue_data0_aifs=1
|
||||
#tx_queue_data0_cwmin=3
|
||||
#tx_queue_data0_cwmax=7
|
||||
#tx_queue_data0_burst=1.5
|
||||
# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
|
||||
#
|
||||
# Special queues; normally not user configurable
|
||||
#
|
||||
#tx_queue_after_beacon_aifs=2
|
||||
#tx_queue_after_beacon_cwmin=15
|
||||
#tx_queue_after_beacon_cwmax=1023
|
||||
#tx_queue_after_beacon_burst=0
|
||||
#
|
||||
#tx_queue_beacon_aifs=2
|
||||
#tx_queue_beacon_cwmin=3
|
||||
#tx_queue_beacon_cwmax=7
|
||||
#tx_queue_beacon_burst=1.5
|
||||
|
||||
# 802.1D Tag 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
|
||||
# 4 CL AC_VI Video
|
||||
# 5 VI AC_VI Video
|
||||
# 6 VO AC_VO Voice
|
||||
# 7 NC AC_VO Voice
|
||||
# Data frames with no priority information: AC_BE
|
||||
# Management frames: AC_VO
|
||||
# PS-Poll frames: AC_BE
|
||||
|
||||
# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
|
||||
# for 802.11a or 802.11g networks
|
||||
# These parameters are sent to WMM clients when they associate.
|
||||
# The parameters will be used by WMM clients for frames transmitted to the
|
||||
# access point.
|
||||
#
|
||||
# note - txop_limit is in units of 32microseconds
|
||||
# note - acm is admission control mandatory flag. 0 = admission control not
|
||||
# required, 1 = mandatory
|
||||
# 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
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
|
||||
|
||||
# Associate as a station to another AP while still acting as an AP on the same
|
||||
# channel.
|
||||
#assoc_ap_addr=00:12:34:56:78:9a
|
||||
|
||||
# Static WEP key configuration
|
||||
#
|
||||
# The key number to use when transmitting.
|
||||
# It must be between 0 and 3, and the corresponding key must be set.
|
||||
# default: not set
|
||||
#wep_default_key=0
|
||||
# The WEP keys to use.
|
||||
# A key may be a quoted string or unquoted hexadecimal digits.
|
||||
# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
|
||||
# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
|
||||
# 128-bit (152-bit) WEP is used.
|
||||
# Only the default key must be supplied; the others are optional.
|
||||
# default: not set
|
||||
#wep_key0=123456789a
|
||||
#wep_key1="vwxyz"
|
||||
#wep_key2=0102030405060708090a0b0c0d
|
||||
#wep_key3=".2.4.6.8.0.23"
|
||||
|
||||
# Station inactivity limit
|
||||
#
|
||||
# If a station does not send anything in ap_max_inactivity seconds, an
|
||||
# empty data frame is sent to it in order to verify whether it is
|
||||
# still in range. If this frame is not ACKed, the station will be
|
||||
# disassociated and then deauthenticated. This feature is used to
|
||||
# clear station table of old entries when the STAs move out of the
|
||||
# range.
|
||||
#
|
||||
# The station can associate again with the AP if it is still in range;
|
||||
# this inactivity poll is just used as a nicer way of verifying
|
||||
# inactivity; i.e., client will not report broken connection because
|
||||
# disassociation frame is not sent immediately without first polling
|
||||
# the STA with a data frame.
|
||||
# default: 300 (i.e., 5 minutes)
|
||||
#ap_max_inactivity=300
|
||||
|
||||
# Enable/disable internal bridge for packets between associated stations.
|
||||
#
|
||||
# When IEEE 802.11 is used in managed mode, packets are usually send through
|
||||
# the AP even if they are from a wireless station to another wireless station.
|
||||
# This functionality requires that the AP has a bridge functionality that sends
|
||||
# frames back to the same interface if their destination is another associated
|
||||
# station. In addition, broadcast/multicast frames from wireless stations will
|
||||
# be sent both to the host system net stack (e.g., to eventually wired network)
|
||||
# and back to the wireless interface.
|
||||
#
|
||||
# The internal bridge is implemented within the wireless kernel module and it
|
||||
# bypasses kernel filtering (netfilter/iptables/ebtables). If direct
|
||||
# communication between the stations needs to be prevented, the internal
|
||||
# bridge can be disabled by setting bridge_packets=0.
|
||||
#
|
||||
# Note: If this variable is not included in hostapd.conf, hostapd does not
|
||||
# change the configuration and iwpriv can be used to set the value with
|
||||
# 'iwpriv wlan# param 10 0' command. If the variable is in hostapd.conf,
|
||||
# hostapd will override possible iwpriv configuration whenever configuration
|
||||
# file is reloaded.
|
||||
#
|
||||
# default: do not control from hostapd (80211.o defaults to 1=enabled)
|
||||
#bridge_packets=1
|
||||
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
#ieee8021x=1
|
||||
|
||||
# IEEE 802.1X/EAPOL version
|
||||
# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
|
||||
# version 2. However, there are many client implementations that do not handle
|
||||
# the new version number correctly (they seem to drop the frames completely).
|
||||
# In order to make hostapd interoperate with these clients, the version number
|
||||
# can be set to the older version (1) with this configuration value.
|
||||
#eapol_version=2
|
||||
|
||||
# Optional displayable message sent with EAP Request-Identity. The first \0
|
||||
# in this string will be converted to ASCII-0 (nul). This can be used to
|
||||
# separate network info (comma separated list of attribute=value pairs); see,
|
||||
# e.g., RFC 4284.
|
||||
#eap_message=hello
|
||||
#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
|
||||
|
||||
# WEP rekeying (disabled if key lengths are not set or are set to 0)
|
||||
# Key lengths for default/broadcast and individual/unicast keys:
|
||||
# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
|
||||
# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
|
||||
#wep_key_len_broadcast=5
|
||||
#wep_key_len_unicast=5
|
||||
# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
|
||||
#wep_rekey_period=300
|
||||
|
||||
# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
|
||||
# only broadcast keys are used)
|
||||
eapol_key_index_workaround=0
|
||||
|
||||
# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
|
||||
# reauthentication).
|
||||
#eap_reauth_period=3600
|
||||
|
||||
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
|
||||
# address when sending EAPOL frames with driver=wired. This is the most common
|
||||
# mechanism used in wired authentication, but it also requires that the port
|
||||
# is only used by one station.
|
||||
#use_pae_group_addr=1
|
||||
|
||||
##### Integrated EAP server ###################################################
|
||||
|
||||
# Optionally, hostapd can be configured to use an integrated EAP server
|
||||
# to process EAP authentication locally without need for an external RADIUS
|
||||
# server. This functionality can be used both as a local authentication server
|
||||
# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
|
||||
|
||||
# Use integrated EAP server instead of external RADIUS authentication
|
||||
# server. This is also needed if hostapd is configured to act as a RADIUS
|
||||
# authentication server.
|
||||
eap_server=0
|
||||
|
||||
# Path for EAP server user database
|
||||
#eap_user_file=/etc/hostapd.eap_user
|
||||
|
||||
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#ca_cert=/etc/hostapd.ca.pem
|
||||
|
||||
# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
|
||||
#server_cert=/etc/hostapd.server.pem
|
||||
|
||||
# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
|
||||
# This may point to the same file as server_cert if both certificate and key
|
||||
# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
|
||||
# used by commenting out server_cert and specifying the PFX file as the
|
||||
# private_key.
|
||||
#private_key=/etc/hostapd.server.prv
|
||||
|
||||
# Passphrase for private key
|
||||
#private_key_passwd=secret passphrase
|
||||
|
||||
# Enable CRL verification.
|
||||
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
|
||||
# valid CRL signed by the CA is required to be included in the ca_cert file.
|
||||
# This can be done by using PEM format for CA certificate and CRL and
|
||||
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
|
||||
# restarted to take the new CRL into use.
|
||||
# 0 = do not verify CRLs (default)
|
||||
# 1 = check the CRL of the user certificate
|
||||
# 2 = check all CRLs in the certificate path
|
||||
#check_crl=1
|
||||
|
||||
# dh_file: File path to DH/DSA parameters file (in PEM format)
|
||||
# This is an optional configuration file for setting parameters for an
|
||||
# ephemeral DH key exchange. In most cases, the default RSA authentication does
|
||||
# not use this configuration. However, it is possible setup RSA to use
|
||||
# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
|
||||
# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
|
||||
# is in DSA parameters format, it will be automatically converted into DH
|
||||
# params. This parameter is required if anonymous EAP-FAST is used.
|
||||
#dh_file=/etc/hostapd.dh.pem
|
||||
|
||||
# Configuration data for EAP-SIM database/authentication gateway interface.
|
||||
# This is a text string in implementation specific format. The example
|
||||
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
|
||||
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
|
||||
# prefix.
|
||||
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
|
||||
|
||||
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
|
||||
# random value. It is configured as a 16-octet value in hex format. It can be
|
||||
# generated, e.g., with the following command:
|
||||
# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
|
||||
#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
|
||||
|
||||
# EAP-FAST authority identity (A-ID)
|
||||
#eap_fast_a_id=test server
|
||||
|
||||
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
|
||||
# (default: 0 = disabled).
|
||||
#eap_sim_aka_result_ind=1
|
||||
|
||||
|
||||
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
|
||||
|
||||
# Interface to be used for IAPP broadcast packets
|
||||
#iapp_interface=eth0
|
||||
|
||||
|
||||
##### RADIUS client configuration #############################################
|
||||
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
|
||||
# authentication with external ACL for MAC addresses, and accounting
|
||||
|
||||
# The own IP address of the access point (used as NAS-IP-Address)
|
||||
own_ip_addr=127.0.0.1
|
||||
|
||||
# Optional NAS-Identifier string for RADIUS messages. When used, this should be
|
||||
# a unique to the NAS within the scope of the RADIUS server. For example, a
|
||||
# fully qualified domain name can be used here.
|
||||
# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
|
||||
# 48 octets long.
|
||||
#nas_identifier=ap.example.com
|
||||
|
||||
# RADIUS authentication server
|
||||
#auth_server_addr=127.0.0.1
|
||||
#auth_server_port=1812
|
||||
#auth_server_shared_secret=secret
|
||||
|
||||
# RADIUS accounting server
|
||||
#acct_server_addr=127.0.0.1
|
||||
#acct_server_port=1813
|
||||
#acct_server_shared_secret=secret
|
||||
|
||||
# Secondary RADIUS servers; to be used if primary one does not reply to
|
||||
# RADIUS packets. These are optional and there can be more than one secondary
|
||||
# server listed.
|
||||
#auth_server_addr=127.0.0.2
|
||||
#auth_server_port=1812
|
||||
#auth_server_shared_secret=secret2
|
||||
#
|
||||
#acct_server_addr=127.0.0.2
|
||||
#acct_server_port=1813
|
||||
#acct_server_shared_secret=secret2
|
||||
|
||||
# Retry interval for trying to return to the primary RADIUS server (in
|
||||
# seconds). RADIUS client code will automatically try to use the next server
|
||||
# when the current server is not replying to requests. If this interval is set,
|
||||
# primary server will be retried after configured amount of time even if the
|
||||
# currently used secondary server is still working.
|
||||
#radius_retry_primary_interval=600
|
||||
|
||||
|
||||
# Interim accounting update interval
|
||||
# If this is set (larger than 0) and acct_server is configured, hostapd will
|
||||
# send interim accounting updates every N seconds. Note: if set, this overrides
|
||||
# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
|
||||
# value should not be configured in hostapd.conf, if RADIUS server is used to
|
||||
# control the interim interval.
|
||||
# This value should not be less 600 (10 minutes) and must not be less than
|
||||
# 60 (1 minute).
|
||||
#radius_acct_interim_interval=600
|
||||
|
||||
# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
|
||||
# is used for the stations. This information is parsed from following RADIUS
|
||||
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
|
||||
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
|
||||
# VLANID as a string). vlan_file option below must be configured if dynamic
|
||||
# VLANs are used.
|
||||
# 0 = disabled (default)
|
||||
# 1 = option; use default interface if RADIUS server does not include VLAN ID
|
||||
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
|
||||
#dynamic_vlan=0
|
||||
|
||||
# VLAN interface list for dynamic VLAN mode is read from a separate text file.
|
||||
# This list is used to map VLAN ID from the RADIUS server to a network
|
||||
# interface. Each station is bound to one interface in the same way as with
|
||||
# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
|
||||
# interface and the line must include VLAN ID and interface name separated by
|
||||
# white space (space or tab).
|
||||
#vlan_file=/etc/hostapd.vlan
|
||||
|
||||
# Interface where 802.1q tagged packets should appear when a RADIUS server is
|
||||
# used to determine which VLAN a station is on. hostapd creates a bridge for
|
||||
# each VLAN. Then hostapd adds a VLAN interface (associated with the interface
|
||||
# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
|
||||
# to the bridge.
|
||||
#vlan_tagged_interface=eth0
|
||||
|
||||
|
||||
##### RADIUS authentication server configuration ##############################
|
||||
|
||||
# hostapd can be used as a RADIUS authentication server for other hosts. This
|
||||
# requires that the integrated EAP server is also enabled and both
|
||||
# authentication services are sharing the same configuration.
|
||||
|
||||
# File name of the RADIUS clients configuration for the RADIUS server. If this
|
||||
# commented out, RADIUS server is disabled.
|
||||
#radius_server_clients=/etc/hostapd.radius_clients
|
||||
|
||||
# The UDP port number for the RADIUS authentication server
|
||||
#radius_server_auth_port=1812
|
||||
|
||||
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
|
||||
#radius_server_ipv6=1
|
||||
|
||||
|
||||
##### WPA/IEEE 802.11i configuration ##########################################
|
||||
|
||||
# Enable WPA. Setting this variable configures the AP to require WPA (either
|
||||
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
|
||||
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
|
||||
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
|
||||
# RADIUS authentication server must be configured, and WPA-EAP must be included
|
||||
# in wpa_key_mgmt.
|
||||
# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
|
||||
# and/or WPA2 (full IEEE 802.11i/RSN):
|
||||
# bit0 = WPA
|
||||
# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
|
||||
#wpa=1
|
||||
|
||||
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
|
||||
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
|
||||
# wpa_psk (dot11RSNAConfigPSKValue)
|
||||
# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
|
||||
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
#wpa_passphrase=secret passphrase
|
||||
|
||||
# Optionally, WPA PSKs can be read from a separate text file (containing list
|
||||
# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
|
||||
# Use absolute path name to make sure that the files can be read on SIGHUP
|
||||
# configuration reloads.
|
||||
#wpa_psk_file=/etc/hostapd.wpa_psk
|
||||
|
||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||
# entries are separated with a space.
|
||||
# (dot11RSNAConfigAuthenticationSuitesTable)
|
||||
#wpa_key_mgmt=WPA-PSK WPA-EAP
|
||||
|
||||
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
|
||||
# (unicast packets). This is a space separated list of algorithms:
|
||||
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
|
||||
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
|
||||
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
|
||||
# is automatically selected based on this configuration. If only CCMP is
|
||||
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
|
||||
# TKIP will be used as the group cipher.
|
||||
# (dot11RSNAConfigPairwiseCiphersTable)
|
||||
# Pairwise cipher for WPA (v1) (default: TKIP)
|
||||
#wpa_pairwise=TKIP CCMP
|
||||
# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
|
||||
#rsn_pairwise=CCMP
|
||||
|
||||
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
|
||||
# seconds. (dot11RSNAConfigGroupRekeyTime)
|
||||
#wpa_group_rekey=600
|
||||
|
||||
# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
|
||||
# (dot11RSNAConfigGroupRekeyStrict)
|
||||
#wpa_strict_rekey=1
|
||||
|
||||
# Time interval for rekeying GMK (master key used internally to generate GTKs
|
||||
# (in seconds).
|
||||
#wpa_gmk_rekey=86400
|
||||
|
||||
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
|
||||
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
|
||||
# authentication and key handshake before actually associating with a new AP.
|
||||
# (dot11RSNAPreauthenticationEnabled)
|
||||
#rsn_preauth=1
|
||||
#
|
||||
# Space separated list of interfaces from which pre-authentication frames are
|
||||
# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
|
||||
# interface that are used for connections to other APs. This could include
|
||||
# wired interfaces and WDS links. The normal wireless data interface towards
|
||||
# associated stations (e.g., wlan0) should not be added, since
|
||||
# pre-authentication is only used with APs other than the currently associated
|
||||
# one.
|
||||
#rsn_preauth_interfaces=eth0
|
||||
|
||||
# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
|
||||
# allowed. This is only used with RSN/WPA2.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#peerkey=1
|
||||
|
||||
# ieee80211w: Whether management frame protection is enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = optional
|
||||
# 2 = required
|
||||
#ieee80211w=0
|
||||
|
||||
|
||||
##### IEEE 802.11r configuration ##############################################
|
||||
|
||||
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||
# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
|
||||
# same SSID) between which a STA can use Fast BSS Transition.
|
||||
# 2-octet identifier as a hex string.
|
||||
#mobility_domain=a1b2
|
||||
|
||||
# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
|
||||
# 1 to 48 octet identifier.
|
||||
# This is configured with nas_identifier (see RADIUS client section above).
|
||||
|
||||
# Default lifetime of the PMK-RO in minutes; range 1..65535
|
||||
# (dot11FTR0KeyLifetime)
|
||||
#r0_key_lifetime=10000
|
||||
|
||||
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
|
||||
# 6-octet identifier as a hex string.
|
||||
#r1_key_holder=000102030405
|
||||
|
||||
# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
|
||||
# (dot11FTReassociationDeadline)
|
||||
#reassociation_deadline=1000
|
||||
|
||||
# List of R0KHs in the same Mobility Domain
|
||||
# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
|
||||
# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
|
||||
# address when requesting PMK-R1 key from the R0KH that the STA used during the
|
||||
# Initial Mobility Domain Association.
|
||||
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
|
||||
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
|
||||
# And so on.. One line per R0KH.
|
||||
|
||||
# List of R1KHs in the same Mobility Domain
|
||||
# format: <MAC address> <R0KH-ID> <128-bit key as hex string>
|
||||
# This list is used to map R1KH-ID to a destination MAC address when sending
|
||||
# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
|
||||
# that can request PMK-R1 keys.
|
||||
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
|
||||
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
|
||||
# And so on.. One line per R1KH.
|
||||
|
||||
# Whether PMK-R1 push is enabled at R0KH
|
||||
# 0 = do not push PMK-R1 to all configured R1KHs (default)
|
||||
# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
|
||||
#pmk_r1_push=1
|
||||
|
||||
##### Passive scanning ########################################################
|
||||
# Scan different channels every N seconds. 0 = disable passive scanning.
|
||||
#passive_scan_interval=60
|
||||
|
||||
# Listen N usecs on each channel when doing passive scanning.
|
||||
# This value plus the time needed for changing channels should be less than
|
||||
# 32 milliseconds (i.e. 32000 usec) to avoid interruptions to normal
|
||||
# operations. Time needed for channel changing varies based on the used wlan
|
||||
# hardware.
|
||||
# default: disabled (0)
|
||||
#passive_scan_listen=10000
|
||||
|
||||
# Passive scanning mode:
|
||||
# 0 = scan all supported modes (802.11a/b/g/Turbo) (default)
|
||||
# 1 = scan only the mode that is currently used for normal operations
|
||||
#passive_scan_mode=1
|
||||
|
||||
# Maximum number of entries kept in AP table (either for passive scanning or
|
||||
# for detecting Overlapping Legacy BSS Condition). The oldest entry will be
|
||||
# removed when adding a new entry that would make the list grow over this
|
||||
# limit. Note! Wi-Fi certification for IEEE 802.11g requires that OLBC is
|
||||
# enabled, so this field should not be set to 0 when using IEEE 802.11g.
|
||||
# default: 255
|
||||
#ap_table_max_size=255
|
||||
|
||||
# Number of seconds of no frames received after which entries may be deleted
|
||||
# from the AP table. Since passive scanning is not usually performed frequently
|
||||
# this should not be set to very small value. In addition, there is no
|
||||
# guarantee that every scan cycle will receive beacon frames from the
|
||||
# neighboring APs.
|
||||
# default: 60
|
||||
#ap_table_expiration_time=3600
|
||||
|
||||
|
||||
##### Multiple BSSID support ##################################################
|
||||
#
|
||||
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
|
||||
# interfaces). Other BSSIDs can be added by using separator 'bss' with
|
||||
# default interface name to be allocated for the data packets of the new BSS.
|
||||
#
|
||||
# hostapd will generate BSSID mask based on the BSSIDs that are
|
||||
# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
|
||||
# not the case, the MAC address of the radio must be changed before starting
|
||||
# hostapd (ifconfig wlan0 hw ether <MAC addr>).
|
||||
#
|
||||
# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
|
||||
# specified using the 'bssid' parameter.
|
||||
# If an explicit BSSID is specified, it must be chosen such that it:
|
||||
# - results in a valid MASK that covers it and the dev_addr
|
||||
# - is not the same as the MAC address of the radio
|
||||
# - is not the same as any other explicitly specified BSSID
|
||||
#
|
||||
# Please note that hostapd uses some of the values configured for the first BSS
|
||||
# as the defaults for the following BSSes. However, it is recommended that all
|
||||
# BSSes include explicit configuration of all relevant configuration items.
|
||||
#
|
||||
#bss=wlan0_0
|
||||
#ssid=test2
|
||||
# most of the above items can be used here (apart from radio interface specific
|
||||
# items, like channel)
|
||||
|
||||
#bss=wlan0_1
|
||||
#bssid=00:13:10:95:fe:0b
|
||||
# ...
|
@ -0,0 +1,5 @@
|
||||
# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
|
||||
# with the AP.
|
||||
00:20:30:40:50:60
|
||||
00:ab:cd:ef:12:34
|
||||
00:00:30:40:50:60
|
@ -0,0 +1,91 @@
|
||||
# hostapd user database for integrated EAP server
|
||||
|
||||
# Each line must contain an identity, EAP method(s), and an optional password
|
||||
# separated with whitespace (space or tab). The identity and password must be
|
||||
# double quoted ("user"). Password can alternatively be stored as
|
||||
# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
|
||||
# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
|
||||
# that the plaintext password does not need to be included in the user file.
|
||||
# Password hash is stored as hash:<16-octets of hex data> without quotation
|
||||
# marks.
|
||||
|
||||
# [2] flag in the end of the line can be used to mark users for tunneled phase
|
||||
# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
|
||||
# identity can be used in the unencrypted phase 1 and the real user identity
|
||||
# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
|
||||
# access is needed, two user entries is needed, one for phase 1 and another
|
||||
# with the same username for phase 2.
|
||||
#
|
||||
# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
|
||||
# password option.
|
||||
# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
|
||||
# password.
|
||||
# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
|
||||
#
|
||||
# * can be used as a wildcard to match any user identity. The main purposes for
|
||||
# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
|
||||
# avoid having to configure every certificate for EAP-TLS authentication. The
|
||||
# first matching entry is selected, so * should be used as the last phase 1
|
||||
# user entry.
|
||||
#
|
||||
# "prefix"* can be used to match the given prefix and anything after this. The
|
||||
# main purpose for this is to be able to avoid EAP method negotiation when the
|
||||
# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
|
||||
# is only allowed for phase 1 identities.
|
||||
#
|
||||
# Multiple methods can be configured to make the authenticator try them one by
|
||||
# one until the peer accepts one. The method names are separated with a
|
||||
# comma (,).
|
||||
#
|
||||
# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
|
||||
# version based on the Phase 1 identity. Without this flag, the EAP
|
||||
# authenticator advertises the highest supported version and select the version
|
||||
# based on the first PEAP packet from the supplicant.
|
||||
#
|
||||
# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
|
||||
# Tunneled EAP methods are configured with standard EAP method name and [2]
|
||||
# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
|
||||
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
|
||||
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
|
||||
# hash.
|
||||
|
||||
# Phase 1 users
|
||||
"user" MD5 "password"
|
||||
"test user" MD5 "secret"
|
||||
"example user" TLS
|
||||
"DOMAIN\user" MSCHAPV2 "password"
|
||||
"gtc user" GTC "password"
|
||||
"pax user" PAX "unknown"
|
||||
"pax.user@example.com" PAX 0123456789abcdef0123456789abcdef
|
||||
"psk user" PSK "unknown"
|
||||
"psk.user@example.com" PSK 0123456789abcdef0123456789abcdef
|
||||
"sake.user@example.com" SAKE 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
"ttls" TTLS
|
||||
"not anonymous" PEAP
|
||||
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
|
||||
"0"* AKA,TTLS,TLS,PEAP,SIM
|
||||
"1"* SIM,TTLS,TLS,PEAP,AKA
|
||||
"2"* AKA,TTLS,TLS,PEAP,SIM
|
||||
"3"* SIM,TTLS,TLS,PEAP,AKA
|
||||
"4"* AKA,TTLS,TLS,PEAP,SIM
|
||||
"5"* SIM,TTLS,TLS,PEAP,AKA
|
||||
|
||||
# Wildcard for all other identities
|
||||
* PEAP,TTLS,TLS,SIM,AKA
|
||||
|
||||
# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
|
||||
"t-md5" MD5 "password" [2]
|
||||
"DOMAIN\t-mschapv2" MSCHAPV2 "password" [2]
|
||||
"t-gtc" GTC "password" [2]
|
||||
"not anonymous" MSCHAPV2 "password" [2]
|
||||
"user" MD5,GTC,MSCHAPV2 "password" [2]
|
||||
"test user" MSCHAPV2 hash:000102030405060708090a0b0c0d0e0f [2]
|
||||
"ttls-user" TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2 "password" [2]
|
||||
|
||||
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
|
||||
"0"* AKA [2]
|
||||
"1"* SIM [2]
|
||||
"2"* AKA [2]
|
||||
"3"* SIM [2]
|
||||
"4"* AKA [2]
|
||||
"5"* SIM [2]
|
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* hostapd / Initialization and configuration
|
||||
* Host AP kernel driver
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef HOSTAPD_H
|
||||
#define HOSTAPD_H
|
||||
|
||||
#include "common.h"
|
||||
#include "ap.h"
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
#ifndef ETH_P_ALL
|
||||
#define ETH_P_ALL 0x0003
|
||||
#endif
|
||||
#ifndef ETH_P_PAE
|
||||
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||
#endif /* ETH_P_PAE */
|
||||
#ifndef ETH_P_EAPOL
|
||||
#define ETH_P_EAPOL ETH_P_PAE
|
||||
#endif /* ETH_P_EAPOL */
|
||||
|
||||
#ifndef ETH_P_RRB
|
||||
#define ETH_P_RRB 0x890D
|
||||
#endif /* ETH_P_RRB */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define MAX_VLAN_ID 4094
|
||||
|
||||
struct ieee8023_hdr {
|
||||
u8 dest[6];
|
||||
u8 src[6];
|
||||
u16 ethertype;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
struct ieee80211_hdr {
|
||||
le16 frame_control;
|
||||
le16 duration_id;
|
||||
u8 addr1[6];
|
||||
u8 addr2[6];
|
||||
u8 addr3[6];
|
||||
le16 seq_ctrl;
|
||||
/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
|
||||
*/
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define IEEE80211_DA_FROMDS addr1
|
||||
#define IEEE80211_BSSID_FROMDS addr2
|
||||
#define IEEE80211_SA_FROMDS addr3
|
||||
|
||||
#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
|
||||
|
||||
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
|
||||
|
||||
/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
|
||||
* frames that might be longer than normal default MTU and they are not
|
||||
* fragmented */
|
||||
#define HOSTAPD_MTU 2290
|
||||
|
||||
extern unsigned char rfc1042_header[6];
|
||||
|
||||
struct hostap_sta_driver_data {
|
||||
unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
|
||||
unsigned long current_tx_rate;
|
||||
unsigned long inactive_msec;
|
||||
unsigned long flags;
|
||||
unsigned long num_ps_buf_frames;
|
||||
unsigned long tx_retry_failed;
|
||||
unsigned long tx_retry_count;
|
||||
int last_rssi;
|
||||
int last_ack_rssi;
|
||||
};
|
||||
|
||||
struct wpa_driver_ops;
|
||||
struct wpa_ctrl_dst;
|
||||
struct radius_server_data;
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
struct full_dynamic_vlan;
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
/**
|
||||
* struct hostapd_data - hostapd per-BSS data structure
|
||||
*/
|
||||
struct hostapd_data {
|
||||
struct hostapd_iface *iface;
|
||||
struct hostapd_config *iconf;
|
||||
struct hostapd_bss_config *conf;
|
||||
int interface_added; /* virtual interface added for this BSS */
|
||||
|
||||
u8 own_addr[ETH_ALEN];
|
||||
|
||||
int num_sta; /* number of entries in sta_list */
|
||||
struct sta_info *sta_list; /* STA info list head */
|
||||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
|
||||
/* pointers to STA info; based on allocated AID or NULL if AID free
|
||||
* AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
|
||||
* and so on
|
||||
*/
|
||||
struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
|
||||
|
||||
const struct wpa_driver_ops *driver;
|
||||
void *drv_priv;
|
||||
|
||||
u8 *default_wep_key;
|
||||
u8 default_wep_key_idx;
|
||||
|
||||
struct radius_client_data *radius;
|
||||
int radius_client_reconfigured;
|
||||
u32 acct_session_id_hi, acct_session_id_lo;
|
||||
|
||||
struct iapp_data *iapp;
|
||||
|
||||
enum { DO_NOT_ASSOC = 0, WAIT_BEACON, AUTHENTICATE, ASSOCIATE,
|
||||
ASSOCIATED } assoc_ap_state;
|
||||
char assoc_ap_ssid[33];
|
||||
int assoc_ap_ssid_len;
|
||||
u16 assoc_ap_aid;
|
||||
|
||||
struct hostapd_cached_radius_acl *acl_cache;
|
||||
struct hostapd_acl_query_data *acl_queries;
|
||||
|
||||
struct wpa_authenticator *wpa_auth;
|
||||
struct eapol_authenticator *eapol_auth;
|
||||
|
||||
struct rsn_preauth_interface *preauth_iface;
|
||||
time_t michael_mic_failure;
|
||||
int michael_mic_failures;
|
||||
int tkip_countermeasures;
|
||||
|
||||
int ctrl_sock;
|
||||
struct wpa_ctrl_dst *ctrl_dst;
|
||||
|
||||
void *ssl_ctx;
|
||||
void *eap_sim_db_priv;
|
||||
struct radius_server_data *radius_srv;
|
||||
|
||||
int parameter_set_count;
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
struct full_dynamic_vlan *full_dynamic_vlan;
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
struct l2_packet_data *l2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_iface_cb - Generic callback type for per-iface asynchronous requests
|
||||
* @iface: the interface the event occured on.
|
||||
* @status: 0 if the request succeeded; -1 if the request failed.
|
||||
*/
|
||||
typedef void (*hostapd_iface_cb)(struct hostapd_iface *iface, int status);
|
||||
|
||||
|
||||
struct hostapd_config_change;
|
||||
|
||||
/**
|
||||
* struct hostapd_iface - hostapd per-interface data structure
|
||||
*/
|
||||
struct hostapd_iface {
|
||||
char *config_fname;
|
||||
struct hostapd_config *conf;
|
||||
|
||||
hostapd_iface_cb setup_cb;
|
||||
|
||||
size_t num_bss;
|
||||
struct hostapd_data **bss;
|
||||
|
||||
int num_ap; /* number of entries in ap_list */
|
||||
struct ap_info *ap_list; /* AP info list head */
|
||||
struct ap_info *ap_hash[STA_HASH_SIZE];
|
||||
struct ap_info *ap_iter_list;
|
||||
|
||||
struct hostapd_hw_modes *hw_features;
|
||||
int num_hw_features;
|
||||
struct hostapd_hw_modes *current_mode;
|
||||
/* Rates that are currently used (i.e., filtered copy of
|
||||
* current_mode->channels */
|
||||
int num_rates;
|
||||
struct hostapd_rate_data *current_rates;
|
||||
hostapd_iface_cb hw_mode_sel_cb;
|
||||
|
||||
u16 hw_flags;
|
||||
|
||||
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
|
||||
* in 802.11g BSS) */
|
||||
int num_sta_non_erp;
|
||||
|
||||
/* Number of associated stations that do not support Short Slot Time */
|
||||
int num_sta_no_short_slot_time;
|
||||
|
||||
/* Number of associated stations that do not support Short Preamble */
|
||||
int num_sta_no_short_preamble;
|
||||
|
||||
int olbc; /* Overlapping Legacy BSS Condition */
|
||||
|
||||
int dfs_enable;
|
||||
u8 pwr_const;
|
||||
unsigned int tx_power;
|
||||
unsigned int sta_max_power;
|
||||
|
||||
unsigned int channel_switch;
|
||||
|
||||
struct hostapd_config_change *change;
|
||||
hostapd_iface_cb reload_iface_cb;
|
||||
hostapd_iface_cb config_reload_cb;
|
||||
};
|
||||
|
||||
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int reassoc);
|
||||
|
||||
#endif /* HOSTAPD_H */
|
@ -0,0 +1,4 @@
|
||||
# RADIUS client configuration for the RADIUS server
|
||||
10.1.2.3 secret passphrase
|
||||
192.168.1.0/24 another very secret passphrase
|
||||
0.0.0.0/0 radius
|
@ -0,0 +1,9 @@
|
||||
# Example GSM authentication triplet file for EAP-SIM authenticator
|
||||
# IMSI:Kc:SRES:RAND
|
||||
# IMSI: ASCII string (numbers)
|
||||
# Kc: hex, 8 octets
|
||||
# SRES: hex, 4 octets
|
||||
# RAND: hex, 16 octets
|
||||
234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||
234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
|
@ -0,0 +1,9 @@
|
||||
# VLAN ID to network interface mapping
|
||||
1 vlan1
|
||||
2 vlan2
|
||||
3 vlan3
|
||||
100 guest
|
||||
# Optional wildcard entry matching all VLAN IDs. The first # in the interface
|
||||
# name will be replaced with the VLAN ID. The network interfaces are created
|
||||
# (and removed) dynamically based on the use.
|
||||
* vlan#
|
@ -0,0 +1,9 @@
|
||||
# List of WPA PSKs. Each line, except for empty lines and lines starting
|
||||
# with #, must contain a MAC address and PSK separated with a space.
|
||||
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
|
||||
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
|
||||
# characters or as a 256-bit hex PSK (64 hex digits).
|
||||
00:00:00:00:00:00 secret passphrase
|
||||
00:11:22:33:44:55 another passphrase
|
||||
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
00:00:00:00:00:00 another passphrase for all STAs
|
@ -0,0 +1,83 @@
|
||||
.TH HOSTAPD_CLI 1 "April 7, 2005" hostapd_cli "hostapd command-line interface"
|
||||
.SH NAME
|
||||
hostapd_cli \- hostapd command-line interface
|
||||
.SH SYNOPSIS
|
||||
.B hostapd_cli
|
||||
[-p<path>] [-i<ifname>] [-hv] [command..]
|
||||
.SH DESCRIPTION
|
||||
This manual page documents briefly the
|
||||
.B hostapd_cli
|
||||
utility.
|
||||
.PP
|
||||
.B hostapd_cli
|
||||
is a command-line interface for the
|
||||
.B hostapd
|
||||
daemon.
|
||||
|
||||
.B hostapd
|
||||
is a user space daemon for access point and authentication servers.
|
||||
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
|
||||
For more information about
|
||||
.B hostapd
|
||||
refer to the
|
||||
.BR hostapd (8)
|
||||
man page.
|
||||
.SH OPTIONS
|
||||
A summary of options is included below.
|
||||
For a complete description, run
|
||||
.BR hostapd_cli
|
||||
from the command line.
|
||||
.TP
|
||||
.B \-p<path>
|
||||
Path to find control sockets.
|
||||
|
||||
Default: /var/run/hostapd
|
||||
.TP
|
||||
.B \-i<ifname>
|
||||
Interface to listen on.
|
||||
|
||||
Default: first interface found in socket path.
|
||||
.TP
|
||||
.B \-h
|
||||
Show usage.
|
||||
.TP
|
||||
.B \-v
|
||||
Show hostapd_cli version.
|
||||
.SH COMMANDS
|
||||
A summary of commands is included below.
|
||||
For a complete description, run
|
||||
.BR hostapd_cli
|
||||
from the command line.
|
||||
.TP
|
||||
.B mib
|
||||
Get MIB variables (dot1x, dot11, radius).
|
||||
.TP
|
||||
.B sta <addr>
|
||||
Get MIB variables for one station.
|
||||
.TP
|
||||
.B all_sta
|
||||
Get MIB variables for all stations.
|
||||
.TP
|
||||
.B help
|
||||
Get usage help.
|
||||
.TP
|
||||
.B interface [ifname]
|
||||
Show interfaces/select interface.
|
||||
.TP
|
||||
.B level <debug level>
|
||||
Change debug level.
|
||||
.TP
|
||||
.B license
|
||||
Show full
|
||||
.B hostapd_cli
|
||||
license.
|
||||
.TP
|
||||
.B quit
|
||||
Exit hostapd_cli.
|
||||
.SH SEE ALSO
|
||||
.BR hostapd (8).
|
||||
.SH AUTHOR
|
||||
hostapd_cli was written by Jouni Malinen <j@w1.fi>.
|
||||
.PP
|
||||
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
|
||||
for the Debian project (but may be used by others).
|
@ -0,0 +1,615 @@
|
||||
/*
|
||||
* hostapd - command line interface for hostapd daemon
|
||||
* Copyright (c) 2004-2008, 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 <dirent.h>
|
||||
|
||||
#include "wpa_ctrl.h"
|
||||
#include "common.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
static const char *hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
|
||||
static const char *hostapd_cli_license =
|
||||
"This program is free software. You can distribute it and/or modify it\n"
|
||||
"under the terms of the GNU General Public License version 2.\n"
|
||||
"\n"
|
||||
"Alternatively, this software may be distributed under the terms of the\n"
|
||||
"BSD license. See README and COPYING for more details.\n";
|
||||
|
||||
static const char *hostapd_cli_full_license =
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License version 2 as\n"
|
||||
"published by the Free Software Foundation.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
|
||||
"\n"
|
||||
"Alternatively, this software may be distributed under the terms of the\n"
|
||||
"BSD license.\n"
|
||||
"\n"
|
||||
"Redistribution and use in source and binary forms, with or without\n"
|
||||
"modification, are permitted provided that the following conditions are\n"
|
||||
"met:\n"
|
||||
"\n"
|
||||
"1. Redistributions of source code must retain the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer.\n"
|
||||
"\n"
|
||||
"2. Redistributions in binary form must reproduce the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer in the\n"
|
||||
" documentation and/or other materials provided with the distribution.\n"
|
||||
"\n"
|
||||
"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
|
||||
" names of its contributors may be used to endorse or promote products\n"
|
||||
" derived from this software without specific prior written permission.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
|
||||
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
|
||||
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
|
||||
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
|
||||
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
|
||||
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
|
||||
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
|
||||
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
|
||||
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
|
||||
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
|
||||
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
"\n";
|
||||
|
||||
static const char *commands_help =
|
||||
"Commands:\n"
|
||||
" mib get MIB variables (dot1x, dot11, radius)\n"
|
||||
" sta <addr> get MIB variables for one station\n"
|
||||
" all_sta get MIB variables for all stations\n"
|
||||
" new_sta <addr> add a new station\n"
|
||||
" help show this usage help\n"
|
||||
" interface [ifname] show interfaces/select interface\n"
|
||||
" level <debug level> change debug level\n"
|
||||
" license show full hostapd_cli license\n"
|
||||
" quit exit hostapd_cli\n";
|
||||
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
static int hostapd_cli_attached = 0;
|
||||
static const char *ctrl_iface_dir = "/var/run/hostapd";
|
||||
static char *ctrl_ifname = NULL;
|
||||
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n", hostapd_cli_version);
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
|
||||
"[command..]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h help (show this usage text)\n"
|
||||
" -v shown version information\n"
|
||||
" -p<path> path to find control sockets (default: "
|
||||
"/var/run/hostapd)\n"
|
||||
" -i<ifname> Interface to listen on (default: first "
|
||||
"interface found in the\n"
|
||||
" socket path)\n\n"
|
||||
"%s",
|
||||
commands_help);
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
{
|
||||
char *cfile;
|
||||
int flen;
|
||||
|
||||
if (ifname == NULL)
|
||||
return NULL;
|
||||
|
||||
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
|
||||
cfile = malloc(flen);
|
||||
if (cfile == NULL)
|
||||
return NULL;
|
||||
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
|
||||
|
||||
ctrl_conn = wpa_ctrl_open(cfile);
|
||||
free(cfile);
|
||||
return ctrl_conn;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_close_connection(void)
|
||||
{
|
||||
if (ctrl_conn == NULL)
|
||||
return;
|
||||
|
||||
if (hostapd_cli_attached) {
|
||||
wpa_ctrl_detach(ctrl_conn);
|
||||
hostapd_cli_attached = 0;
|
||||
}
|
||||
wpa_ctrl_close(ctrl_conn);
|
||||
ctrl_conn = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_msg_cb(char *msg, size_t len)
|
||||
{
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
|
||||
|
||||
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||
{
|
||||
char buf[4096];
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (ctrl_conn == NULL) {
|
||||
printf("Not connected to hostapd - command dropped.\n");
|
||||
return -1;
|
||||
}
|
||||
len = sizeof(buf) - 1;
|
||||
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||
hostapd_cli_msg_cb);
|
||||
if (ret == -2) {
|
||||
printf("'%s' command timed out.\n", cmd);
|
||||
return -2;
|
||||
} else if (ret < 0) {
|
||||
printf("'%s' command failed.\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
if (print) {
|
||||
buf[len] = '\0';
|
||||
printf("%s", buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
|
||||
{
|
||||
return _wpa_ctrl_command(ctrl, cmd, 1);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "PING");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "MIB");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char buf[64];
|
||||
if (argc != 1) {
|
||||
printf("Invalid 'sta' command - exactly one argument, STA "
|
||||
"address, is required.\n");
|
||||
return -1;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "STA %s", argv[0]);
|
||||
return wpa_ctrl_command(ctrl, buf);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char buf[64];
|
||||
if (argc != 1) {
|
||||
printf("Invalid 'new_sta' command - exactly one argument, STA "
|
||||
"address, is required.\n");
|
||||
return -1;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
|
||||
return wpa_ctrl_command(ctrl, buf);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||
char *addr, size_t addr_len)
|
||||
{
|
||||
char buf[4096], *pos;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (ctrl_conn == NULL) {
|
||||
printf("Not connected to hostapd - command dropped.\n");
|
||||
return -1;
|
||||
}
|
||||
len = sizeof(buf) - 1;
|
||||
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||
hostapd_cli_msg_cb);
|
||||
if (ret == -2) {
|
||||
printf("'%s' command timed out.\n", cmd);
|
||||
return -2;
|
||||
} else if (ret < 0) {
|
||||
printf("'%s' command failed.\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
if (memcmp(buf, "FAIL", 4) == 0)
|
||||
return -1;
|
||||
printf("%s", buf);
|
||||
|
||||
pos = buf;
|
||||
while (*pos != '\0' && *pos != '\n')
|
||||
pos++;
|
||||
*pos = '\0';
|
||||
os_strlcpy(addr, buf, addr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
|
||||
return 0;
|
||||
do {
|
||||
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
printf("%s", commands_help);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
hostapd_cli_quit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
if (argc != 1) {
|
||||
printf("Invalid LEVEL command: needs one argument (debug "
|
||||
"level)\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
struct dirent *dent;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(ctrl_iface_dir);
|
||||
if (dir == NULL) {
|
||||
printf("Control interface directory '%s' could not be "
|
||||
"openned.\n", ctrl_iface_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Available interfaces:\n");
|
||||
while ((dent = readdir(dir))) {
|
||||
if (strcmp(dent->d_name, ".") == 0 ||
|
||||
strcmp(dent->d_name, "..") == 0)
|
||||
continue;
|
||||
printf("%s\n", dent->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
if (argc < 1) {
|
||||
hostapd_cli_list_interfaces(ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hostapd_cli_close_connection();
|
||||
free(ctrl_ifname);
|
||||
ctrl_ifname = strdup(argv[0]);
|
||||
|
||||
if (hostapd_cli_open_connection(ctrl_ifname)) {
|
||||
printf("Connected to interface '%s.\n", ctrl_ifname);
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
"hostapd.\n");
|
||||
}
|
||||
} else {
|
||||
printf("Could not connect to interface '%s' - re-trying\n",
|
||||
ctrl_ifname);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
};
|
||||
|
||||
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "ping", hostapd_cli_cmd_ping },
|
||||
{ "mib", hostapd_cli_cmd_mib },
|
||||
{ "sta", hostapd_cli_cmd_sta },
|
||||
{ "all_sta", hostapd_cli_cmd_all_sta },
|
||||
{ "new_sta", hostapd_cli_cmd_new_sta },
|
||||
{ "help", hostapd_cli_cmd_help },
|
||||
{ "interface", hostapd_cli_cmd_interface },
|
||||
{ "level", hostapd_cli_cmd_level },
|
||||
{ "license", hostapd_cli_cmd_license },
|
||||
{ "quit", hostapd_cli_cmd_quit },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
struct hostapd_cli_cmd *cmd, *match = NULL;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
cmd = hostapd_cli_commands;
|
||||
while (cmd->cmd) {
|
||||
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
|
||||
match = cmd;
|
||||
count++;
|
||||
}
|
||||
cmd++;
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
printf("Ambiguous command '%s'; possible commands:", argv[0]);
|
||||
cmd = hostapd_cli_commands;
|
||||
while (cmd->cmd) {
|
||||
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
|
||||
0) {
|
||||
printf(" %s", cmd->cmd);
|
||||
}
|
||||
cmd++;
|
||||
}
|
||||
printf("\n");
|
||||
} else if (count == 0) {
|
||||
printf("Unknown command '%s'\n", argv[0]);
|
||||
} else {
|
||||
match->handler(ctrl, argc - 1, &argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
|
||||
{
|
||||
int first = 1;
|
||||
if (ctrl_conn == NULL)
|
||||
return;
|
||||
while (wpa_ctrl_pending(ctrl)) {
|
||||
char buf[256];
|
||||
size_t len = sizeof(buf) - 1;
|
||||
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
|
||||
buf[len] = '\0';
|
||||
if (in_read && first)
|
||||
printf("\n");
|
||||
first = 0;
|
||||
printf("%s\n", buf);
|
||||
} else {
|
||||
printf("Could not read pending message.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_interactive(void)
|
||||
{
|
||||
const int max_args = 10;
|
||||
char cmd[256], *res, *argv[max_args], *pos;
|
||||
int argc;
|
||||
|
||||
printf("\nInteractive mode\n\n");
|
||||
|
||||
do {
|
||||
hostapd_cli_recv_pending(ctrl_conn, 0);
|
||||
printf("> ");
|
||||
alarm(1);
|
||||
res = fgets(cmd, sizeof(cmd), stdin);
|
||||
alarm(0);
|
||||
if (res == NULL)
|
||||
break;
|
||||
pos = cmd;
|
||||
while (*pos != '\0') {
|
||||
if (*pos == '\n') {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
argc = 0;
|
||||
pos = cmd;
|
||||
for (;;) {
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
if (*pos == '\0')
|
||||
break;
|
||||
argv[argc] = pos;
|
||||
argc++;
|
||||
if (argc == max_args)
|
||||
break;
|
||||
while (*pos != '\0' && *pos != ' ')
|
||||
pos++;
|
||||
if (*pos == ' ')
|
||||
*pos++ = '\0';
|
||||
}
|
||||
if (argc)
|
||||
wpa_request(ctrl_conn, argc, argv);
|
||||
} while (!hostapd_cli_quit);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_terminate(int sig)
|
||||
{
|
||||
hostapd_cli_close_connection();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_alarm(int sig)
|
||||
{
|
||||
if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
|
||||
printf("Connection to hostapd lost - trying to reconnect\n");
|
||||
hostapd_cli_close_connection();
|
||||
}
|
||||
if (!ctrl_conn) {
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
printf("Connection to hostapd re-established\n");
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
"hostapd.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ctrl_conn)
|
||||
hostapd_cli_recv_pending(ctrl_conn, 1);
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int interactive;
|
||||
int warning_displayed = 0;
|
||||
int c;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "hi:p:v");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
case 'v':
|
||||
printf("%s\n", hostapd_cli_version);
|
||||
return 0;
|
||||
case 'i':
|
||||
free(ctrl_ifname);
|
||||
ctrl_ifname = strdup(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
ctrl_iface_dir = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
interactive = argc == optind;
|
||||
|
||||
if (interactive) {
|
||||
printf("%s\n\n%s\n\n", hostapd_cli_version,
|
||||
hostapd_cli_license);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (ctrl_ifname == NULL) {
|
||||
struct dirent *dent;
|
||||
DIR *dir = opendir(ctrl_iface_dir);
|
||||
if (dir) {
|
||||
while ((dent = readdir(dir))) {
|
||||
if (strcmp(dent->d_name, ".") == 0 ||
|
||||
strcmp(dent->d_name, "..") == 0)
|
||||
continue;
|
||||
printf("Selected interface '%s'\n",
|
||||
dent->d_name);
|
||||
ctrl_ifname = strdup(dent->d_name);
|
||||
break;
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
if (warning_displayed)
|
||||
printf("Connection established.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!interactive) {
|
||||
perror("Failed to connect to hostapd - "
|
||||
"wpa_ctrl_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!warning_displayed) {
|
||||
printf("Could not connect to hostapd - re-trying\n");
|
||||
warning_displayed = 1;
|
||||
}
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
signal(SIGINT, hostapd_cli_terminate);
|
||||
signal(SIGTERM, hostapd_cli_terminate);
|
||||
signal(SIGALRM, hostapd_cli_alarm);
|
||||
|
||||
if (interactive) {
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
} else {
|
||||
printf("Warning: Failed to attach to hostapd.\n");
|
||||
}
|
||||
hostapd_cli_interactive();
|
||||
} else
|
||||
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
|
||||
|
||||
free(ctrl_ifname);
|
||||
hostapd_cli_close_connection();
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* hostapd / Hardware feature query and different modes
|
||||
* Copyright 2002-2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, 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 "hostapd.h"
|
||||
#include "hw_features.h"
|
||||
#include "driver.h"
|
||||
#include "config.h"
|
||||
#include "eloop.h"
|
||||
|
||||
|
||||
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
size_t num_hw_features)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (hw_features == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_hw_features; i++) {
|
||||
os_free(hw_features[i].channels);
|
||||
os_free(hw_features[i].rates);
|
||||
}
|
||||
|
||||
os_free(hw_features);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
int ret = 0, i, j;
|
||||
u16 num_modes, flags;
|
||||
struct hostapd_hw_modes *modes;
|
||||
|
||||
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
|
||||
if (modes == NULL) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Fetching hardware channel/rate support not "
|
||||
"supported.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
iface->hw_flags = flags;
|
||||
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = modes;
|
||||
iface->num_hw_features = num_modes;
|
||||
|
||||
for (i = 0; i < num_modes; i++) {
|
||||
struct hostapd_hw_modes *feature = &modes[i];
|
||||
/* set flag for channels we can use in current regulatory
|
||||
* domain */
|
||||
for (j = 0; j < feature->num_channels; j++) {
|
||||
/* TODO: add regulatory domain lookup */
|
||||
unsigned char power_level = 0;
|
||||
unsigned char antenna_max = 0;
|
||||
|
||||
if ((feature->mode == HOSTAPD_MODE_IEEE80211G ||
|
||||
feature->mode == HOSTAPD_MODE_IEEE80211B) &&
|
||||
feature->channels[j].chan >= 1 &&
|
||||
feature->channels[j].chan <= 11) {
|
||||
power_level = 20;
|
||||
feature->channels[j].flag |=
|
||||
HOSTAPD_CHAN_W_SCAN;
|
||||
} else
|
||||
feature->channels[j].flag &=
|
||||
~HOSTAPD_CHAN_W_SCAN;
|
||||
|
||||
hostapd_set_channel_flag(hapd, feature->mode,
|
||||
feature->channels[j].chan,
|
||||
feature->channels[j].flag,
|
||||
power_level,
|
||||
antenna_max);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_prepare_rates(struct hostapd_data *hapd,
|
||||
struct hostapd_hw_modes *mode)
|
||||
{
|
||||
int i, num_basic_rates = 0;
|
||||
int basic_rates_a[] = { 60, 120, 240, -1 };
|
||||
int basic_rates_b[] = { 10, 20, -1 };
|
||||
int basic_rates_g[] = { 10, 20, 55, 110, -1 };
|
||||
int *basic_rates;
|
||||
|
||||
if (hapd->iconf->basic_rates)
|
||||
basic_rates = hapd->iconf->basic_rates;
|
||||
else switch (mode->mode) {
|
||||
case HOSTAPD_MODE_IEEE80211A:
|
||||
basic_rates = basic_rates_a;
|
||||
break;
|
||||
case HOSTAPD_MODE_IEEE80211B:
|
||||
basic_rates = basic_rates_b;
|
||||
break;
|
||||
case HOSTAPD_MODE_IEEE80211G:
|
||||
basic_rates = basic_rates_g;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
|
||||
basic_rates, mode->mode)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
|
||||
"module");
|
||||
}
|
||||
|
||||
os_free(hapd->iface->current_rates);
|
||||
hapd->iface->num_rates = 0;
|
||||
|
||||
hapd->iface->current_rates =
|
||||
os_malloc(mode->num_rates * sizeof(struct hostapd_rate_data));
|
||||
if (!hapd->iface->current_rates) {
|
||||
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
|
||||
"table.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < mode->num_rates; i++) {
|
||||
struct hostapd_rate_data *rate;
|
||||
|
||||
if (hapd->iconf->supported_rates &&
|
||||
!hostapd_rate_found(hapd->iconf->supported_rates,
|
||||
mode->rates[i].rate))
|
||||
continue;
|
||||
|
||||
rate = &hapd->iface->current_rates[hapd->iface->num_rates];
|
||||
os_memcpy(rate, &mode->rates[i],
|
||||
sizeof(struct hostapd_rate_data));
|
||||
if (hostapd_rate_found(basic_rates, rate->rate)) {
|
||||
rate->flags |= HOSTAPD_RATE_BASIC;
|
||||
num_basic_rates++;
|
||||
} else
|
||||
rate->flags &= ~HOSTAPD_RATE_BASIC;
|
||||
wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
|
||||
hapd->iface->num_rates, rate->rate, rate->flags);
|
||||
hapd->iface->num_rates++;
|
||||
}
|
||||
|
||||
if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
|
||||
wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
|
||||
"rate sets (%d,%d).",
|
||||
hapd->iface->num_rates, num_basic_rates);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void select_hw_mode_start(void *eloop_data, void *user_ctx);
|
||||
static void select_hw_mode2_handler(void *eloop_data, void *user_ctx);
|
||||
|
||||
/**
|
||||
* select_hw_mode_finalize - Finish select HW mode & call the callback
|
||||
* @iface: Pointer to interface data.
|
||||
* @status: Status of the select HW mode (0 on success; -1 on failure).
|
||||
* Returns: 0 on success; -1 on failure (e.g., was not in progress).
|
||||
*/
|
||||
static int select_hw_mode_finalize(struct hostapd_iface *iface, int status)
|
||||
{
|
||||
hostapd_iface_cb cb;
|
||||
|
||||
if (!iface->hw_mode_sel_cb)
|
||||
return -1;
|
||||
|
||||
eloop_cancel_timeout(select_hw_mode_start, iface, NULL);
|
||||
eloop_cancel_timeout(select_hw_mode2_handler, iface, NULL);
|
||||
|
||||
cb = iface->hw_mode_sel_cb;
|
||||
|
||||
iface->hw_mode_sel_cb = NULL;
|
||||
|
||||
cb(iface, status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* select_hw_mode2 - Select the hardware mode (part 2)
|
||||
* @iface: Pointer to interface data.
|
||||
* @status: Status of auto chanel selection.
|
||||
*
|
||||
* Setup the rates and passive scanning based on the configuration.
|
||||
*/
|
||||
static void select_hw_mode2(struct hostapd_iface *iface, int status)
|
||||
{
|
||||
int ret = status;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
if (iface->current_mode == NULL) {
|
||||
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Hardware does not support configured channel");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
|
||||
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Failed to prepare rates table.");
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = hostapd_passive_scan(iface->bss[0], 0,
|
||||
iface->conf->passive_scan_mode,
|
||||
iface->conf->passive_scan_interval,
|
||||
iface->conf->passive_scan_listen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_ERROR, "Could not set passive scanning: %s",
|
||||
strerror(ret));
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
fail:
|
||||
select_hw_mode_finalize(iface, ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* select_hw_mode2_handler - Calls select_hw_mode2 when auto chan isn't used
|
||||
* @eloop_data: Stores the struct hostapd_iface * for the interface.
|
||||
* @user_ctx: Unused.
|
||||
*/
|
||||
static void select_hw_mode2_handler(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_data;
|
||||
|
||||
select_hw_mode2(iface, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* select_hw_mode1 - Select the hardware mode (part 1)
|
||||
* @iface: Pointer to interface data.
|
||||
* Returns: 0 on success; -1 on failure.
|
||||
*
|
||||
* Setup the hardware mode and channel based on the configuration.
|
||||
* Schedules select_hw_mode2() to be called immediately or after automatic
|
||||
* channel selection takes place.
|
||||
*/
|
||||
static int select_hw_mode1(struct hostapd_iface *iface)
|
||||
{
|
||||
int i, j, ok;
|
||||
|
||||
if (iface->num_hw_features < 1)
|
||||
return -1;
|
||||
|
||||
iface->current_mode = NULL;
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
struct hostapd_hw_modes *mode = &iface->hw_features[i];
|
||||
if (mode->mode == (int) iface->conf->hw_mode) {
|
||||
iface->current_mode = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iface->current_mode == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Hardware does not support configured "
|
||||
"mode");
|
||||
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Hardware does not support configured mode "
|
||||
"(%d)", (int) iface->conf->hw_mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
for (j = 0; j < iface->current_mode->num_channels; j++) {
|
||||
struct hostapd_channel_data *chan =
|
||||
&iface->current_mode->channels[j];
|
||||
if ((chan->flag & HOSTAPD_CHAN_W_SCAN) &&
|
||||
(chan->chan == iface->conf->channel)) {
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok == 0 && iface->conf->channel != 0) {
|
||||
hostapd_logger(iface->bss[0], NULL,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Configured channel (%d) not found from the "
|
||||
"channel list of current mode (%d) %s",
|
||||
iface->conf->channel,
|
||||
iface->current_mode->mode,
|
||||
hostapd_hw_mode_txt(iface->current_mode->mode));
|
||||
iface->current_mode = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls select_hw_mode2() via a handler, so that the function is
|
||||
* always executed from eloop.
|
||||
*/
|
||||
eloop_register_timeout(0, 0, select_hw_mode2_handler, iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* select_hw_mode_start - Handler to start select HW mode
|
||||
* @eloop_data: Stores the struct hostapd_iface * for the interface.
|
||||
* @user_ctx: Unused.
|
||||
*
|
||||
* An eloop handler is used so that all errors can be processed by the
|
||||
* callback without introducing stack recursion.
|
||||
*/
|
||||
static void select_hw_mode_start(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct hostapd_iface *iface = (struct hostapd_iface *)eloop_data;
|
||||
|
||||
int ret;
|
||||
|
||||
ret = select_hw_mode1(iface);
|
||||
if (ret)
|
||||
select_hw_mode_finalize(iface, ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_select_hw_mode_start - Start selection of the hardware mode
|
||||
* @iface: Pointer to interface data.
|
||||
* @cb: The function to callback when done.
|
||||
* Returns: 0 if it starts successfully; cb will be called when done.
|
||||
* -1 on failure; cb will not be called.
|
||||
*
|
||||
* Sets up the hardware mode, channel, rates, and passive scanning
|
||||
* based on the configuration.
|
||||
*/
|
||||
int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
|
||||
hostapd_iface_cb cb)
|
||||
{
|
||||
if (iface->hw_mode_sel_cb) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Hardware mode select already in progress.",
|
||||
iface->bss[0]->conf->iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iface->hw_mode_sel_cb = cb;
|
||||
|
||||
eloop_register_timeout(0, 0, select_hw_mode_start, iface, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_auto_chan_select_stop - Stops automatic channel selection
|
||||
* @iface: Pointer to interface data.
|
||||
* Returns: 0 if successfully stopped;
|
||||
* -1 on failure (i.e., was not in progress)
|
||||
*/
|
||||
int hostapd_select_hw_mode_stop(struct hostapd_iface *iface)
|
||||
{
|
||||
return select_hw_mode_finalize(iface, -1);
|
||||
}
|
||||
|
||||
|
||||
const char * hostapd_hw_mode_txt(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case HOSTAPD_MODE_IEEE80211A:
|
||||
return "IEEE 802.11a";
|
||||
case HOSTAPD_MODE_IEEE80211B:
|
||||
return "IEEE 802.11b";
|
||||
case HOSTAPD_MODE_IEEE80211G:
|
||||
return "IEEE 802.11g";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
|
||||
struct hostapd_channel_data *ch =
|
||||
&hapd->iface->current_mode->channels[i];
|
||||
if (ch->chan == chan)
|
||||
return ch->freq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
|
||||
struct hostapd_channel_data *ch =
|
||||
&hapd->iface->current_mode->channels[i];
|
||||
if (ch->freq == freq)
|
||||
return ch->chan;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* hostapd / Hardware feature query and different modes
|
||||
* Copyright 2002-2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, 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.
|
||||
*/
|
||||
|
||||
#ifndef HW_FEATURES_H
|
||||
#define HW_FEATURES_H
|
||||
|
||||
#define HOSTAPD_CHAN_W_SCAN 0x00000001
|
||||
#define HOSTAPD_CHAN_W_ACTIVE_SCAN 0x00000002
|
||||
#define HOSTAPD_CHAN_W_IBSS 0x00000004
|
||||
|
||||
struct hostapd_channel_data {
|
||||
short chan; /* channel number (IEEE 802.11) */
|
||||
short freq; /* frequency in MHz */
|
||||
int flag; /* flag for hostapd use (HOSTAPD_CHAN_*) */
|
||||
};
|
||||
|
||||
#define HOSTAPD_RATE_ERP 0x00000001
|
||||
#define HOSTAPD_RATE_BASIC 0x00000002
|
||||
#define HOSTAPD_RATE_PREAMBLE2 0x00000004
|
||||
#define HOSTAPD_RATE_SUPPORTED 0x00000010
|
||||
#define HOSTAPD_RATE_OFDM 0x00000020
|
||||
#define HOSTAPD_RATE_CCK 0x00000040
|
||||
#define HOSTAPD_RATE_MANDATORY 0x00000100
|
||||
|
||||
struct hostapd_rate_data {
|
||||
int rate; /* rate in 100 kbps */
|
||||
int flags; /* HOSTAPD_RATE_ flags */
|
||||
};
|
||||
|
||||
struct hostapd_hw_modes {
|
||||
int mode;
|
||||
int num_channels;
|
||||
struct hostapd_channel_data *channels;
|
||||
int num_rates;
|
||||
struct hostapd_rate_data *rates;
|
||||
};
|
||||
|
||||
|
||||
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
size_t num_hw_features);
|
||||
int hostapd_get_hw_features(struct hostapd_iface *iface);
|
||||
int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
|
||||
hostapd_iface_cb cb);
|
||||
int hostapd_select_hw_mode_stop(struct hostapd_iface *iface);
|
||||
const char * hostapd_hw_mode_txt(int mode);
|
||||
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
|
||||
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
|
||||
|
||||
#endif /* HW_FEATURES_H */
|
@ -0,0 +1,542 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*
|
||||
* Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
|
||||
* and IEEE has withdrawn it. In other words, it is likely better to look at
|
||||
* using some other mechanism for AP-to-AP communication than extenting the
|
||||
* implementation here.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
* Level 1: no administrative or security support
|
||||
* (e.g., static BSSID to IP address mapping in each AP)
|
||||
* Level 2: support for dynamic mapping of BSSID to IP address
|
||||
* Level 3: support for encryption and authentication of IAPP messages
|
||||
* - add support for MOVE-notify and MOVE-response (this requires support for
|
||||
* finding out IP address for previous AP using RADIUS)
|
||||
* - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
|
||||
* reassociation to another AP
|
||||
* - implement counters etc. for IAPP MIB
|
||||
* - verify endianness of fields in IAPP messages; are they big-endian as
|
||||
* used here?
|
||||
* - RADIUS connection for AP registration and BSSID to IP address mapping
|
||||
* - TCP connection for IAPP MOVE, CACHE
|
||||
* - broadcast ESP for IAPP ADD-notify
|
||||
* - ESP for IAPP MOVE messages
|
||||
* - security block sending/processing
|
||||
* - IEEE 802.11 context transfer
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef USE_KERNEL_HEADERS
|
||||
#include <linux/if_packet.h>
|
||||
#else /* USE_KERNEL_HEADERS */
|
||||
#include <netpacket/packet.h>
|
||||
#endif /* USE_KERNEL_HEADERS */
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "iapp.h"
|
||||
#include "eloop.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
|
||||
#define IAPP_MULTICAST "224.0.1.178"
|
||||
#define IAPP_UDP_PORT 3517
|
||||
#define IAPP_TCP_PORT 3517
|
||||
|
||||
struct iapp_hdr {
|
||||
u8 version;
|
||||
u8 command;
|
||||
be16 identifier;
|
||||
be16 length;
|
||||
/* followed by length-6 octets of data */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define IAPP_VERSION 0
|
||||
|
||||
enum IAPP_COMMAND {
|
||||
IAPP_CMD_ADD_notify = 0,
|
||||
IAPP_CMD_MOVE_notify = 1,
|
||||
IAPP_CMD_MOVE_response = 2,
|
||||
IAPP_CMD_Send_Security_Block = 3,
|
||||
IAPP_CMD_ACK_Security_Block = 4,
|
||||
IAPP_CMD_CACHE_notify = 5,
|
||||
IAPP_CMD_CACHE_response = 6,
|
||||
};
|
||||
|
||||
|
||||
/* ADD-notify - multicast UDP on the local LAN */
|
||||
struct iapp_add_notify {
|
||||
u8 addr_len; /* ETH_ALEN */
|
||||
u8 reserved;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
be16 seq_num;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
|
||||
struct iapp_layer2_update {
|
||||
u8 da[ETH_ALEN]; /* broadcast */
|
||||
u8 sa[ETH_ALEN]; /* STA addr */
|
||||
be16 len; /* 6 */
|
||||
u8 dsap; /* null DSAP address */
|
||||
u8 ssap; /* null SSAP address, CR=Response */
|
||||
u8 control;
|
||||
u8 xid_info[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* MOVE-notify - unicast TCP */
|
||||
struct iapp_move_notify {
|
||||
u8 addr_len; /* ETH_ALEN */
|
||||
u8 reserved;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u16 seq_num;
|
||||
u16 ctx_block_len;
|
||||
/* followed by ctx_block_len bytes */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* MOVE-response - unicast TCP */
|
||||
struct iapp_move_response {
|
||||
u8 addr_len; /* ETH_ALEN */
|
||||
u8 status;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u16 seq_num;
|
||||
u16 ctx_block_len;
|
||||
/* followed by ctx_block_len bytes */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum {
|
||||
IAPP_MOVE_SUCCESSFUL = 0,
|
||||
IAPP_MOVE_DENIED = 1,
|
||||
IAPP_MOVE_STALE_MOVE = 2,
|
||||
};
|
||||
|
||||
|
||||
/* CACHE-notify */
|
||||
struct iapp_cache_notify {
|
||||
u8 addr_len; /* ETH_ALEN */
|
||||
u8 reserved;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u16 seq_num;
|
||||
u8 current_ap[ETH_ALEN];
|
||||
u16 ctx_block_len;
|
||||
/* ctx_block_len bytes of context block followed by 16-bit context
|
||||
* timeout */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* CACHE-response - unicast TCP */
|
||||
struct iapp_cache_response {
|
||||
u8 addr_len; /* ETH_ALEN */
|
||||
u8 status;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u16 seq_num;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum {
|
||||
IAPP_CACHE_SUCCESSFUL = 0,
|
||||
IAPP_CACHE_STALE_CACHE = 1,
|
||||
};
|
||||
|
||||
|
||||
/* Send-Security-Block - unicast TCP */
|
||||
struct iapp_send_security_block {
|
||||
u8 iv[8];
|
||||
u16 sec_block_len;
|
||||
/* followed by sec_block_len bytes of security block */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* ACK-Security-Block - unicast TCP */
|
||||
struct iapp_ack_security_block {
|
||||
u8 iv[8];
|
||||
u8 new_ap_ack_authenticator[48];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct iapp_data {
|
||||
struct hostapd_data *hapd;
|
||||
u16 identifier; /* next IAPP identifier */
|
||||
struct in_addr own, multicast;
|
||||
int udp_sock;
|
||||
int packet_sock;
|
||||
};
|
||||
|
||||
|
||||
static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
|
||||
{
|
||||
char buf[128];
|
||||
struct iapp_hdr *hdr;
|
||||
struct iapp_add_notify *add;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
/* Send IAPP ADD-notify to remove possible association from other APs
|
||||
*/
|
||||
|
||||
hdr = (struct iapp_hdr *) buf;
|
||||
hdr->version = IAPP_VERSION;
|
||||
hdr->command = IAPP_CMD_ADD_notify;
|
||||
hdr->identifier = host_to_be16(iapp->identifier++);
|
||||
hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
|
||||
|
||||
add = (struct iapp_add_notify *) (hdr + 1);
|
||||
add->addr_len = ETH_ALEN;
|
||||
add->reserved = 0;
|
||||
os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
|
||||
|
||||
add->seq_num = host_to_be16(seq_num);
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = iapp->multicast.s_addr;
|
||||
addr.sin_port = htons(IAPP_UDP_PORT);
|
||||
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
|
||||
(struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||
perror("sendto[IAPP-ADD]");
|
||||
}
|
||||
|
||||
|
||||
static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
|
||||
{
|
||||
struct iapp_layer2_update msg;
|
||||
|
||||
/* Send Level 2 Update Frame to update forwarding tables in layer 2
|
||||
* bridge devices */
|
||||
|
||||
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
|
||||
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
|
||||
|
||||
os_memset(msg.da, 0xff, ETH_ALEN);
|
||||
os_memcpy(msg.sa, addr, ETH_ALEN);
|
||||
msg.len = host_to_be16(6);
|
||||
msg.dsap = 0; /* NULL DSAP address */
|
||||
msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
|
||||
msg.control = 0xaf; /* XID response lsb.1111F101.
|
||||
* F=0 (no poll command; unsolicited frame) */
|
||||
msg.xid_info[0] = 0x81; /* XID format identifier */
|
||||
msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
|
||||
msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
|
||||
* FIX: what is correct RW with 802.11? */
|
||||
|
||||
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
|
||||
perror("send[L2 Update]");
|
||||
}
|
||||
|
||||
|
||||
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_mgmt *assoc;
|
||||
u16 seq;
|
||||
|
||||
if (iapp == NULL)
|
||||
return;
|
||||
|
||||
assoc = sta->last_assoc_req;
|
||||
seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
|
||||
|
||||
/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
|
||||
hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
|
||||
HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
|
||||
iapp_send_layer2_update(iapp, sta->addr);
|
||||
iapp_send_add(iapp, sta->addr, seq);
|
||||
|
||||
if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
|
||||
WLAN_FC_STYPE_REASSOC_REQ) {
|
||||
/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
|
||||
* Context Block, Timeout)
|
||||
*/
|
||||
/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
|
||||
* IP address */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void iapp_process_add_notify(struct iapp_data *iapp,
|
||||
struct sockaddr_in *from,
|
||||
struct iapp_hdr *hdr, int len)
|
||||
{
|
||||
struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
|
||||
struct sta_info *sta;
|
||||
|
||||
if (len != sizeof(*add)) {
|
||||
printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
|
||||
len, (unsigned long) sizeof(*add));
|
||||
return;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(iapp->hapd, add->mac_addr);
|
||||
|
||||
/* IAPP-ADD.indication(MAC Address, Sequence Number) */
|
||||
hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Received IAPP ADD-notify (seq# %d) from %s:%d%s",
|
||||
be_to_host16(add->seq_num),
|
||||
inet_ntoa(from->sin_addr), ntohs(from->sin_port),
|
||||
sta ? "" : " (STA not found)");
|
||||
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
/* TODO: could use seq_num to try to determine whether last association
|
||||
* to this AP is newer than the one advertised in IAPP-ADD. Although,
|
||||
* this is not really a reliable verification. */
|
||||
|
||||
hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Removing STA due to IAPP ADD-notify");
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
|
||||
eloop_cancel_timeout(ap_handle_timer, iapp->hapd, sta);
|
||||
eloop_register_timeout(0, 0, ap_handle_timer, iapp->hapd, sta);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
}
|
||||
|
||||
|
||||
static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
struct iapp_data *iapp = eloop_ctx;
|
||||
int len, hlen;
|
||||
unsigned char buf[128];
|
||||
struct sockaddr_in from;
|
||||
socklen_t fromlen;
|
||||
struct iapp_hdr *hdr;
|
||||
|
||||
/* Handle incoming IAPP frames (over UDP/IP) */
|
||||
|
||||
fromlen = sizeof(from);
|
||||
len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *) &from, &fromlen);
|
||||
if (len < 0) {
|
||||
perror("recvfrom");
|
||||
return;
|
||||
}
|
||||
|
||||
if (from.sin_addr.s_addr == iapp->own.s_addr)
|
||||
return; /* ignore own IAPP messages */
|
||||
|
||||
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Received %d byte IAPP frame from %s%s\n",
|
||||
len, inet_ntoa(from.sin_addr),
|
||||
len < (int) sizeof(*hdr) ? " (too short)" : "");
|
||||
|
||||
if (len < (int) sizeof(*hdr))
|
||||
return;
|
||||
|
||||
hdr = (struct iapp_hdr *) buf;
|
||||
hlen = be_to_host16(hdr->length);
|
||||
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"RX: version=%d command=%d id=%d len=%d\n",
|
||||
hdr->version, hdr->command,
|
||||
be_to_host16(hdr->identifier), hlen);
|
||||
if (hdr->version != IAPP_VERSION) {
|
||||
printf("Dropping IAPP frame with unknown version %d\n",
|
||||
hdr->version);
|
||||
return;
|
||||
}
|
||||
if (hlen > len) {
|
||||
printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
|
||||
return;
|
||||
}
|
||||
if (hlen < len) {
|
||||
printf("Ignoring %d extra bytes from IAPP frame\n",
|
||||
len - hlen);
|
||||
len = hlen;
|
||||
}
|
||||
|
||||
switch (hdr->command) {
|
||||
case IAPP_CMD_ADD_notify:
|
||||
iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
|
||||
break;
|
||||
case IAPP_CMD_MOVE_notify:
|
||||
/* TODO: MOVE is using TCP; so move this to TCP handler once it
|
||||
* is implemented.. */
|
||||
/* IAPP-MOVE.indication(MAC Address, New BSSID,
|
||||
* Sequence Number, AP Address, Context Block) */
|
||||
/* TODO: process */
|
||||
break;
|
||||
default:
|
||||
printf("Unknown IAPP command %d\n", hdr->command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_ll addr;
|
||||
int ifindex;
|
||||
struct sockaddr_in *paddr, uaddr;
|
||||
struct iapp_data *iapp;
|
||||
struct ip_mreqn mreq;
|
||||
|
||||
iapp = os_zalloc(sizeof(*iapp));
|
||||
if (iapp == NULL)
|
||||
return NULL;
|
||||
iapp->hapd = hapd;
|
||||
iapp->udp_sock = iapp->packet_sock = -1;
|
||||
|
||||
/* TODO:
|
||||
* open socket for sending and receiving IAPP frames over TCP
|
||||
*/
|
||||
|
||||
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (iapp->udp_sock < 0) {
|
||||
perror("socket[PF_INET,SOCK_DGRAM]");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
|
||||
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
|
||||
perror("ioctl(SIOCGIFINDEX)");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
ifindex = ifr.ifr_ifindex;
|
||||
|
||||
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
|
||||
perror("ioctl(SIOCGIFADDR)");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
|
||||
if (paddr->sin_family != AF_INET) {
|
||||
printf("Invalid address family %i (SIOCGIFADDR)\n",
|
||||
paddr->sin_family);
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
iapp->own.s_addr = paddr->sin_addr.s_addr;
|
||||
|
||||
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
|
||||
perror("ioctl(SIOCGIFBRDADDR)");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
|
||||
if (paddr->sin_family != AF_INET) {
|
||||
printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
|
||||
paddr->sin_family);
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
inet_aton(IAPP_MULTICAST, &iapp->multicast);
|
||||
|
||||
os_memset(&uaddr, 0, sizeof(uaddr));
|
||||
uaddr.sin_family = AF_INET;
|
||||
uaddr.sin_port = htons(IAPP_UDP_PORT);
|
||||
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
|
||||
sizeof(uaddr)) < 0) {
|
||||
perror("bind[UDP]");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.imr_multiaddr = iapp->multicast;
|
||||
mreq.imr_address.s_addr = INADDR_ANY;
|
||||
mreq.imr_ifindex = 0;
|
||||
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq)) < 0) {
|
||||
perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (iapp->packet_sock < 0) {
|
||||
perror("socket[PF_PACKET,SOCK_RAW]");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sll_family = AF_PACKET;
|
||||
addr.sll_ifindex = ifindex;
|
||||
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
|
||||
sizeof(addr)) < 0) {
|
||||
perror("bind[PACKET]");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
|
||||
iapp, NULL)) {
|
||||
printf("Could not register read socket for IAPP.\n");
|
||||
iapp_deinit(iapp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
|
||||
|
||||
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
|
||||
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
|
||||
* be openned only after receiving Initiate-Accept. If Initiate-Reject
|
||||
* is received, IAPP is not started. */
|
||||
|
||||
return iapp;
|
||||
}
|
||||
|
||||
|
||||
void iapp_deinit(struct iapp_data *iapp)
|
||||
{
|
||||
struct ip_mreqn mreq;
|
||||
|
||||
if (iapp == NULL)
|
||||
return;
|
||||
|
||||
if (iapp->udp_sock >= 0) {
|
||||
os_memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.imr_multiaddr = iapp->multicast;
|
||||
mreq.imr_address.s_addr = INADDR_ANY;
|
||||
mreq.imr_ifindex = 0;
|
||||
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
|
||||
&mreq, sizeof(mreq)) < 0) {
|
||||
perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
|
||||
}
|
||||
|
||||
eloop_unregister_read_sock(iapp->udp_sock);
|
||||
close(iapp->udp_sock);
|
||||
}
|
||||
if (iapp->packet_sock >= 0) {
|
||||
eloop_unregister_read_sock(iapp->packet_sock);
|
||||
close(iapp->packet_sock);
|
||||
}
|
||||
os_free(iapp);
|
||||
}
|
||||
|
||||
int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||
struct hostapd_bss_config *oldbss)
|
||||
{
|
||||
if (hapd->conf->ieee802_11f != oldbss->ieee802_11f ||
|
||||
os_strcmp(hapd->conf->iapp_iface, oldbss->iapp_iface) != 0) {
|
||||
iapp_deinit(hapd->iapp);
|
||||
hapd->iapp = NULL;
|
||||
|
||||
if (hapd->conf->ieee802_11f) {
|
||||
hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface);
|
||||
if (hapd->iapp == NULL)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
|
||||
* Copyright (c) 2002-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 IAPP_H
|
||||
#define IAPP_H
|
||||
|
||||
struct iapp_data;
|
||||
|
||||
#ifdef CONFIG_IAPP
|
||||
|
||||
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
|
||||
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
|
||||
void iapp_deinit(struct iapp_data *iapp);
|
||||
int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||
struct hostapd_bss_config *oldbss);
|
||||
|
||||
#else /* CONFIG_IAPP */
|
||||
|
||||
static inline void iapp_new_station(struct iapp_data *iapp,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
|
||||
const char *iface)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void iapp_deinit(struct iapp_data *iapp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int
|
||||
iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||
struct hostapd_bss_config *oldbss)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IAPP */
|
||||
|
||||
#endif /* IAPP_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 Management
|
||||
* Copyright (c) 2002-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.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11_H
|
||||
#define IEEE802_11_H
|
||||
|
||||
#include "ieee802_11_defs.h"
|
||||
|
||||
/* Parsed Information Elements */
|
||||
struct ieee802_11_elems {
|
||||
u8 *ssid;
|
||||
u8 ssid_len;
|
||||
u8 *supp_rates;
|
||||
u8 supp_rates_len;
|
||||
u8 *fh_params;
|
||||
u8 fh_params_len;
|
||||
u8 *ds_params;
|
||||
u8 ds_params_len;
|
||||
u8 *cf_params;
|
||||
u8 cf_params_len;
|
||||
u8 *tim;
|
||||
u8 tim_len;
|
||||
u8 *ibss_params;
|
||||
u8 ibss_params_len;
|
||||
u8 *challenge;
|
||||
u8 challenge_len;
|
||||
u8 *erp_info;
|
||||
u8 erp_info_len;
|
||||
u8 *ext_supp_rates;
|
||||
u8 ext_supp_rates_len;
|
||||
u8 *wpa_ie;
|
||||
u8 wpa_ie_len;
|
||||
u8 *rsn_ie;
|
||||
u8 rsn_ie_len;
|
||||
u8 *wme;
|
||||
u8 wme_len;
|
||||
u8 *wme_tspec;
|
||||
u8 wme_tspec_len;
|
||||
u8 *power_cap;
|
||||
u8 power_cap_len;
|
||||
u8 *supp_channels;
|
||||
u8 supp_channels_len;
|
||||
u8 *mdie;
|
||||
u8 mdie_len;
|
||||
u8 *ftie;
|
||||
u8 ftie_len;
|
||||
};
|
||||
|
||||
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
|
||||
|
||||
|
||||
struct hostapd_frame_info {
|
||||
u32 phytype;
|
||||
u32 channel;
|
||||
u32 datarate;
|
||||
u32 ssi_signal;
|
||||
|
||||
unsigned int passive_scan:1;
|
||||
};
|
||||
|
||||
struct hostapd_data;
|
||||
struct sta_info;
|
||||
|
||||
void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason);
|
||||
void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len,
|
||||
u16 stype, struct hostapd_frame_info *fi);
|
||||
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
|
||||
u16 stype, int ok);
|
||||
ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
|
||||
size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
int show_errors);
|
||||
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
|
||||
void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
|
||||
int local);
|
||||
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
|
||||
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
char *buf, size_t buflen);
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int probe);
|
||||
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
@ -0,0 +1,471 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 authentication (ACL)
|
||||
* Copyright (c) 2003-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"
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "eloop.h"
|
||||
|
||||
#define RADIUS_ACL_TIMEOUT 30
|
||||
|
||||
|
||||
struct hostapd_cached_radius_acl {
|
||||
time_t timestamp;
|
||||
macaddr addr;
|
||||
int accepted; /* HOSTAPD_ACL_* */
|
||||
struct hostapd_cached_radius_acl *next;
|
||||
u32 session_timeout;
|
||||
u32 acct_interim_interval;
|
||||
int vlan_id;
|
||||
};
|
||||
|
||||
|
||||
struct hostapd_acl_query_data {
|
||||
time_t timestamp;
|
||||
u8 radius_id;
|
||||
macaddr addr;
|
||||
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
|
||||
size_t auth_msg_len;
|
||||
struct hostapd_acl_query_data *next;
|
||||
};
|
||||
|
||||
|
||||
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
|
||||
{
|
||||
struct hostapd_cached_radius_acl *prev;
|
||||
|
||||
while (acl_cache) {
|
||||
prev = acl_cache;
|
||||
acl_cache = acl_cache->next;
|
||||
os_free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||
u32 *session_timeout,
|
||||
u32 *acct_interim_interval, int *vlan_id)
|
||||
{
|
||||
struct hostapd_cached_radius_acl *entry;
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
entry = hapd->acl_cache;
|
||||
|
||||
while (entry) {
|
||||
if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
|
||||
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
|
||||
return -1; /* entry has expired */
|
||||
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||
*session_timeout = entry->session_timeout;
|
||||
*acct_interim_interval = entry->acct_interim_interval;
|
||||
if (vlan_id)
|
||||
*vlan_id = entry->vlan_id;
|
||||
return entry->accepted;
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
|
||||
{
|
||||
if (query == NULL)
|
||||
return;
|
||||
os_free(query->auth_msg);
|
||||
os_free(query);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct hostapd_acl_query_data *query)
|
||||
{
|
||||
struct radius_msg *msg;
|
||||
char buf[128];
|
||||
|
||||
query->radius_id = radius_client_get_id(hapd->radius);
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
|
||||
radius_msg_make_authenticator(msg, addr, ETH_ALEN);
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
|
||||
os_strlen(buf))) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add User-Name");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_user_password(
|
||||
msg, (u8 *) buf, os_strlen(buf),
|
||||
hapd->conf->radius->auth_server->shared_secret,
|
||||
hapd->conf->radius->auth_server->shared_secret_len)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add User-Password");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
if (hapd->conf->nas_identifier &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||
(u8 *) hapd->conf->nas_identifier,
|
||||
os_strlen(hapd->conf->nas_identifier))) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
|
||||
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
|
||||
MAC2STR(addr));
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
|
||||
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
radius_msg_free(msg);
|
||||
os_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *msg, size_t len, u32 *session_timeout,
|
||||
u32 *acct_interim_interval, int *vlan_id)
|
||||
{
|
||||
*session_timeout = 0;
|
||||
*acct_interim_interval = 0;
|
||||
if (vlan_id)
|
||||
*vlan_id = 0;
|
||||
|
||||
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
||||
hapd->conf->num_accept_mac, addr))
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
|
||||
if (hostapd_maclist_found(hapd->conf->deny_mac,
|
||||
hapd->conf->num_deny_mac, addr))
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
|
||||
struct hostapd_acl_query_data *query;
|
||||
|
||||
/* Check whether ACL cache has an entry for this station */
|
||||
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||
acct_interim_interval,
|
||||
vlan_id);
|
||||
if (res == HOSTAPD_ACL_ACCEPT ||
|
||||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||
return res;
|
||||
if (res == HOSTAPD_ACL_REJECT)
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
query = hapd->acl_queries;
|
||||
while (query) {
|
||||
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
|
||||
/* pending query in RADIUS retransmit queue;
|
||||
* do not generate a new one */
|
||||
return HOSTAPD_ACL_PENDING;
|
||||
}
|
||||
query = query->next;
|
||||
}
|
||||
|
||||
if (!hapd->conf->radius->auth_server)
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
/* No entry in the cache - query external RADIUS server */
|
||||
query = os_zalloc(sizeof(*query));
|
||||
if (query == NULL) {
|
||||
wpa_printf(MSG_ERROR, "malloc for query data failed");
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
time(&query->timestamp);
|
||||
os_memcpy(query->addr, addr, ETH_ALEN);
|
||||
if (hostapd_radius_acl_query(hapd, addr, query)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
|
||||
"for ACL query.");
|
||||
hostapd_acl_query_free(query);
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
|
||||
query->auth_msg = os_malloc(len);
|
||||
if (query->auth_msg == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
|
||||
"auth frame.");
|
||||
hostapd_acl_query_free(query);
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
os_memcpy(query->auth_msg, msg, len);
|
||||
query->auth_msg_len = len;
|
||||
query->next = hapd->acl_queries;
|
||||
hapd->acl_queries = query;
|
||||
|
||||
/* Queued data will be processed in hostapd_acl_recv_radius()
|
||||
* when RADIUS server replies to the sent Access-Request. */
|
||||
return HOSTAPD_ACL_PENDING;
|
||||
}
|
||||
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
|
||||
{
|
||||
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
|
||||
|
||||
prev = NULL;
|
||||
entry = hapd->acl_cache;
|
||||
|
||||
while (entry) {
|
||||
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
|
||||
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
|
||||
" has expired.", MAC2STR(entry->addr));
|
||||
if (prev)
|
||||
prev->next = entry->next;
|
||||
else
|
||||
hapd->acl_cache = entry->next;
|
||||
|
||||
tmp = entry;
|
||||
entry = entry->next;
|
||||
os_free(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
|
||||
{
|
||||
struct hostapd_acl_query_data *prev, *entry, *tmp;
|
||||
|
||||
prev = NULL;
|
||||
entry = hapd->acl_queries;
|
||||
|
||||
while (entry) {
|
||||
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
|
||||
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
|
||||
" has expired.", MAC2STR(entry->addr));
|
||||
if (prev)
|
||||
prev->next = entry->next;
|
||||
else
|
||||
hapd->acl_queries = entry->next;
|
||||
|
||||
tmp = entry;
|
||||
entry = entry->next;
|
||||
hostapd_acl_query_free(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
hostapd_acl_expire_cache(hapd, now);
|
||||
hostapd_acl_expire_queries(hapd, now);
|
||||
|
||||
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Return 0 if RADIUS message was a reply to ACL query (and was processed here)
|
||||
* or -1 if not. */
|
||||
static RadiusRxResult
|
||||
hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
u8 *shared_secret, size_t shared_secret_len,
|
||||
void *data)
|
||||
{
|
||||
struct hostapd_data *hapd = data;
|
||||
struct hostapd_acl_query_data *query, *prev;
|
||||
struct hostapd_cached_radius_acl *cache;
|
||||
|
||||
query = hapd->acl_queries;
|
||||
prev = NULL;
|
||||
while (query) {
|
||||
if (query->radius_id == msg->hdr->identifier)
|
||||
break;
|
||||
prev = query;
|
||||
query = query->next;
|
||||
}
|
||||
if (query == NULL)
|
||||
return RADIUS_RX_UNKNOWN;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
|
||||
"message (id=%d)", query->radius_id);
|
||||
|
||||
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
|
||||
"correct authenticator - dropped\n");
|
||||
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||
}
|
||||
|
||||
if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
|
||||
msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) {
|
||||
wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
|
||||
"query", msg->hdr->code);
|
||||
return RADIUS_RX_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Insert Accept/Reject info into ACL cache */
|
||||
cache = os_zalloc(sizeof(*cache));
|
||||
if (cache == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
|
||||
goto done;
|
||||
}
|
||||
time(&cache->timestamp);
|
||||
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
|
||||
if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
|
||||
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
|
||||
&cache->session_timeout) == 0)
|
||||
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
|
||||
else
|
||||
cache->accepted = HOSTAPD_ACL_ACCEPT;
|
||||
|
||||
if (radius_msg_get_attr_int32(
|
||||
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
|
||||
&cache->acct_interim_interval) == 0 &&
|
||||
cache->acct_interim_interval < 60) {
|
||||
wpa_printf(MSG_DEBUG, "Ignored too small "
|
||||
"Acct-Interim-Interval %d for STA " MACSTR,
|
||||
cache->acct_interim_interval,
|
||||
MAC2STR(query->addr));
|
||||
cache->acct_interim_interval = 0;
|
||||
}
|
||||
|
||||
cache->vlan_id = radius_msg_get_vlanid(msg);
|
||||
} else
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
cache->next = hapd->acl_cache;
|
||||
hapd->acl_cache = cache;
|
||||
|
||||
/* Re-send original authentication frame for 802.11 processing */
|
||||
wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
|
||||
"successful RADIUS ACL query");
|
||||
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
|
||||
WLAN_FC_STYPE_AUTH, NULL);
|
||||
|
||||
done:
|
||||
if (prev == NULL)
|
||||
hapd->acl_queries = query->next;
|
||||
else
|
||||
prev->next = query->next;
|
||||
|
||||
hostapd_acl_query_free(query);
|
||||
|
||||
return RADIUS_RX_PROCESSED;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_acl_init(struct hostapd_data *hapd)
|
||||
{
|
||||
if (radius_client_register(hapd->radius, RADIUS_AUTH,
|
||||
hostapd_acl_recv_radius, hapd))
|
||||
return -1;
|
||||
|
||||
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_acl_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_acl_query_data *query, *prev;
|
||||
|
||||
eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
|
||||
|
||||
hostapd_acl_cache_free(hapd->acl_cache);
|
||||
|
||||
query = hapd->acl_queries;
|
||||
while (query) {
|
||||
prev = query;
|
||||
query = query->next;
|
||||
hostapd_acl_query_free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int hostapd_acl_reconfig(struct hostapd_data *hapd,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
if (!hapd->radius_client_reconfigured)
|
||||
return 0;
|
||||
|
||||
hostapd_acl_deinit(hapd);
|
||||
return hostapd_acl_init(hapd);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 authentication (ACL)
|
||||
* 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 IEEE802_11_AUTH_H
|
||||
#define IEEE802_11_AUTH_H
|
||||
|
||||
enum {
|
||||
HOSTAPD_ACL_REJECT = 0,
|
||||
HOSTAPD_ACL_ACCEPT = 1,
|
||||
HOSTAPD_ACL_PENDING = 2,
|
||||
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
|
||||
};
|
||||
|
||||
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *msg, size_t len, u32 *session_timeout,
|
||||
u32 *acct_interim_interval, int *vlan_id);
|
||||
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
||||
int hostapd_acl_reconfig(struct hostapd_data *hapd,
|
||||
struct hostapd_config *oldconf);
|
||||
|
||||
#endif /* IEEE802_11_AUTH_H */
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11h
|
||||
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||
* 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"
|
||||
|
||||
#include "hostapd.h"
|
||||
|
||||
|
||||
int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len)
|
||||
{
|
||||
unsigned int max_pwr;
|
||||
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "Too short power capability IE");
|
||||
return -1;
|
||||
}
|
||||
max_pwr = power[1];
|
||||
if (max_pwr > hapd->iface->sta_max_power)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11h
|
||||
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11H_H
|
||||
#define IEEE802_11H_H
|
||||
|
||||
#define SPECT_LOOSE_BINDING 1
|
||||
#define SPECT_STRICT_BINDING 2
|
||||
|
||||
#define CHAN_SWITCH_MODE_NOISY 0
|
||||
#define CHAN_SWITCH_MODE_QUIET 1
|
||||
|
||||
int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len);
|
||||
|
||||
#endif /* IEEE802_11H_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.1X-2004 Authenticator
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_1X_H
|
||||
#define IEEE802_1X_H
|
||||
|
||||
struct hostapd_data;
|
||||
struct sta_info;
|
||||
struct eapol_state_machine;
|
||||
struct hostapd_config;
|
||||
struct hostapd_bss_config;
|
||||
|
||||
/* RFC 3580, 4. RC4 EAPOL-Key Frame */
|
||||
|
||||
struct ieee802_1x_eapol_key {
|
||||
u8 type;
|
||||
u16 key_length;
|
||||
u8 replay_counter[8]; /* does not repeat within the life of the keying
|
||||
* material used to encrypt the Key field;
|
||||
* 64-bit NTP timestamp MAY be used here */
|
||||
u8 key_iv[16]; /* cryptographically random number */
|
||||
u8 key_index; /* key flag in the most significant bit:
|
||||
* 0 = broadcast (default key),
|
||||
* 1 = unicast (key mapping key); key index is in the
|
||||
* 7 least significant bits */
|
||||
u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
|
||||
* MS-MPPE-Send-Key as the key */
|
||||
|
||||
/* followed by key: if packet body length = 44 + key length, then the
|
||||
* key field (of key_length bytes) contains the key in encrypted form;
|
||||
* if packet body length = 44, key field is absent and key_length
|
||||
* represents the number of least significant octets from
|
||||
* MS-MPPE-Send-Key attribute to be used as the keying material;
|
||||
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
size_t len);
|
||||
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_free_station(struct sta_info *sta);
|
||||
|
||||
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
|
||||
int ieee802_1x_init(struct hostapd_data *hapd);
|
||||
void ieee802_1x_deinit(struct hostapd_data *hapd);
|
||||
int ieee802_1x_reconfig(struct hostapd_data *hapd,
|
||||
struct hostapd_config *oldconf,
|
||||
struct hostapd_bss_config *oldbss);
|
||||
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *buf, size_t len, int ack);
|
||||
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
|
||||
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
|
||||
int idx);
|
||||
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
|
||||
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
int enabled);
|
||||
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
|
||||
int valid);
|
||||
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
|
||||
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
|
||||
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
char *buf, size_t buflen);
|
||||
void hostapd_get_ntp_timestamp(u8 *buf);
|
||||
char *eap_type_text(u8 type);
|
||||
|
||||
struct radius_class_data;
|
||||
|
||||
void ieee802_1x_free_radius_class(struct radius_class_data *class);
|
||||
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
|
||||
struct radius_class_data *src);
|
||||
|
||||
#endif /* IEEE802_1X_H */
|
@ -0,0 +1,9 @@
|
||||
Logwatch is a utility for analyzing system logs and provide a human
|
||||
readable summary. This directory has a configuration file and a log
|
||||
analyzer script for parsing hostapd system log entries for logwatch.
|
||||
These files can be installed by copying them to following locations:
|
||||
|
||||
/etc/log.d/conf/services/hostapd.conf
|
||||
/etc/log.d/scripts/services/hostapd
|
||||
|
||||
More information about logwatch is available from http://www.logwatch.org/
|
@ -0,0 +1,10 @@
|
||||
# Logwatch configuration for hostapd
|
||||
#
|
||||
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# Alternatively, this file may be distributed under the terms of the BSD License
|
||||
|
||||
Title = "hostapd"
|
||||
LogFile = messages
|
||||
*OnlyService = hostapd
|
||||
*RemoveHeaders
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 MLME
|
||||
* Copyright 2003-2006, Jouni Malinen <j@w1.fi>
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, 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 "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "wpa.h"
|
||||
#include "mlme.h"
|
||||
|
||||
|
||||
static const char * mlme_auth_alg_str(int alg)
|
||||
{
|
||||
switch (alg) {
|
||||
case WLAN_AUTH_OPEN:
|
||||
return "OPEN_SYSTEM";
|
||||
case WLAN_AUTH_SHARED_KEY:
|
||||
return "SHARED_KEY";
|
||||
case WLAN_AUTH_FT:
|
||||
return "FT";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mlme_authenticate_indication - Report the establishment of an authentication
|
||||
* relationship with a specific peer MAC entity
|
||||
* @hapd: BSS data
|
||||
* @sta: peer STA data
|
||||
*
|
||||
* MLME calls this function as a result of the establishment of an
|
||||
* authentication relationship with a specific peer MAC entity that
|
||||
* resulted from an authentication procedure that was initiated by
|
||||
* that specific peer MAC entity.
|
||||
*
|
||||
* PeerSTAAddress = sta->addr
|
||||
* AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
|
||||
*/
|
||||
void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
|
||||
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mlme_deauthenticate_indication - Report the invalidation of an
|
||||
* authentication relationship with a specific peer MAC entity
|
||||
* @hapd: BSS data
|
||||
* @sta: Peer STA data
|
||||
* @reason_code: ReasonCode from Deauthentication frame
|
||||
*
|
||||
* MLME calls this function as a result of the invalidation of an
|
||||
* authentication relationship with a specific peer MAC entity.
|
||||
*
|
||||
* PeerSTAAddress = sta->addr
|
||||
*/
|
||||
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason_code)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
|
||||
MAC2STR(sta->addr), reason_code);
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mlme_associate_indication - Report the establishment of an association with
|
||||
* a specific peer MAC entity
|
||||
* @hapd: BSS data
|
||||
* @sta: peer STA data
|
||||
*
|
||||
* MLME calls this function as a result of the establishment of an
|
||||
* association with a specific peer MAC entity that resulted from an
|
||||
* association procedure that was initiated by that specific peer MAC entity.
|
||||
*
|
||||
* PeerSTAAddress = sta->addr
|
||||
*/
|
||||
void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-ASSOCIATE.indication(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mlme_reassociate_indication - Report the establishment of an reassociation
|
||||
* with a specific peer MAC entity
|
||||
* @hapd: BSS data
|
||||
* @sta: peer STA data
|
||||
*
|
||||
* MLME calls this function as a result of the establishment of an
|
||||
* reassociation with a specific peer MAC entity that resulted from a
|
||||
* reassociation procedure that was initiated by that specific peer MAC entity.
|
||||
*
|
||||
* PeerSTAAddress = sta->addr
|
||||
*
|
||||
* sta->previous_ap contains the "Current AP" information from ReassocReq.
|
||||
*/
|
||||
void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-REASSOCIATE.indication(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mlme_disassociate_indication - Report disassociation with a specific peer
|
||||
* MAC entity
|
||||
* @hapd: BSS data
|
||||
* @sta: Peer STA data
|
||||
* @reason_code: ReasonCode from Disassociation frame
|
||||
*
|
||||
* MLME calls this function as a result of the invalidation of an association
|
||||
* relationship with a specific peer MAC entity.
|
||||
*
|
||||
* PeerSTAAddress = sta->addr
|
||||
*/
|
||||
void mlme_disassociate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason_code)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
|
||||
MAC2STR(sta->addr), reason_code);
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-MichaelMICFailure.indication(" MACSTR ")",
|
||||
MAC2STR(addr));
|
||||
}
|
||||
|
||||
|
||||
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-DELETEKEYS.request(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
|
||||
if (sta->wpa_sm)
|
||||
wpa_remove_ptk(sta->wpa_sm);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11 MLME
|
||||
* Copyright 2003, Jouni Malinen <j@w1.fi>
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, 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.
|
||||
*/
|
||||
|
||||
#ifndef MLME_H
|
||||
#define MLME_H
|
||||
|
||||
void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason_code);
|
||||
|
||||
void mlme_associate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
void mlme_disassociate_indication(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 reason_code);
|
||||
|
||||
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
|
||||
const u8 *addr);
|
||||
|
||||
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
#endif /* MLME_H */
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* hostapd - Plaintext password to NtPasswordHash
|
||||
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "ms_funcs.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned char password_hash[16];
|
||||
size_t i;
|
||||
char *password, buf[64], *pos;
|
||||
|
||||
if (argc > 1)
|
||||
password = argv[1];
|
||||
else {
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||
printf("Failed to read password\n");
|
||||
return 1;
|
||||
}
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
pos = buf;
|
||||
while (*pos != '\0') {
|
||||
if (*pos == '\r' || *pos == '\n') {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
password = buf;
|
||||
}
|
||||
|
||||
nt_password_hash((u8 *) password, strlen(password), password_hash);
|
||||
for (i = 0; i < sizeof(password_hash); i++)
|
||||
printf("%02x", password_hash[i]);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,396 @@
|
||||
/*
|
||||
* hostapd - PeerKey for Direct Link Setup (DLS)
|
||||
* Copyright (c) 2006-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 "common.h"
|
||||
#include "eloop.h"
|
||||
#include "sha1.h"
|
||||
#include "wpa.h"
|
||||
#include "defs.h"
|
||||
#include "wpa_auth_i.h"
|
||||
#include "wpa_auth_ie.h"
|
||||
|
||||
#ifdef CONFIG_PEERKEY
|
||||
|
||||
static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
#if 0
|
||||
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
||||
struct wpa_stsl_negotiation *neg = timeout_ctx;
|
||||
#endif
|
||||
|
||||
/* TODO: ? */
|
||||
}
|
||||
|
||||
|
||||
struct wpa_stsl_search {
|
||||
const u8 *addr;
|
||||
struct wpa_state_machine *sm;
|
||||
};
|
||||
|
||||
|
||||
static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
|
||||
{
|
||||
struct wpa_stsl_search *search = ctx;
|
||||
if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
|
||||
search->sm = sm;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, const u8 *peer,
|
||||
u16 mui, u16 error_type)
|
||||
{
|
||||
u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||
2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
|
||||
u8 *pos;
|
||||
struct rsn_error_kde error;
|
||||
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK Error");
|
||||
|
||||
pos = kde;
|
||||
|
||||
if (peer) {
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
error.mui = host_to_be16(mui);
|
||||
error.error_type = host_to_be16(error_type);
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
|
||||
(u8 *) &error, sizeof(error), NULL, 0);
|
||||
|
||||
__wpa_send_eapol(wpa_auth, sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
|
||||
NULL, NULL, kde, pos - kde, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
|
||||
{
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
struct wpa_stsl_search search;
|
||||
u8 *buf, *pos;
|
||||
size_t buf_len;
|
||||
|
||||
if (wpa_parse_kde_ies((const u8 *) (key + 1),
|
||||
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
|
||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
|
||||
kde.mac_addr_len < ETH_ALEN) {
|
||||
wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
|
||||
"SMK M1");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initiator = sm->addr; Peer = kde.mac_addr */
|
||||
|
||||
search.addr = kde.mac_addr;
|
||||
search.sm = NULL;
|
||||
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||
0 || search.sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
|
||||
" aborted - STA not associated anymore",
|
||||
MAC2STR(kde.mac_addr));
|
||||
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
|
||||
STK_ERR_STA_NR);
|
||||
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
|
||||
return;
|
||||
}
|
||||
|
||||
buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
|
||||
buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
/* Initiator RSN IE */
|
||||
os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
|
||||
pos = buf + kde.rsn_ie_len;
|
||||
/* Initiator MAC Address */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
|
||||
NULL, 0);
|
||||
|
||||
/* SMK M2:
|
||||
* EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
|
||||
* MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
|
||||
*/
|
||||
|
||||
wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK M2");
|
||||
|
||||
__wpa_send_eapol(wpa_auth, search.sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
|
||||
NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_eapol_key *key,
|
||||
struct wpa_eapol_ie_parse *kde,
|
||||
const u8 *smk)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
size_t buf_len;
|
||||
u32 lifetime;
|
||||
|
||||
/* SMK M4:
|
||||
* EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
|
||||
* MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
|
||||
* Lifetime KDE)
|
||||
*/
|
||||
|
||||
buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
|
||||
pos = buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
/* Initiator MAC Address */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
|
||||
NULL, 0);
|
||||
|
||||
/* Initiator Nonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
|
||||
NULL, 0);
|
||||
|
||||
/* SMK with PNonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
|
||||
key->key_nonce, WPA_NONCE_LEN);
|
||||
|
||||
/* Lifetime */
|
||||
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
|
||||
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
|
||||
|
||||
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK M4");
|
||||
|
||||
__wpa_send_eapol(wpa_auth, sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
|
||||
NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_eapol_key *key,
|
||||
struct wpa_eapol_ie_parse *kde,
|
||||
const u8 *smk, const u8 *peer)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
size_t buf_len;
|
||||
u32 lifetime;
|
||||
|
||||
/* SMK M5:
|
||||
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
|
||||
* MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
|
||||
* Lifetime KDE))
|
||||
*/
|
||||
|
||||
buf_len = kde->rsn_ie_len +
|
||||
2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
|
||||
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
|
||||
pos = buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
/* Peer RSN IE */
|
||||
os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
|
||||
pos = buf + kde->rsn_ie_len;
|
||||
|
||||
/* Peer MAC Address */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
|
||||
|
||||
/* PNonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
|
||||
WPA_NONCE_LEN, NULL, 0);
|
||||
|
||||
/* SMK and INonce */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
|
||||
kde->nonce, WPA_NONCE_LEN);
|
||||
|
||||
/* Lifetime */
|
||||
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
|
||||
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
|
||||
|
||||
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"Sending SMK M5");
|
||||
|
||||
__wpa_send_eapol(wpa_auth, sm,
|
||||
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||
WPA_KEY_INFO_SMK_MESSAGE,
|
||||
NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
|
||||
{
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
struct wpa_stsl_search search;
|
||||
u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
|
||||
|
||||
if (wpa_parse_kde_ies((const u8 *) (key + 1),
|
||||
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
|
||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kde.rsn_ie == NULL ||
|
||||
kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
|
||||
kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
|
||||
wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
|
||||
"Nonce KDE in SMK M3");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Peer = sm->addr; Initiator = kde.mac_addr;
|
||||
* Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
|
||||
|
||||
search.addr = kde.mac_addr;
|
||||
search.sm = NULL;
|
||||
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||
0 || search.sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
|
||||
" aborted - STA not associated anymore",
|
||||
MAC2STR(kde.mac_addr));
|
||||
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
|
||||
STK_ERR_STA_NR);
|
||||
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
|
||||
return;
|
||||
}
|
||||
|
||||
if (os_get_random(smk, PMK_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* SMK = PRF-256(Random number, "SMK Derivation",
|
||||
* AA || Time || INonce || PNonce)
|
||||
*/
|
||||
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
|
||||
pos = buf + ETH_ALEN;
|
||||
wpa_get_ntp_timestamp(pos);
|
||||
pos += 8;
|
||||
os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
|
||||
pos += WPA_NONCE_LEN;
|
||||
os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
|
||||
sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
|
||||
smk, PMK_LEN);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
|
||||
|
||||
wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
|
||||
wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
|
||||
|
||||
/* Authenticator does not need SMK anymore and it is required to forget
|
||||
* it. */
|
||||
os_memset(smk, 0, sizeof(*smk));
|
||||
}
|
||||
|
||||
|
||||
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
|
||||
{
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
struct wpa_stsl_search search;
|
||||
struct rsn_error_kde error;
|
||||
u16 mui, error_type;
|
||||
|
||||
if (wpa_parse_kde_ies((const u8 *) (key + 1),
|
||||
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
|
||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
|
||||
kde.error == NULL || kde.error_len < sizeof(error)) {
|
||||
wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
|
||||
"SMK Error");
|
||||
return;
|
||||
}
|
||||
|
||||
search.addr = kde.mac_addr;
|
||||
search.sm = NULL;
|
||||
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||
0 || search.sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
|
||||
"associated for SMK Error message from " MACSTR,
|
||||
MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(&error, kde.error, sizeof(error));
|
||||
mui = be_to_host16(error.mui);
|
||||
error_type = be_to_host16(error.error_type);
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"STA reported SMK Error: Peer " MACSTR
|
||||
" MUI %d Error Type %d",
|
||||
MAC2STR(kde.mac_addr), mui, error_type);
|
||||
|
||||
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
|
||||
}
|
||||
|
||||
|
||||
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_stsl_negotiation *neg)
|
||||
{
|
||||
struct wpa_stsl_negotiation *pos, *prev;
|
||||
|
||||
if (wpa_auth == NULL)
|
||||
return -1;
|
||||
pos = wpa_auth->stsl_negotiations;
|
||||
prev = NULL;
|
||||
while (pos) {
|
||||
if (pos == neg) {
|
||||
if (prev)
|
||||
prev->next = pos->next;
|
||||
else
|
||||
wpa_auth->stsl_negotiations = pos->next;
|
||||
|
||||
eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
|
||||
os_free(pos);
|
||||
return 0;
|
||||
}
|
||||
prev = pos;
|
||||
pos = pos->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PEERKEY */
|
@ -0,0 +1,368 @@
|
||||
/*
|
||||
* hostapd - PMKSA cache for IEEE 802.11i RSN
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "ap.h"
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "eloop.h"
|
||||
#include "sha1.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "eapol_sm.h"
|
||||
#include "pmksa_cache.h"
|
||||
|
||||
|
||||
static const int pmksa_cache_max_entries = 1024;
|
||||
static const int dot11RSNAConfigPMKLifetime = 43200;
|
||||
|
||||
struct rsn_pmksa_cache {
|
||||
#define PMKID_HASH_SIZE 128
|
||||
#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
|
||||
struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
|
||||
struct rsn_pmksa_cache_entry *pmksa;
|
||||
int pmksa_count;
|
||||
|
||||
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* rsn_pmkid - Calculate PMK identifier
|
||||
* @pmk: Pairwise master key
|
||||
* @pmk_len: Length of pmk in bytes
|
||||
* @aa: Authenticator address
|
||||
* @spa: Supplicant address
|
||||
*
|
||||
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||
* PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
|
||||
*/
|
||||
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||
u8 *pmkid)
|
||||
{
|
||||
char *title = "PMK Name";
|
||||
const u8 *addr[3];
|
||||
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
|
||||
unsigned char hash[SHA1_MAC_LEN];
|
||||
|
||||
addr[0] = (u8 *) title;
|
||||
addr[1] = aa;
|
||||
addr[2] = spa;
|
||||
|
||||
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
|
||||
os_memcpy(pmkid, hash, PMKID_LEN);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
|
||||
|
||||
|
||||
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
|
||||
{
|
||||
if (entry == NULL)
|
||||
return;
|
||||
os_free(entry->identity);
|
||||
ieee802_1x_free_radius_class(&entry->radius_class);
|
||||
os_free(entry);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||
struct rsn_pmksa_cache_entry *entry)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *pos, *prev;
|
||||
|
||||
pmksa->pmksa_count--;
|
||||
pmksa->free_cb(entry, pmksa->ctx);
|
||||
pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
|
||||
prev = NULL;
|
||||
while (pos) {
|
||||
if (pos == entry) {
|
||||
if (prev != NULL) {
|
||||
prev->hnext = pos->hnext;
|
||||
} else {
|
||||
pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
|
||||
pos->hnext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = pos;
|
||||
pos = pos->hnext;
|
||||
}
|
||||
|
||||
pos = pmksa->pmksa;
|
||||
prev = NULL;
|
||||
while (pos) {
|
||||
if (pos == entry) {
|
||||
if (prev != NULL)
|
||||
prev->next = pos->next;
|
||||
else
|
||||
pmksa->pmksa = pos->next;
|
||||
break;
|
||||
}
|
||||
prev = pos;
|
||||
pos = pos->next;
|
||||
}
|
||||
_pmksa_cache_free_entry(entry);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct rsn_pmksa_cache *pmksa = eloop_ctx;
|
||||
struct os_time now;
|
||||
|
||||
os_get_time(&now);
|
||||
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
|
||||
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
|
||||
pmksa->pmksa = entry->next;
|
||||
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
|
||||
MACSTR, MAC2STR(entry->spa));
|
||||
pmksa_cache_free_entry(pmksa, entry);
|
||||
}
|
||||
|
||||
pmksa_cache_set_expiration(pmksa);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
|
||||
{
|
||||
int sec;
|
||||
struct os_time now;
|
||||
|
||||
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
|
||||
if (pmksa->pmksa == NULL)
|
||||
return;
|
||||
os_get_time(&now);
|
||||
sec = pmksa->pmksa->expiration - now.sec;
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
if (eapol == NULL)
|
||||
return;
|
||||
|
||||
if (eapol->identity) {
|
||||
entry->identity = os_malloc(eapol->identity_len);
|
||||
if (entry->identity) {
|
||||
entry->identity_len = eapol->identity_len;
|
||||
os_memcpy(entry->identity, eapol->identity,
|
||||
eapol->identity_len);
|
||||
}
|
||||
}
|
||||
|
||||
ieee802_1x_copy_radius_class(&entry->radius_class,
|
||||
&eapol->radius_class);
|
||||
|
||||
entry->eap_type_authsrv = eapol->eap_type_authsrv;
|
||||
entry->vlan_id = eapol->sta->vlan_id;
|
||||
}
|
||||
|
||||
|
||||
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
if (entry == NULL || eapol == NULL)
|
||||
return;
|
||||
|
||||
if (entry->identity) {
|
||||
os_free(eapol->identity);
|
||||
eapol->identity = os_malloc(entry->identity_len);
|
||||
if (eapol->identity) {
|
||||
eapol->identity_len = entry->identity_len;
|
||||
os_memcpy(eapol->identity, entry->identity,
|
||||
entry->identity_len);
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
|
||||
eapol->identity, eapol->identity_len);
|
||||
}
|
||||
|
||||
ieee802_1x_free_radius_class(&eapol->radius_class);
|
||||
ieee802_1x_copy_radius_class(&eapol->radius_class,
|
||||
&entry->radius_class);
|
||||
if (eapol->radius_class.attr) {
|
||||
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
|
||||
"PMKSA", (unsigned long) eapol->radius_class.count);
|
||||
}
|
||||
|
||||
eapol->eap_type_authsrv = entry->eap_type_authsrv;
|
||||
eapol->sta->vlan_id = entry->vlan_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_add - Add a PMKSA cache entry
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
|
||||
* @pmk: The new pairwise master key
|
||||
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
|
||||
* @aa: Authenticator address
|
||||
* @spa: Supplicant address
|
||||
* @session_timeout: Session timeout
|
||||
* @eapol: Pointer to EAPOL state machine data
|
||||
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
|
||||
*
|
||||
* This function create a PMKSA entry for a new PMK and adds it to the PMKSA
|
||||
* cache. If an old entry is already in the cache for the same Supplicant,
|
||||
* this entry will be replaced with the new entry. PMKID will be calculated
|
||||
* based on the PMK.
|
||||
*/
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
|
||||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
|
||||
struct os_time now;
|
||||
|
||||
if (pmk_len > PMK_LEN)
|
||||
return NULL;
|
||||
|
||||
entry = os_zalloc(sizeof(*entry));
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
os_memcpy(entry->pmk, pmk, pmk_len);
|
||||
entry->pmk_len = pmk_len;
|
||||
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
|
||||
os_get_time(&now);
|
||||
entry->expiration = now.sec;
|
||||
if (session_timeout > 0)
|
||||
entry->expiration += session_timeout;
|
||||
else
|
||||
entry->expiration += dot11RSNAConfigPMKLifetime;
|
||||
entry->akmp = WPA_KEY_MGMT_IEEE8021X;
|
||||
os_memcpy(entry->spa, spa, ETH_ALEN);
|
||||
pmksa_cache_from_eapol_data(entry, eapol);
|
||||
|
||||
/* Replace an old entry for the same STA (if found) with the new entry
|
||||
*/
|
||||
pos = pmksa_cache_get(pmksa, spa, NULL);
|
||||
if (pos)
|
||||
pmksa_cache_free_entry(pmksa, pos);
|
||||
|
||||
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
|
||||
/* Remove the oldest entry to make room for the new entry */
|
||||
wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
|
||||
"entry (for " MACSTR ") to make room for new one",
|
||||
MAC2STR(pmksa->pmksa->spa));
|
||||
pmksa_cache_free_entry(pmksa, pmksa->pmksa);
|
||||
}
|
||||
|
||||
/* Add the new entry; order by expiration time */
|
||||
pos = pmksa->pmksa;
|
||||
prev = NULL;
|
||||
while (pos) {
|
||||
if (pos->expiration > entry->expiration)
|
||||
break;
|
||||
prev = pos;
|
||||
pos = pos->next;
|
||||
}
|
||||
if (prev == NULL) {
|
||||
entry->next = pmksa->pmksa;
|
||||
pmksa->pmksa = entry;
|
||||
} else {
|
||||
entry->next = prev->next;
|
||||
prev->next = entry;
|
||||
}
|
||||
entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
|
||||
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
|
||||
|
||||
pmksa->pmksa_count++;
|
||||
wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
|
||||
MAC2STR(entry->spa));
|
||||
wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_deinit - Free all entries in PMKSA cache
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
|
||||
*/
|
||||
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *entry, *prev;
|
||||
int i;
|
||||
|
||||
if (pmksa == NULL)
|
||||
return;
|
||||
|
||||
entry = pmksa->pmksa;
|
||||
while (entry) {
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
_pmksa_cache_free_entry(prev);
|
||||
}
|
||||
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
|
||||
for (i = 0; i < PMKID_HASH_SIZE; i++)
|
||||
pmksa->pmkid[i] = NULL;
|
||||
os_free(pmksa);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_get - Fetch a PMKSA cache entry
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
|
||||
* @spa: Supplicant address or %NULL to match any
|
||||
* @pmkid: PMKID or %NULL to match any
|
||||
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
|
||||
*/
|
||||
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
|
||||
const u8 *spa, const u8 *pmkid)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *entry;
|
||||
|
||||
if (pmkid)
|
||||
entry = pmksa->pmkid[PMKID_HASH(pmkid)];
|
||||
else
|
||||
entry = pmksa->pmksa;
|
||||
while (entry) {
|
||||
if ((spa == NULL ||
|
||||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
|
||||
(pmkid == NULL ||
|
||||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
|
||||
return entry;
|
||||
entry = pmkid ? entry->hnext : entry->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_init - Initialize PMKSA cache
|
||||
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
|
||||
* @ctx: Context pointer for free_cb function
|
||||
* Returns: Pointer to PMKSA cache data or %NULL on failure
|
||||
*/
|
||||
struct rsn_pmksa_cache *
|
||||
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx), void *ctx)
|
||||
{
|
||||
struct rsn_pmksa_cache *pmksa;
|
||||
|
||||
pmksa = os_zalloc(sizeof(*pmksa));
|
||||
if (pmksa) {
|
||||
pmksa->free_cb = free_cb;
|
||||
pmksa->ctx = ctx;
|
||||
}
|
||||
|
||||
return pmksa;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* hostapd - PMKSA cache for IEEE 802.11i RSN
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PMKSA_CACHE_H
|
||||
#define PMKSA_CACHE_H
|
||||
|
||||
/**
|
||||
* struct rsn_pmksa_cache_entry - PMKSA cache entry
|
||||
*/
|
||||
struct rsn_pmksa_cache_entry {
|
||||
struct rsn_pmksa_cache_entry *next, *hnext;
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN];
|
||||
size_t pmk_len;
|
||||
os_time_t expiration;
|
||||
int akmp; /* WPA_KEY_MGMT_* */
|
||||
u8 spa[ETH_ALEN];
|
||||
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
struct radius_class_data radius_class;
|
||||
u8 eap_type_authsrv;
|
||||
int vlan_id;
|
||||
};
|
||||
|
||||
struct rsn_pmksa_cache;
|
||||
|
||||
struct rsn_pmksa_cache *
|
||||
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx), void *ctx);
|
||||
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
|
||||
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
|
||||
const u8 *spa, const u8 *pmkid);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
|
||||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol);
|
||||
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
struct eapol_state_machine *eapol);
|
||||
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||
u8 *pmkid);
|
||||
|
||||
#endif /* PMKSA_CACHE_H */
|
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef CONFIG_RSN_PREAUTH
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "eloop.h"
|
||||
#include "sta_info.h"
|
||||
#include "wpa_common.h"
|
||||
#include "eapol_sm.h"
|
||||
#include "wpa.h"
|
||||
#include "preauth.h"
|
||||
|
||||
#ifndef ETH_P_PREAUTH
|
||||
#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
|
||||
#endif /* ETH_P_PREAUTH */
|
||||
|
||||
static const int dot11RSNAConfigPMKLifetime = 43200;
|
||||
|
||||
struct rsn_preauth_interface {
|
||||
struct rsn_preauth_interface *next;
|
||||
struct hostapd_data *hapd;
|
||||
struct l2_packet_data *l2;
|
||||
char *ifname;
|
||||
int ifindex;
|
||||
};
|
||||
|
||||
|
||||
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct rsn_preauth_interface *piface = ctx;
|
||||
struct hostapd_data *hapd = piface->hapd;
|
||||
struct ieee802_1x_hdr *hdr;
|
||||
struct sta_info *sta;
|
||||
struct l2_ethhdr *ethhdr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
|
||||
"from interface '%s'", piface->ifname);
|
||||
if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
|
||||
"(len=%lu)", (unsigned long) len);
|
||||
return;
|
||||
}
|
||||
|
||||
ethhdr = (struct l2_ethhdr *) buf;
|
||||
hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
|
||||
|
||||
if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
|
||||
MACSTR, MAC2STR(ethhdr->h_dest));
|
||||
return;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, ethhdr->h_source);
|
||||
if (sta && (sta->flags & WLAN_STA_ASSOC)) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
|
||||
"STA " MACSTR, MAC2STR(sta->addr));
|
||||
return;
|
||||
}
|
||||
if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
|
||||
sta = ap_sta_add(hapd, ethhdr->h_source);
|
||||
if (sta == NULL)
|
||||
return;
|
||||
sta->flags = WLAN_STA_PREAUTH;
|
||||
|
||||
ieee802_1x_new_station(hapd, sta);
|
||||
if (sta->eapol_sm == NULL) {
|
||||
ap_free_sta(hapd, sta);
|
||||
sta = NULL;
|
||||
} else {
|
||||
sta->eapol_sm->radius_identifier = -1;
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
|
||||
}
|
||||
}
|
||||
if (sta == NULL)
|
||||
return;
|
||||
sta->preauth_iface = piface;
|
||||
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
|
||||
len - sizeof(*ethhdr));
|
||||
}
|
||||
|
||||
|
||||
static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
|
||||
{
|
||||
struct rsn_preauth_interface *piface;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
|
||||
|
||||
piface = os_zalloc(sizeof(*piface));
|
||||
if (piface == NULL)
|
||||
return -1;
|
||||
piface->hapd = hapd;
|
||||
|
||||
piface->ifname = os_strdup(ifname);
|
||||
if (piface->ifname == NULL) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
|
||||
rsn_preauth_receive, piface, 1);
|
||||
if (piface->l2 == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
|
||||
"to ETH_P_PREAUTH");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
piface->next = hapd->preauth_iface;
|
||||
hapd->preauth_iface = piface;
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
os_free(piface->ifname);
|
||||
fail1:
|
||||
os_free(piface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
struct rsn_preauth_interface *piface, *prev;
|
||||
|
||||
piface = hapd->preauth_iface;
|
||||
hapd->preauth_iface = NULL;
|
||||
while (piface) {
|
||||
prev = piface;
|
||||
piface = piface->next;
|
||||
l2_packet_deinit(prev->l2);
|
||||
os_free(prev->ifname);
|
||||
os_free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int rsn_preauth_iface_init(struct hostapd_data *hapd)
|
||||
{
|
||||
char *tmp, *start, *end;
|
||||
|
||||
if (hapd->conf->rsn_preauth_interfaces == NULL)
|
||||
return 0;
|
||||
|
||||
tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
|
||||
if (tmp == NULL)
|
||||
return -1;
|
||||
start = tmp;
|
||||
for (;;) {
|
||||
while (*start == ' ')
|
||||
start++;
|
||||
if (*start == '\0')
|
||||
break;
|
||||
end = os_strchr(start, ' ');
|
||||
if (end)
|
||||
*end = '\0';
|
||||
|
||||
if (rsn_preauth_iface_add(hapd, start)) {
|
||||
rsn_preauth_iface_deinit(hapd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (end)
|
||||
start = end + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
os_free(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
ap_free_sta(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int success)
|
||||
{
|
||||
const u8 *key;
|
||||
size_t len;
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||
HOSTAPD_LEVEL_INFO, "pre-authentication %s",
|
||||
success ? "succeeded" : "failed");
|
||||
|
||||
key = ieee802_1x_get_key(sta->eapol_sm, &len);
|
||||
if (len > PMK_LEN)
|
||||
len = PMK_LEN;
|
||||
if (success && key) {
|
||||
if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
|
||||
sta->addr,
|
||||
dot11RSNAConfigPMKLifetime,
|
||||
sta->eapol_sm) == 0) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"added PMKSA cache entry (pre-auth)");
|
||||
} else {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"failed to add PMKSA cache entry "
|
||||
"(pre-auth)");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish STA entry removal from timeout in order to avoid freeing
|
||||
* STA data before the caller has finished processing.
|
||||
*/
|
||||
eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *buf, size_t len)
|
||||
{
|
||||
struct rsn_preauth_interface *piface;
|
||||
struct l2_ethhdr *ethhdr;
|
||||
|
||||
piface = hapd->preauth_iface;
|
||||
while (piface) {
|
||||
if (piface == sta->preauth_iface)
|
||||
break;
|
||||
piface = piface->next;
|
||||
}
|
||||
|
||||
if (piface == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
|
||||
"interface for " MACSTR, MAC2STR(sta->addr));
|
||||
return;
|
||||
}
|
||||
|
||||
ethhdr = os_malloc(sizeof(*ethhdr) + len);
|
||||
if (ethhdr == NULL)
|
||||
return;
|
||||
|
||||
os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
|
||||
os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
|
||||
ethhdr->h_proto = htons(ETH_P_PREAUTH);
|
||||
os_memcpy(ethhdr + 1, buf, len);
|
||||
|
||||
if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
|
||||
sizeof(*ethhdr) + len) < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
|
||||
"l2_packet_send\n");
|
||||
}
|
||||
os_free(ethhdr);
|
||||
}
|
||||
|
||||
|
||||
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RSN_PREAUTH */
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PREAUTH_H
|
||||
#define PREAUTH_H
|
||||
|
||||
#ifdef CONFIG_RSN_PREAUTH
|
||||
|
||||
int rsn_preauth_iface_init(struct hostapd_data *hapd);
|
||||
void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
|
||||
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int success);
|
||||
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *buf, size_t len);
|
||||
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
#else /* CONFIG_RSN_PREAUTH */
|
||||
|
||||
static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rsn_preauth_finished(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
int success)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rsn_preauth_send(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
u8 *buf, size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RSN_PREAUTH */
|
||||
|
||||
#endif /* PREAUTH_H */
|
@ -0,0 +1,177 @@
|
||||
#ifndef PRISM54_H
|
||||
#define PRISM54_H
|
||||
|
||||
struct ieee802_3_hdr_s {
|
||||
unsigned char da[6];
|
||||
unsigned char sa[6];
|
||||
unsigned short type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct ieee802_3_hdr_s ieee802_3_hdr;
|
||||
|
||||
#define PIMOP_GET 0
|
||||
#define PIMOP_SET 1
|
||||
#define PIMOP_RESPONSE 2
|
||||
#define PIMOP_ERROR 3
|
||||
#define PIMOP_TRAP 4
|
||||
|
||||
struct pimdev_hdr_s {
|
||||
int op;
|
||||
unsigned long oid;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct pimdev_hdr_s pimdev_hdr;
|
||||
|
||||
#define DOT11_OID_ATTACHMENT 0x19000003
|
||||
|
||||
/* really need to check */
|
||||
#define DOT11_PKT_BEACON 0x80
|
||||
#define DOT11_PKT_ASSOC_RESP 0x10
|
||||
#define DOT11_PKT_REASSOC_RESP 0x30
|
||||
#define DOT11_PKT_PROBE_RESP 0x50
|
||||
|
||||
struct obj_attachment_hdr {
|
||||
char type;
|
||||
char reserved;
|
||||
short id;
|
||||
short size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct obj_attachment {
|
||||
char type;
|
||||
char reserved;
|
||||
short id;
|
||||
short size;
|
||||
char data[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_MLMEAUTOLEVEL 0x19000001
|
||||
#define DOT11_MLME_AUTO 0
|
||||
#define DOT11_MLME_INTERMEDIATE 0x01000000
|
||||
#define DOT11_MLME_EXTENDED 0x02000000
|
||||
|
||||
#define DOT11_OID_DEAUTHENTICATE 0x18000000
|
||||
#define DOT11_OID_AUTHENTICATE 0x18000001
|
||||
#define DOT11_OID_DISASSOCIATE 0x18000002
|
||||
#define DOT11_OID_ASSOCIATE 0x18000003
|
||||
#define DOT11_OID_BEACON 0x18000005
|
||||
#define DOT11_OID_PROBE 0x18000006
|
||||
#define DOT11_OID_REASSOCIATE 0x1800000b
|
||||
|
||||
struct obj_mlme {
|
||||
char address[6];
|
||||
short id;
|
||||
short state;
|
||||
short code;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_DEAUTHENTICATEEX 0x18000007
|
||||
#define DOT11_OID_AUTHENTICATEEX 0x18000008
|
||||
#define DOT11_OID_DISASSOCIATEEX 0x18000009
|
||||
#define DOT11_OID_ASSOCIATEEX 0x1800000a
|
||||
#define DOT11_OID_REASSOCIATEEX 0x1800000c
|
||||
|
||||
struct obj_mlmeex {
|
||||
char address[6];
|
||||
short id;
|
||||
short state;
|
||||
short code;
|
||||
short size;
|
||||
char data[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_STAKEY 0x12000008
|
||||
|
||||
#define DOT11_PRIV_WEP 0
|
||||
#define DOT11_PRIV_TKIP 1
|
||||
|
||||
/* endian reversed to bigger endian */
|
||||
#define DOT11_STAKEY_OPTION_DEFAULTKEY 0x100
|
||||
|
||||
struct obj_stakey {
|
||||
char address[6];
|
||||
char keyid;
|
||||
char reserved;
|
||||
short options;
|
||||
char type;
|
||||
char length;
|
||||
char key[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_DEFKEYID 0x12000003
|
||||
#define DOT11_OID_DEFKEY1 0x12000004
|
||||
#define DOT11_OID_DEFKEY2 0x12000005
|
||||
#define DOT11_OID_DEFKEY3 0x12000006
|
||||
#define DOT11_OID_DEFKEY4 0x12000007
|
||||
|
||||
struct obj_key {
|
||||
char type;
|
||||
char length;
|
||||
char key[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_STASC 0x1200000a
|
||||
|
||||
struct obj_stasc {
|
||||
char address[6];
|
||||
char keyid;
|
||||
char tx_sc;
|
||||
unsigned long sc_high;
|
||||
unsigned short sc_low;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_CLIENTS 0x15000001
|
||||
#define DOT11_OID_CLIENTSASSOCIATED 0x15000002
|
||||
#define DOT11_OID_CLIENTST 0x15000003
|
||||
#define DOT11_OID_CLIENTEND 0x150007d9
|
||||
#define DOT11_OID_CLIENTFIND 0x150007db
|
||||
|
||||
#define DOT11_NODE_UNKNOWN
|
||||
#define DOT11_NODE_CLIENT
|
||||
#define DOT11_NODE_AP
|
||||
|
||||
/* endian reversed to bigger endian */
|
||||
#define DOT11_STATE_NONE 0
|
||||
#define DOT11_STATE_AUTHING 0x100
|
||||
#define DOT11_STATE_AUTH 0x200
|
||||
#define DOT11_STATE_ASSOCING 0x300
|
||||
#define DOT11_STATE_REASSOCING 0x400
|
||||
#define DOT11_STATE_ASSOC 0x500
|
||||
#define DOT11_STATE_WDS 0x600
|
||||
|
||||
struct obj_sta {
|
||||
char address[6];
|
||||
char pad[2];
|
||||
char state;
|
||||
char node;
|
||||
short age;
|
||||
char reserved1;
|
||||
char rssi;
|
||||
char rate;
|
||||
char reserved2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_SSID 0x10000002
|
||||
#define DOT11_OID_SSIDOVERRIDE 0x10000006
|
||||
|
||||
struct obj_ssid {
|
||||
char length;
|
||||
char octets[33];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define DOT11_OID_EAPAUTHSTA 0x150007de
|
||||
#define DOT11_OID_EAPUNAUTHSTA 0x150007df
|
||||
/* not in 38801 datasheet??? */
|
||||
#define DOT11_OID_DOT1XENABLE 0x150007e0
|
||||
#define DOT11_OID_MICFAILURE 0x150007e1
|
||||
#define DOT11_OID_AUTHENABLE 0x12000000
|
||||
#define DOT11_OID_PRIVACYINVOKED 0x12000001
|
||||
#define DOT11_OID_EXUNENCRYPTED 0x12000002
|
||||
|
||||
#define DOT11_AUTH_OS 0x01000000
|
||||
#define DOT11_AUTH_SK 0x02000000
|
||||
#define DOT11_AUTH_BOTH 0x03000000
|
||||
|
||||
#define DOT11_BOOL_TRUE 0x01000000
|
||||
|
||||
#endif /* PRISM54_H */
|
@ -0,0 +1,71 @@
|
||||
#ifndef PRIV_NETLINK_H
|
||||
#define PRIV_NETLINK_H
|
||||
|
||||
/* Private copy of needed Linux netlink/rtnetlink definitions.
|
||||
*
|
||||
* This should be replaced with user space header once one is available with C
|
||||
* library, etc..
|
||||
*/
|
||||
|
||||
#ifndef IFLA_IFNAME
|
||||
#define IFLA_IFNAME 3
|
||||
#endif
|
||||
#ifndef IFLA_WIRELESS
|
||||
#define IFLA_WIRELESS 11
|
||||
#endif
|
||||
|
||||
#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 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)))
|
||||
|
||||
|
||||
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 */
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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 */
|
@ -0,0 +1,712 @@
|
||||
/*
|
||||
* hostapd / Configuration reloading
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||
* Copyright (c) 2005-2006, Devicescape Software, 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 "hostapd.h"
|
||||
#include "beacon.h"
|
||||
#include "hw_features.h"
|
||||
#include "driver.h"
|
||||
#include "sta_info.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "iapp.h"
|
||||
#include "ap_list.h"
|
||||
#include "wpa.h"
|
||||
#include "vlan_init.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "accounting.h"
|
||||
#include "eloop.h"
|
||||
|
||||
|
||||
/**
|
||||
* struct hostapd_config_change - Configuration change information
|
||||
* This is for two purposes:
|
||||
* - Storing configuration information in the hostapd_iface during
|
||||
* the asynchronous parts of reconfiguration.
|
||||
* - Passing configuration information for per-station reconfiguration.
|
||||
*/
|
||||
struct hostapd_config_change {
|
||||
struct hostapd_data *hapd;
|
||||
struct hostapd_config *newconf, *oldconf;
|
||||
struct hostapd_bss_config *newbss, *oldbss;
|
||||
int mac_acl_changed;
|
||||
int num_sta_remove; /* number of STAs that need to be removed */
|
||||
int beacon_changed;
|
||||
struct hostapd_iface *hapd_iface;
|
||||
struct hostapd_data **new_hapd, **old_hapd;
|
||||
int num_old_hapd;
|
||||
};
|
||||
|
||||
|
||||
static int hostapd_config_reload_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, void *data)
|
||||
{
|
||||
struct hostapd_config_change *change = data;
|
||||
struct hostapd_bss_config *newbss, *oldbss;
|
||||
int deauth = 0;
|
||||
u8 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
|
||||
|
||||
newbss = change->newbss;
|
||||
oldbss = change->oldbss;
|
||||
hapd = change->hapd;
|
||||
|
||||
if (sta->ssid == &oldbss->ssid) {
|
||||
sta->ssid = &newbss->ssid;
|
||||
|
||||
if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
|
||||
os_memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
|
||||
newbss->ssid.ssid_len) != 0) {
|
||||
/* main SSID was changed - kick STA out */
|
||||
deauth++;
|
||||
}
|
||||
}
|
||||
sta->ssid_probe = sta->ssid;
|
||||
|
||||
/*
|
||||
* If MAC ACL configuration has changed, deauthenticate stations that
|
||||
* have been removed from accepted list or have been added to denied
|
||||
* list. If external RADIUS server is used for ACL, all stations are
|
||||
* deauthenticated and they will need to authenticate again. This
|
||||
* limits sudden load on the RADIUS server since the verification will
|
||||
* be done over the time needed for the STAs to reauthenticate
|
||||
* themselves.
|
||||
*/
|
||||
if (change->mac_acl_changed &&
|
||||
(newbss->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH ||
|
||||
!hostapd_allowed_address(hapd, sta->addr, NULL, 0, NULL, NULL,
|
||||
NULL)))
|
||||
deauth++;
|
||||
|
||||
if (newbss->ieee802_1x != oldbss->ieee802_1x &&
|
||||
sta->ssid == &hapd->conf->ssid)
|
||||
deauth++;
|
||||
|
||||
if (newbss->wpa != oldbss->wpa)
|
||||
deauth++;
|
||||
|
||||
if (!newbss->wme_enabled && (sta->flags & WLAN_STA_WME))
|
||||
deauth++;
|
||||
|
||||
if (newbss->auth_algs != oldbss->auth_algs &&
|
||||
((sta->auth_alg == WLAN_AUTH_OPEN &&
|
||||
!(newbss->auth_algs & WPA_AUTH_ALG_OPEN)) ||
|
||||
(sta->auth_alg == WLAN_AUTH_SHARED_KEY &&
|
||||
!(newbss->auth_algs & WPA_AUTH_ALG_SHARED))))
|
||||
deauth++;
|
||||
|
||||
if (change->num_sta_remove > 0) {
|
||||
deauth++;
|
||||
reason = WLAN_REASON_DISASSOC_AP_BUSY;
|
||||
}
|
||||
|
||||
if (deauth) {
|
||||
wpa_printf(MSG_DEBUG, "STA " MACSTR " deauthenticated during "
|
||||
"config reloading (reason=%d)",
|
||||
MAC2STR(sta->addr), reason);
|
||||
ieee802_11_send_deauth(hapd, sta->addr, reason);
|
||||
ap_sta_deauthenticate(hapd, sta, reason);
|
||||
change->num_sta_remove--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_reconfig_tx_queue_params(struct hostapd_data *hapd,
|
||||
struct hostapd_config *newconf,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_tx_queue_params *o, *n;
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
o = &oldconf->tx_queue[i];
|
||||
n = &newconf->tx_queue[i];
|
||||
|
||||
if (!n->configured)
|
||||
continue;
|
||||
|
||||
if ((n->aifs != o->aifs || n->cwmin != o->cwmin ||
|
||||
n->cwmax != o->cwmax || n->burst != o->burst) &&
|
||||
hostapd_set_tx_queue_params(hapd, i, n->aifs, n->cwmin,
|
||||
n->cwmax, n->burst))
|
||||
printf("Failed to set TX queue parameters for queue %d"
|
||||
".\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_reconfig_wme(struct hostapd_data *hapd,
|
||||
struct hostapd_config *newconf,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
int beacon_changed = 0;
|
||||
size_t i;
|
||||
struct hostapd_wme_ac_params *o, *n;
|
||||
|
||||
for (i = 0; i < sizeof(newconf->wme_ac_params) /
|
||||
sizeof(newconf->wme_ac_params[0]); i++) {
|
||||
o = &oldconf->wme_ac_params[i];
|
||||
n = &newconf->wme_ac_params[i];
|
||||
if (n->cwmin != o->cwmin ||
|
||||
n->cwmax != o->cwmax ||
|
||||
n->aifs != o->aifs ||
|
||||
n->txopLimit != o->txopLimit ||
|
||||
n->admission_control_mandatory !=
|
||||
o->admission_control_mandatory) {
|
||||
beacon_changed++;
|
||||
hapd->parameter_set_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return beacon_changed;
|
||||
}
|
||||
|
||||
|
||||
static int rate_array_diff(int *a1, int *a2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (a1 == NULL && a2 == NULL)
|
||||
return 0;
|
||||
if (a1 == NULL || a2 == NULL)
|
||||
return 1;
|
||||
|
||||
i = 0;
|
||||
for (;;) {
|
||||
if (a1[i] != a2[i])
|
||||
return 1;
|
||||
if (a1[i] == -1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_acl_diff(struct hostapd_bss_config *a,
|
||||
struct hostapd_bss_config *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (a->macaddr_acl != b->macaddr_acl ||
|
||||
a->num_accept_mac != b->num_accept_mac ||
|
||||
a->num_deny_mac != b->num_deny_mac)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < a->num_accept_mac; i++) {
|
||||
if (os_memcmp(a->accept_mac[i], b->accept_mac[i], ETH_ALEN) !=
|
||||
0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < a->num_deny_mac; i++) {
|
||||
if (os_memcmp(a->deny_mac[i], b->deny_mac[i], ETH_ALEN) != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reload_iface2 - Part 2 of reload_iface
|
||||
* @hapd_iface: Pointer to hostapd interface data.
|
||||
*/
|
||||
static void reload_iface2(struct hostapd_iface *hapd_iface)
|
||||
{
|
||||
struct hostapd_data *hapd = hapd_iface->bss[0];
|
||||
struct hostapd_config *newconf = hapd_iface->change->newconf;
|
||||
struct hostapd_config *oldconf = hapd_iface->change->oldconf;
|
||||
int beacon_changed = hapd_iface->change->beacon_changed;
|
||||
hostapd_iface_cb cb = hapd_iface->reload_iface_cb;
|
||||
|
||||
if (newconf->preamble != oldconf->preamble) {
|
||||
if (hostapd_set_preamble(hapd, hapd->iconf->preamble))
|
||||
printf("Could not set preamble for kernel driver\n");
|
||||
beacon_changed++;
|
||||
}
|
||||
|
||||
if (newconf->beacon_int != oldconf->beacon_int) {
|
||||
/* Need to change beacon interval if it has changed or if
|
||||
* auto channel selection was used. */
|
||||
if (hostapd_set_beacon_int(hapd, newconf->beacon_int))
|
||||
printf("Could not set beacon interval for kernel "
|
||||
"driver\n");
|
||||
if (newconf->beacon_int != oldconf->beacon_int)
|
||||
beacon_changed++;
|
||||
}
|
||||
|
||||
if (newconf->cts_protection_type != oldconf->cts_protection_type)
|
||||
beacon_changed++;
|
||||
|
||||
if (newconf->rts_threshold > -1 &&
|
||||
newconf->rts_threshold != oldconf->rts_threshold &&
|
||||
hostapd_set_rts(hapd, newconf->rts_threshold))
|
||||
printf("Could not set RTS threshold for kernel driver\n");
|
||||
|
||||
if (newconf->fragm_threshold > -1 &&
|
||||
newconf->fragm_threshold != oldconf->fragm_threshold &&
|
||||
hostapd_set_frag(hapd, newconf->fragm_threshold))
|
||||
printf("Could not set fragmentation threshold for kernel "
|
||||
"driver\n");
|
||||
|
||||
hostapd_reconfig_tx_queue_params(hapd, newconf, oldconf);
|
||||
|
||||
if (hostapd_reconfig_wme(hapd, newconf, oldconf) > 0)
|
||||
beacon_changed++;
|
||||
|
||||
ap_list_reconfig(hapd_iface, oldconf);
|
||||
|
||||
hapd_iface->change->beacon_changed = beacon_changed;
|
||||
|
||||
hapd_iface->reload_iface_cb = NULL;
|
||||
cb(hapd_iface, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reload_iface2_handler - Handler that calls reload_face2
|
||||
* @eloop_data: Stores the struct hostapd_iface for the interface.
|
||||
* @user_ctx: Unused.
|
||||
*/
|
||||
static void reload_iface2_handler(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct hostapd_iface *hapd_iface = eloop_data;
|
||||
|
||||
reload_iface2(hapd_iface);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reload_hw_mode_done - Callback for after the HW mode is setup
|
||||
* @hapd_iface: Pointer to interface data.
|
||||
* @status: Status of the HW mode setup.
|
||||
*/
|
||||
static void reload_hw_mode_done(struct hostapd_iface *hapd_iface, int status)
|
||||
{
|
||||
struct hostapd_data *hapd = hapd_iface->bss[0];
|
||||
struct hostapd_config_change *change = hapd_iface->change;
|
||||
struct hostapd_config *newconf = change->newconf;
|
||||
hostapd_iface_cb cb;
|
||||
int freq;
|
||||
|
||||
if (status) {
|
||||
printf("Failed to select hw_mode.\n");
|
||||
|
||||
cb = hapd_iface->reload_iface_cb;
|
||||
hapd_iface->reload_iface_cb = NULL;
|
||||
cb(hapd_iface, -1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
freq = hostapd_hw_get_freq(hapd, newconf->channel);
|
||||
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d Frequency: %d MHz",
|
||||
hostapd_hw_mode_txt(newconf->hw_mode),
|
||||
newconf->channel, freq);
|
||||
|
||||
if (hostapd_set_freq(hapd, newconf->hw_mode, freq)) {
|
||||
printf("Could not set channel %d (%d MHz) for kernel "
|
||||
"driver\n", newconf->channel, freq);
|
||||
}
|
||||
|
||||
change->beacon_changed++;
|
||||
|
||||
reload_iface2(hapd_iface);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_config_reload_iface_start - Start interface reload
|
||||
* @hapd_iface: Pointer to interface data.
|
||||
* @cb: The function to callback when done.
|
||||
* Returns: 0 if it starts successfully; cb will be called when done.
|
||||
* -1 on failure; cb will not be called.
|
||||
*/
|
||||
static int hostapd_config_reload_iface_start(struct hostapd_iface *hapd_iface,
|
||||
hostapd_iface_cb cb)
|
||||
{
|
||||
struct hostapd_config_change *change = hapd_iface->change;
|
||||
struct hostapd_config *newconf = change->newconf;
|
||||
struct hostapd_config *oldconf = change->oldconf;
|
||||
struct hostapd_data *hapd = hapd_iface->bss[0];
|
||||
|
||||
if (hapd_iface->reload_iface_cb) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Interface reload already in progress.",
|
||||
hapd_iface->bss[0]->conf->iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hapd_iface->reload_iface_cb = cb;
|
||||
|
||||
if (newconf->bridge_packets != oldconf->bridge_packets &&
|
||||
hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
|
||||
hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets))
|
||||
printf("Failed to set bridge_packets for kernel driver\n");
|
||||
|
||||
if (newconf->channel != oldconf->channel ||
|
||||
newconf->hw_mode != oldconf->hw_mode ||
|
||||
rate_array_diff(newconf->supported_rates,
|
||||
oldconf->supported_rates) ||
|
||||
rate_array_diff(newconf->basic_rates, oldconf->basic_rates)) {
|
||||
hostapd_free_stas(hapd);
|
||||
|
||||
if (hostapd_get_hw_features(hapd_iface)) {
|
||||
printf("Could not read HW feature info from the kernel"
|
||||
" driver.\n");
|
||||
hapd_iface->reload_iface_cb = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_select_hw_mode_start(hapd_iface,
|
||||
reload_hw_mode_done)) {
|
||||
printf("Failed to start select hw_mode.\n");
|
||||
hapd_iface->reload_iface_cb = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
eloop_register_timeout(0, 0, reload_iface2_handler, hapd_iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_reconfig_bss(struct hostapd_data *hapd,
|
||||
struct hostapd_bss_config *newbss,
|
||||
struct hostapd_bss_config *oldbss,
|
||||
struct hostapd_config *oldconf,
|
||||
int beacon_changed)
|
||||
{
|
||||
struct hostapd_config_change change;
|
||||
int encr_changed = 0;
|
||||
struct radius_client_data *old_radius;
|
||||
|
||||
radius_client_flush(hapd->radius, 0);
|
||||
|
||||
if (hostapd_set_dtim_period(hapd, newbss->dtim_period))
|
||||
printf("Could not set DTIM period for kernel driver\n");
|
||||
|
||||
if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
|
||||
os_memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
|
||||
newbss->ssid.ssid_len) != 0) {
|
||||
if (hostapd_set_ssid(hapd, (u8 *) newbss->ssid.ssid,
|
||||
newbss->ssid.ssid_len))
|
||||
printf("Could not set SSID for kernel driver\n");
|
||||
beacon_changed++;
|
||||
}
|
||||
|
||||
if (newbss->ignore_broadcast_ssid != oldbss->ignore_broadcast_ssid)
|
||||
beacon_changed++;
|
||||
|
||||
if (hostapd_wep_key_cmp(&newbss->ssid.wep, &oldbss->ssid.wep)) {
|
||||
encr_changed++;
|
||||
beacon_changed++;
|
||||
}
|
||||
|
||||
vlan_reconfig(hapd, oldconf, oldbss);
|
||||
|
||||
if (beacon_changed) {
|
||||
wpa_printf(MSG_DEBUG, "Updating beacon frame information");
|
||||
ieee802_11_set_beacon(hapd);
|
||||
}
|
||||
|
||||
change.hapd = hapd;
|
||||
change.oldconf = oldconf;
|
||||
change.newconf = hapd->iconf;
|
||||
change.oldbss = oldbss;
|
||||
change.newbss = newbss;
|
||||
change.mac_acl_changed = hostapd_acl_diff(newbss, oldbss);
|
||||
if (newbss->max_num_sta != oldbss->max_num_sta &&
|
||||
newbss->max_num_sta < hapd->num_sta) {
|
||||
change.num_sta_remove = hapd->num_sta - newbss->max_num_sta;
|
||||
} else
|
||||
change.num_sta_remove = 0;
|
||||
ap_for_each_sta(hapd, hostapd_config_reload_sta, &change);
|
||||
|
||||
old_radius = hapd->radius;
|
||||
hapd->radius = radius_client_reconfig(hapd->radius, hapd,
|
||||
oldbss->radius, newbss->radius);
|
||||
hapd->radius_client_reconfigured = old_radius != hapd->radius ||
|
||||
hostapd_ip_diff(&newbss->own_ip_addr, &oldbss->own_ip_addr);
|
||||
|
||||
ieee802_1x_reconfig(hapd, oldconf, oldbss);
|
||||
iapp_reconfig(hapd, oldconf, oldbss);
|
||||
|
||||
hostapd_acl_reconfig(hapd, oldconf);
|
||||
accounting_reconfig(hapd, oldconf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* config_reload2 - Part 2 of configuration reloading
|
||||
* @hapd_iface:
|
||||
*/
|
||||
static void config_reload2(struct hostapd_iface *hapd_iface, int status)
|
||||
{
|
||||
struct hostapd_config_change *change = hapd_iface->change;
|
||||
struct hostapd_data *hapd = change->hapd;
|
||||
struct hostapd_config *newconf = change->newconf;
|
||||
struct hostapd_config *oldconf = change->oldconf;
|
||||
int beacon_changed = change->beacon_changed;
|
||||
struct hostapd_data **new_hapd = change->new_hapd;
|
||||
struct hostapd_data **old_hapd = change->old_hapd;
|
||||
int num_old_hapd = change->num_old_hapd;
|
||||
size_t i, j, max_bss, same_bssid;
|
||||
struct hostapd_bss_config *newbss, *oldbss;
|
||||
u8 *prev_addr;
|
||||
hostapd_iface_cb cb;
|
||||
|
||||
os_free(change);
|
||||
hapd_iface->change = NULL;
|
||||
|
||||
if (status) {
|
||||
printf("Failed to setup new interface config\n");
|
||||
|
||||
cb = hapd_iface->config_reload_cb;
|
||||
hapd_iface->config_reload_cb = NULL;
|
||||
|
||||
/* Invalid configuration - cleanup and terminate hostapd */
|
||||
hapd_iface->bss = old_hapd;
|
||||
hapd_iface->num_bss = num_old_hapd;
|
||||
hapd_iface->conf = hapd->iconf = oldconf;
|
||||
hapd->conf = &oldconf->bss[0];
|
||||
hostapd_config_free(newconf);
|
||||
os_free(new_hapd);
|
||||
|
||||
cb(hapd_iface, -2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any BSSes have been removed, added, or had their BSSIDs changed,
|
||||
* completely remove and reinitialize such BSSes and all the BSSes
|
||||
* following them since their BSSID might have changed.
|
||||
*/
|
||||
max_bss = oldconf->num_bss;
|
||||
if (max_bss > newconf->num_bss)
|
||||
max_bss = newconf->num_bss;
|
||||
|
||||
for (i = 0; i < max_bss; i++) {
|
||||
if (os_strcmp(oldconf->bss[i].iface, newconf->bss[i].iface) !=
|
||||
0 || hostapd_mac_comp(oldconf->bss[i].bssid,
|
||||
newconf->bss[i].bssid) != 0)
|
||||
break;
|
||||
}
|
||||
same_bssid = i;
|
||||
|
||||
for (i = 0; i < oldconf->num_bss; i++) {
|
||||
oldbss = &oldconf->bss[i];
|
||||
newbss = NULL;
|
||||
for (j = 0; j < newconf->num_bss; j++) {
|
||||
if (os_strcmp(oldbss->iface, newconf->bss[j].iface) ==
|
||||
0) {
|
||||
newbss = &newconf->bss[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newbss && i < same_bssid) {
|
||||
hapd = hapd_iface->bss[j] = old_hapd[i];
|
||||
hapd->iconf = newconf;
|
||||
hapd->conf = newbss;
|
||||
hostapd_reconfig_bss(hapd, newbss, oldbss, oldconf,
|
||||
beacon_changed);
|
||||
} else {
|
||||
hapd = old_hapd[i];
|
||||
wpa_printf(MSG_DEBUG, "Removing BSS (ifname %s)",
|
||||
hapd->conf->iface);
|
||||
hostapd_free_stas(hapd);
|
||||
/* Send broadcast deauthentication for this BSS, but do
|
||||
* not clear all STAs from the driver since other BSSes
|
||||
* may have STA entries. The driver will remove all STA
|
||||
* entries for this BSS anyway when the interface is
|
||||
* being removed. */
|
||||
#if 0
|
||||
hostapd_deauth_all_stas(hapd);
|
||||
hostapd_cleanup(hapd);
|
||||
#endif
|
||||
|
||||
os_free(hapd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
prev_addr = hapd_iface->bss[0]->own_addr;
|
||||
hapd = hapd_iface->bss[0];
|
||||
for (j = 0; j < newconf->num_bss; j++) {
|
||||
if (hapd_iface->bss[j] != NULL) {
|
||||
prev_addr = hapd_iface->bss[j]->own_addr;
|
||||
continue;
|
||||
}
|
||||
|
||||
newbss = &newconf->bss[j];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Reconfiguration: adding new BSS "
|
||||
"(ifname=%s)", newbss->iface);
|
||||
|
||||
#if 0
|
||||
hapd = hapd_iface->bss[j] =
|
||||
hostapd_alloc_bss_data(hapd_iface, newconf, newbss);
|
||||
if (hapd == NULL) {
|
||||
printf("Failed to initialize new BSS\n");
|
||||
/* FIX: This one is somewhat hard to recover
|
||||
* from.. Would need to remove this BSS from
|
||||
* conf and BSS list. */
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
hapd->driver = hapd_iface->bss[0]->driver;
|
||||
hapd->iface = hapd_iface;
|
||||
hapd->iconf = newconf;
|
||||
hapd->conf = newbss;
|
||||
|
||||
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
|
||||
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
|
||||
prev_addr = hapd->own_addr;
|
||||
|
||||
#if 0
|
||||
if (hostapd_setup_bss(hapd, j == 0)) {
|
||||
printf("Failed to setup new BSS\n");
|
||||
/* FIX */
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
os_free(old_hapd);
|
||||
hostapd_config_free(oldconf);
|
||||
|
||||
cb = hapd_iface->config_reload_cb;
|
||||
hapd_iface->config_reload_cb = NULL;
|
||||
|
||||
cb(hapd_iface, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_config_reload_start - Start reconfiguration of an interface
|
||||
* @hapd_iface: Pointer to hostapd interface data
|
||||
* @cb: Function to be called back when done.
|
||||
* The status indicates:
|
||||
* 0 = success, new configuration in use;
|
||||
* -1 = failed to update configuraiton, old configuration in use;
|
||||
* -2 = failed to update configuration and failed to recover; caller
|
||||
* should cleanup and terminate hostapd
|
||||
* Returns:
|
||||
* 0 = reconfiguration started;
|
||||
* -1 = failed to update configuration, old configuration in use;
|
||||
* -2 = failed to update configuration and failed to recover; caller
|
||||
* should cleanup and terminate hostapd
|
||||
*/
|
||||
int hostapd_config_reload_start(struct hostapd_iface *hapd_iface,
|
||||
hostapd_iface_cb cb)
|
||||
{
|
||||
struct hostapd_config *newconf, *oldconf;
|
||||
struct hostapd_config_change *change;
|
||||
struct hostapd_data *hapd = NULL;
|
||||
struct hostapd_data **old_hapd, **new_hapd;
|
||||
int num_old_hapd;
|
||||
|
||||
if (hapd_iface->config_reload_cb) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Config reload already in progress.",
|
||||
hapd_iface->bss[0]->conf->iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
newconf = hostapd_config_read(hapd_iface->config_fname);
|
||||
if (newconf == NULL) {
|
||||
printf("Failed to read new configuration file - continuing "
|
||||
"with old.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_strcmp(newconf->bss[0].iface, hapd_iface->conf->bss[0].iface) !=
|
||||
0) {
|
||||
printf("Interface name changing is not allowed in "
|
||||
"configuration reloading (%s -> %s).\n",
|
||||
hapd_iface->conf->bss[0].iface, newconf->bss[0].iface);
|
||||
hostapd_config_free(newconf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_hapd = os_zalloc(newconf->num_bss *
|
||||
sizeof(struct hostapd_data *));
|
||||
if (new_hapd == NULL) {
|
||||
hostapd_config_free(newconf);
|
||||
return -1;
|
||||
}
|
||||
old_hapd = hapd_iface->bss;
|
||||
num_old_hapd = hapd_iface->num_bss;
|
||||
|
||||
hapd_iface->bss = new_hapd;
|
||||
hapd_iface->num_bss = newconf->num_bss;
|
||||
/*
|
||||
* First BSS remains the same since interface name changing was
|
||||
* prohibited above. Now, this is only used in
|
||||
* hostapd_config_reload_iface() and following loop will anyway set
|
||||
* this again.
|
||||
*/
|
||||
hapd = hapd_iface->bss[0] = old_hapd[0];
|
||||
|
||||
oldconf = hapd_iface->conf;
|
||||
hapd->iconf = hapd_iface->conf = newconf;
|
||||
hapd->conf = &newconf->bss[0];
|
||||
|
||||
change = os_zalloc(sizeof(struct hostapd_config_change));
|
||||
if (change == NULL) {
|
||||
hostapd_config_free(newconf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
change->hapd = hapd;
|
||||
change->newconf = newconf;
|
||||
change->oldconf = oldconf;
|
||||
change->beacon_changed = 0;
|
||||
change->hapd_iface = hapd_iface;
|
||||
change->new_hapd = new_hapd;
|
||||
change->old_hapd = old_hapd;
|
||||
change->num_old_hapd = num_old_hapd;
|
||||
|
||||
hapd_iface->config_reload_cb = cb;
|
||||
hapd_iface->change = change;
|
||||
if (hostapd_config_reload_iface_start(hapd_iface, config_reload2)) {
|
||||
printf("Failed to start setup of new interface config\n");
|
||||
|
||||
hapd_iface->config_reload_cb = NULL;
|
||||
os_free(change);
|
||||
hapd_iface->change = NULL;
|
||||
|
||||
/* Invalid configuration - cleanup and terminate hostapd */
|
||||
hapd_iface->bss = old_hapd;
|
||||
hapd_iface->num_bss = num_old_hapd;
|
||||
hapd_iface->conf = hapd->iconf = oldconf;
|
||||
hapd->conf = &oldconf->bss[0];
|
||||
hostapd_config_free(newconf);
|
||||
os_free(new_hapd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,580 @@
|
||||
/*
|
||||
* hostapd / Station table
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "eloop.h"
|
||||
#include "accounting.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "radius/radius.h"
|
||||
#include "wpa.h"
|
||||
#include "preauth.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "driver.h"
|
||||
#include "beacon.h"
|
||||
#include "hw_features.h"
|
||||
#include "mlme.h"
|
||||
#include "vlan_init.h"
|
||||
|
||||
static int ap_sta_in_other_bss(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u32 flags);
|
||||
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void *ctx),
|
||||
void *ctx)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (cb(hapd, sta, ctx))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||
{
|
||||
struct sta_info *s;
|
||||
|
||||
s = hapd->sta_hash[STA_HASH(sta)];
|
||||
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
|
||||
s = s->hnext;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
struct sta_info *tmp;
|
||||
|
||||
if (hapd->sta_list == sta) {
|
||||
hapd->sta_list = sta->next;
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = hapd->sta_list;
|
||||
while (tmp != NULL && tmp->next != sta)
|
||||
tmp = tmp->next;
|
||||
if (tmp == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
|
||||
"list.", MAC2STR(sta->addr));
|
||||
} else
|
||||
tmp->next = sta->next;
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
|
||||
hapd->sta_hash[STA_HASH(sta->addr)] = sta;
|
||||
}
|
||||
|
||||
|
||||
static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
struct sta_info *s;
|
||||
|
||||
s = hapd->sta_hash[STA_HASH(sta->addr)];
|
||||
if (s == NULL) return;
|
||||
if (os_memcmp(s->addr, sta->addr, 6) == 0) {
|
||||
hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
|
||||
return;
|
||||
}
|
||||
|
||||
while (s->hnext != NULL &&
|
||||
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
|
||||
s = s->hnext;
|
||||
if (s->hnext != NULL)
|
||||
s->hnext = s->hnext->hnext;
|
||||
else
|
||||
wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
|
||||
" from hash table", MAC2STR(sta->addr));
|
||||
}
|
||||
|
||||
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
int set_beacon = 0;
|
||||
|
||||
accounting_sta_stop(hapd, sta);
|
||||
|
||||
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_sta_remove(hapd, sta->addr);
|
||||
|
||||
ap_sta_hash_del(hapd, sta);
|
||||
ap_sta_list_del(hapd, sta);
|
||||
|
||||
if (sta->aid > 0)
|
||||
hapd->sta_aid[sta->aid - 1] = NULL;
|
||||
|
||||
hapd->num_sta--;
|
||||
if (sta->nonerp_set) {
|
||||
sta->nonerp_set = 0;
|
||||
hapd->iface->num_sta_non_erp--;
|
||||
if (hapd->iface->num_sta_non_erp == 0)
|
||||
set_beacon++;
|
||||
}
|
||||
|
||||
if (sta->no_short_slot_time_set) {
|
||||
sta->no_short_slot_time_set = 0;
|
||||
hapd->iface->num_sta_no_short_slot_time--;
|
||||
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||
&& hapd->iface->num_sta_no_short_slot_time == 0)
|
||||
set_beacon++;
|
||||
}
|
||||
|
||||
if (sta->no_short_preamble_set) {
|
||||
sta->no_short_preamble_set = 0;
|
||||
hapd->iface->num_sta_no_short_preamble--;
|
||||
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||
&& hapd->iface->num_sta_no_short_preamble == 0)
|
||||
set_beacon++;
|
||||
}
|
||||
|
||||
if (set_beacon)
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||
|
||||
ieee802_1x_free_station(sta);
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
rsn_preauth_free_station(hapd, sta);
|
||||
radius_client_flush_auth(hapd->radius, sta->addr);
|
||||
|
||||
os_free(sta->last_assoc_req);
|
||||
os_free(sta->challenge);
|
||||
os_free(sta);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_free_stas(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sta_info *sta, *prev;
|
||||
|
||||
sta = hapd->sta_list;
|
||||
|
||||
while (sta) {
|
||||
prev = sta;
|
||||
if (sta->flags & WLAN_STA_AUTH) {
|
||||
mlme_deauthenticate_indication(
|
||||
hapd, sta, WLAN_REASON_UNSPECIFIED);
|
||||
}
|
||||
sta = sta->next;
|
||||
wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
|
||||
MAC2STR(prev->addr));
|
||||
ap_free_sta(hapd, prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
unsigned long next_time = 0;
|
||||
|
||||
if (sta->timeout_next == STA_REMOVE) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||
"local deauth request");
|
||||
ap_free_sta(hapd, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
(sta->timeout_next == STA_NULLFUNC ||
|
||||
sta->timeout_next == STA_DISASSOC)) {
|
||||
int inactive_sec;
|
||||
wpa_printf(MSG_DEBUG, "Checking STA " MACSTR " inactivity:",
|
||||
MAC2STR(sta->addr));
|
||||
inactive_sec = hostapd_get_inact_sec(hapd, sta->addr);
|
||||
if (inactive_sec == -1) {
|
||||
wpa_printf(MSG_DEBUG, "Could not get station info "
|
||||
"from kernel driver for " MACSTR ".",
|
||||
MAC2STR(sta->addr));
|
||||
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
|
||||
sta->flags & WLAN_STA_ASSOC) {
|
||||
/* station activity detected; reset timeout state */
|
||||
wpa_printf(MSG_DEBUG, " Station has been active");
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
next_time = hapd->conf->ap_max_inactivity -
|
||||
inactive_sec;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
sta->timeout_next == STA_DISASSOC &&
|
||||
!(sta->flags & WLAN_STA_PENDING_POLL)) {
|
||||
wpa_printf(MSG_DEBUG, " Station has ACKed data poll");
|
||||
/* data nullfunc frame poll did not produce TX errors; assume
|
||||
* station ACKed it */
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
next_time = hapd->conf->ap_max_inactivity;
|
||||
}
|
||||
|
||||
if (next_time) {
|
||||
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
|
||||
sta);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sta->timeout_next == STA_NULLFUNC &&
|
||||
(sta->flags & WLAN_STA_ASSOC)) {
|
||||
/* send data frame to poll STA and check whether this frame
|
||||
* is ACKed */
|
||||
struct ieee80211_hdr hdr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, " Polling STA with data frame");
|
||||
sta->flags |= WLAN_STA_PENDING_POLL;
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
/* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
|
||||
* it is apparently not retried so TX Exc events are not
|
||||
* received for it */
|
||||
os_memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.frame_control =
|
||||
IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
|
||||
hdr.frame_control |= host_to_le16(BIT(1));
|
||||
hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
|
||||
os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
|
||||
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
|
||||
|
||||
if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0)
|
||||
perror("ap_handle_timer: send");
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
} else if (sta->timeout_next != STA_REMOVE) {
|
||||
int deauth = sta->timeout_next == STA_DEAUTH;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
|
||||
deauth ? "deauthentication" : "disassociation",
|
||||
MAC2STR(sta->addr));
|
||||
|
||||
if (deauth) {
|
||||
hostapd_sta_deauth(hapd, sta->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
} else {
|
||||
hostapd_sta_disassoc(
|
||||
hapd, sta->addr,
|
||||
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
|
||||
}
|
||||
}
|
||||
|
||||
switch (sta->timeout_next) {
|
||||
case STA_NULLFUNC:
|
||||
sta->timeout_next = STA_DISASSOC;
|
||||
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
|
||||
hapd, sta);
|
||||
break;
|
||||
case STA_DISASSOC:
|
||||
sta->flags &= ~WLAN_STA_ASSOC;
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
if (!sta->acct_terminate_cause)
|
||||
sta->acct_terminate_cause =
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(sta);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disassociated due to "
|
||||
"inactivity");
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
|
||||
hapd, sta);
|
||||
mlme_disassociate_indication(
|
||||
hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
|
||||
break;
|
||||
case STA_DEAUTH:
|
||||
case STA_REMOVE:
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||
"inactivity");
|
||||
if (!sta->acct_terminate_cause)
|
||||
sta->acct_terminate_cause =
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
||||
mlme_deauthenticate_indication(
|
||||
hapd, sta,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
ap_free_sta(hapd, sta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
u8 addr[ETH_ALEN];
|
||||
|
||||
if (!(sta->flags & WLAN_STA_AUTH))
|
||||
return;
|
||||
|
||||
mlme_deauthenticate_indication(hapd, sta,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||
"session timeout");
|
||||
sta->acct_terminate_cause =
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
|
||||
os_memcpy(addr, sta->addr, ETH_ALEN);
|
||||
ap_free_sta(hapd, sta);
|
||||
hostapd_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u32 session_timeout)
|
||||
{
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
|
||||
"seconds", session_timeout);
|
||||
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||
eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
|
||||
hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
return sta;
|
||||
|
||||
wpa_printf(MSG_DEBUG, " New STA");
|
||||
if (hapd->num_sta >= hapd->conf->max_num_sta) {
|
||||
/* FIX: might try to remove some old STAs first? */
|
||||
wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
|
||||
hapd->num_sta, hapd->conf->max_num_sta);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sta = os_zalloc(sizeof(struct sta_info));
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_ERROR, "malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
|
||||
|
||||
/* initialize STA info data */
|
||||
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
os_memcpy(sta->addr, addr, ETH_ALEN);
|
||||
sta->next = hapd->sta_list;
|
||||
hapd->sta_list = sta;
|
||||
hapd->num_sta++;
|
||||
ap_sta_hash_add(hapd, sta);
|
||||
sta->ssid = &hapd->conf->ssid;
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
|
||||
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
|
||||
MAC2STR(sta->addr));
|
||||
if (hostapd_sta_remove(hapd, sta->addr) &&
|
||||
sta->flags & WLAN_STA_ASSOC) {
|
||||
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
|
||||
" from kernel driver.", MAC2STR(sta->addr));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ap_sta_in_other_bss(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u32 flags)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
struct sta_info *sta2;
|
||||
/* bss should always be set during operation, but it may be
|
||||
* NULL during reconfiguration. Assume the STA is not
|
||||
* associated to another BSS in that case to avoid NULL pointer
|
||||
* dereferences. */
|
||||
if (bss == hapd || bss == NULL)
|
||||
continue;
|
||||
sta2 = ap_get_sta(bss, sta->addr);
|
||||
if (sta2 && ((sta2->flags & flags) == flags))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->flags &= ~WLAN_STA_ASSOC;
|
||||
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
|
||||
ap_sta_remove(hapd, sta);
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(sta);
|
||||
|
||||
mlme_disassociate_indication(hapd, sta, reason);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
|
||||
ap_sta_remove(hapd, sta);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(sta);
|
||||
|
||||
mlme_deauthenticate_indication(hapd, sta, reason);
|
||||
}
|
||||
|
||||
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int old_vlanid)
|
||||
{
|
||||
const char *iface;
|
||||
struct hostapd_vlan *vlan = NULL;
|
||||
|
||||
/*
|
||||
* Do not proceed furthur if the vlan id remains same. We do not want
|
||||
* duplicate dynamic vlan entries.
|
||||
*/
|
||||
if (sta->vlan_id == old_vlanid)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* During 1x reauth, if the vlan id changes, then remove the old id and
|
||||
* proceed furthur to add the new one.
|
||||
*/
|
||||
if (old_vlanid > 0)
|
||||
vlan_remove_dynamic(hapd, old_vlanid);
|
||||
|
||||
iface = hapd->conf->iface;
|
||||
if (sta->ssid->vlan[0])
|
||||
iface = sta->ssid->vlan;
|
||||
|
||||
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
sta->vlan_id = 0;
|
||||
else if (sta->vlan_id > 0) {
|
||||
vlan = hapd->conf->vlan;
|
||||
while (vlan) {
|
||||
if (vlan->vlan_id == sta->vlan_id ||
|
||||
vlan->vlan_id == VLAN_ID_WILDCARD) {
|
||||
iface = vlan->ifname;
|
||||
break;
|
||||
}
|
||||
vlan = vlan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (sta->vlan_id > 0 && vlan == NULL) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
|
||||
"binding station to (vlan_id=%d)",
|
||||
sta->vlan_id);
|
||||
return -1;
|
||||
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
|
||||
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
|
||||
if (vlan == NULL) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not add "
|
||||
"dynamic VLAN interface for vlan_id=%d",
|
||||
sta->vlan_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iface = vlan->ifname;
|
||||
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||
"configure encryption for dynamic VLAN "
|
||||
"interface for vlan_id=%d",
|
||||
sta->vlan_id);
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
|
||||
"interface '%s'", iface);
|
||||
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
|
||||
if (sta->vlan_id > 0) {
|
||||
vlan->dynamic_vlan++;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "updated existing "
|
||||
"dynamic VLAN interface '%s'", iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update encryption configuration for statically generated
|
||||
* VLAN interface. This is only used for static WEP
|
||||
* configuration for the case where hostapd did not yet know
|
||||
* which keys are to be used when the interface was added.
|
||||
*/
|
||||
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||
"configure encryption for VLAN "
|
||||
"interface for vlan_id=%d",
|
||||
sta->vlan_id);
|
||||
}
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
|
||||
"'%s'", iface);
|
||||
|
||||
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
|
||||
|
||||
return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* hostapd / Station table
|
||||
* Copyright (c) 2002-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.
|
||||
*/
|
||||
|
||||
#ifndef STA_INFO_H
|
||||
#define STA_INFO_H
|
||||
|
||||
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void *ctx),
|
||||
void *ctx);
|
||||
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
||||
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void hostapd_free_stas(struct hostapd_data *hapd);
|
||||
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u32 session_timeout);
|
||||
void ap_sta_no_session_timeout(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
|
||||
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason);
|
||||
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason);
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int old_vlanid);
|
||||
|
||||
#endif /* STA_INFO_H */
|
@ -0,0 +1,832 @@
|
||||
/*
|
||||
* hostapd / VLAN initialization
|
||||
* Copyright 2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, 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 "hostapd.h"
|
||||
#include "driver.h"
|
||||
#include "vlan_init.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if_vlan.h>
|
||||
typedef __uint64_t __u64;
|
||||
typedef __uint32_t __u32;
|
||||
typedef __int32_t __s32;
|
||||
typedef __uint16_t __u16;
|
||||
typedef __int16_t __s16;
|
||||
typedef __uint8_t __u8;
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#include "priv_netlink.h"
|
||||
#include "eloop.h"
|
||||
|
||||
|
||||
struct full_dynamic_vlan {
|
||||
int s; /* socket on which to listen for new/removed interfaces. */
|
||||
};
|
||||
|
||||
|
||||
static int ifconfig_helper(const char *if_name, int up)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
|
||||
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
|
||||
perror("ioctl[SIOCGIFFLAGS]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (up)
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
|
||||
perror("ioctl[SIOCSIFFLAGS]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ifconfig_up(const char *if_name)
|
||||
{
|
||||
return ifconfig_helper(if_name, 1);
|
||||
}
|
||||
|
||||
|
||||
static int ifconfig_down(const char *if_name)
|
||||
{
|
||||
return ifconfig_helper(if_name, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These are only available in recent linux headers (without the leading
|
||||
* underscore).
|
||||
*/
|
||||
#define _GET_VLAN_REALDEV_NAME_CMD 8
|
||||
#define _GET_VLAN_VID_CMD 9
|
||||
|
||||
/* This value should be 256 ONLY. If it is something else, then hostapd
|
||||
* might crash!, as this value has been hard-coded in 2.4.x kernel
|
||||
* bridging code.
|
||||
*/
|
||||
#define MAX_BR_PORTS 256
|
||||
|
||||
static int br_delif(const char *br_name, const char *if_name)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
unsigned long args[2];
|
||||
int if_index;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
printf("Failure determining interface index for '%s'\n",
|
||||
if_name);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args[0] = BRCTL_DEL_IF;
|
||||
args[1] = if_index;
|
||||
|
||||
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = (__caddr_t) args;
|
||||
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
|
||||
/* No error if interface already removed. */
|
||||
perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add interface 'if_name' to the bridge 'br_name'
|
||||
|
||||
returns -1 on error
|
||||
returns 1 if the interface is already part of the bridge
|
||||
returns 0 otherwise
|
||||
*/
|
||||
static int br_addif(const char *br_name, const char *if_name)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
unsigned long args[2];
|
||||
int if_index;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
printf("Failure determining interface index for '%s'\n",
|
||||
if_name);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args[0] = BRCTL_ADD_IF;
|
||||
args[1] = if_index;
|
||||
|
||||
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = (__caddr_t) args;
|
||||
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||
if (errno == EBUSY) {
|
||||
/* The interface is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int br_delbr(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
unsigned long arg[2];
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_DEL_BRIDGE;
|
||||
arg[1] = (unsigned long) br_name;
|
||||
|
||||
if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
|
||||
/* No error if bridge already removed. */
|
||||
perror("ioctl[BRCTL_DEL_BRIDGE]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add a bridge with the name 'br_name'.
|
||||
|
||||
returns -1 on error
|
||||
returns 1 if the bridge already exists
|
||||
returns 0 otherwise
|
||||
*/
|
||||
static int br_addbr(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
unsigned long arg[2];
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_ADD_BRIDGE;
|
||||
arg[1] = (unsigned long) br_name;
|
||||
|
||||
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
/* The bridge is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
} else {
|
||||
perror("ioctl[BRCTL_ADD_BRIDGE]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int br_getnumports(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
int port_cnt = 0;
|
||||
unsigned long arg[4];
|
||||
int ifindices[MAX_BR_PORTS];
|
||||
struct ifreq ifr;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_GET_PORT_LIST;
|
||||
arg[1] = (unsigned long) ifindices;
|
||||
arg[2] = MAX_BR_PORTS;
|
||||
arg[3] = 0;
|
||||
|
||||
os_memset(ifindices, 0, sizeof(ifindices));
|
||||
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = (__caddr_t) arg;
|
||||
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||
perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < MAX_BR_PORTS; i++) {
|
||||
if (ifindices[i] > 0) {
|
||||
port_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return port_cnt;
|
||||
}
|
||||
|
||||
|
||||
static int vlan_rem(const char *if_name)
|
||||
{
|
||||
int fd;
|
||||
struct vlan_ioctl_args if_request;
|
||||
|
||||
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||
fprintf(stderr, "Interface name to long.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
|
||||
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
|
||||
if_request.cmd = DEL_VLAN_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||
perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add a vlan interface with VLAN ID 'vid' and tagged interface
|
||||
'if_name'.
|
||||
|
||||
returns -1 on error
|
||||
returns 1 if the interface already exists
|
||||
returns 0 otherwise
|
||||
*/
|
||||
static int vlan_add(const char *if_name, int vid)
|
||||
{
|
||||
int fd;
|
||||
struct vlan_ioctl_args if_request;
|
||||
|
||||
ifconfig_up(if_name);
|
||||
|
||||
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||
fprintf(stderr, "Interface name to long.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
|
||||
/* Determine if a suitable vlan device already exists. */
|
||||
|
||||
os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
|
||||
vid);
|
||||
|
||||
if_request.cmd = _GET_VLAN_VID_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
|
||||
|
||||
if (if_request.u.VID == vid) {
|
||||
if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
|
||||
os_strncmp(if_request.u.device2, if_name,
|
||||
sizeof(if_request.u.device2)) == 0) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A suitable vlan device does not already exist, add one. */
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
|
||||
if_request.u.VID = vid;
|
||||
if_request.cmd = ADD_VLAN_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||
perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vlan_set_name_type(unsigned int name_type)
|
||||
{
|
||||
int fd;
|
||||
struct vlan_ioctl_args if_request;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket[AF_INET,SOCK_STREAM]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
|
||||
if_request.u.name_type = name_type;
|
||||
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||
perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
|
||||
{
|
||||
char vlan_ifname[IFNAMSIZ];
|
||||
char br_name[IFNAMSIZ];
|
||||
struct hostapd_vlan *vlan = hapd->conf->vlan;
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
|
||||
while (vlan) {
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||
|
||||
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
|
||||
vlan->vlan_id);
|
||||
|
||||
if (!br_addbr(br_name))
|
||||
vlan->clean |= DVLAN_CLEAN_BR;
|
||||
|
||||
ifconfig_up(br_name);
|
||||
|
||||
if (tagged_interface) {
|
||||
|
||||
if (!vlan_add(tagged_interface, vlan->vlan_id))
|
||||
vlan->clean |= DVLAN_CLEAN_VLAN;
|
||||
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
|
||||
"vlan%d", vlan->vlan_id);
|
||||
|
||||
if (!br_addif(br_name, vlan_ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
|
||||
|
||||
ifconfig_up(vlan_ifname);
|
||||
}
|
||||
|
||||
if (!br_addif(br_name, ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
|
||||
|
||||
ifconfig_up(ifname);
|
||||
|
||||
break;
|
||||
}
|
||||
vlan = vlan->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
|
||||
{
|
||||
char vlan_ifname[IFNAMSIZ];
|
||||
char br_name[IFNAMSIZ];
|
||||
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
int numports;
|
||||
|
||||
first = prev = vlan;
|
||||
|
||||
while (vlan) {
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
|
||||
vlan->vlan_id);
|
||||
|
||||
if (tagged_interface) {
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
|
||||
"vlan%d", vlan->vlan_id);
|
||||
|
||||
numports = br_getnumports(br_name);
|
||||
if (numports == 1) {
|
||||
br_delif(br_name, vlan_ifname);
|
||||
|
||||
vlan_rem(vlan_ifname);
|
||||
|
||||
ifconfig_down(br_name);
|
||||
br_delbr(br_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (vlan == first) {
|
||||
hapd->conf->vlan = vlan->next;
|
||||
} else {
|
||||
prev->next = vlan->next;
|
||||
}
|
||||
os_free(vlan);
|
||||
|
||||
break;
|
||||
}
|
||||
prev = vlan;
|
||||
vlan = vlan->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
|
||||
struct hostapd_data *hapd)
|
||||
{
|
||||
struct ifinfomsg *ifi;
|
||||
int attrlen, nlmsg_len, rta_len;
|
||||
struct rtattr *attr;
|
||||
|
||||
if (len < sizeof(*ifi))
|
||||
return;
|
||||
|
||||
ifi = NLMSG_DATA(h);
|
||||
|
||||
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
|
||||
|
||||
attrlen = h->nlmsg_len - nlmsg_len;
|
||||
if (attrlen < 0)
|
||||
return;
|
||||
|
||||
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
|
||||
|
||||
rta_len = RTA_ALIGN(sizeof(struct rtattr));
|
||||
while (RTA_OK(attr, attrlen)) {
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
|
||||
if (attr->rta_type == IFLA_IFNAME) {
|
||||
int n = attr->rta_len - rta_len;
|
||||
if (n < 0)
|
||||
break;
|
||||
|
||||
os_memset(ifname, 0, sizeof(ifname));
|
||||
|
||||
if ((size_t) n > sizeof(ifname))
|
||||
n = sizeof(ifname);
|
||||
os_memcpy(ifname, ((char *) attr) + rta_len, n);
|
||||
|
||||
if (del)
|
||||
vlan_dellink(ifname, hapd);
|
||||
else
|
||||
vlan_newlink(ifname, hapd);
|
||||
}
|
||||
|
||||
attr = RTA_NEXT(attr, attrlen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
char buf[8192];
|
||||
int left;
|
||||
struct sockaddr_nl from;
|
||||
socklen_t fromlen;
|
||||
struct nlmsghdr *h;
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
|
||||
(struct sockaddr *) &from, &fromlen);
|
||||
if (left < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
perror("recvfrom(netlink)");
|
||||
return;
|
||||
}
|
||||
|
||||
h = (struct nlmsghdr *) buf;
|
||||
while (left >= (int) sizeof(*h)) {
|
||||
int len, plen;
|
||||
|
||||
len = h->nlmsg_len;
|
||||
plen = len - sizeof(*h);
|
||||
if (len > left || plen < 0) {
|
||||
printf("Malformed netlink message: "
|
||||
"len=%d left=%d plen=%d", len, left, plen);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (h->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
vlan_read_ifnames(h, plen, 0, hapd);
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
vlan_read_ifnames(h, plen, 1, hapd);
|
||||
break;
|
||||
}
|
||||
|
||||
len = NLMSG_ALIGN(len);
|
||||
left -= len;
|
||||
h = (struct nlmsghdr *) ((char *) h + len);
|
||||
}
|
||||
|
||||
if (left > 0) {
|
||||
printf("%d extra bytes in the end of netlink message",
|
||||
left);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct full_dynamic_vlan *
|
||||
full_dynamic_vlan_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sockaddr_nl local;
|
||||
struct full_dynamic_vlan *priv;
|
||||
|
||||
priv = os_zalloc(sizeof(*priv));
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
|
||||
|
||||
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (priv->s < 0) {
|
||||
perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
|
||||
os_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_groups = RTMGRP_LINK;
|
||||
if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("bind(netlink)");
|
||||
close(priv->s);
|
||||
os_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
|
||||
{
|
||||
close(priv->s);
|
||||
os_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
|
||||
static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
|
||||
{
|
||||
if (priv == NULL)
|
||||
return;
|
||||
eloop_unregister_read_sock(priv->s);
|
||||
close(priv->s);
|
||||
os_free(priv);
|
||||
}
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
|
||||
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
struct hostapd_ssid *mssid, const char *dyn_vlan)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dyn_vlan == NULL)
|
||||
return 0;
|
||||
|
||||
/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
|
||||
* functions for setting up dynamic broadcast keys. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (mssid->wep.key[i] &&
|
||||
hostapd_set_encryption(dyn_vlan, hapd, "WEP", NULL,
|
||||
i, mssid->wep.key[i],
|
||||
mssid->wep.len[i],
|
||||
i == mssid->wep.idx)) {
|
||||
printf("VLAN: Could not set WEP encryption for "
|
||||
"dynamic VLAN.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vlan_dynamic_add(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan)
|
||||
{
|
||||
while (vlan) {
|
||||
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
|
||||
hostapd_if_add(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL))
|
||||
{
|
||||
if (errno != EEXIST) {
|
||||
printf("Could not add VLAN iface: %s: %s\n",
|
||||
vlan->ifname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
vlan = vlan->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void vlan_dynamic_remove(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan)
|
||||
{
|
||||
struct hostapd_vlan *next;
|
||||
|
||||
while (vlan) {
|
||||
next = vlan->next;
|
||||
|
||||
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
|
||||
hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
|
||||
NULL)) {
|
||||
printf("Could not remove VLAN iface: %s: %s\n",
|
||||
vlan->ifname, strerror(errno));
|
||||
}
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
if (vlan->clean)
|
||||
vlan_dellink(vlan->ifname, hapd);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
vlan = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int vlan_init(struct hostapd_data *hapd)
|
||||
{
|
||||
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vlan_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
vlan_dynamic_remove(hapd, hapd->conf->vlan);
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
}
|
||||
|
||||
|
||||
int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||
struct hostapd_bss_config *oldbss)
|
||||
{
|
||||
vlan_dynamic_remove(hapd, oldbss->vlan);
|
||||
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan,
|
||||
int vlan_id)
|
||||
{
|
||||
struct hostapd_vlan *n;
|
||||
char *ifname, *pos;
|
||||
|
||||
if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
|
||||
vlan->vlan_id != VLAN_ID_WILDCARD)
|
||||
return NULL;
|
||||
|
||||
ifname = os_strdup(vlan->ifname);
|
||||
if (ifname == NULL)
|
||||
return NULL;
|
||||
pos = os_strchr(ifname, '#');
|
||||
if (pos == NULL) {
|
||||
os_free(ifname);
|
||||
return NULL;
|
||||
}
|
||||
*pos++ = '\0';
|
||||
|
||||
n = os_zalloc(sizeof(*n));
|
||||
if (n == NULL) {
|
||||
os_free(ifname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n->vlan_id = vlan_id;
|
||||
n->dynamic_vlan = 1;
|
||||
|
||||
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
|
||||
pos);
|
||||
os_free(ifname);
|
||||
|
||||
if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
|
||||
os_free(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n->next = hapd->conf->vlan;
|
||||
hapd->conf->vlan = n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
||||
{
|
||||
struct hostapd_vlan *vlan;
|
||||
|
||||
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
|
||||
return 1;
|
||||
|
||||
vlan = hapd->conf->vlan;
|
||||
while (vlan) {
|
||||
if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
|
||||
vlan->dynamic_vlan--;
|
||||
break;
|
||||
}
|
||||
vlan = vlan->next;
|
||||
}
|
||||
|
||||
if (vlan == NULL)
|
||||
return 1;
|
||||
|
||||
if (vlan->dynamic_vlan == 0)
|
||||
hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* hostapd / VLAN initialization
|
||||
* Copyright 2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005, Devicescape Software, 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.
|
||||
*/
|
||||
|
||||
#ifndef VLAN_INIT_H
|
||||
#define VLAN_INIT_H
|
||||
|
||||
int vlan_init(struct hostapd_data *hapd);
|
||||
void vlan_deinit(struct hostapd_data *hapd);
|
||||
int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||
struct hostapd_bss_config *oldbss);
|
||||
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan,
|
||||
int vlan_id);
|
||||
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
|
||||
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
struct hostapd_ssid *mssid,
|
||||
const char *dyn_vlan);
|
||||
|
||||
#endif /* VLAN_INIT_H */
|
@ -0,0 +1,40 @@
|
||||
##### hostapd configuration file ##############################################
|
||||
# Empty lines and lines starting with # are ignored
|
||||
|
||||
# Example configuration file for wired authenticator. See hostapd.conf for
|
||||
# more details.
|
||||
|
||||
interface=eth0
|
||||
driver=wired
|
||||
logger_stdout=-1
|
||||
logger_stdout_level=1
|
||||
debug=2
|
||||
dump_file=/tmp/hostapd.dump
|
||||
|
||||
ieee8021x=1
|
||||
eap_reauth_period=3600
|
||||
|
||||
use_pae_group_addr=1
|
||||
|
||||
|
||||
##### RADIUS configuration ####################################################
|
||||
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
|
||||
# authentication with external ACL for MAC addresses, and accounting
|
||||
|
||||
# The own IP address of the access point (used as NAS-IP-Address)
|
||||
own_ip_addr=127.0.0.1
|
||||
|
||||
# Optional NAS-Identifier string for RADIUS messages. When used, this should be
|
||||
# a unique to the NAS within the scope of the RADIUS server. For example, a
|
||||
# fully qualified domain name can be used here.
|
||||
nas_identifier=ap.example.com
|
||||
|
||||
# RADIUS authentication server
|
||||
auth_server_addr=127.0.0.1
|
||||
auth_server_port=1812
|
||||
auth_server_shared_secret=radius
|
||||
|
||||
# RADIUS accounting server
|
||||
acct_server_addr=127.0.0.1
|
||||
acct_server_port=1813
|
||||
acct_server_shared_secret=radius
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue