summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/hostapd
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2009-03-02 02:23:47 +0000
committersam <sam@FreeBSD.org>2009-03-02 02:23:47 +0000
commit2af41b09fa9d6ff3f4c736a224f545663be143d2 (patch)
treedafc9df301d15cbf876d2639326ce6bf658e6dea /contrib/wpa/hostapd
parent5d319a10b1559b57e7042e8c644949049d7c0c56 (diff)
parentced3a3de988600636bda6479d27de8823307f171 (diff)
downloadFreeBSD-src-2af41b09fa9d6ff3f4c736a224f545663be143d2.zip
FreeBSD-src-2af41b09fa9d6ff3f4c736a224f545663be143d2.tar.gz
connect vendor wpa area to contrib
Diffstat (limited to 'contrib/wpa/hostapd')
-rw-r--r--contrib/wpa/hostapd/.gitignore7
-rw-r--r--contrib/wpa/hostapd/ChangeLog565
-rw-r--r--contrib/wpa/hostapd/README390
-rw-r--r--contrib/wpa/hostapd/README-WPS232
-rw-r--r--contrib/wpa/hostapd/accounting.c510
-rw-r--r--contrib/wpa/hostapd/accounting.h26
-rw-r--r--contrib/wpa/hostapd/ap.h139
-rw-r--r--contrib/wpa/hostapd/ap_list.c501
-rw-r--r--contrib/wpa/hostapd/ap_list.h71
-rw-r--r--contrib/wpa/hostapd/beacon.c467
-rw-r--r--contrib/wpa/hostapd/beacon.h24
-rw-r--r--contrib/wpa/hostapd/config.c2617
-rw-r--r--contrib/wpa/hostapd/config.h415
-rw-r--r--contrib/wpa/hostapd/ctrl_iface.c560
-rw-r--r--contrib/wpa/hostapd/ctrl_iface.h21
-rw-r--r--contrib/wpa/hostapd/defconfig144
-rw-r--r--contrib/wpa/hostapd/doc/.gitignore4
-rw-r--r--contrib/wpa/hostapd/doc/code_structure.doxygen5
-rw-r--r--contrib/wpa/hostapd/doc/ctrl_iface.doxygen66
-rw-r--r--contrib/wpa/hostapd/doc/doxygen.fast238
-rw-r--r--contrib/wpa/hostapd/doc/doxygen.full238
-rw-r--r--contrib/wpa/hostapd/doc/driver_wrapper.doxygen20
-rw-r--r--contrib/wpa/hostapd/doc/eap.doxygen56
-rw-r--r--contrib/wpa/hostapd/doc/hostapd.fig264
-rwxr-xr-xcontrib/wpa/hostapd/doc/kerneldoc2doxygen.pl129
-rw-r--r--contrib/wpa/hostapd/doc/mainpage.doxygen52
-rw-r--r--contrib/wpa/hostapd/doc/porting.doxygen5
-rw-r--r--contrib/wpa/hostapd/driver.h798
-rw-r--r--contrib/wpa/hostapd/drivers.c71
-rw-r--r--contrib/wpa/hostapd/eap_testing.txt77
-rw-r--r--contrib/wpa/hostapd/eapol_sm.c1342
-rw-r--r--contrib/wpa/hostapd/eapol_sm.h260
-rw-r--r--contrib/wpa/hostapd/hostap_common.h216
-rw-r--r--contrib/wpa/hostapd/hostapd.859
-rw-r--r--contrib/wpa/hostapd/hostapd.accept6
-rw-r--r--contrib/wpa/hostapd/hostapd.c2027
-rw-r--r--contrib/wpa/hostapd/hostapd.conf1024
-rw-r--r--contrib/wpa/hostapd/hostapd.deny5
-rw-r--r--contrib/wpa/hostapd/hostapd.eap_user91
-rw-r--r--contrib/wpa/hostapd/hostapd.h238
-rw-r--r--contrib/wpa/hostapd/hostapd.radius_clients4
-rw-r--r--contrib/wpa/hostapd/hostapd.sim_db9
-rw-r--r--contrib/wpa/hostapd/hostapd.vlan9
-rw-r--r--contrib/wpa/hostapd/hostapd.wpa_psk9
-rw-r--r--contrib/wpa/hostapd/hostapd_cli.183
-rw-r--r--contrib/wpa/hostapd/hostapd_cli.c673
-rw-r--r--contrib/wpa/hostapd/hw_features.c487
-rw-r--r--contrib/wpa/hostapd/hw_features.h62
-rw-r--r--contrib/wpa/hostapd/iapp.c553
-rw-r--r--contrib/wpa/hostapd/iapp.h54
-rw-r--r--contrib/wpa/hostapd/ieee802_11.c1768
-rw-r--r--contrib/wpa/hostapd/ieee802_11.h56
-rw-r--r--contrib/wpa/hostapd/ieee802_11_auth.c523
-rw-r--r--contrib/wpa/hostapd/ieee802_11_auth.h33
-rw-r--r--contrib/wpa/hostapd/ieee802_1x.c2042
-rw-r--r--contrib/wpa/hostapd/ieee802_1x.h90
-rw-r--r--contrib/wpa/hostapd/logwatch/README9
-rwxr-xr-xcontrib/wpa/hostapd/logwatch/hostapd65
-rw-r--r--contrib/wpa/hostapd/logwatch/hostapd.conf10
-rw-r--r--contrib/wpa/hostapd/mlme.c180
-rw-r--r--contrib/wpa/hostapd/mlme.h40
-rw-r--r--contrib/wpa/hostapd/nt_password_hash.c52
-rw-r--r--contrib/wpa/hostapd/peerkey.c402
-rw-r--r--contrib/wpa/hostapd/pmksa_cache.c455
-rw-r--r--contrib/wpa/hostapd/pmksa_cache.h62
-rw-r--r--contrib/wpa/hostapd/preauth.c275
-rw-r--r--contrib/wpa/hostapd/preauth.h58
-rw-r--r--contrib/wpa/hostapd/sta_info.c711
-rw-r--r--contrib/wpa/hostapd/sta_info.h43
-rw-r--r--contrib/wpa/hostapd/vlan_init.c826
-rw-r--r--contrib/wpa/hostapd/vlan_init.h31
-rw-r--r--contrib/wpa/hostapd/wired.conf40
-rw-r--r--contrib/wpa/hostapd/wme.c262
-rw-r--r--contrib/wpa/hostapd/wme.h129
-rw-r--r--contrib/wpa/hostapd/wpa.c2447
-rw-r--r--contrib/wpa/hostapd/wpa.h284
-rw-r--r--contrib/wpa/hostapd/wpa_auth_i.h221
-rw-r--r--contrib/wpa/hostapd/wpa_auth_ie.c864
-rw-r--r--contrib/wpa/hostapd/wpa_auth_ie.h54
-rw-r--r--contrib/wpa/hostapd/wpa_ft.c1499
-rw-r--r--contrib/wpa/hostapd/wps_hostapd.c998
-rw-r--r--contrib/wpa/hostapd/wps_hostapd.h48
82 files changed, 30500 insertions, 0 deletions
diff --git a/contrib/wpa/hostapd/.gitignore b/contrib/wpa/hostapd/.gitignore
new file mode 100644
index 0000000..6dd2c2f
--- /dev/null
+++ b/contrib/wpa/hostapd/.gitignore
@@ -0,0 +1,7 @@
+*.d
+.config
+driver_conf.c
+hostapd
+hostapd_cli
+hlr_auc_gw
+nt_password_hash
diff --git a/contrib/wpa/hostapd/ChangeLog b/contrib/wpa/hostapd/ChangeLog
new file mode 100644
index 0000000..46f0852
--- /dev/null
+++ b/contrib/wpa/hostapd/ChangeLog
@@ -0,0 +1,565 @@
+ChangeLog for hostapd
+
+2009-02-15 - v0.6.8
+ * increased hostapd_cli ping interval to 5 seconds and made this
+ configurable with a new command line options (-G<seconds>)
+ * driver_nl80211: use Linux socket filter to improve performance
+ * added support for external Registrars with WPS (UPnP transport)
+
+2009-01-06 - v0.6.7
+ * added support for Wi-Fi Protected Setup (WPS)
+ (hostapd can now be configured to act as an integrated WPS Registrar
+ and provision credentials for WPS Enrollees using PIN and PBC
+ methods; external wireless Registrar can configure the AP, but
+ external WLAN Manager Registrars are not supported); WPS support can
+ be enabled by adding CONFIG_WPS=y into .config and setting the
+ runtime configuration variables in hostapd.conf (see WPS section in
+ the example configuration file); new hostapd_cli commands wps_pin and
+ wps_pbc are used to configure WPS negotiation; see README-WPS for
+ more details
+ * added IEEE 802.11n HT capability configuration (ht_capab)
+ * added support for generating Country IE based on nl80211 regulatory
+ information (added if ieee80211d=1 in configuration)
+ * fixed WEP authentication (both Open System and Shared Key) with
+ mac80211
+ * added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
+ * added support for using driver_test over UDP socket
+ * changed EAP-GPSK to use the IANA assigned EAP method type 51
+ * updated management frame protection to use IEEE 802.11w/D7.0
+ * fixed retransmission of EAP requests if no response is received
+
+2008-11-23 - v0.6.6
+ * added a new configuration option, wpa_ptk_rekey, that can be used to
+ enforce frequent PTK rekeying, e.g., to mitigate some attacks against
+ TKIP deficiencies
+ * updated OpenSSL code for EAP-FAST to use an updated version of the
+ session ticket overriding API that was included into the upstream
+ OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
+ needed with that version anymore)
+ * changed channel flags configuration to read the information from
+ the driver (e.g., via driver_nl80211 when using mac80211) instead of
+ using hostapd as the source of the regulatory information (i.e.,
+ information from CRDA is now used with mac80211); this allows 5 GHz
+ channels to be used with hostapd (if allowed in the current
+ regulatory domain)
+ * fixed EAP-TLS message processing for the last TLS message if it is
+ large enough to require fragmentation (e.g., if a large Session
+ Ticket data is included)
+ * fixed listen interval configuration for nl80211 drivers
+
+2008-11-01 - v0.6.5
+ * added support for SHA-256 as X.509 certificate digest when using the
+ internal X.509/TLSv1 implementation
+ * fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer
+ identity lengths)
+ * fixed internal TLSv1 implementation for abbreviated handshake (used
+ by EAP-FAST server)
+ * added support for setting VLAN ID for STAs based on local MAC ACL
+ (accept_mac_file) as an alternative for RADIUS server-based
+ configuration
+ * updated management frame protection to use IEEE 802.11w/D6.0
+ (adds a new association ping to protect against unauthenticated
+ authenticate or (re)associate request frames dropping association)
+ * added support for using SHA256-based stronger key derivation for WPA2
+ (IEEE 802.11w)
+ * added new "driver wrapper" for RADIUS-only configuration
+ (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config)
+ * fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2)
+ is enabled in configuration
+ * changed EAP-FAST configuration to use separate fields for A-ID and
+ A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed
+ 16-octet len binary value for better interoperability with some peer
+ implementations; eap_fast_a_id is now configured as a hex string
+ * driver_nl80211: Updated to match the current Linux mac80211 AP mode
+ configuration (wireless-testing.git and Linux kernel releases
+ starting from 2.6.29)
+
+2008-08-10 - v0.6.4
+ * added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
+ Identity Request if identity is already known
+ * added support for EAP Sequences in EAP-FAST Phase 2
+ * added support for EAP-TNC (Trusted Network Connect)
+ (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST
+ changes needed to run two methods in sequence (IF-T) and the IF-IMV
+ and IF-TNCCS interfaces from TNCS)
+ * added support for optional cryptobinding with PEAPv0
+ * added fragmentation support for EAP-TNC
+ * added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
+ data
+ * added support for opportunistic key caching (OKC)
+
+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.
diff --git a/contrib/wpa/hostapd/README b/contrib/wpa/hostapd/README
new file mode 100644
index 0000000..eb9aa48
--- /dev/null
+++ b/contrib/wpa/hostapd/README
@@ -0,0 +1,390 @@
+hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
+ Authenticator and RADIUS authentication server
+================================================================
+
+Copyright (c) 2002-2009, 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/)
+
+ mac80211-based drivers that support AP mode (with driver=nl80211).
+ This includes drivers for Atheros (ath9k) and Broadcom (b43)
+ chipsets.
+
+ 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
diff --git a/contrib/wpa/hostapd/README-WPS b/contrib/wpa/hostapd/README-WPS
new file mode 100644
index 0000000..b46d767
--- /dev/null
+++ b/contrib/wpa/hostapd/README-WPS
@@ -0,0 +1,232 @@
+hostapd and Wi-Fi Protected Setup (WPS)
+=======================================
+
+This document describes how the WPS implementation in hostapd can be
+configured and how an external component on an AP (e.g., web UI) is
+used to enable enrollment of client devices.
+
+
+Introduction to WPS
+-------------------
+
+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
+wireless network. It allows automated generation of random keys (WPA
+passphrase/PSK) and configuration of an access point and client
+devices. WPS includes number of methods for setting up connections
+with PIN method and push-button configuration (PBC) being the most
+commonly deployed options.
+
+While WPS can enable more home networks to use encryption in the
+wireless network, it should be noted that the use of the PIN and
+especially PBC mechanisms for authenticating the initial key setup is
+not very secure. As such, use of WPS may not be suitable for
+environments that require secure network access without chance for
+allowing outsiders to gain access during the setup phase.
+
+WPS uses following terms to describe the entities participating in the
+network setup:
+- access point: the WLAN access point
+- Registrar: a device that control a network and can authorize
+ addition of new devices); this may be either in the AP ("internal
+ Registrar") or in an external device, e.g., a laptop, ("external
+ Registrar")
+- Enrollee: a device that is being authorized to use the network
+
+It should also be noted that the AP and a client device may change
+roles (i.e., AP acts as an Enrollee and client device as a Registrar)
+when WPS is used to configure the access point.
+
+
+More information about WPS is available from Wi-Fi Alliance:
+http://www.wi-fi.org/wifi-protected-setup
+
+
+hostapd implementation
+----------------------
+
+hostapd includes an optional WPS component that can be used as an
+internal WPS Registrar to manage addition of new WPS enabled clients
+to the network. In addition, WPS Enrollee functionality in hostapd can
+be used to allow external WPS Registrars to configure the access
+point, e.g., for initial network setup. In addition, hostapd can proxy a
+WPS registration between a wireless Enrollee and an external Registrar
+(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
+
+
+hostapd configuration
+---------------------
+
+WPS is an optional component that needs to be enabled in hostapd build
+configuration (.config). Here is an example configuration that
+includes WPS support and uses madwifi driver interface:
+
+CONFIG_DRIVER_MADWIFI=y
+CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_EAP=y
+CONFIG_WPS=y
+CONFIG_WPS_UPNP=y
+
+
+Following section shows an example runtime configuration
+(hostapd.conf) that enables WPS:
+
+# Configure the driver and network interface
+driver=madwifi
+interface=ath0
+
+# WPA2-Personal configuration for the AP
+ssid=wps-test
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+# Default WPA passphrase for legacy (non-WPS) clients
+wpa_passphrase=12345678
+# Enable random per-device PSK generation for WPS clients
+# Please note that the file has to exists for hostapd to start (i.e., create an
+# empty file as a starting point).
+wpa_psk_file=/etc/hostapd.psk
+
+# Enable control interface for PBC/PIN entry
+ctrl_interface=/var/run/hostapd
+
+# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
+eap_server=1
+
+# WPS configuration (AP configured, do not allow external WPS Registrars)
+wps_state=2
+ap_setup_locked=1
+# If UUID is not configured, it will be generated based on local MAC address.
+uuid=87654321-9abc-def0-1234-56789abc0000
+wps_pin_requests=/var/run/hostapd.pin-req
+device_name=Wireless AP
+manufacturer=Company
+model_name=WAP
+model_number=123
+serial_number=12345
+device_type=6-0050F204-1
+os_version=01020300
+config_methods=label display push_button keypad
+
+# if external Registrars are allowed, UPnP support could be added:
+#upnp_iface=br0
+#friendly_name=WPS Access Point
+
+
+External operations
+-------------------
+
+WPS requires either a device PIN code (usually, 8-digit number) or a
+pushbutton event (for PBC) to allow a new WPS Enrollee to join the
+network. hostapd uses the control interface as an input channel for
+these events.
+
+When a client device (WPS Enrollee) connects to hostapd (WPS
+Registrar) in order to start PIN mode negotiation for WPS, an
+identifier (Enrollee UUID) is sent. hostapd will need to be configured
+with a device password (PIN) for this Enrollee. This is an operation
+that requires user interaction (assuming there are no pre-configured
+PINs on the AP for a set of Enrollee).
+
+The PIN request with information about the device is appended to the
+wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
+addition, hostapd control interface event is sent as a notification of
+a new device. The AP could use, e.g., a web UI for showing active
+Enrollees to the user and request a PIN for an Enrollee.
+
+The PIN request file has one line for every Enrollee that connected to
+the AP, but for which there was no PIN. Following information is
+provided for each Enrollee (separated with tabulators):
+- timestamp (seconds from 1970-01-01)
+- Enrollee UUID
+- MAC address
+- Device name
+- Manufacturer
+- Model Name
+- Model Number
+- Serial Number
+- Device category
+
+Example line in the /var/run/hostapd.pin-req file:
+1200188391 53b63a98-d29e-4457-a2ed-094d7e6a669c Intel(R) Centrino(R) Intel Corporation Intel(R) Centrino(R) - - 1-0050F204-1
+
+Control interface data:
+WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
+For example:
+<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
+
+When the user enters a PIN for a pending Enrollee, e.g., on the web
+UI), hostapd needs to be notified of the new PIN over the control
+interface. This can be done either by using the UNIX domain socket
+-based control interface directly (src/common/wpa_ctrl.c provides
+helper functions for using the interface) or by calling hostapd_cli.
+
+Example command to add a PIN (12345670) for an Enrollee:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
+
+If the UUID-E is not available (e.g., Enrollee waits for the Registrar
+to be selected before connecting), wildcard UUID may be used to allow the PIN to be used once with any UUID:
+
+hostapd_cli wps_pin any 12345670
+
+
+After this, the Enrollee can connect to the AP again and complete WPS
+negotiation. At that point, a new, random WPA PSK is generated for the
+client device and the client can then use that key to connect to the
+AP to access the network.
+
+
+If the AP includes a pushbutton, WPS PBC mode can be used. It is
+enabled by pushing a button on both the AP and the client at about the
+same time (2 minute window). hostapd needs to be notified about the AP
+button pushed event over the control interface, e.g., by calling
+hostapd_cli:
+
+hostapd_cli wps_pbc
+
+At this point, the client has two minutes to complete WPS negotiation
+which will generate a new WPA PSK in the same way as the PIN method
+described above.
+
+
+Credential generation and configuration changes
+-----------------------------------------------
+
+By default, hostapd generates credentials for Enrollees and processing
+AP configuration updates internally. However, it is possible to
+control these operations from external programs, if desired.
+
+The internal credential generation can be disabled with
+skip_cred_build=1 option in the configuration. extra_cred option will
+then need to be used to provide pre-configured Credential attribute(s)
+for hostapd to use. The exact data from this binary file will be sent,
+i.e., it will have to include valid WPS attributes. extra_cred can
+also be used to add additional networks if the Registrar is used to
+configure credentials for multiple networks.
+
+Processing of received configuration updates can be disabled with
+wps_cred_processing=1 option. When this is used, an external program
+is responsible for creating hostapd configuration files and processing
+configuration updates based on messages received from hostapd over
+control interface. This will also include the initial configuration on
+first successful registration if the AP is initially set in
+unconfigured state.
+
+Following control interface messages are sent out for external programs:
+
+WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
+For example:
+<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
+
+This can be used to tricker change from unconfigured to configured
+state (random configuration based on the first successful WPS
+registration). In addition, this can be used to update AP UI about the
+status of WPS registration progress.
+
+
+WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
+For example:
+<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
+
+This can be used to update the externally stored AP configuration and
+then update hostapd configuration (followed by restarting of hostapd).
diff --git a/contrib/wpa/hostapd/accounting.c b/contrib/wpa/hostapd/accounting.c
new file mode 100644
index 0000000..ce71678
--- /dev/null
+++ b/contrib/wpa/hostapd/accounting.c
@@ -0,0 +1,510 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-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 "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
+
+static void accounting_sta_get_id(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);
+}
+
+
+/**
+ * accounting_sta_start - Start STA accounting
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct radius_msg *msg;
+ int interval;
+
+ if (sta->acct_session_started)
+ return;
+
+ accounting_sta_get_id(hapd, sta);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "starting accounting session %08X-%08X",
+ sta->acct_session_id_hi, sta->acct_session_id_lo);
+
+ 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;
+}
+
+
+static 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);
+}
+
+
+/**
+ * accounting_sta_interim - Send a interim STA accounting report
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (sta->acct_session_started)
+ accounting_sta_report(hapd, sta, 0);
+}
+
+
+/**
+ * accounting_sta_stop - Stop STA accounting
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+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);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "stopped accounting session %08X-%08X",
+ sta->acct_session_id_hi,
+ sta->acct_session_id_lo);
+ sta->acct_session_started = 0;
+ }
+}
+
+
+static 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;
+}
+
+
+/**
+ * accounting_receive - Process the RADIUS frames from Accounting Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
+static RadiusRxResult
+accounting_receive(struct radius_msg *msg, struct radius_msg *req,
+ const 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);
+}
+
+
+/**
+ * accounting_init: Initialize accounting
+ * @hapd: hostapd BSS data
+ * Returns: 0 on success, -1 on failure
+ */
+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;
+}
+
+
+/**
+ * accounting_deinit: Deinitilize accounting
+ * @hapd: hostapd BSS data
+ */
+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);
+}
diff --git a/contrib/wpa/hostapd/accounting.h b/contrib/wpa/hostapd/accounting.h
new file mode 100644
index 0000000..51e6b4d
--- /dev/null
+++ b/contrib/wpa/hostapd/accounting.h
@@ -0,0 +1,26 @@
+/*
+ * 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);
+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 */
diff --git a/contrib/wpa/hostapd/ap.h b/contrib/wpa/hostapd/ap.h
new file mode 100644
index 0000000..98f8ee7
--- /dev/null
+++ b/contrib/wpa/hostapd/ap.h
@@ -0,0 +1,139 @@
+/*
+ * hostapd / Station table data structures
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef AP_H
+#define AP_H
+
+#ifdef CONFIG_IEEE80211N
+#include "ieee802_11_defs.h"
+#endif /* CONFIG_IEEE80211N */
+
+/* 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_MFP BIT(10)
+#define WLAN_STA_HT BIT(11)
+#define WLAN_STA_WPS BIT(12)
+#define WLAN_STA_MAYBE_WPS BIT(13)
+#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;
+ unsigned int no_ht_gf_set:1;
+ unsigned int no_ht_set:1;
+ unsigned int ht_20mhz_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;
+
+#ifdef CONFIG_IEEE80211N
+ struct ht_cap_ie ht_capabilities; /* IEEE 802.11n capabilities */
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211W
+ int sa_query_count; /* number of pending SA Query requests;
+ * 0 = no SA Query in progress */
+ int sa_query_timed_out;
+ u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
+ * sa_query_count octets of pending SA Query
+ * transaction identifiers */
+ struct os_time sa_query_start;
+#endif /* CONFIG_IEEE80211W */
+
+ struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
+};
+
+
+/* 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 */
diff --git a/contrib/wpa/hostapd/ap_list.c b/contrib/wpa/hostapd/ap_list.c
new file mode 100644
index 0000000..4f217dc
--- /dev/null
+++ b/contrib/wpa/hostapd/ap_list.c
@@ -0,0 +1,501 @@
+/*
+ * hostapd / AP table
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2006, Devicescape Software, Inc.
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "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;
+}
+
+
+#ifdef CONFIG_IEEE80211N
+static int ap_list_beacon_olbc_ht(struct hostapd_iface *iface,
+ struct ap_info *ap)
+{
+ return !ap->ht_support;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+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;
+ int set_beacon = 0;
+
+ 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;
+
+ if (elems->ht_capabilities)
+ ap->ht_support = 1;
+ else
+ ap->ht_support = 0;
+
+ 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)) {
+ iface->olbc = 1;
+ wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
+ "protection", MAC2STR(ap->addr));
+ set_beacon++;
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (!iface->olbc_ht && ap_list_beacon_olbc_ht(iface, ap)) {
+ iface->olbc_ht = 1;
+ hostapd_ht_operation_update(iface);
+ wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
+ " - enable protection", MAC2STR(ap->addr));
+ set_beacon++;
+ }
+#endif /* CONFIG_IEEE80211N */
+
+ if (set_beacon)
+ ieee802_11_set_beacons(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;
+ int set_beacon = 0;
+
+ 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 || iface->olbc_ht) {
+ int olbc = 0;
+ int olbc_ht = 0;
+
+ ap = iface->ap_list;
+ while (ap && (olbc == 0 || olbc_ht == 0)) {
+ if (ap_list_beacon_olbc(iface, ap))
+ olbc = 1;
+#ifdef CONFIG_IEEE80211N
+ if (ap_list_beacon_olbc_ht(iface, ap))
+ olbc_ht = 1;
+#endif /* CONFIG_IEEE80211N */
+ ap = ap->next;
+ }
+ if (!olbc && iface->olbc) {
+ wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
+ iface->olbc = 0;
+ set_beacon++;
+ }
+#ifdef CONFIG_IEEE80211N
+ if (!olbc_ht && iface->olbc_ht) {
+ wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
+ iface->olbc_ht = 0;
+ hostapd_ht_operation_update(iface);
+ set_beacon++;
+ }
+#endif /* CONFIG_IEEE80211N */
+ }
+
+ if (set_beacon)
+ ieee802_11_set_beacons(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;
+}
diff --git a/contrib/wpa/hostapd/ap_list.h b/contrib/wpa/hostapd/ap_list.h
new file mode 100644
index 0000000..93704f8
--- /dev/null
+++ b/contrib/wpa/hostapd/ap_list.h
@@ -0,0 +1,71 @@
+/*
+ * hostapd / AP table
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2006, Devicescape Software, Inc.
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#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;
+
+ int ht_support;
+
+ 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 */
diff --git a/contrib/wpa/hostapd/beacon.c b/contrib/wpa/hostapd/beacon.c
new file mode 100644
index 0000000..31323e8
--- /dev/null
+++ b/contrib/wpa/hostapd/beacon.c
@@ -0,0 +1,467 @@
+/*
+ * 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>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#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 "wps_hostapd.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_add(u8 *pos, u8 *end, int chan_spacing,
+ struct hostapd_channel_data *start,
+ struct hostapd_channel_data *prev)
+{
+ if (end - pos < 3)
+ return pos;
+
+ /* first channel number */
+ *pos++ = start->chan;
+ /* number of channels */
+ *pos++ = (prev->chan - start->chan) / chan_spacing + 1;
+ /* maximum transmit power level */
+ *pos++ = start->max_tx_power;
+
+ return pos;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+ int max_len)
+{
+ u8 *pos = eid;
+ u8 *end = eid + max_len;
+ int i;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *start, *prev;
+ int chan_spacing = 1;
+
+ if (!hapd->iconf->ieee80211d || max_len < 6 ||
+ hapd->iface->current_mode == NULL)
+ return eid;
+
+ *pos++ = WLAN_EID_COUNTRY;
+ pos++; /* length will be set later */
+ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+ pos += 3;
+
+ mode = hapd->iface->current_mode;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A)
+ chan_spacing = 4;
+
+ start = prev = NULL;
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ if (start && prev &&
+ prev->chan + chan_spacing == chan->chan &&
+ start->max_tx_power == chan->max_tx_power) {
+ prev = chan;
+ continue; /* can use same entry */
+ }
+
+ if (start) {
+ pos = hostapd_eid_country_add(pos, end, chan_spacing,
+ start, prev);
+ start = NULL;
+ }
+
+ /* Start new group */
+ start = prev = chan;
+ }
+
+ if (start) {
+ pos = hostapd_eid_country_add(pos, end, chan_spacing,
+ start, prev);
+ }
+
+ if ((pos - eid) & 1) {
+ if (end - pos < 1)
+ return eid;
+ *pos++ = 0; /* pad for 16-bit alignment */
+ }
+
+ eid[1] = (pos - eid) - 2;
+
+ return pos;
+}
+
+
+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));
+
+ hostapd_wps_probe_req_rx(hapd, mgmt->sa, ie, ie_len);
+
+ if (!hapd->iconf->send_probe_response)
+ return;
+
+ if (ieee802_11_parse_elems(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);
+
+ /* 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 */
+ pos = hostapd_eid_wme(hapd, pos);
+
+ pos = hostapd_eid_ht_capabilities_info(hapd, pos);
+ pos = hostapd_eid_ht_operation(hapd, pos);
+
+#ifdef CONFIG_WPS
+ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
+ os_memcpy(pos, hapd->wps_probe_resp_ie,
+ hapd->wps_probe_resp_ie_len);
+ pos += hapd->wps_probe_resp_ie_len;
+ }
+#endif /* CONFIG_WPS */
+
+ 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);
+
+ /* 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 */
+ tailpos = hostapd_eid_wme(hapd, tailpos);
+
+#ifdef CONFIG_IEEE80211N
+ if (hapd->iconf->ieee80211n) {
+ u8 *ht_capab, *ht_oper;
+ ht_capab = tailpos;
+ tailpos = hostapd_eid_ht_capabilities_info(hapd, tailpos);
+
+ ht_oper = tailpos;
+ tailpos = hostapd_eid_ht_operation(hapd, tailpos);
+
+ if (tailpos > ht_oper && ht_oper > ht_capab &&
+ hostapd_set_ht_params(hapd->conf->iface, hapd,
+ ht_capab + 2, ht_capab[1],
+ ht_oper + 2, ht_oper[1])) {
+ wpa_printf(MSG_ERROR, "Could not set HT capabilities "
+ "for kernel driver");
+ }
+ }
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS
+ if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
+ os_memcpy(tailpos, hapd->wps_beacon_ie,
+ hapd->wps_beacon_ie_len);
+ tailpos += hapd->wps_beacon_ie_len;
+ }
+#endif /* CONFIG_WPS */
+
+ 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 */
diff --git a/contrib/wpa/hostapd/beacon.h b/contrib/wpa/hostapd/beacon.h
new file mode 100644
index 0000000..18e0da2
--- /dev/null
+++ b/contrib/wpa/hostapd/beacon.h
@@ -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 */
diff --git a/contrib/wpa/hostapd/config.c b/contrib/wpa/hostapd/config.c
new file mode 100644
index 0000000..6ad14d2
--- /dev/null
+++ b/contrib/wpa/hostapd/config.c
@@ -0,0 +1,2617 @@
+/*
+ * hostapd / Configuration file
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "hostapd.h"
+#include "driver.h"
+#include "sha1.h"
+#include "eap_server/eap.h"
+#include "radius/radius_client.h"
+#include "wpa_common.h"
+#include "wpa.h"
+#include "uuid.h"
+#include "eap_common/eap_wsc_common.h"
+
+
+#define MAX_STA_COUNT 2007
+
+extern struct wpa_driver_ops *hostapd_drivers[];
+
+
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+ const char *fname)
+{
+ FILE *f;
+ char buf[128], *pos, *pos2;
+ int line = 0, vlan_id;
+ struct hostapd_vlan *vlan;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (buf[0] == '*') {
+ vlan_id = VLAN_ID_WILDCARD;
+ pos = buf + 1;
+ } else {
+ vlan_id = strtol(buf, &pos, 10);
+ if (buf == pos || vlan_id < 1 ||
+ vlan_id > MAX_VLAN_ID) {
+ wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
+ "line %d in '%s'", line, fname);
+ fclose(f);
+ return -1;
+ }
+ }
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ pos2 = pos;
+ while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+ pos2++;
+ *pos2 = '\0';
+ if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
+ "in '%s'", line, fname);
+ fclose(f);
+ return -1;
+ }
+
+ vlan = os_malloc(sizeof(*vlan));
+ if (vlan == NULL) {
+ wpa_printf(MSG_ERROR, "Out of memory while reading "
+ "VLAN interfaces from '%s'", fname);
+ fclose(f);
+ return -1;
+ }
+
+ os_memset(vlan, 0, sizeof(*vlan));
+ vlan->vlan_id = vlan_id;
+ os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+ if (bss->vlan_tail)
+ bss->vlan_tail->next = vlan;
+ else
+ bss->vlan = vlan;
+ bss->vlan_tail = vlan;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
+{
+ struct hostapd_vlan *vlan, *prev;
+
+ vlan = bss->vlan;
+ prev = NULL;
+ while (vlan) {
+ prev = vlan;
+ vlan = vlan->next;
+ os_free(prev);
+ }
+
+ bss->vlan = NULL;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+ int i, d;
+ char *pos;
+
+ i = atoi(value);
+ pos = os_strchr(value, '.');
+ d = 0;
+ if (pos) {
+ pos++;
+ if (*pos >= '0' && *pos <= '9')
+ d = *pos - '0';
+ }
+
+ return i * 10 + d;
+}
+
+
+static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
+{
+ bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
+ bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
+ bss->logger_syslog = (unsigned int) -1;
+ bss->logger_stdout = (unsigned int) -1;
+
+ bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
+
+ bss->wep_rekeying_period = 300;
+ /* use key0 in individual key and key1 in broadcast key */
+ bss->broadcast_key_idx_min = 1;
+ bss->broadcast_key_idx_max = 2;
+ bss->eap_reauth_period = 3600;
+
+ bss->wpa_group_rekey = 600;
+ bss->wpa_gmk_rekey = 86400;
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ bss->wpa_pairwise = WPA_CIPHER_TKIP;
+ bss->wpa_group = WPA_CIPHER_TKIP;
+ bss->rsn_pairwise = 0;
+
+ bss->max_num_sta = MAX_STA_COUNT;
+
+ bss->dtim_period = 2;
+
+ bss->radius_server_auth_port = 1812;
+ bss->ap_max_inactivity = AP_MAX_INACTIVITY;
+ bss->eapol_version = EAPOL_VERSION;
+
+ bss->max_listen_interval = 65535;
+
+#ifdef CONFIG_IEEE80211W
+ bss->assoc_sa_query_max_timeout = 1000;
+ bss->assoc_sa_query_retry_timeout = 201;
+#endif /* CONFIG_IEEE80211W */
+#ifdef EAP_FAST
+ /* both anonymous and authenticated provisioning */
+ bss->eap_fast_prov = 3;
+ bss->pac_key_lifetime = 7 * 24 * 60 * 60;
+ bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
+#endif /* EAP_FAST */
+}
+
+
+static struct hostapd_config * hostapd_config_defaults(void)
+{
+ struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
+ int i;
+ const int aCWmin = 15, aCWmax = 1024;
+ const struct hostapd_wme_ac_params ac_bk =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wme_ac_params ac_be =
+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+ const struct hostapd_wme_ac_params ac_vi = /* video traffic */
+ { aCWmin >> 1, aCWmin, 2, 3000 / 32, 1 };
+ const struct hostapd_wme_ac_params ac_vo = /* voice traffic */
+ { aCWmin >> 2, aCWmin >> 1, 2, 1500 / 32, 1 };
+
+ conf = os_zalloc(sizeof(*conf));
+ bss = os_zalloc(sizeof(*bss));
+ if (conf == NULL || bss == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+ "configuration data.");
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+
+ /* set default driver based on configuration */
+ conf->driver = hostapd_drivers[0];
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+
+ bss->radius = os_zalloc(sizeof(*bss->radius));
+ if (bss->radius == NULL) {
+ os_free(conf);
+ os_free(bss);
+ return NULL;
+ }
+
+ hostapd_config_defaults_bss(bss);
+
+ conf->num_bss = 1;
+ conf->bss = bss;
+
+ conf->beacon_int = 100;
+ conf->rts_threshold = -1; /* use driver default: 2347 */
+ conf->fragm_threshold = -1; /* user driver default: 2346 */
+ conf->send_probe_response = 1;
+ conf->bridge_packets = INTERNAL_BRIDGE_DO_NOT_CONTROL;
+
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ conf->tx_queue[i].aifs = -1; /* use hw default */
+
+ conf->wme_ac_params[0] = ac_be;
+ conf->wme_ac_params[1] = ac_bk;
+ conf->wme_ac_params[2] = ac_vi;
+ conf->wme_ac_params[3] = ac_vo;
+
+#ifdef CONFIG_IEEE80211N
+ conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
+#endif /* CONFIG_IEEE80211N */
+
+ return conf;
+}
+
+
+int hostapd_mac_comp(const void *a, const void *b)
+{
+ return os_memcmp(a, b, sizeof(macaddr));
+}
+
+
+int hostapd_mac_comp_empty(const void *a)
+{
+ macaddr empty = { 0 };
+ return os_memcmp(a, empty, sizeof(macaddr));
+}
+
+
+static int hostapd_acl_comp(const void *a, const void *b)
+{
+ const struct mac_acl_entry *aa = a;
+ const struct mac_acl_entry *bb = b;
+ return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname,
+ struct mac_acl_entry **acl, int *num)
+{
+ FILE *f;
+ char buf[128], *pos;
+ int line = 0;
+ u8 addr[ETH_ALEN];
+ struct mac_acl_entry *newacl;
+ int vlan_id;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (hwaddr_aton(buf, addr)) {
+ wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
+ "line %d in '%s'", buf, line, fname);
+ fclose(f);
+ return -1;
+ }
+
+ vlan_id = 0;
+ pos = buf;
+ while (*pos != '\0' && *pos != ' ' && *pos != '\t')
+ pos++;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos != '\0')
+ vlan_id = atoi(pos);
+
+ newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
+ if (newacl == NULL) {
+ wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ fclose(f);
+ return -1;
+ }
+
+ *acl = newacl;
+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+ (*acl)[*num].vlan_id = vlan_id;
+ (*num)++;
+ }
+
+ fclose(f);
+
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+
+ return 0;
+}
+
+
+static int hostapd_config_read_wpa_psk(const char *fname,
+ struct hostapd_ssid *ssid)
+{
+ FILE *f;
+ char buf[128], *pos;
+ int line = 0, ret = 0, len, ok;
+ u8 addr[ETH_ALEN];
+ struct hostapd_wpa_psk *psk;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (hwaddr_aton(buf, addr)) {
+ wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
+ "line %d in '%s'", buf, line, fname);
+ ret = -1;
+ break;
+ }
+
+ psk = os_zalloc(sizeof(*psk));
+ if (psk == NULL) {
+ wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
+ ret = -1;
+ break;
+ }
+ if (is_zero_ether_addr(addr))
+ psk->group = 1;
+ else
+ os_memcpy(psk->addr, addr, ETH_ALEN);
+
+ pos = buf + 17;
+ if (*pos == '\0') {
+ wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
+ line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+ pos++;
+
+ ok = 0;
+ len = os_strlen(pos);
+ if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ ok = 1;
+ else if (len >= 8 && len < 64) {
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+ 4096, psk->psk, PMK_LEN);
+ ok = 1;
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
+ "'%s'", pos, line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+
+ psk->next = ssid->wpa_psk;
+ ssid->wpa_psk = psk;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+
+
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
+{
+ struct hostapd_ssid *ssid = &conf->ssid;
+
+ if (ssid->wpa_passphrase != NULL) {
+ if (ssid->wpa_psk != NULL) {
+ wpa_printf(MSG_ERROR, "Warning: both WPA PSK and "
+ "passphrase set. Using passphrase.");
+ os_free(ssid->wpa_psk);
+ }
+ ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (ssid->wpa_psk == NULL) {
+ wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
+ return -1;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "SSID",
+ (u8 *) ssid->ssid, ssid->ssid_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "PSK (ASCII passphrase)",
+ (u8 *) ssid->wpa_passphrase,
+ os_strlen(ssid->wpa_passphrase));
+ pbkdf2_sha1(ssid->wpa_passphrase,
+ ssid->ssid, ssid->ssid_len,
+ 4096, ssid->wpa_psk->psk, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "PSK (from passphrase)",
+ ssid->wpa_psk->psk, PMK_LEN);
+ ssid->wpa_psk->group = 1;
+ }
+
+ if (ssid->wpa_psk_file) {
+ if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
+ &conf->ssid))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_config_read_eap_user(const char *fname,
+ struct hostapd_bss_config *conf)
+{
+ FILE *f;
+ char buf[512], *pos, *start, *pos2;
+ int line = 0, ret = 0, num_methods;
+ struct hostapd_eap_user *user, *tail = NULL;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
+ return -1;
+ }
+
+ /* Lines: "user" METHOD,METHOD2 "password" (password optional) */
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ user = NULL;
+
+ if (buf[0] != '"' && buf[0] != '*') {
+ wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
+ "start) on line %d in '%s'", line, fname);
+ goto failed;
+ }
+
+ user = os_zalloc(sizeof(*user));
+ if (user == NULL) {
+ wpa_printf(MSG_ERROR, "EAP user allocation failed");
+ goto failed;
+ }
+ user->force_version = -1;
+
+ if (buf[0] == '*') {
+ pos = buf;
+ } else {
+ pos = buf + 1;
+ start = pos;
+ while (*pos != '"' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ wpa_printf(MSG_ERROR, "Invalid EAP identity "
+ "(no \" in end) on line %d in '%s'",
+ line, fname);
+ goto failed;
+ }
+
+ user->identity = os_malloc(pos - start);
+ if (user->identity == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate "
+ "memory for EAP identity");
+ goto failed;
+ }
+ os_memcpy(user->identity, start, pos - start);
+ user->identity_len = pos - start;
+
+ if (pos[0] == '"' && pos[1] == '*') {
+ user->wildcard_prefix = 1;
+ pos++;
+ }
+ }
+ pos++;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '\0') {
+ wpa_printf(MSG_ERROR, "No EAP method on line %d in "
+ "'%s'", line, fname);
+ goto failed;
+ }
+
+ start = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ pos = NULL;
+ } else {
+ *pos = '\0';
+ pos++;
+ }
+ num_methods = 0;
+ while (*start) {
+ char *pos3 = os_strchr(start, ',');
+ if (pos3) {
+ *pos3++ = '\0';
+ }
+ user->methods[num_methods].method =
+ eap_server_get_type(
+ start,
+ &user->methods[num_methods].vendor);
+ if (user->methods[num_methods].vendor ==
+ EAP_VENDOR_IETF &&
+ user->methods[num_methods].method == EAP_TYPE_NONE)
+ {
+ if (os_strcmp(start, "TTLS-PAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-CHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+ user->ttls_auth |=
+ EAP_TTLS_AUTH_MSCHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+ user->ttls_auth |=
+ EAP_TTLS_AUTH_MSCHAPV2;
+ goto skip_eap;
+ }
+ wpa_printf(MSG_ERROR, "Unsupported EAP type "
+ "'%s' on line %d in '%s'",
+ start, line, fname);
+ goto failed;
+ }
+
+ num_methods++;
+ if (num_methods >= EAP_USER_MAX_METHODS)
+ break;
+ skip_eap:
+ if (pos3 == NULL)
+ break;
+ start = pos3;
+ }
+ if (num_methods == 0 && user->ttls_auth == 0) {
+ wpa_printf(MSG_ERROR, "No EAP types configured on "
+ "line %d in '%s'", line, fname);
+ goto failed;
+ }
+
+ if (pos == NULL)
+ goto done;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos == '\0')
+ goto done;
+
+ if (os_strncmp(pos, "[ver=0]", 7) == 0) {
+ user->force_version = 0;
+ goto done;
+ }
+
+ if (os_strncmp(pos, "[ver=1]", 7) == 0) {
+ user->force_version = 1;
+ goto done;
+ }
+
+ if (os_strncmp(pos, "[2]", 3) == 0) {
+ user->phase2 = 1;
+ goto done;
+ }
+
+ if (*pos == '"') {
+ pos++;
+ start = pos;
+ while (*pos != '"' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ wpa_printf(MSG_ERROR, "Invalid EAP password "
+ "(no \" in end) on line %d in '%s'",
+ line, fname);
+ goto failed;
+ }
+
+ user->password = os_malloc(pos - start);
+ if (user->password == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate "
+ "memory for EAP password");
+ goto failed;
+ }
+ os_memcpy(user->password, start, pos - start);
+ user->password_len = pos - start;
+
+ pos++;
+ } else if (os_strncmp(pos, "hash:", 5) == 0) {
+ pos += 5;
+ pos2 = pos;
+ while (*pos2 != '\0' && *pos2 != ' ' &&
+ *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+ if (pos2 - pos != 32) {
+ wpa_printf(MSG_ERROR, "Invalid password hash "
+ "on line %d in '%s'", line, fname);
+ goto failed;
+ }
+ user->password = os_malloc(16);
+ if (user->password == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate "
+ "memory for EAP password hash");
+ goto failed;
+ }
+ if (hexstr2bin(pos, user->password, 16) < 0) {
+ wpa_printf(MSG_ERROR, "Invalid hash password "
+ "on line %d in '%s'", line, fname);
+ goto failed;
+ }
+ user->password_len = 16;
+ user->password_hash = 1;
+ pos = pos2;
+ } else {
+ pos2 = pos;
+ while (*pos2 != '\0' && *pos2 != ' ' &&
+ *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+ if ((pos2 - pos) & 1) {
+ wpa_printf(MSG_ERROR, "Invalid hex password "
+ "on line %d in '%s'", line, fname);
+ goto failed;
+ }
+ user->password = os_malloc((pos2 - pos) / 2);
+ if (user->password == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate "
+ "memory for EAP password");
+ goto failed;
+ }
+ if (hexstr2bin(pos, user->password,
+ (pos2 - pos) / 2) < 0) {
+ wpa_printf(MSG_ERROR, "Invalid hex password "
+ "on line %d in '%s'", line, fname);
+ goto failed;
+ }
+ user->password_len = (pos2 - pos) / 2;
+ pos = pos2;
+ }
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (os_strncmp(pos, "[2]", 3) == 0) {
+ user->phase2 = 1;
+ }
+
+ done:
+ if (tail == NULL) {
+ tail = conf->eap_user = user;
+ } else {
+ tail->next = user;
+ tail = user;
+ }
+ continue;
+
+ failed:
+ if (user) {
+ os_free(user->password);
+ os_free(user->identity);
+ os_free(user);
+ }
+ ret = -1;
+ break;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+#endif /* EAP_SERVER */
+
+
+static int
+hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
+ int *num_server, const char *val, int def_port,
+ struct hostapd_radius_server **curr_serv)
+{
+ struct hostapd_radius_server *nserv;
+ int ret;
+ static int server_index = 1;
+
+ nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+ if (nserv == NULL)
+ return -1;
+
+ *server = nserv;
+ nserv = &nserv[*num_server];
+ (*num_server)++;
+ (*curr_serv) = nserv;
+
+ os_memset(nserv, 0, sizeof(*nserv));
+ nserv->port = def_port;
+ ret = hostapd_parse_ip_addr(val, &nserv->addr);
+ nserv->index = server_index++;
+
+ return ret;
+}
+
+
+static int hostapd_config_parse_key_mgmt(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = os_strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (*start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (os_strcmp(start, "WPA-PSK") == 0)
+ val |= WPA_KEY_MGMT_PSK;
+ else if (os_strcmp(start, "WPA-EAP") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_IEEE80211R
+ else if (os_strcmp(start, "FT-PSK") == 0)
+ val |= WPA_KEY_MGMT_FT_PSK;
+ else if (os_strcmp(start, "FT-EAP") == 0)
+ val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+ val |= WPA_KEY_MGMT_PSK_SHA256;
+ else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+ line, start);
+ os_free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ os_free(buf);
+ if (val == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
+ "configured.", line);
+ return -1;
+ }
+
+ return val;
+}
+
+
+static int hostapd_config_parse_cipher(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = os_strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (*start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (os_strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (os_strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (os_strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (os_strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, start);
+ os_free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ os_free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+ line);
+ return -1;
+ }
+ return val;
+}
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+ struct hostapd_config *conf)
+{
+ if (bss->ieee802_1x && !bss->eap_server &&
+ !bss->radius->auth_servers) {
+ wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+ "EAP authenticator configured).");
+ return -1;
+ }
+
+ if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+ bss->ssid.wpa_psk_file == NULL) {
+ wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+ "is not configured.");
+ return -1;
+ }
+
+ if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if ((&conf->bss[i] != bss) &&
+ (hostapd_mac_comp(conf->bss[i].bssid,
+ bss->bssid) == 0)) {
+ wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+ " on interface '%s' and '%s'.",
+ MAC2STR(bss->bssid),
+ conf->bss[i].iface, bss->iface);
+ return -1;
+ }
+ }
+ }
+
+#ifdef CONFIG_IEEE80211R
+ if ((bss->wpa_key_mgmt &
+ (WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X)) &&
+ (bss->nas_identifier == NULL ||
+ os_strlen(bss->nas_identifier) < 1 ||
+ os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+ wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+ "nas_identifier to be configured as a 1..48 octet "
+ "string");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+ if (conf->ieee80211n && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+ "requires CCMP to be enabled");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211N */
+
+ return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+ size_t i;
+
+ if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+ "setting the country_code");
+ return -1;
+ }
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (hostapd_config_check_bss(&conf->bss[i], conf))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+ char *val)
+{
+ size_t len = os_strlen(val);
+
+ if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+ return -1;
+
+ if (val[0] == '"') {
+ if (len < 2 || val[len - 1] != '"')
+ return -1;
+ len -= 2;
+ wep->key[keyidx] = os_malloc(len);
+ if (wep->key[keyidx] == NULL)
+ return -1;
+ os_memcpy(wep->key[keyidx], val + 1, len);
+ wep->len[keyidx] = len;
+ } else {
+ if (len & 1)
+ return -1;
+ len /= 2;
+ wep->key[keyidx] = os_malloc(len);
+ if (wep->key[keyidx] == NULL)
+ return -1;
+ wep->len[keyidx] = len;
+ if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+ return -1;
+ }
+
+ wep->keys_set++;
+
+ return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+ int *list;
+ int count;
+ char *pos, *end;
+
+ os_free(*rate_list);
+ *rate_list = NULL;
+
+ pos = val;
+ count = 0;
+ while (*pos != '\0') {
+ if (*pos == ' ')
+ count++;
+ pos++;
+ }
+
+ list = os_malloc(sizeof(int) * (count + 2));
+ if (list == NULL)
+ return -1;
+ pos = val;
+ count = 0;
+ while (*pos != '\0') {
+ end = os_strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+
+ list[count++] = atoi(pos);
+ if (!end)
+ break;
+ pos = end + 1;
+ }
+ list[count] = -1;
+
+ *rate_list = list;
+ return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+ struct hostapd_bss_config *bss;
+
+ if (*ifname == '\0')
+ return -1;
+
+ bss = os_realloc(conf->bss, (conf->num_bss + 1) *
+ sizeof(struct hostapd_bss_config));
+ if (bss == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+ "multi-BSS entry");
+ return -1;
+ }
+ conf->bss = bss;
+
+ bss = &(conf->bss[conf->num_bss]);
+ os_memset(bss, 0, sizeof(*bss));
+ bss->radius = os_zalloc(sizeof(*bss->radius));
+ if (bss->radius == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+ "multi-BSS RADIUS data");
+ return -1;
+ }
+
+ conf->num_bss++;
+ conf->last_bss = bss;
+
+ hostapd_config_defaults_bss(bss);
+ os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+ os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+ return 0;
+}
+
+
+static int valid_cw(int cw)
+{
+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+ IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+ IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+ IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+ IEEE80211_TX_QUEUE_DATA3 = 3, /* used for EDCA AC_BK data */
+ IEEE80211_TX_QUEUE_DATA4 = 4,
+ IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+ IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+ char *val)
+{
+ int num;
+ char *pos;
+ struct hostapd_tx_queue_params *queue;
+
+ /* skip 'tx_queue_' prefix */
+ pos = name + 9;
+ if (os_strncmp(pos, "data", 4) == 0 &&
+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+ num = pos[4] - '0';
+ pos += 6;
+ } else if (os_strncmp(pos, "after_beacon_", 13) == 0) {
+ num = IEEE80211_TX_QUEUE_AFTER_BEACON;
+ pos += 13;
+ } else if (os_strncmp(pos, "beacon_", 7) == 0) {
+ num = IEEE80211_TX_QUEUE_BEACON;
+ pos += 7;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+ return -1;
+ }
+
+ queue = &conf->tx_queue[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ queue->aifs = atoi(val);
+ if (queue->aifs < 0 || queue->aifs > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+ queue->aifs);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ queue->cwmin = atoi(val);
+ if (!valid_cw(queue->cwmin)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+ queue->cwmin);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ queue->cwmax = atoi(val);
+ if (!valid_cw(queue->cwmax)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+ queue->cwmax);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "burst") == 0) {
+ queue->burst = hostapd_config_read_int10(val);
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
+ return -1;
+ }
+
+ queue->configured = 1;
+
+ return 0;
+}
+
+
+static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
+ char *val)
+{
+ int num, v;
+ char *pos;
+ struct hostapd_wme_ac_params *ac;
+
+ /* skip 'wme_ac_' prefix */
+ pos = name + 7;
+ if (os_strncmp(pos, "be_", 3) == 0) {
+ num = 0;
+ pos += 3;
+ } else if (os_strncmp(pos, "bk_", 3) == 0) {
+ num = 1;
+ pos += 3;
+ } else if (os_strncmp(pos, "vi_", 3) == 0) {
+ num = 2;
+ pos += 3;
+ } else if (os_strncmp(pos, "vo_", 3) == 0) {
+ num = 3;
+ pos += 3;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown wme name '%s'", pos);
+ return -1;
+ }
+
+ ac = &conf->wme_ac_params[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ v = atoi(val);
+ if (v < 1 || v > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
+ return -1;
+ }
+ ac->aifs = v;
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
+ return -1;
+ }
+ ac->cwmin = v;
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
+ return -1;
+ }
+ ac->cwmax = v;
+ } else if (os_strcmp(pos, "txop_limit") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 0xffff) {
+ wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
+ return -1;
+ }
+ ac->txopLimit = v;
+ } else if (os_strcmp(pos, "acm") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 1) {
+ wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
+ return -1;
+ }
+ ac->admission_control_mandatory = v;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown wme_ac_ field '%s'", pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int add_r0kh(struct hostapd_bss_config *bss, char *value)
+{
+ struct ft_remote_r0kh *r0kh;
+ char *pos, *next;
+
+ r0kh = os_zalloc(sizeof(*r0kh));
+ if (r0kh == NULL)
+ return -1;
+
+ /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
+ pos = value;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
+ wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
+ os_free(r0kh);
+ return -1;
+ }
+
+ pos = next;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
+ os_free(r0kh);
+ return -1;
+ }
+ r0kh->id_len = next - pos - 1;
+ os_memcpy(r0kh->id, pos, r0kh->id_len);
+
+ pos = next;
+ if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+ wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
+ os_free(r0kh);
+ return -1;
+ }
+
+ r0kh->next = bss->r0kh_list;
+ bss->r0kh_list = r0kh;
+
+ return 0;
+}
+
+
+static int add_r1kh(struct hostapd_bss_config *bss, char *value)
+{
+ struct ft_remote_r1kh *r1kh;
+ char *pos, *next;
+
+ r1kh = os_zalloc(sizeof(*r1kh));
+ if (r1kh == NULL)
+ return -1;
+
+ /* 02:01:02:03:04:05 02:01:02:03:04:05
+ * 000102030405060708090a0b0c0d0e0f */
+ pos = value;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
+ wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
+ os_free(r1kh);
+ return -1;
+ }
+
+ pos = next;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
+ wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
+ os_free(r1kh);
+ return -1;
+ }
+
+ pos = next;
+ if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+ wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
+ os_free(r1kh);
+ return -1;
+ }
+
+ r1kh->next = bss->r1kh_list;
+ bss->r1kh_list = r1kh;
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_IEEE80211N
+static int hostapd_config_ht_capab(struct hostapd_config *conf,
+ const char *capab)
+{
+ if (os_strstr(capab, "[LDPC]"))
+ conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
+ if (os_strstr(capab, "[HT40-]")) {
+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ conf->secondary_channel = -1;
+ }
+ if (os_strstr(capab, "[HT40+]")) {
+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ conf->secondary_channel = 1;
+ }
+ if (os_strstr(capab, "[SMPS-STATIC]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+ conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
+ }
+ if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+ conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
+ }
+ if (os_strstr(capab, "[GF]"))
+ conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
+ if (os_strstr(capab, "[SHORT-GI-20]"))
+ conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
+ if (os_strstr(capab, "[SHORT-GI-40]"))
+ conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
+ if (os_strstr(capab, "[TX-STBC]"))
+ conf->ht_capab |= HT_CAP_INFO_TX_STBC;
+ if (os_strstr(capab, "[RX-STBC1]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
+ }
+ if (os_strstr(capab, "[RX-STBC12]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
+ }
+ if (os_strstr(capab, "[RX-STBC123]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
+ }
+ if (os_strstr(capab, "[DELAYED-BA]"))
+ conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
+ if (os_strstr(capab, "[MAX-AMSDU-7935]"))
+ conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
+ if (os_strstr(capab, "[DSSS_CCK-40]"))
+ conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
+ if (os_strstr(capab, "[PSMP]"))
+ conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
+ if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
+ conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+ struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
+ FILE *f;
+ char buf[256], *pos;
+ int line = 0;
+ int errors = 0;
+ int pairwise;
+ size_t i;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ "for reading.", fname);
+ return NULL;
+ }
+
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+ bss = conf->last_bss = conf->bss;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ bss = conf->last_bss;
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ pos = os_strchr(buf, '=');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+ line, buf);
+ errors++;
+ continue;
+ }
+ *pos = '\0';
+ pos++;
+
+ if (os_strcmp(buf, "interface") == 0) {
+ os_strlcpy(conf->bss[0].iface, pos,
+ sizeof(conf->bss[0].iface));
+ } else if (os_strcmp(buf, "bridge") == 0) {
+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+ } else if (os_strcmp(buf, "driver") == 0) {
+ int i;
+ /* clear to get error below if setting is invalid */
+ conf->driver = NULL;
+ for (i = 0; hostapd_drivers[i]; i++) {
+ if (os_strcmp(pos, hostapd_drivers[i]->name) ==
+ 0) {
+ conf->driver = hostapd_drivers[i];
+ break;
+ }
+ }
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid/"
+ "unknown driver '%s'", line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "debug") == 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
+ "configuration variable is not used "
+ "anymore", line);
+ } else if (os_strcmp(buf, "logger_syslog_level") == 0) {
+ bss->logger_syslog_level = atoi(pos);
+ } else if (os_strcmp(buf, "logger_stdout_level") == 0) {
+ bss->logger_stdout_level = atoi(pos);
+ } else if (os_strcmp(buf, "logger_syslog") == 0) {
+ bss->logger_syslog = atoi(pos);
+ } else if (os_strcmp(buf, "logger_stdout") == 0) {
+ bss->logger_stdout = atoi(pos);
+ } else if (os_strcmp(buf, "dump_file") == 0) {
+ bss->dump_log_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "ssid") == 0) {
+ bss->ssid.ssid_len = os_strlen(pos);
+ if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+ bss->ssid.ssid_len < 1) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+ "'%s'", line, pos);
+ errors++;
+ } else {
+ os_memcpy(bss->ssid.ssid, pos,
+ bss->ssid.ssid_len);
+ bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
+ bss->ssid.ssid_set = 1;
+ }
+ } else if (os_strcmp(buf, "macaddr_acl") == 0) {
+ bss->macaddr_acl = atoi(pos);
+ if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+ bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown "
+ "macaddr_acl %d",
+ line, bss->macaddr_acl);
+ }
+ } else if (os_strcmp(buf, "accept_mac_file") == 0) {
+ if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+ &bss->num_accept_mac))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to "
+ "read accept_mac_file '%s'",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "deny_mac_file") == 0) {
+ if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+ &bss->num_deny_mac)) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to "
+ "read deny_mac_file '%s'",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
+ bss->ap_max_inactivity = atoi(pos);
+ } else if (os_strcmp(buf, "country_code") == 0) {
+ os_memcpy(conf->country, pos, 2);
+ /* FIX: make this configurable */
+ conf->country[2] = ' ';
+ } else if (os_strcmp(buf, "ieee80211d") == 0) {
+ conf->ieee80211d = atoi(pos);
+ } else if (os_strcmp(buf, "ieee8021x") == 0) {
+ bss->ieee802_1x = atoi(pos);
+ } else if (os_strcmp(buf, "eapol_version") == 0) {
+ bss->eapol_version = atoi(pos);
+ if (bss->eapol_version < 1 ||
+ bss->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
+ "version (%d): '%s'.",
+ line, bss->eapol_version, pos);
+ errors++;
+ } else
+ wpa_printf(MSG_DEBUG, "eapol_version=%d",
+ bss->eapol_version);
+#ifdef EAP_SERVER
+ } else if (os_strcmp(buf, "eap_authenticator") == 0) {
+ bss->eap_server = atoi(pos);
+ wpa_printf(MSG_ERROR, "Line %d: obsolete "
+ "eap_authenticator used; this has been "
+ "renamed to eap_server", line);
+ } else if (os_strcmp(buf, "eap_server") == 0) {
+ bss->eap_server = atoi(pos);
+ } else if (os_strcmp(buf, "eap_user_file") == 0) {
+ if (hostapd_config_read_eap_user(pos, bss))
+ errors++;
+ } else if (os_strcmp(buf, "ca_cert") == 0) {
+ os_free(bss->ca_cert);
+ bss->ca_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "server_cert") == 0) {
+ os_free(bss->server_cert);
+ bss->server_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key") == 0) {
+ os_free(bss->private_key);
+ bss->private_key = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key_passwd") == 0) {
+ os_free(bss->private_key_passwd);
+ bss->private_key_passwd = os_strdup(pos);
+ } else if (os_strcmp(buf, "check_crl") == 0) {
+ bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "dh_file") == 0) {
+ os_free(bss->dh_file);
+ bss->dh_file = os_strdup(pos);
+#ifdef EAP_FAST
+ } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
+ os_free(bss->pac_opaque_encr_key);
+ bss->pac_opaque_encr_key = os_malloc(16);
+ if (bss->pac_opaque_encr_key == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: No memory for "
+ "pac_opaque_encr_key", line);
+ errors++;
+ } else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
+ 16)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "pac_opaque_encr_key", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
+ size_t idlen = os_strlen(pos);
+ if (idlen & 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "eap_fast_a_id", line);
+ errors++;
+ } else {
+ os_free(bss->eap_fast_a_id);
+ bss->eap_fast_a_id = os_malloc(idlen / 2);
+ if (bss->eap_fast_a_id == NULL ||
+ hexstr2bin(pos, bss->eap_fast_a_id,
+ idlen / 2)) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "Failed to parse "
+ "eap_fast_a_id", line);
+ errors++;
+ } else
+ bss->eap_fast_a_id_len = idlen / 2;
+ }
+ } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
+ os_free(bss->eap_fast_a_id_info);
+ bss->eap_fast_a_id_info = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
+ bss->eap_fast_prov = atoi(pos);
+ } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
+ bss->pac_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
+ bss->pac_key_refresh_time = atoi(pos);
+#endif /* EAP_FAST */
+#ifdef EAP_SIM
+ } else if (os_strcmp(buf, "eap_sim_db") == 0) {
+ os_free(bss->eap_sim_db);
+ bss->eap_sim_db = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
+ bss->eap_sim_aka_result_ind = atoi(pos);
+#endif /* EAP_SIM */
+#ifdef EAP_TNC
+ } else if (os_strcmp(buf, "tnc") == 0) {
+ bss->tnc = atoi(pos);
+#endif /* EAP_TNC */
+#endif /* EAP_SERVER */
+ } else if (os_strcmp(buf, "eap_message") == 0) {
+ char *term;
+ bss->eap_req_id_text = os_strdup(pos);
+ if (bss->eap_req_id_text == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to "
+ "allocate memory for "
+ "eap_req_id_text", line);
+ errors++;
+ continue;
+ }
+ bss->eap_req_id_text_len =
+ os_strlen(bss->eap_req_id_text);
+ term = os_strstr(bss->eap_req_id_text, "\\0");
+ if (term) {
+ *term++ = '\0';
+ os_memmove(term, term + 1,
+ bss->eap_req_id_text_len -
+ (term - bss->eap_req_id_text) - 1);
+ bss->eap_req_id_text_len--;
+ }
+ } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
+ bss->default_wep_key_len = atoi(pos);
+ if (bss->default_wep_key_len > 13) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+ "key len %lu (= %lu bits)", line,
+ (unsigned long)
+ bss->default_wep_key_len,
+ (unsigned long)
+ bss->default_wep_key_len * 8);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
+ bss->individual_wep_key_len = atoi(pos);
+ if (bss->individual_wep_key_len < 0 ||
+ bss->individual_wep_key_len > 13) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+ "key len %d (= %d bits)", line,
+ bss->individual_wep_key_len,
+ bss->individual_wep_key_len * 8);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wep_rekey_period") == 0) {
+ bss->wep_rekeying_period = atoi(pos);
+ if (bss->wep_rekeying_period < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "period %d",
+ line, bss->wep_rekeying_period);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
+ bss->eap_reauth_period = atoi(pos);
+ if (bss->eap_reauth_period < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "period %d",
+ line, bss->eap_reauth_period);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
+ bss->eapol_key_index_workaround = atoi(pos);
+#ifdef CONFIG_IAPP
+ } else if (os_strcmp(buf, "iapp_interface") == 0) {
+ bss->ieee802_11f = 1;
+ os_strlcpy(bss->iapp_iface, pos,
+ sizeof(bss->iapp_iface));
+#endif /* CONFIG_IAPP */
+ } else if (os_strcmp(buf, "own_ip_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+ "address '%s'", line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "nas_identifier") == 0) {
+ bss->nas_identifier = os_strdup(pos);
+ } else if (os_strcmp(buf, "auth_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &bss->radius->auth_servers,
+ &bss->radius->num_auth_servers, pos, 1812,
+ &bss->radius->auth_server)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+ "address '%s'", line, pos);
+ errors++;
+ }
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_port") == 0) {
+ bss->radius->auth_server->port = atoi(pos);
+ } else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_shared_secret") == 0) {
+ int len = os_strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ wpa_printf(MSG_ERROR, "Line %d: empty shared "
+ "secret is not allowed.", line);
+ errors++;
+ }
+ bss->radius->auth_server->shared_secret =
+ (u8 *) os_strdup(pos);
+ bss->radius->auth_server->shared_secret_len = len;
+ } else if (os_strcmp(buf, "acct_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &bss->radius->acct_servers,
+ &bss->radius->num_acct_servers, pos, 1813,
+ &bss->radius->acct_server)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+ "address '%s'", line, pos);
+ errors++;
+ }
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_port") == 0) {
+ bss->radius->acct_server->port = atoi(pos);
+ } else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_shared_secret") == 0) {
+ int len = os_strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ wpa_printf(MSG_ERROR, "Line %d: empty shared "
+ "secret is not allowed.", line);
+ errors++;
+ }
+ bss->radius->acct_server->shared_secret =
+ (u8 *) os_strdup(pos);
+ bss->radius->acct_server->shared_secret_len = len;
+ } else if (os_strcmp(buf, "radius_retry_primary_interval") ==
+ 0) {
+ bss->radius->retry_primary_interval = atoi(pos);
+ } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
+ {
+ bss->radius->acct_interim_interval = atoi(pos);
+ } else if (os_strcmp(buf, "auth_algs") == 0) {
+ bss->auth_algs = atoi(pos);
+ if (bss->auth_algs == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no "
+ "authentication algorithms allowed",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "max_num_sta") == 0) {
+ bss->max_num_sta = atoi(pos);
+ if (bss->max_num_sta < 0 ||
+ bss->max_num_sta > MAX_STA_COUNT) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "max_num_sta=%d; allowed range "
+ "0..%d", line, bss->max_num_sta,
+ MAX_STA_COUNT);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wpa") == 0) {
+ bss->wpa = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
+ bss->wpa_group_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
+ bss->wpa_strict_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
+ bss->wpa_gmk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
+ bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
+ int len = os_strlen(pos);
+ if (len < 8 || len > 63) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
+ "passphrase length %d (expected "
+ "8..63)", line, len);
+ errors++;
+ } else {
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = os_strdup(pos);
+ }
+ } else if (os_strcmp(buf, "wpa_psk") == 0) {
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk == NULL)
+ errors++;
+ else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+ PMK_LEN) ||
+ pos[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
+ "'%s'.", line, pos);
+ errors++;
+ } else {
+ bss->ssid.wpa_psk->group = 1;
+ }
+ } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
+ os_free(bss->ssid.wpa_psk_file);
+ bss->ssid.wpa_psk_file = os_strdup(pos);
+ if (!bss->ssid.wpa_psk_file) {
+ wpa_printf(MSG_ERROR, "Line %d: allocation "
+ "failed", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
+ bss->wpa_key_mgmt =
+ hostapd_config_parse_key_mgmt(line, pos);
+ if (bss->wpa_key_mgmt == -1)
+ errors++;
+ } else if (os_strcmp(buf, "wpa_pairwise") == 0) {
+ bss->wpa_pairwise =
+ hostapd_config_parse_cipher(line, pos);
+ if (bss->wpa_pairwise == -1 ||
+ bss->wpa_pairwise == 0)
+ errors++;
+ else if (bss->wpa_pairwise &
+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104)) {
+ wpa_printf(MSG_ERROR, "Line %d: unsupported "
+ "pairwise cipher suite '%s'",
+ bss->wpa_pairwise, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "rsn_pairwise") == 0) {
+ bss->rsn_pairwise =
+ hostapd_config_parse_cipher(line, pos);
+ if (bss->rsn_pairwise == -1 ||
+ bss->rsn_pairwise == 0)
+ errors++;
+ else if (bss->rsn_pairwise &
+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104)) {
+ wpa_printf(MSG_ERROR, "Line %d: unsupported "
+ "pairwise cipher suite '%s'",
+ bss->rsn_pairwise, pos);
+ errors++;
+ }
+#ifdef CONFIG_RSN_PREAUTH
+ } else if (os_strcmp(buf, "rsn_preauth") == 0) {
+ bss->rsn_preauth = atoi(pos);
+ } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
+ bss->rsn_preauth_interfaces = os_strdup(pos);
+#endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+ } else if (os_strcmp(buf, "peerkey") == 0) {
+ bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+ } else if (os_strcmp(buf, "mobility_domain") == 0) {
+ if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
+ hexstr2bin(pos, bss->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "mobility_domain '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "r1_key_holder") == 0) {
+ if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
+ hexstr2bin(pos, bss->r1_key_holder,
+ FT_R1KH_ID_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "r1_key_holder '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+ bss->r0_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "reassociation_deadline") == 0) {
+ bss->reassociation_deadline = atoi(pos);
+ } else if (os_strcmp(buf, "r0kh") == 0) {
+ if (add_r0kh(bss, pos) < 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "r0kh '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "r1kh") == 0) {
+ if (add_r1kh(bss, pos) < 0) {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+ "r1kh '%s'", line, pos);
+ errors++;
+ continue;
+ }
+ } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
+ bss->pmk_r1_push = atoi(pos);
+#endif /* CONFIG_IEEE80211R */
+ } else if (os_strcmp(buf, "ctrl_interface") == 0) {
+ os_free(bss->ctrl_interface);
+ bss->ctrl_interface = os_strdup(pos);
+ } else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
+ struct group *grp;
+ char *endp;
+ const char *group = pos;
+
+ grp = getgrnam(group);
+ if (grp) {
+ bss->ctrl_interface_gid = grp->gr_gid;
+ bss->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ bss->ctrl_interface_gid, group);
+ continue;
+ }
+
+ /* Group name not found - try to parse this as gid */
+ bss->ctrl_interface_gid = strtol(group, &endp, 10);
+ if (*group == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+ "'%s'", line, group);
+ errors++;
+ continue;
+ }
+ bss->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
+#ifdef RADIUS_SERVER
+ } else if (os_strcmp(buf, "radius_server_clients") == 0) {
+ os_free(bss->radius_server_clients);
+ bss->radius_server_clients = os_strdup(pos);
+ } else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
+ bss->radius_server_auth_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
+ bss->radius_server_ipv6 = atoi(pos);
+#endif /* RADIUS_SERVER */
+ } else if (os_strcmp(buf, "test_socket") == 0) {
+ os_free(bss->test_socket);
+ bss->test_socket = os_strdup(pos);
+ } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
+ bss->use_pae_group_addr = atoi(pos);
+ } else if (os_strcmp(buf, "hw_mode") == 0) {
+ if (os_strcmp(pos, "a") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ else if (os_strcmp(pos, "b") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ else if (os_strcmp(pos, "g") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: unknown "
+ "hw_mode '%s'", line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "channel") == 0) {
+ conf->channel = atoi(pos);
+ } else if (os_strcmp(buf, "beacon_int") == 0) {
+ int val = atoi(pos);
+ /* MIB defines range as 1..65535, but very small values
+ * cause problems with the current implementation.
+ * Since it is unlikely that this small numbers are
+ * useful in real life scenarios, do not allow beacon
+ * period to be set below 15 TU. */
+ if (val < 15 || val > 65535) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "beacon_int %d (expected "
+ "15..65535)", line, val);
+ errors++;
+ } else
+ conf->beacon_int = val;
+ } else if (os_strcmp(buf, "dtim_period") == 0) {
+ bss->dtim_period = atoi(pos);
+ if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "dtim_period %d",
+ line, bss->dtim_period);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "rts_threshold") == 0) {
+ conf->rts_threshold = atoi(pos);
+ if (conf->rts_threshold < 0 ||
+ conf->rts_threshold > 2347) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "rts_threshold %d",
+ line, conf->rts_threshold);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "fragm_threshold") == 0) {
+ conf->fragm_threshold = atoi(pos);
+ if (conf->fragm_threshold < 256 ||
+ conf->fragm_threshold > 2346) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "fragm_threshold %d",
+ line, conf->fragm_threshold);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "send_probe_response") == 0) {
+ int val = atoi(pos);
+ if (val != 0 && val != 1) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "send_probe_response %d (expected "
+ "0 or 1)", line, val);
+ } else
+ conf->send_probe_response = val;
+ } else if (os_strcmp(buf, "supported_rates") == 0) {
+ if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+ "list", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "basic_rates") == 0) {
+ if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+ "list", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "preamble") == 0) {
+ if (atoi(pos))
+ conf->preamble = SHORT_PREAMBLE;
+ else
+ conf->preamble = LONG_PREAMBLE;
+ } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
+ bss->ignore_broadcast_ssid = atoi(pos);
+ } else if (os_strcmp(buf, "bridge_packets") == 0) {
+ conf->bridge_packets = atoi(pos);
+ } else if (os_strcmp(buf, "wep_default_key") == 0) {
+ bss->ssid.wep.idx = atoi(pos);
+ if (bss->ssid.wep.idx > 3) {
+ wpa_printf(MSG_ERROR, "Invalid "
+ "wep_default_key index %d",
+ bss->ssid.wep.idx);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wep_key0") == 0 ||
+ os_strcmp(buf, "wep_key1") == 0 ||
+ os_strcmp(buf, "wep_key2") == 0 ||
+ os_strcmp(buf, "wep_key3") == 0) {
+ if (hostapd_config_read_wep(&bss->ssid.wep,
+ buf[7] - '0', pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+ "key '%s'", line, buf);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
+ bss->ssid.dynamic_vlan = atoi(pos);
+ } else if (os_strcmp(buf, "vlan_file") == 0) {
+ if (hostapd_config_read_vlan_file(bss, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "read VLAN file '%s'", line, pos);
+ errors++;
+ }
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
+ bss->ssid.vlan_tagged_interface = os_strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ } else if (os_strcmp(buf, "passive_scan_interval") == 0) {
+ conf->passive_scan_interval = atoi(pos);
+ } else if (os_strcmp(buf, "passive_scan_listen") == 0) {
+ conf->passive_scan_listen = atoi(pos);
+ } else if (os_strcmp(buf, "passive_scan_mode") == 0) {
+ conf->passive_scan_mode = atoi(pos);
+ } else if (os_strcmp(buf, "ap_table_max_size") == 0) {
+ conf->ap_table_max_size = atoi(pos);
+ } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
+ conf->ap_table_expiration_time = atoi(pos);
+ } else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
+ if (hostapd_config_tx_queue(conf, buf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid TX "
+ "queue item", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wme_enabled") == 0) {
+ bss->wme_enabled = atoi(pos);
+ } else if (os_strncmp(buf, "wme_ac_", 7) == 0) {
+ if (hostapd_config_wme_ac(conf, buf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid wme "
+ "ac item", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "bss") == 0) {
+ if (hostapd_config_bss(conf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid bss "
+ "item", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "bssid") == 0) {
+ if (bss == conf->bss &&
+ (!conf->driver || !conf->driver->init_bssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: bssid item "
+ "not allowed for the default "
+ "interface and this driver", line);
+ errors++;
+ } else if (hwaddr_aton(pos, bss->bssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
+ "item", line);
+ errors++;
+ }
+#ifdef CONFIG_IEEE80211W
+ } else if (os_strcmp(buf, "ieee80211w") == 0) {
+ bss->ieee80211w = atoi(pos);
+ } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
+ bss->assoc_sa_query_max_timeout = atoi(pos);
+ if (bss->assoc_sa_query_max_timeout == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "assoc_sa_query_max_timeout", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
+ {
+ bss->assoc_sa_query_retry_timeout = atoi(pos);
+ if (bss->assoc_sa_query_retry_timeout == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "assoc_sa_query_retry_timeout",
+ line);
+ errors++;
+ }
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211N
+ } else if (os_strcmp(buf, "ieee80211n") == 0) {
+ conf->ieee80211n = atoi(pos);
+ } else if (os_strcmp(buf, "ht_capab") == 0) {
+ if (hostapd_config_ht_capab(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "ht_capab", line);
+ errors++;
+ }
+#endif /* CONFIG_IEEE80211N */
+ } else if (os_strcmp(buf, "max_listen_interval") == 0) {
+ bss->max_listen_interval = atoi(pos);
+ } else if (os_strcmp(buf, "okc") == 0) {
+ bss->okc = atoi(pos);
+#ifdef CONFIG_WPS
+ } else if (os_strcmp(buf, "wps_state") == 0) {
+ bss->wps_state = atoi(pos);
+ if (bss->wps_state < 0 || bss->wps_state > 2) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "wps_state", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
+ bss->ap_setup_locked = atoi(pos);
+ } else if (os_strcmp(buf, "uuid") == 0) {
+ if (uuid_str2bin(pos, bss->uuid)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
+ os_free(bss->wps_pin_requests);
+ bss->wps_pin_requests = os_strdup(pos);
+ } else if (os_strcmp(buf, "device_name") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long "
+ "device_name", line);
+ errors++;
+ }
+ os_free(bss->device_name);
+ bss->device_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "manufacturer") == 0) {
+ if (os_strlen(pos) > 64) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long "
+ "manufacturer", line);
+ errors++;
+ }
+ os_free(bss->manufacturer);
+ bss->manufacturer = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_name") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long "
+ "model_name", line);
+ errors++;
+ }
+ os_free(bss->model_name);
+ bss->model_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_number") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long "
+ "model_number", line);
+ errors++;
+ }
+ os_free(bss->model_number);
+ bss->model_number = os_strdup(pos);
+ } else if (os_strcmp(buf, "serial_number") == 0) {
+ if (os_strlen(pos) > 32) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long "
+ "serial_number", line);
+ errors++;
+ }
+ os_free(bss->serial_number);
+ bss->serial_number = os_strdup(pos);
+ } else if (os_strcmp(buf, "device_type") == 0) {
+ os_free(bss->device_type);
+ bss->device_type = os_strdup(pos);
+ } else if (os_strcmp(buf, "config_methods") == 0) {
+ os_free(bss->config_methods);
+ bss->config_methods = os_strdup(pos);
+ } else if (os_strcmp(buf, "os_version") == 0) {
+ if (hexstr2bin(pos, bss->os_version, 4)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "os_version", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ap_pin") == 0) {
+ os_free(bss->ap_pin);
+ bss->ap_pin = os_strdup(pos);
+ } else if (os_strcmp(buf, "skip_cred_build") == 0) {
+ bss->skip_cred_build = atoi(pos);
+ } else if (os_strcmp(buf, "extra_cred") == 0) {
+ os_free(bss->extra_cred);
+ bss->extra_cred =
+ (u8 *) os_readfile(pos, &bss->extra_cred_len);
+ if (bss->extra_cred == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: could not "
+ "read Credentials from '%s'",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wps_cred_processing") == 0) {
+ bss->wps_cred_processing = atoi(pos);
+ } else if (os_strcmp(buf, "ap_settings") == 0) {
+ os_free(bss->ap_settings);
+ bss->ap_settings =
+ (u8 *) os_readfile(pos, &bss->ap_settings_len);
+ if (bss->ap_settings == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: could not "
+ "read AP Settings from '%s'",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "upnp_iface") == 0) {
+ bss->upnp_iface = os_strdup(pos);
+ } else if (os_strcmp(buf, "friendly_name") == 0) {
+ os_free(bss->friendly_name);
+ bss->friendly_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "manufacturer_url") == 0) {
+ os_free(bss->manufacturer_url);
+ bss->manufacturer_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_description") == 0) {
+ os_free(bss->model_description);
+ bss->model_description = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_url") == 0) {
+ os_free(bss->model_url);
+ bss->model_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "upc") == 0) {
+ os_free(bss->upc);
+ bss->upc = os_strdup(pos);
+#endif /* CONFIG_WPS */
+ } else {
+ wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
+ "item '%s'", line, buf);
+ errors++;
+ }
+ }
+
+ fclose(f);
+
+ if (bss->individual_wep_key_len == 0) {
+ /* individual keys are not use; can use key idx0 for broadcast
+ * keys */
+ bss->broadcast_key_idx_min = 0;
+ }
+
+ /* Select group cipher based on the enabled pairwise cipher suites */
+ pairwise = 0;
+ if (bss->wpa & 1)
+ pairwise |= bss->wpa_pairwise;
+ if (bss->wpa & 2) {
+ if (bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ pairwise |= bss->rsn_pairwise;
+ }
+ if (pairwise & WPA_CIPHER_TKIP)
+ bss->wpa_group = WPA_CIPHER_TKIP;
+ else
+ bss->wpa_group = WPA_CIPHER_CCMP;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ bss = &conf->bss[i];
+
+ bss->radius->auth_server = bss->radius->auth_servers;
+ bss->radius->acct_server = bss->radius->acct_servers;
+
+ if (bss->wpa && bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_WPA;
+ } else if (bss->wpa) {
+ bss->ssid.security_policy = SECURITY_WPA_PSK;
+ } else if (bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+ bss->ssid.wep.default_len = bss->default_wep_key_len;
+ } else if (bss->ssid.wep.keys_set)
+ bss->ssid.security_policy = SECURITY_STATIC_WEP;
+ else
+ bss->ssid.security_policy = SECURITY_PLAINTEXT;
+ }
+
+ if (hostapd_config_check(conf))
+ errors++;
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d errors found in configuration file "
+ "'%s'", errors, fname);
+ hostapd_config_free(conf);
+ conf = NULL;
+ }
+
+ return conf;
+}
+
+
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
+{
+ int i;
+
+ if (a->idx != b->idx || a->default_len != b->default_len)
+ return 1;
+ for (i = 0; i < NUM_WEP_KEYS; i++)
+ if (a->len[i] != b->len[i] ||
+ os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
+ return 1;
+ return 0;
+}
+
+
+static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
+ int num_servers)
+{
+ int i;
+
+ for (i = 0; i < num_servers; i++) {
+ os_free(servers[i].shared_secret);
+ }
+ os_free(servers);
+}
+
+
+static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+{
+ os_free(user->identity);
+ os_free(user->password);
+ os_free(user);
+}
+
+
+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
+{
+ int i;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ os_free(keys->key[i]);
+ keys->key[i] = NULL;
+ }
+}
+
+
+static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+{
+ struct hostapd_wpa_psk *psk, *prev;
+ struct hostapd_eap_user *user, *prev_user;
+
+ if (conf == NULL)
+ return;
+
+ psk = conf->ssid.wpa_psk;
+ while (psk) {
+ prev = psk;
+ psk = psk->next;
+ os_free(prev);
+ }
+
+ os_free(conf->ssid.wpa_passphrase);
+ os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ os_free(conf->ssid.vlan_tagged_interface);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+ user = conf->eap_user;
+ while (user) {
+ prev_user = user;
+ user = user->next;
+ hostapd_config_free_eap_user(prev_user);
+ }
+
+ os_free(conf->dump_log_name);
+ os_free(conf->eap_req_id_text);
+ os_free(conf->accept_mac);
+ os_free(conf->deny_mac);
+ os_free(conf->nas_identifier);
+ hostapd_config_free_radius(conf->radius->auth_servers,
+ conf->radius->num_auth_servers);
+ hostapd_config_free_radius(conf->radius->acct_servers,
+ conf->radius->num_acct_servers);
+ os_free(conf->rsn_preauth_interfaces);
+ os_free(conf->ctrl_interface);
+ os_free(conf->ca_cert);
+ os_free(conf->server_cert);
+ os_free(conf->private_key);
+ os_free(conf->private_key_passwd);
+ os_free(conf->dh_file);
+ os_free(conf->pac_opaque_encr_key);
+ os_free(conf->eap_fast_a_id);
+ os_free(conf->eap_fast_a_id_info);
+ os_free(conf->eap_sim_db);
+ os_free(conf->radius_server_clients);
+ os_free(conf->test_socket);
+ os_free(conf->radius);
+ hostapd_config_free_vlan(conf);
+ if (conf->ssid.dyn_vlan_keys) {
+ struct hostapd_ssid *ssid = &conf->ssid;
+ size_t i;
+ for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+ if (ssid->dyn_vlan_keys[i] == NULL)
+ continue;
+ hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
+ os_free(ssid->dyn_vlan_keys[i]);
+ }
+ os_free(ssid->dyn_vlan_keys);
+ ssid->dyn_vlan_keys = NULL;
+ }
+
+#ifdef CONFIG_IEEE80211R
+ {
+ struct ft_remote_r0kh *r0kh, *r0kh_prev;
+ struct ft_remote_r1kh *r1kh, *r1kh_prev;
+
+ r0kh = conf->r0kh_list;
+ conf->r0kh_list = NULL;
+ while (r0kh) {
+ r0kh_prev = r0kh;
+ r0kh = r0kh->next;
+ os_free(r0kh_prev);
+ }
+
+ r1kh = conf->r1kh_list;
+ conf->r1kh_list = NULL;
+ while (r1kh) {
+ r1kh_prev = r1kh;
+ r1kh = r1kh->next;
+ os_free(r1kh_prev);
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_WPS
+ os_free(conf->wps_pin_requests);
+ os_free(conf->device_name);
+ os_free(conf->manufacturer);
+ os_free(conf->model_name);
+ os_free(conf->model_number);
+ os_free(conf->serial_number);
+ os_free(conf->device_type);
+ os_free(conf->config_methods);
+ os_free(conf->ap_pin);
+ os_free(conf->extra_cred);
+ os_free(conf->ap_settings);
+ os_free(conf->upnp_iface);
+ os_free(conf->friendly_name);
+ os_free(conf->manufacturer_url);
+ os_free(conf->model_description);
+ os_free(conf->model_url);
+ os_free(conf->upc);
+#endif /* CONFIG_WPS */
+}
+
+
+/**
+ * hostapd_config_free - Free hostapd configuration
+ * @conf: Configuration data from hostapd_config_read().
+ */
+void hostapd_config_free(struct hostapd_config *conf)
+{
+ size_t i;
+
+ if (conf == NULL)
+ return;
+
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_config_free_bss(&conf->bss[i]);
+ os_free(conf->bss);
+
+ os_free(conf);
+}
+
+
+/**
+ * hostapd_maclist_found - Find a MAC address from a list
+ * @list: MAC address list
+ * @num_entries: Number of addresses in the list
+ * @addr: Address to search for
+ * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
+ * Returns: 1 if address is in the list or 0 if not.
+ *
+ * Perform a binary search for given MAC address from a pre-sorted list.
+ */
+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
+ const u8 *addr, int *vlan_id)
+{
+ int start, end, middle, res;
+
+ start = 0;
+ end = num_entries - 1;
+
+ while (start <= end) {
+ middle = (start + end) / 2;
+ res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
+ if (res == 0) {
+ if (vlan_id)
+ *vlan_id = list[middle].vlan_id;
+ return 1;
+ }
+ if (res < 0)
+ start = middle + 1;
+ else
+ end = middle - 1;
+ }
+
+ return 0;
+}
+
+
+int hostapd_rate_found(int *list, int rate)
+{
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0; list[i] >= 0; i++)
+ if (list[i] == rate)
+ return 1;
+
+ return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+ struct hostapd_vlan *v = vlan;
+ while (v) {
+ if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ return v->ifname;
+ v = v->next;
+ }
+ return NULL;
+}
+
+
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+ const u8 *addr, const u8 *prev_psk)
+{
+ struct hostapd_wpa_psk *psk;
+ int next_ok = prev_psk == NULL;
+
+ for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
+ if (next_ok &&
+ (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
+ return psk->psk;
+
+ if (psk->psk == prev_psk)
+ next_ok = 1;
+ }
+
+ return NULL;
+}
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+ if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+ static struct hostapd_eap_user wsc_enrollee;
+ os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+ wsc_enrollee.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_enrollee.methods[0].vendor);
+ return &wsc_enrollee;
+ }
+
+ if (conf->wps_state && conf->ap_pin &&
+ identity_len == WSC_ID_REGISTRAR_LEN &&
+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+ static struct hostapd_eap_user wsc_registrar;
+ os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+ wsc_registrar.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_registrar.methods[0].vendor);
+ wsc_registrar.password = (u8 *) conf->ap_pin;
+ wsc_registrar.password_len = os_strlen(conf->ap_pin);
+ return &wsc_registrar;
+ }
+#endif /* CONFIG_WPS */
+
+ while (user) {
+ if (!phase2 && user->identity == NULL) {
+ /* Wildcard match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+ identity_len >= user->identity_len &&
+ os_memcmp(user->identity, identity, user->identity_len) ==
+ 0) {
+ /* Wildcard prefix match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 &&
+ user->identity_len == identity_len &&
+ os_memcmp(user->identity, identity, identity_len) == 0)
+ break;
+ user = user->next;
+ }
+
+ return user;
+}
diff --git a/contrib/wpa/hostapd/config.h b/contrib/wpa/hostapd/config.h
new file mode 100644
index 0000000..a3247f2
--- /dev/null
+++ b/contrib/wpa/hostapd/config.h
@@ -0,0 +1,415 @@
+/*
+ * hostapd / Configuration file
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#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 mac_acl_entry {
+ macaddr addr;
+ int vlan_id;
+};
+
+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 */
+
+ enum {
+ ACCEPT_UNLESS_DENIED = 0,
+ DENY_UNLESS_ACCEPTED = 1,
+ USE_EXTERNAL_RADIUS_AUTH = 2
+ } macaddr_acl;
+ struct mac_acl_entry *accept_mac;
+ int num_accept_mac;
+ struct mac_acl_entry *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;
+ /* dot11AssociationSAQueryMaximumTimeout (in TUs) */
+ unsigned int assoc_sa_query_max_timeout;
+ /* dot11AssociationSAQueryRetryTimeout (in TUs) */
+ int assoc_sa_query_retry_timeout;
+#endif /* CONFIG_IEEE80211W */
+ int wpa_pairwise;
+ int wpa_group;
+ int wpa_group_rekey;
+ int wpa_strict_rekey;
+ int wpa_gmk_rekey;
+ int wpa_ptk_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;
+ u8 *eap_fast_a_id;
+ size_t eap_fast_a_id_len;
+ char *eap_fast_a_id_info;
+ int eap_fast_prov;
+ int pac_key_lifetime;
+ int pac_key_refresh_time;
+ int eap_sim_aka_result_ind;
+ int tnc;
+
+ 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;
+
+ /*
+ * Maximum listen interval that STAs can use when associating with this
+ * BSS. If a STA tries to use larger value, the association will be
+ * denied with status code 51.
+ */
+ u16 max_listen_interval;
+
+ int okc; /* Opportunistic Key Caching */
+
+ int wps_state;
+#ifdef CONFIG_WPS
+ int ap_setup_locked;
+ u8 uuid[16];
+ char *wps_pin_requests;
+ char *device_name;
+ char *manufacturer;
+ char *model_name;
+ char *model_number;
+ char *serial_number;
+ char *device_type;
+ char *config_methods;
+ u8 os_version[4];
+ char *ap_pin;
+ int skip_cred_build;
+ u8 *extra_cred;
+ size_t extra_cred_len;
+ int wps_cred_processing;
+ u8 *ap_settings;
+ size_t ap_settings_len;
+ char *upnp_iface;
+ char *friendly_name;
+ char *manufacturer_url;
+ char *model_description;
+ char *model_url;
+ char *upc;
+#endif /* CONFIG_WPS */
+};
+
+
+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;
+ 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;
+
+ 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;
+
+#ifdef CONFIG_IEEE80211N
+ int ht_op_mode_fixed;
+ u16 ht_capab;
+#endif /* CONFIG_IEEE80211N */
+ int ieee80211n;
+ int secondary_channel;
+};
+
+
+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(struct mac_acl_entry *list, int num_entries,
+ const u8 *addr, int *vlan_id);
+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 */
diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c
new file mode 100644
index 0000000..fe63e7c
--- /dev/null
+++ b/contrib/wpa/hostapd/ctrl_iface.c
@@ -0,0 +1,560 @@
+/*
+ * 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"
+#include "wps_hostapd.h"
+
+
+struct wpa_ctrl_dst {
+ struct wpa_ctrl_dst *next;
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ const char *buf, size_t len);
+
+
+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);
+ return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+ ieee802_11_send_sa_query_req(hapd, addr, trans_id);
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
+{
+ char *pin = os_strchr(txt, ' ');
+ if (pin == NULL)
+ return -1;
+ *pin++ = '\0';
+ return hostapd_wps_add_pin(hapd, txt, pin);
+}
+#endif /* CONFIG_WPS */
+
+
+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;
+#ifdef CONFIG_IEEE80211W
+ } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
+ if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
+ reply_len = -1;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+ } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+ if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "WPS_PBC") == 0) {
+ if (hostapd_wps_button_pushed(hapd))
+ reply_len = -1;
+#endif /* CONFIG_WPS */
+ } 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;
+}
+
+
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+ const char *txt, size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ if (hapd == NULL)
+ return;
+ hostapd_ctrl_iface_send(hapd, level, txt, len);
+}
+
+
+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);
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+ 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);
+ }
+}
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ const 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 = (char *) 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 */
diff --git a/contrib/wpa/hostapd/ctrl_iface.h b/contrib/wpa/hostapd/ctrl_iface.h
new file mode 100644
index 0000000..d86de8c
--- /dev/null
+++ b/contrib/wpa/hostapd/ctrl_iface.h
@@ -0,0 +1,21 @@
+/*
+ * 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);
+
+#endif /* CTRL_IFACE_H */
diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig
new file mode 100644
index 0000000..96a023d
--- /dev/null
+++ b/contrib/wpa/hostapd/defconfig
@@ -0,0 +1,144 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for 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 (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+#CONFIG_IEEE80211N=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
diff --git a/contrib/wpa/hostapd/doc/.gitignore b/contrib/wpa/hostapd/doc/.gitignore
new file mode 100644
index 0000000..987a5e9
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/.gitignore
@@ -0,0 +1,4 @@
+html
+latex
+hostapd.eps
+hostapd.png
diff --git a/contrib/wpa/hostapd/doc/code_structure.doxygen b/contrib/wpa/hostapd/doc/code_structure.doxygen
new file mode 100644
index 0000000..fdcf725
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/code_structure.doxygen
@@ -0,0 +1,5 @@
+/**
+\page code_structure Structure of the source code
+
+
+*/
diff --git a/contrib/wpa/hostapd/doc/ctrl_iface.doxygen b/contrib/wpa/hostapd/doc/ctrl_iface.doxygen
new file mode 100644
index 0000000..76cfc6a
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/ctrl_iface.doxygen
@@ -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.
+
+*/
diff --git a/contrib/wpa/hostapd/doc/doxygen.fast b/contrib/wpa/hostapd/doc/doxygen.fast
new file mode 100644
index 0000000..650c73d
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/doxygen.fast
@@ -0,0 +1,238 @@
+# Doxyfile 1.4.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = hostapd
+PROJECT_NUMBER = 0.6.x
+OUTPUT_DIRECTORY = hostapd/doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+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 = YES
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = hostapd \
+ src/common \
+ src/crypto \
+ src/eap_common \
+ src/eap_server \
+ src/l2_packet \
+ src/radius \
+ src/rsn_supp \
+ src/tls \
+ src/utils \
+ src/wps
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = hostapd/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 = 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_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/contrib/wpa/hostapd/doc/doxygen.full b/contrib/wpa/hostapd/doc/doxygen.full
new file mode 100644
index 0000000..f8c49bf
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/doxygen.full
@@ -0,0 +1,238 @@
+# Doxyfile 1.4.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = hostapd
+PROJECT_NUMBER = 0.6.x
+OUTPUT_DIRECTORY = hostapd/doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+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 = YES
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = hostapd \
+ src/common \
+ src/crypto \
+ src/eap_common \
+ src/eap_server \
+ src/l2_packet \
+ src/radius \
+ src/rsn_supp \
+ src/tls \
+ src/utils \
+ src/wps
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = hostapd/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_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = YES
diff --git a/contrib/wpa/hostapd/doc/driver_wrapper.doxygen b/contrib/wpa/hostapd/doc/driver_wrapper.doxygen
new file mode 100644
index 0000000..0ad196f
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/driver_wrapper.doxygen
@@ -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.
+
+*/
diff --git a/contrib/wpa/hostapd/doc/eap.doxygen b/contrib/wpa/hostapd/doc/eap.doxygen
new file mode 100644
index 0000000..f0f135a
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/eap.doxygen
@@ -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.
+
+*/
diff --git a/contrib/wpa/hostapd/doc/hostapd.fig b/contrib/wpa/hostapd/doc/hostapd.fig
new file mode 100644
index 0000000..af3f0be
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/hostapd.fig
@@ -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
diff --git a/contrib/wpa/hostapd/doc/kerneldoc2doxygen.pl b/contrib/wpa/hostapd/doc/kerneldoc2doxygen.pl
new file mode 100755
index 0000000..68835a1
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/kerneldoc2doxygen.pl
@@ -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 $_;
+
diff --git a/contrib/wpa/hostapd/doc/mainpage.doxygen b/contrib/wpa/hostapd/doc/mainpage.doxygen
new file mode 100644
index 0000000..7cf95de
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/mainpage.doxygen
@@ -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
+
+*/
diff --git a/contrib/wpa/hostapd/doc/porting.doxygen b/contrib/wpa/hostapd/doc/porting.doxygen
new file mode 100644
index 0000000..0621791
--- /dev/null
+++ b/contrib/wpa/hostapd/doc/porting.doxygen
@@ -0,0 +1,5 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+
+*/
diff --git a/contrib/wpa/hostapd/driver.h b/contrib/wpa/hostapd/driver.h
new file mode 100644
index 0000000..45f5460
--- /dev/null
+++ b/contrib/wpa/hostapd/driver.h
@@ -0,0 +1,798 @@
+/*
+ * hostapd - driver interface definition
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+struct hostapd_sta_add_params {
+ const u8 *addr;
+ u16 aid;
+ u16 capability;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ int flags;
+ u16 listen_interval;
+ const struct ht_cap_ie *ht_capabilities;
+};
+
+struct hostapd_freq_params {
+ int mode;
+ int freq;
+ int ht_enabled;
+ int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+ * secondary channel below primary, 1 = HT40
+ * enabled, secondary channel above primary */
+};
+
+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);
+ /* note: sta_add() is deprecated; use sta_add2() instead */
+ 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, u16 listen_interval);
+ int (*sta_add2)(const char *ifname, void *priv,
+ struct hostapd_sta_add_params *params);
+ int (*get_inact_sec)(void *priv, const u8 *addr);
+ int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+ /* note: set_freq() is deprecated; use set_freq2() instead */
+ int (*set_freq)(void *priv, int mode, int freq);
+ int (*set_freq2)(void *priv, struct hostapd_freq_params *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_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);
+
+ int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
+ u32 session_timeout);
+ int (*set_radius_acl_expire)(void *priv, const u8 *mac);
+
+ int (*set_ht_params)(const char *ifname, void *priv,
+ const u8 *ht_capab, size_t ht_capab_len,
+ const u8 *ht_oper, size_t ht_oper_len);
+
+ int (*set_wps_beacon_ie)(const char *ifname, void *priv,
+ const u8 *ie, size_t len);
+ int (*set_wps_probe_resp_ie)(const char *ifname, void *priv,
+ const u8 *ie, size_t 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, const u8 *supp_rates,
+ size_t supp_rates_len, int flags, u16 listen_interval,
+ const struct ht_cap_ie *ht_capabilities)
+{
+ if (hapd->driver == NULL)
+ return 0;
+
+ if (hapd->driver->sta_add2) {
+ struct hostapd_sta_add_params params;
+ os_memset(&params, 0, sizeof(params));
+ params.addr = addr;
+ params.aid = aid;
+ params.capability = capability;
+ params.supp_rates = supp_rates;
+ params.supp_rates_len = supp_rates_len;
+ params.flags = flags;
+ params.listen_interval = listen_interval;
+ params.ht_capabilities = ht_capabilities;
+ return hapd->driver->sta_add2(ifname, hapd->drv_priv, &params);
+ }
+
+ if (hapd->driver->sta_add == NULL)
+ return 0;
+ return hapd->driver->sta_add(ifname, hapd->drv_priv, addr, aid,
+ capability, (u8 *) supp_rates,
+ supp_rates_len,
+ flags, listen_interval);
+}
+
+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, int ht_enabled,
+ int sec_channel_offset)
+{
+ if (hapd->driver == NULL)
+ return 0;
+ if (hapd->driver->set_freq2) {
+ struct hostapd_freq_params data;
+ os_memset(&data, 0, sizeof(data));
+ data.mode = mode;
+ data.freq = freq;
+ data.ht_enabled = ht_enabled;
+ data.sec_channel_offset = sec_channel_offset;
+ return hapd->driver->set_freq2(hapd->drv_priv, &data);
+ }
+
+ if (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_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);
+}
+
+static inline int
+hostapd_set_radius_acl_auth(struct hostapd_data *hapd, const u8 *mac,
+ int accepted, u32 session_timeout)
+{
+ if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
+ return 0;
+ return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
+ session_timeout);
+}
+
+static inline int
+hostapd_set_radius_acl_expire(struct hostapd_data *hapd, const u8 *mac)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_radius_acl_expire == NULL)
+ return 0;
+ return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
+}
+
+#ifdef CONFIG_IEEE80211N
+static inline int
+hostapd_set_ht_params(const char *ifname, struct hostapd_data *hapd,
+ const u8 *ht_capab, size_t ht_capab_len,
+ const u8 *ht_oper, size_t ht_oper_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
+ ht_capab == NULL || ht_oper == NULL)
+ return 0;
+ return hapd->driver->set_ht_params(
+ ifname, hapd->drv_priv, ht_capab, ht_capab_len,
+ ht_oper, ht_oper_len);
+}
+#endif /* CONFIG_IEEE80211N */
+
+static inline int
+hostapd_drv_none(struct hostapd_data *hapd)
+{
+ return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
+}
+
+static inline int
+hostapd_set_wps_beacon_ie(struct hostapd_data *hapd, const u8 *ie, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_wps_beacon_ie == NULL)
+ return 0;
+ return hapd->driver->set_wps_beacon_ie(hapd->conf->iface,
+ hapd->drv_priv, ie, len);
+}
+
+static inline int
+hostapd_set_wps_probe_resp_ie(struct hostapd_data *hapd, const u8 *ie,
+ size_t len)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_wps_probe_resp_ie == NULL)
+ return 0;
+ return hapd->driver->set_wps_probe_resp_ie(hapd->conf->iface,
+ hapd->drv_priv, ie, len);
+}
+
+#endif /* DRIVER_H */
diff --git a/contrib/wpa/hostapd/drivers.c b/contrib/wpa/hostapd/drivers.c
new file mode 100644
index 0000000..3006190
--- /dev/null
+++ b/contrib/wpa/hostapd/drivers.c
@@ -0,0 +1,71 @@
+/*
+ * 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 */
+#ifdef CONFIG_DRIVER_NONE
+extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
+#endif /* CONFIG_DRIVER_NONE */
+
+
+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 */
+#ifdef CONFIG_DRIVER_NONE
+ &wpa_driver_none_ops,
+#endif /* CONFIG_DRIVER_NONE */
+ NULL
+};
diff --git a/contrib/wpa/hostapd/eap_testing.txt b/contrib/wpa/hostapd/eap_testing.txt
new file mode 100644
index 0000000..04468c3
--- /dev/null
+++ b/contrib/wpa/hostapd/eap_testing.txt
@@ -0,0 +1,77 @@
+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-TTLS + TNC + - - - -
+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-FAST + TNC + - - - -
+EAP-IKEv2 + - - - -
+EAP-TNC + - - - -
+
+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?)
diff --git a/contrib/wpa/hostapd/eapol_sm.c b/contrib/wpa/hostapd/eapol_sm.c
new file mode 100644
index 0000000..8e9d56c
--- /dev/null
+++ b/contrib/wpa/hostapd/eapol_sm.c
@@ -0,0 +1,1342 @@
+/*
+ * hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine
+ * Copyright (c) 2002-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 "hostapd.h"
+#include "ieee802_1x.h"
+#include "eapol_sm.h"
+#include "eloop.h"
+#include "wpa.h"
+#include "preauth.h"
+#include "sta_info.h"
+#include "eap_server/eap.h"
+#include "state_machine.h"
+#include "eap_common/eap_common.h"
+
+#define STATE_MACHINE_DATA struct eapol_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
+#define STATE_MACHINE_ADDR sm->addr
+
+static struct eapol_callbacks eapol_cb;
+
+/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
+
+#define setPortAuthorized() \
+sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 1)
+#define setPortUnauthorized() \
+sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 0)
+
+/* procedures */
+#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
+#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
+#define txReq() eapol_auth_tx_req(sm)
+#define abortAuth() sm->eapol->cb.abort_auth(sm->hapd, sm->sta)
+#define txKey() sm->eapol->cb.tx_key(sm->hapd, sm->sta)
+#define processKey() do { } while (0)
+
+
+static void eapol_sm_step_run(struct eapol_state_machine *sm);
+static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
+
+
+static void eapol_auth_logger(struct eapol_authenticator *eapol,
+ const u8 *addr, logger_level level,
+ const char *txt)
+{
+ if (eapol->cb.logger == NULL)
+ return;
+ eapol->cb.logger(eapol->conf.hapd, addr, level, txt);
+}
+
+
+static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
+ const u8 *addr, logger_level level,
+ const char *fmt, ...)
+{
+ char *format;
+ int maxlen;
+ va_list ap;
+
+ if (eapol->cb.logger == NULL)
+ return;
+
+ maxlen = os_strlen(fmt) + 100;
+ format = os_malloc(maxlen);
+ if (!format)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(format, maxlen, fmt, ap);
+ va_end(ap);
+
+ eapol_auth_logger(eapol, addr, level, format);
+
+ os_free(format);
+}
+
+
+static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
+ int success)
+{
+ struct eap_hdr eap;
+
+ os_memset(&eap, 0, sizeof(eap));
+
+ eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
+ eap.identifier = ++sm->last_eap_id;
+ eap.length = host_to_be16(sizeof(eap));
+
+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
+ "Sending canned EAP packet %s (identifier %d)",
+ success ? "SUCCESS" : "FAILURE", eap.identifier);
+ sm->eapol->cb.eapol_send(sm->hapd, sm->sta, IEEE802_1X_TYPE_EAP_PACKET,
+ (u8 *) &eap, sizeof(eap));
+ sm->dot1xAuthEapolFramesTx++;
+}
+
+
+static void eapol_auth_tx_req(struct eapol_state_machine *sm)
+{
+ if (sm->eap_if->eapReqData == NULL ||
+ wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
+ eapol_auth_logger(sm->eapol, sm->addr,
+ EAPOL_LOGGER_DEBUG,
+ "TxReq called, but there is no EAP request "
+ "from authentication server");
+ return;
+ }
+
+ if (sm->flags & EAPOL_SM_WAIT_START) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
+ " while waiting for EAPOL-Start",
+ MAC2STR(sm->addr));
+ return;
+ }
+
+ sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
+ "Sending EAP Packet (identifier %d)",
+ sm->last_eap_id);
+ sm->eapol->cb.eapol_send(sm->hapd, sm->sta, IEEE802_1X_TYPE_EAP_PACKET,
+ wpabuf_head(sm->eap_if->eapReqData),
+ wpabuf_len(sm->eap_if->eapReqData));
+ sm->dot1xAuthEapolFramesTx++;
+ if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
+ sm->dot1xAuthEapolReqIdFramesTx++;
+ else
+ sm->dot1xAuthEapolReqFramesTx++;
+}
+
+
+/**
+ * eapol_port_timers_tick - Port Timers state machine
+ * @eloop_ctx: struct eapol_state_machine *
+ * @timeout_ctx: Not used
+ *
+ * This statemachine is implemented as a function that will be called
+ * once a second as a registered event loop timeout.
+ */
+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
+{
+ struct eapol_state_machine *state = timeout_ctx;
+
+ if (state->aWhile > 0) {
+ state->aWhile--;
+ if (state->aWhile == 0) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " - aWhile --> 0",
+ MAC2STR(state->addr));
+ }
+ }
+
+ if (state->quietWhile > 0) {
+ state->quietWhile--;
+ if (state->quietWhile == 0) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " - quietWhile --> 0",
+ MAC2STR(state->addr));
+ }
+ }
+
+ if (state->reAuthWhen > 0) {
+ state->reAuthWhen--;
+ if (state->reAuthWhen == 0) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " - reAuthWhen --> 0",
+ MAC2STR(state->addr));
+ }
+ }
+
+ if (state->eap_if->retransWhile > 0) {
+ state->eap_if->retransWhile--;
+ if (state->eap_if->retransWhile == 0) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " - (EAP) retransWhile --> 0",
+ MAC2STR(state->addr));
+ }
+ }
+
+ eapol_sm_step_run(state);
+
+ eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
+}
+
+
+
+/* Authenticator PAE state machine */
+
+SM_STATE(AUTH_PAE, INITIALIZE)
+{
+ SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
+ sm->portMode = Auto;
+}
+
+
+SM_STATE(AUTH_PAE, DISCONNECTED)
+{
+ int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
+
+ if (sm->eapolLogoff) {
+ if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
+ sm->authEapLogoffsWhileConnecting++;
+ else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
+ sm->authAuthEapLogoffWhileAuthenticated++;
+ }
+
+ SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
+
+ sm->authPortStatus = Unauthorized;
+ setPortUnauthorized();
+ sm->reAuthCount = 0;
+ sm->eapolLogoff = FALSE;
+ if (!from_initialize) {
+ sm->eapol->cb.finished(sm->hapd, sm->sta, 0,
+ sm->flags & EAPOL_SM_PREAUTH);
+ }
+}
+
+
+SM_STATE(AUTH_PAE, RESTART)
+{
+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
+ if (sm->reAuthenticate)
+ sm->authAuthReauthsWhileAuthenticated++;
+ if (sm->eapolStart)
+ sm->authAuthEapStartsWhileAuthenticated++;
+ if (sm->eapolLogoff)
+ sm->authAuthEapLogoffWhileAuthenticated++;
+ }
+
+ SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
+
+ sm->eap_if->eapRestart = TRUE;
+}
+
+
+SM_STATE(AUTH_PAE, CONNECTING)
+{
+ if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
+ sm->authEntersConnecting++;
+
+ SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
+
+ sm->reAuthenticate = FALSE;
+ sm->reAuthCount++;
+}
+
+
+SM_STATE(AUTH_PAE, HELD)
+{
+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
+ sm->authAuthFailWhileAuthenticating++;
+
+ SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
+
+ sm->authPortStatus = Unauthorized;
+ setPortUnauthorized();
+ sm->quietWhile = sm->quietPeriod;
+ sm->eapolLogoff = FALSE;
+
+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
+ "authentication failed - EAP type: %d (%s)",
+ sm->eap_type_authsrv,
+ eap_type_text(sm->eap_type_authsrv));
+ if (sm->eap_type_authsrv != sm->eap_type_supp) {
+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
+ "Supplicant used different EAP type: "
+ "%d (%s)", sm->eap_type_supp,
+ eap_type_text(sm->eap_type_supp));
+ }
+ sm->eapol->cb.finished(sm->hapd, sm->sta, 0,
+ sm->flags & EAPOL_SM_PREAUTH);
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATED)
+{
+ char *extra = "";
+
+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
+ sm->authAuthSuccessesWhileAuthenticating++;
+
+ SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
+
+ sm->authPortStatus = Authorized;
+ setPortAuthorized();
+ sm->reAuthCount = 0;
+ if (sm->flags & EAPOL_SM_PREAUTH)
+ extra = " (pre-authentication)";
+ else if (wpa_auth_sta_get_pmksa(sm->sta->wpa_sm))
+ extra = " (PMKSA cache)";
+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
+ "authenticated - EAP type: %d (%s)%s",
+ sm->eap_type_authsrv,
+ eap_type_text(sm->eap_type_authsrv), extra);
+ sm->eapol->cb.finished(sm->hapd, sm->sta, 1,
+ sm->flags & EAPOL_SM_PREAUTH);
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATING)
+{
+ SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
+
+ sm->eapolStart = FALSE;
+ sm->authSuccess = FALSE;
+ sm->authFail = FALSE;
+ sm->authTimeout = FALSE;
+ sm->authStart = TRUE;
+ sm->keyRun = FALSE;
+ sm->keyDone = FALSE;
+}
+
+
+SM_STATE(AUTH_PAE, ABORTING)
+{
+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
+ if (sm->authTimeout)
+ sm->authAuthTimeoutsWhileAuthenticating++;
+ if (sm->eapolStart)
+ sm->authAuthEapStartsWhileAuthenticating++;
+ if (sm->eapolLogoff)
+ sm->authAuthEapLogoffWhileAuthenticating++;
+ }
+
+ SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
+
+ sm->authAbort = TRUE;
+ sm->keyRun = FALSE;
+ sm->keyDone = FALSE;
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_AUTH)
+{
+ SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
+
+ sm->authPortStatus = Authorized;
+ setPortAuthorized();
+ sm->portMode = ForceAuthorized;
+ sm->eapolStart = FALSE;
+ txCannedSuccess();
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_UNAUTH)
+{
+ SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
+
+ sm->authPortStatus = Unauthorized;
+ setPortUnauthorized();
+ sm->portMode = ForceUnauthorized;
+ sm->eapolStart = FALSE;
+ txCannedFail();
+}
+
+
+SM_STEP(AUTH_PAE)
+{
+ if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
+ sm->initialize || !sm->eap_if->portEnabled)
+ SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
+ else if (sm->portControl == ForceAuthorized &&
+ sm->portMode != sm->portControl &&
+ !(sm->initialize || !sm->eap_if->portEnabled))
+ SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
+ else if (sm->portControl == ForceUnauthorized &&
+ sm->portMode != sm->portControl &&
+ !(sm->initialize || !sm->eap_if->portEnabled))
+ SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
+ else {
+ switch (sm->auth_pae_state) {
+ case AUTH_PAE_INITIALIZE:
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ break;
+ case AUTH_PAE_DISCONNECTED:
+ SM_ENTER(AUTH_PAE, RESTART);
+ break;
+ case AUTH_PAE_RESTART:
+ if (!sm->eap_if->eapRestart)
+ SM_ENTER(AUTH_PAE, CONNECTING);
+ break;
+ case AUTH_PAE_HELD:
+ if (sm->quietWhile == 0)
+ SM_ENTER(AUTH_PAE, RESTART);
+ break;
+ case AUTH_PAE_CONNECTING:
+ if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ else if ((sm->eap_if->eapReq &&
+ sm->reAuthCount <= sm->reAuthMax) ||
+ sm->eap_if->eapSuccess || sm->eap_if->eapFail)
+ SM_ENTER(AUTH_PAE, AUTHENTICATING);
+ break;
+ case AUTH_PAE_AUTHENTICATED:
+ if (sm->eapolStart || sm->reAuthenticate)
+ SM_ENTER(AUTH_PAE, RESTART);
+ else if (sm->eapolLogoff || !sm->portValid)
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ break;
+ case AUTH_PAE_AUTHENTICATING:
+ if (sm->authSuccess && sm->portValid)
+ SM_ENTER(AUTH_PAE, AUTHENTICATED);
+ else if (sm->authFail ||
+ (sm->keyDone && !sm->portValid))
+ SM_ENTER(AUTH_PAE, HELD);
+ else if (sm->eapolStart || sm->eapolLogoff ||
+ sm->authTimeout)
+ SM_ENTER(AUTH_PAE, ABORTING);
+ break;
+ case AUTH_PAE_ABORTING:
+ if (sm->eapolLogoff && !sm->authAbort)
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ else if (!sm->eapolLogoff && !sm->authAbort)
+ SM_ENTER(AUTH_PAE, RESTART);
+ break;
+ case AUTH_PAE_FORCE_AUTH:
+ if (sm->eapolStart)
+ SM_ENTER(AUTH_PAE, FORCE_AUTH);
+ break;
+ case AUTH_PAE_FORCE_UNAUTH:
+ if (sm->eapolStart)
+ SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
+ break;
+ }
+ }
+}
+
+
+
+/* Backend Authentication state machine */
+
+SM_STATE(BE_AUTH, INITIALIZE)
+{
+ SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
+
+ abortAuth();
+ sm->eap_if->eapNoReq = FALSE;
+ sm->authAbort = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, REQUEST)
+{
+ SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
+
+ txReq();
+ sm->eap_if->eapReq = FALSE;
+ sm->backendOtherRequestsToSupplicant++;
+
+ /*
+ * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
+ * it looks like this would be logical thing to do there since the old
+ * EAP response would not be valid anymore after the new EAP request
+ * was sent out.
+ *
+ * A race condition has been reported, in which hostapd ended up
+ * sending out EAP-Response/Identity as a response to the first
+ * EAP-Request from the main EAP method. This can be avoided by
+ * clearing eapolEap here.
+ */
+ sm->eapolEap = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, RESPONSE)
+{
+ SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
+
+ sm->authTimeout = FALSE;
+ sm->eapolEap = FALSE;
+ sm->eap_if->eapNoReq = FALSE;
+ sm->aWhile = sm->serverTimeout;
+ sm->eap_if->eapResp = TRUE;
+ /* sendRespToServer(); */
+ sm->backendResponses++;
+}
+
+
+SM_STATE(BE_AUTH, SUCCESS)
+{
+ SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
+
+ txReq();
+ sm->authSuccess = TRUE;
+ sm->keyRun = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, FAIL)
+{
+ SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
+
+ txReq();
+ sm->authFail = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, TIMEOUT)
+{
+ SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
+
+ sm->authTimeout = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, IDLE)
+{
+ SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
+
+ sm->authStart = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, IGNORE)
+{
+ SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
+
+ sm->eap_if->eapNoReq = FALSE;
+}
+
+
+SM_STEP(BE_AUTH)
+{
+ if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
+ SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
+ return;
+ }
+
+ switch (sm->be_auth_state) {
+ case BE_AUTH_INITIALIZE:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_REQUEST:
+ if (sm->eapolEap)
+ SM_ENTER(BE_AUTH, RESPONSE);
+ else if (sm->eap_if->eapReq)
+ SM_ENTER(BE_AUTH, REQUEST);
+ else if (sm->eap_if->eapTimeout)
+ SM_ENTER(BE_AUTH, TIMEOUT);
+ break;
+ case BE_AUTH_RESPONSE:
+ if (sm->eap_if->eapNoReq)
+ SM_ENTER(BE_AUTH, IGNORE);
+ if (sm->eap_if->eapReq) {
+ sm->backendAccessChallenges++;
+ SM_ENTER(BE_AUTH, REQUEST);
+ } else if (sm->aWhile == 0)
+ SM_ENTER(BE_AUTH, TIMEOUT);
+ else if (sm->eap_if->eapFail) {
+ sm->backendAuthFails++;
+ SM_ENTER(BE_AUTH, FAIL);
+ } else if (sm->eap_if->eapSuccess) {
+ sm->backendAuthSuccesses++;
+ SM_ENTER(BE_AUTH, SUCCESS);
+ }
+ break;
+ case BE_AUTH_SUCCESS:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_FAIL:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_TIMEOUT:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_IDLE:
+ if (sm->eap_if->eapFail && sm->authStart)
+ SM_ENTER(BE_AUTH, FAIL);
+ else if (sm->eap_if->eapReq && sm->authStart)
+ SM_ENTER(BE_AUTH, REQUEST);
+ else if (sm->eap_if->eapSuccess && sm->authStart)
+ SM_ENTER(BE_AUTH, SUCCESS);
+ break;
+ case BE_AUTH_IGNORE:
+ if (sm->eapolEap)
+ SM_ENTER(BE_AUTH, RESPONSE);
+ else if (sm->eap_if->eapReq)
+ SM_ENTER(BE_AUTH, REQUEST);
+ else if (sm->eap_if->eapTimeout)
+ SM_ENTER(BE_AUTH, TIMEOUT);
+ break;
+ }
+}
+
+
+
+/* Reauthentication Timer state machine */
+
+SM_STATE(REAUTH_TIMER, INITIALIZE)
+{
+ SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
+
+ sm->reAuthWhen = sm->reAuthPeriod;
+}
+
+
+SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
+{
+ SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
+
+ sm->reAuthenticate = TRUE;
+ wpa_auth_sm_event(sm->sta->wpa_sm, WPA_REAUTH_EAPOL);
+}
+
+
+SM_STEP(REAUTH_TIMER)
+{
+ if (sm->portControl != Auto || sm->initialize ||
+ sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
+ SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
+ return;
+ }
+
+ switch (sm->reauth_timer_state) {
+ case REAUTH_TIMER_INITIALIZE:
+ if (sm->reAuthWhen == 0)
+ SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
+ break;
+ case REAUTH_TIMER_REAUTHENTICATE:
+ SM_ENTER(REAUTH_TIMER, INITIALIZE);
+ break;
+ }
+}
+
+
+
+/* Authenticator Key Transmit state machine */
+
+SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
+{
+ SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
+}
+
+
+SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
+{
+ SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
+
+ txKey();
+ sm->eap_if->eapKeyAvailable = FALSE;
+ sm->keyDone = TRUE;
+}
+
+
+SM_STEP(AUTH_KEY_TX)
+{
+ if (sm->initialize || sm->portControl != Auto) {
+ SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+ return;
+ }
+
+ switch (sm->auth_key_tx_state) {
+ case AUTH_KEY_TX_NO_KEY_TRANSMIT:
+ if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
+ sm->keyRun && !wpa_auth_sta_wpa_version(sm->sta->wpa_sm))
+ SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+ break;
+ case AUTH_KEY_TX_KEY_TRANSMIT:
+ if (!sm->keyTxEnabled || !sm->keyRun)
+ SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+ else if (sm->eap_if->eapKeyAvailable)
+ SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+ break;
+ }
+}
+
+
+
+/* Key Receive state machine */
+
+SM_STATE(KEY_RX, NO_KEY_RECEIVE)
+{
+ SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
+}
+
+
+SM_STATE(KEY_RX, KEY_RECEIVE)
+{
+ SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
+
+ processKey();
+ sm->rxKey = FALSE;
+}
+
+
+SM_STEP(KEY_RX)
+{
+ if (sm->initialize || !sm->eap_if->portEnabled) {
+ SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
+ return;
+ }
+
+ switch (sm->key_rx_state) {
+ case KEY_RX_NO_KEY_RECEIVE:
+ if (sm->rxKey)
+ SM_ENTER(KEY_RX, KEY_RECEIVE);
+ break;
+ case KEY_RX_KEY_RECEIVE:
+ if (sm->rxKey)
+ SM_ENTER(KEY_RX, KEY_RECEIVE);
+ break;
+ }
+}
+
+
+
+/* Controlled Directions state machine */
+
+SM_STATE(CTRL_DIR, FORCE_BOTH)
+{
+ SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
+ sm->operControlledDirections = Both;
+}
+
+
+SM_STATE(CTRL_DIR, IN_OR_BOTH)
+{
+ SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
+ sm->operControlledDirections = sm->adminControlledDirections;
+}
+
+
+SM_STEP(CTRL_DIR)
+{
+ if (sm->initialize) {
+ SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
+ return;
+ }
+
+ switch (sm->ctrl_dir_state) {
+ case CTRL_DIR_FORCE_BOTH:
+ if (sm->eap_if->portEnabled && sm->operEdge)
+ SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+ break;
+ case CTRL_DIR_IN_OR_BOTH:
+ if (sm->operControlledDirections !=
+ sm->adminControlledDirections)
+ SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+ if (!sm->eap_if->portEnabled || !sm->operEdge)
+ SM_ENTER(CTRL_DIR, FORCE_BOTH);
+ break;
+ }
+}
+
+
+
+struct eapol_state_machine *
+eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
+ int preauth, struct sta_info *sta)
+{
+ struct eapol_state_machine *sm;
+ struct hostapd_data *hapd; /* TODO: to be removed */
+ struct eap_config eap_conf;
+
+ if (eapol == NULL)
+ return NULL;
+ hapd = eapol->conf.hapd;
+
+ sm = os_zalloc(sizeof(*sm));
+ if (sm == NULL) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
+ "failed");
+ return NULL;
+ }
+ sm->radius_identifier = -1;
+ os_memcpy(sm->addr, addr, ETH_ALEN);
+ if (preauth)
+ sm->flags |= EAPOL_SM_PREAUTH;
+
+ sm->hapd = hapd;
+ sm->eapol = eapol;
+ sm->sta = sta;
+
+ /* Set default values for state machine constants */
+ sm->auth_pae_state = AUTH_PAE_INITIALIZE;
+ sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
+ sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
+
+ sm->be_auth_state = BE_AUTH_INITIALIZE;
+ sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
+
+ sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
+ sm->reAuthPeriod = eapol->conf.eap_reauth_period;
+ sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
+
+ sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
+
+ sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
+
+ sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
+
+ sm->portControl = Auto;
+
+ if (!eapol->conf.wpa &&
+ (hapd->default_wep_key || eapol->conf.individual_wep_key_len > 0))
+ sm->keyTxEnabled = TRUE;
+ else
+ sm->keyTxEnabled = FALSE;
+ if (eapol->conf.wpa)
+ sm->portValid = FALSE;
+ else
+ sm->portValid = TRUE;
+
+ os_memset(&eap_conf, 0, sizeof(eap_conf));
+ eap_conf.eap_server = eapol->conf.eap_server;
+ eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
+ eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
+ eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
+ eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
+ eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
+ eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
+ eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
+ eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
+ eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
+ eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
+ eap_conf.tnc = eapol->conf.tnc;
+ eap_conf.wps = eapol->conf.wps;
+ eap_conf.assoc_wps_ie = sta->wps_ie;
+ sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
+ if (sm->eap == NULL) {
+ eapol_auth_free(sm);
+ return NULL;
+ }
+ sm->eap_if = eap_get_interface(sm->eap);
+
+ eapol_auth_initialize(sm);
+
+ return sm;
+}
+
+
+void eapol_auth_free(struct eapol_state_machine *sm)
+{
+ if (sm == NULL)
+ return;
+
+ eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+ eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
+ if (sm->eap)
+ eap_server_sm_deinit(sm->eap);
+ os_free(sm);
+}
+
+
+static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
+ const u8 *addr)
+{
+ return eapol->cb.sta_entry_alive(eapol->conf.hapd, addr);
+}
+
+
+static void eapol_sm_step_run(struct eapol_state_machine *sm)
+{
+ struct eapol_authenticator *eapol = sm->eapol;
+ u8 addr[ETH_ALEN];
+ unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
+ prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
+ int max_steps = 100;
+
+ os_memcpy(addr, sm->addr, ETH_ALEN);
+
+ /*
+ * Allow EAPOL state machines to run as long as there are state
+ * changes, but exit and return here through event loop if more than
+ * 100 steps is needed as a precaution against infinite loops inside
+ * eloop callback.
+ */
+restart:
+ prev_auth_pae = sm->auth_pae_state;
+ prev_be_auth = sm->be_auth_state;
+ prev_reauth_timer = sm->reauth_timer_state;
+ prev_auth_key_tx = sm->auth_key_tx_state;
+ prev_key_rx = sm->key_rx_state;
+ prev_ctrl_dir = sm->ctrl_dir_state;
+
+ SM_STEP_RUN(AUTH_PAE);
+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+ SM_STEP_RUN(BE_AUTH);
+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+ SM_STEP_RUN(REAUTH_TIMER);
+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+ SM_STEP_RUN(AUTH_KEY_TX);
+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+ SM_STEP_RUN(KEY_RX);
+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+ SM_STEP_RUN(CTRL_DIR);
+
+ if (prev_auth_pae != sm->auth_pae_state ||
+ prev_be_auth != sm->be_auth_state ||
+ prev_reauth_timer != sm->reauth_timer_state ||
+ prev_auth_key_tx != sm->auth_key_tx_state ||
+ prev_key_rx != sm->key_rx_state ||
+ prev_ctrl_dir != sm->ctrl_dir_state) {
+ if (--max_steps > 0)
+ goto restart;
+ /* Re-run from eloop timeout */
+ eapol_auth_step(sm);
+ return;
+ }
+
+ if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
+ if (eap_server_sm_step(sm->eap)) {
+ if (--max_steps > 0)
+ goto restart;
+ /* Re-run from eloop timeout */
+ eapol_auth_step(sm);
+ return;
+ }
+
+ /* TODO: find a better location for this */
+ if (sm->eap_if->aaaEapResp) {
+ sm->eap_if->aaaEapResp = FALSE;
+ if (sm->eap_if->aaaEapRespData == NULL) {
+ wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
+ "but no aaaEapRespData available");
+ return;
+ }
+ sm->eapol->cb.aaa_send(
+ sm->hapd, sm->sta,
+ wpabuf_head(sm->eap_if->aaaEapRespData),
+ wpabuf_len(sm->eap_if->aaaEapRespData));
+ }
+ }
+
+ if (eapol_sm_sta_entry_alive(eapol, addr))
+ wpa_auth_sm_notify(sm->sta->wpa_sm);
+}
+
+
+static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct eapol_state_machine *sm = eloop_ctx;
+ eapol_sm_step_run(sm);
+}
+
+
+/**
+ * eapol_auth_step - Advance EAPOL state machines
+ * @sm: EAPOL state machine
+ *
+ * This function is called to advance EAPOL state machines after any change
+ * that could affect their state.
+ */
+void eapol_auth_step(struct eapol_state_machine *sm)
+{
+ /*
+ * Run eapol_sm_step_run from a registered timeout to make sure that
+ * other possible timeouts/events are processed and to avoid long
+ * function call chains.
+ */
+
+ eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
+}
+
+
+void eapol_auth_initialize(struct eapol_state_machine *sm)
+{
+ sm->initializing = TRUE;
+ /* Initialize the state machines by asserting initialize and then
+ * deasserting it after one step */
+ sm->initialize = TRUE;
+ eapol_sm_step_run(sm);
+ sm->initialize = FALSE;
+ eapol_sm_step_run(sm);
+ sm->initializing = FALSE;
+
+ /* Start one second tick for port timers state machine */
+ eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+ eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+}
+
+
+#ifdef HOSTAPD_DUMP_STATE
+static inline const char * port_type_txt(PortTypes pt)
+{
+ switch (pt) {
+ case ForceUnauthorized: return "ForceUnauthorized";
+ case ForceAuthorized: return "ForceAuthorized";
+ case Auto: return "Auto";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * port_state_txt(PortState ps)
+{
+ switch (ps) {
+ case Unauthorized: return "Unauthorized";
+ case Authorized: return "Authorized";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * ctrl_dir_txt(ControlledDirection dir)
+{
+ switch (dir) {
+ case Both: return "Both";
+ case In: return "In";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * auth_pae_state_txt(int s)
+{
+ switch (s) {
+ case AUTH_PAE_INITIALIZE: return "INITIALIZE";
+ case AUTH_PAE_DISCONNECTED: return "DISCONNECTED";
+ case AUTH_PAE_CONNECTING: return "CONNECTING";
+ case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING";
+ case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED";
+ case AUTH_PAE_ABORTING: return "ABORTING";
+ case AUTH_PAE_HELD: return "HELD";
+ case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH";
+ case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH";
+ case AUTH_PAE_RESTART: return "RESTART";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * be_auth_state_txt(int s)
+{
+ switch (s) {
+ case BE_AUTH_REQUEST: return "REQUEST";
+ case BE_AUTH_RESPONSE: return "RESPONSE";
+ case BE_AUTH_SUCCESS: return "SUCCESS";
+ case BE_AUTH_FAIL: return "FAIL";
+ case BE_AUTH_TIMEOUT: return "TIMEOUT";
+ case BE_AUTH_IDLE: return "IDLE";
+ case BE_AUTH_INITIALIZE: return "INITIALIZE";
+ case BE_AUTH_IGNORE: return "IGNORE";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * reauth_timer_state_txt(int s)
+{
+ switch (s) {
+ case REAUTH_TIMER_INITIALIZE: return "INITIALIZE";
+ case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * auth_key_tx_state_txt(int s)
+{
+ switch (s) {
+ case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT";
+ case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * key_rx_state_txt(int s)
+{
+ switch (s) {
+ case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE";
+ case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE";
+ default: return "Unknown";
+ }
+}
+
+
+static inline const char * ctrl_dir_state_txt(int s)
+{
+ switch (s) {
+ case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH";
+ case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH";
+ default: return "Unknown";
+ }
+}
+
+
+void eapol_auth_dump_state(FILE *f, const char *prefix,
+ struct eapol_state_machine *sm)
+{
+ fprintf(f, "%sEAPOL state machine:\n", prefix);
+ fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
+ sm->aWhile, sm->quietWhile, sm->reAuthWhen);
+#define _SB(b) ((b) ? "TRUE" : "FALSE")
+ fprintf(f,
+ "%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
+ "%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
+ "%s eapSuccess=%s eapTimeout=%s initialize=%s "
+ "keyAvailable=%s\n"
+ "%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
+ "%s portEnabled=%s portValid=%s reAuthenticate=%s\n",
+ prefix, _SB(sm->authAbort), _SB(sm->authFail),
+ port_state_txt(sm->authPortStatus), _SB(sm->authStart),
+ prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
+ _SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
+ prefix, _SB(sm->eap_if->eapSuccess),
+ _SB(sm->eap_if->eapTimeout),
+ _SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
+ prefix, _SB(sm->keyDone), _SB(sm->keyRun),
+ _SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
+ prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
+ _SB(sm->reAuthenticate));
+
+ fprintf(f, "%s Authenticator PAE:\n"
+ "%s state=%s\n"
+ "%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
+ "%s portMode=%s reAuthCount=%d\n"
+ "%s quietPeriod=%d reAuthMax=%d\n"
+ "%s authEntersConnecting=%d\n"
+ "%s authEapLogoffsWhileConnecting=%d\n"
+ "%s authEntersAuthenticating=%d\n"
+ "%s authAuthSuccessesWhileAuthenticating=%d\n"
+ "%s authAuthTimeoutsWhileAuthenticating=%d\n"
+ "%s authAuthFailWhileAuthenticating=%d\n"
+ "%s authAuthEapStartsWhileAuthenticating=%d\n"
+ "%s authAuthEapLogoffWhileAuthenticating=%d\n"
+ "%s authAuthReauthsWhileAuthenticated=%d\n"
+ "%s authAuthEapStartsWhileAuthenticated=%d\n"
+ "%s authAuthEapLogoffWhileAuthenticated=%d\n",
+ prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
+ _SB(sm->eapolLogoff), _SB(sm->eapolStart),
+ _SB(sm->eap_if->eapRestart),
+ prefix, port_type_txt(sm->portMode), sm->reAuthCount,
+ prefix, sm->quietPeriod, sm->reAuthMax,
+ prefix, sm->authEntersConnecting,
+ prefix, sm->authEapLogoffsWhileConnecting,
+ prefix, sm->authEntersAuthenticating,
+ prefix, sm->authAuthSuccessesWhileAuthenticating,
+ prefix, sm->authAuthTimeoutsWhileAuthenticating,
+ prefix, sm->authAuthFailWhileAuthenticating,
+ prefix, sm->authAuthEapStartsWhileAuthenticating,
+ prefix, sm->authAuthEapLogoffWhileAuthenticating,
+ prefix, sm->authAuthReauthsWhileAuthenticated,
+ prefix, sm->authAuthEapStartsWhileAuthenticated,
+ prefix, sm->authAuthEapLogoffWhileAuthenticated);
+
+ fprintf(f, "%s Backend Authentication:\n"
+ "%s state=%s\n"
+ "%s eapNoReq=%s eapReq=%s eapResp=%s\n"
+ "%s serverTimeout=%d\n"
+ "%s backendResponses=%d\n"
+ "%s backendAccessChallenges=%d\n"
+ "%s backendOtherRequestsToSupplicant=%d\n"
+ "%s backendAuthSuccesses=%d\n"
+ "%s backendAuthFails=%d\n",
+ prefix, prefix,
+ be_auth_state_txt(sm->be_auth_state),
+ prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
+ _SB(sm->eap_if->eapResp),
+ prefix, sm->serverTimeout,
+ prefix, sm->backendResponses,
+ prefix, sm->backendAccessChallenges,
+ prefix, sm->backendOtherRequestsToSupplicant,
+ prefix, sm->backendAuthSuccesses,
+ prefix, sm->backendAuthFails);
+
+ fprintf(f, "%s Reauthentication Timer:\n"
+ "%s state=%s\n"
+ "%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
+ reauth_timer_state_txt(sm->reauth_timer_state), prefix,
+ sm->reAuthPeriod, _SB(sm->reAuthEnabled));
+
+ fprintf(f, "%s Authenticator Key Transmit:\n"
+ "%s state=%s\n", prefix, prefix,
+ auth_key_tx_state_txt(sm->auth_key_tx_state));
+
+ fprintf(f, "%s Key Receive:\n"
+ "%s state=%s\n"
+ "%s rxKey=%s\n", prefix, prefix,
+ key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
+
+ fprintf(f, "%s Controlled Directions:\n"
+ "%s state=%s\n"
+ "%s adminControlledDirections=%s "
+ "operControlledDirections=%s\n"
+ "%s operEdge=%s\n", prefix, prefix,
+ ctrl_dir_state_txt(sm->ctrl_dir_state),
+ prefix, ctrl_dir_txt(sm->adminControlledDirections),
+ ctrl_dir_txt(sm->operControlledDirections),
+ prefix, _SB(sm->operEdge));
+#undef _SB
+}
+#endif /* HOSTAPD_DUMP_STATE */
+
+
+static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->cb.get_eap_user(sm->hapd, identity, identity_len,
+ phase2, user);
+}
+
+
+static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
+{
+ struct eapol_state_machine *sm = ctx;
+ *len = sm->eapol->conf.eap_req_id_text_len;
+ return sm->eapol->conf.eap_req_id_text;
+}
+
+
+static struct eapol_callbacks eapol_cb =
+{
+ .get_eap_user = eapol_sm_get_eap_user,
+ .get_eap_req_id_text = eapol_sm_get_eap_req_id_text,
+};
+
+
+int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
+{
+ if (sm == NULL || ctx != sm->eap)
+ return -1;
+
+ eap_sm_pending_cb(sm->eap);
+ eapol_auth_step(sm);
+
+ return 0;
+}
+
+
+static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
+ struct eapol_auth_config *src)
+{
+ dst->hapd = src->hapd;
+ dst->eap_reauth_period = src->eap_reauth_period;
+ dst->wpa = src->wpa;
+ dst->individual_wep_key_len = src->individual_wep_key_len;
+ dst->eap_server = src->eap_server;
+ dst->ssl_ctx = src->ssl_ctx;
+ dst->eap_sim_db_priv = src->eap_sim_db_priv;
+ os_free(dst->eap_req_id_text);
+ if (src->eap_req_id_text) {
+ dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
+ if (dst->eap_req_id_text == NULL)
+ return -1;
+ os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
+ src->eap_req_id_text_len);
+ dst->eap_req_id_text_len = src->eap_req_id_text_len;
+ } else {
+ dst->eap_req_id_text = NULL;
+ dst->eap_req_id_text_len = 0;
+ }
+ if (src->pac_opaque_encr_key) {
+ dst->pac_opaque_encr_key = os_malloc(16);
+ os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
+ 16);
+ } else
+ dst->pac_opaque_encr_key = NULL;
+ if (src->eap_fast_a_id) {
+ dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
+ if (dst->eap_fast_a_id == NULL) {
+ os_free(dst->eap_req_id_text);
+ return -1;
+ }
+ os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
+ src->eap_fast_a_id_len);
+ dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
+ } else
+ dst->eap_fast_a_id = NULL;
+ if (src->eap_fast_a_id_info) {
+ dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
+ if (dst->eap_fast_a_id_info == NULL) {
+ os_free(dst->eap_req_id_text);
+ os_free(dst->eap_fast_a_id);
+ return -1;
+ }
+ } else
+ dst->eap_fast_a_id_info = NULL;
+ dst->eap_fast_prov = src->eap_fast_prov;
+ dst->pac_key_lifetime = src->pac_key_lifetime;
+ dst->pac_key_refresh_time = src->pac_key_refresh_time;
+ dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
+ dst->tnc = src->tnc;
+ dst->wps = src->wps;
+ return 0;
+}
+
+
+static void eapol_auth_conf_free(struct eapol_auth_config *conf)
+{
+ os_free(conf->eap_req_id_text);
+ conf->eap_req_id_text = NULL;
+ os_free(conf->pac_opaque_encr_key);
+ conf->pac_opaque_encr_key = NULL;
+ os_free(conf->eap_fast_a_id);
+ conf->eap_fast_a_id = NULL;
+ os_free(conf->eap_fast_a_id_info);
+ conf->eap_fast_a_id_info = NULL;
+}
+
+
+struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
+ struct eapol_auth_cb *cb)
+{
+ struct eapol_authenticator *eapol;
+
+ eapol = os_zalloc(sizeof(*eapol));
+ if (eapol == NULL)
+ return NULL;
+
+ if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
+ os_free(eapol);
+ return NULL;
+ }
+
+ eapol->cb.eapol_send = cb->eapol_send;
+ eapol->cb.aaa_send = cb->aaa_send;
+ eapol->cb.finished = cb->finished;
+ eapol->cb.get_eap_user = cb->get_eap_user;
+ eapol->cb.sta_entry_alive = cb->sta_entry_alive;
+ eapol->cb.logger = cb->logger;
+ eapol->cb.set_port_authorized = cb->set_port_authorized;
+ eapol->cb.abort_auth = cb->abort_auth;
+ eapol->cb.tx_key = cb->tx_key;
+
+ return eapol;
+}
+
+
+void eapol_auth_deinit(struct eapol_authenticator *eapol)
+{
+ if (eapol == NULL)
+ return;
+
+ eapol_auth_conf_free(&eapol->conf);
+ os_free(eapol);
+}
diff --git a/contrib/wpa/hostapd/eapol_sm.h b/contrib/wpa/hostapd/eapol_sm.h
new file mode 100644
index 0000000..7a13e8e
--- /dev/null
+++ b/contrib/wpa/hostapd/eapol_sm.h
@@ -0,0 +1,260 @@
+/*
+ * 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;
+ u8 *eap_fast_a_id;
+ size_t eap_fast_a_id_len;
+ char *eap_fast_a_id_info;
+ int eap_fast_prov;
+ int pac_key_lifetime;
+ int pac_key_refresh_time;
+ int eap_sim_aka_result_ind;
+ int tnc;
+ struct wps_context *wps;
+
+ /*
+ * 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 */
diff --git a/contrib/wpa/hostapd/hostap_common.h b/contrib/wpa/hostapd/hostap_common.h
new file mode 100644
index 0000000..5a57dca
--- /dev/null
+++ b/contrib/wpa/hostapd/hostap_common.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 \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 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 */
diff --git a/contrib/wpa/hostapd/hostapd.8 b/contrib/wpa/hostapd/hostapd.8
new file mode 100644
index 0000000..9258512
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.8
@@ -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).
diff --git a/contrib/wpa/hostapd/hostapd.accept b/contrib/wpa/hostapd/hostapd.accept
new file mode 100644
index 0000000..2d2a0a2
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.accept
@@ -0,0 +1,6 @@
+# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
+# with the AP. Optional VLAN ID can be assigned for clients based on the
+# MAC address if dynamic VLANs (hostapd.conf dynamic_vlan option) are used.
+00:11:22:33:44:55
+00:66:77:88:99:aa
+00:00:22:33:44:55 1
diff --git a/contrib/wpa/hostapd/hostapd.c b/contrib/wpa/hostapd/hostapd.c
new file mode 100644
index 0000000..df6062b
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.c
@@ -0,0 +1,2027 @@
+/*
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <syslog.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "eloop.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "ieee802_11.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "accounting.h"
+#include "eapol_sm.h"
+#include "iapp.h"
+#include "ap.h"
+#include "ieee802_11_auth.h"
+#include "ap_list.h"
+#include "sta_info.h"
+#include "driver.h"
+#include "radius/radius_client.h"
+#include "radius/radius_server.h"
+#include "wpa.h"
+#include "preauth.h"
+#include "wme.h"
+#include "vlan_init.h"
+#include "ctrl_iface.h"
+#include "tls.h"
+#include "eap_server/eap_sim_db.h"
+#include "eap_server/eap.h"
+#include "eap_server/tncs.h"
+#include "version.h"
+#include "l2_packet/l2_packet.h"
+#include "wps_hostapd.h"
+
+
+static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user);
+static int hostapd_flush_old_stations(struct hostapd_data *hapd);
+static int hostapd_setup_wpa(struct hostapd_data *hapd);
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
+
+struct hapd_interfaces {
+ size_t count;
+ struct hostapd_iface **iface;
+};
+
+unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+ int level, const char *txt, size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ char *format, *module_str;
+ int maxlen;
+ int conf_syslog_level, conf_stdout_level;
+ unsigned int conf_syslog, conf_stdout;
+
+ maxlen = len + 100;
+ format = os_malloc(maxlen);
+ if (!format)
+ return;
+
+ if (hapd && hapd->conf) {
+ conf_syslog_level = hapd->conf->logger_syslog_level;
+ conf_stdout_level = hapd->conf->logger_stdout_level;
+ conf_syslog = hapd->conf->logger_syslog;
+ conf_stdout = hapd->conf->logger_stdout;
+ } else {
+ conf_syslog_level = conf_stdout_level = 0;
+ conf_syslog = conf_stdout = (unsigned int) -1;
+ }
+
+ switch (module) {
+ case HOSTAPD_MODULE_IEEE80211:
+ module_str = "IEEE 802.11";
+ break;
+ case HOSTAPD_MODULE_IEEE8021X:
+ module_str = "IEEE 802.1X";
+ break;
+ case HOSTAPD_MODULE_RADIUS:
+ module_str = "RADIUS";
+ break;
+ case HOSTAPD_MODULE_WPA:
+ module_str = "WPA";
+ break;
+ case HOSTAPD_MODULE_DRIVER:
+ module_str = "DRIVER";
+ break;
+ case HOSTAPD_MODULE_IAPP:
+ module_str = "IAPP";
+ break;
+ case HOSTAPD_MODULE_MLME:
+ module_str = "MLME";
+ break;
+ default:
+ module_str = NULL;
+ break;
+ }
+
+ if (hapd && hapd->conf && addr)
+ os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
+ hapd->conf->iface, MAC2STR(addr),
+ module_str ? " " : "", module_str, txt);
+ else if (hapd && hapd->conf)
+ os_snprintf(format, maxlen, "%s:%s%s %s",
+ hapd->conf->iface, module_str ? " " : "",
+ module_str, txt);
+ else if (addr)
+ os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
+ MAC2STR(addr), module_str ? " " : "",
+ module_str, txt);
+ else
+ os_snprintf(format, maxlen, "%s%s%s",
+ module_str, module_str ? ": " : "", txt);
+
+ if ((conf_stdout & module) && level >= conf_stdout_level) {
+ wpa_debug_print_timestamp();
+ printf("%s\n", format);
+ }
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ if ((conf_syslog & module) && level >= conf_syslog_level) {
+ int priority;
+ switch (level) {
+ case HOSTAPD_LEVEL_DEBUG_VERBOSE:
+ case HOSTAPD_LEVEL_DEBUG:
+ priority = LOG_DEBUG;
+ break;
+ case HOSTAPD_LEVEL_INFO:
+ priority = LOG_INFO;
+ break;
+ case HOSTAPD_LEVEL_NOTICE:
+ priority = LOG_NOTICE;
+ break;
+ case HOSTAPD_LEVEL_WARNING:
+ priority = LOG_WARNING;
+ break;
+ default:
+ priority = LOG_INFO;
+ break;
+ }
+ syslog(priority, "%s", format);
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ os_free(format);
+}
+
+
+static void hostapd_deauth_all_stas(struct hostapd_data *hapd)
+{
+ u8 addr[ETH_ALEN];
+
+ /* New Prism2.5/3 STA firmware versions seem to have issues with this
+ * broadcast deauth frame. This gets the firmware in odd state where
+ * nothing works correctly, so let's skip sending this for the hostap
+ * driver. */
+
+ if (hapd->driver && os_strcmp(hapd->driver->name, "hostap") != 0) {
+ os_memset(addr, 0xff, ETH_ALEN);
+ hostapd_sta_deauth(hapd, addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+}
+
+
+/**
+ * hostapd_prune_associations - Remove extraneous associations
+ * @hapd: Pointer to BSS data for the most recent association
+ * @sta: Pointer to the associated STA data
+ *
+ * This function looks through all radios and BSS's for previous
+ * (stale) associations of STA. If any are found they are removed.
+ */
+static void hostapd_prune_associations(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct sta_info *osta;
+ struct hostapd_data *ohapd;
+ size_t i, j;
+ struct hapd_interfaces *interfaces = eloop_get_user_data();
+
+ for (i = 0; i < interfaces->count; i++) {
+ for (j = 0; j < interfaces->iface[i]->num_bss; j++) {
+ ohapd = interfaces->iface[i]->bss[j];
+ if (ohapd == hapd)
+ continue;
+ osta = ap_get_sta(ohapd, sta->addr);
+ if (!osta)
+ continue;
+
+ ap_sta_disassociate(ohapd, osta,
+ WLAN_REASON_UNSPECIFIED);
+ }
+ }
+}
+
+
+/**
+ * hostapd_new_assoc_sta - Notify that a new station associated with the AP
+ * @hapd: Pointer to BSS data
+ * @sta: Pointer to the associated STA data
+ * @reassoc: 1 to indicate this was a re-association; 0 = first association
+ *
+ * This function will be called whenever a station associates with the AP. It
+ * can be called for ieee802_11.c for drivers that export MLME to hostapd and
+ * from driver_*.c for drivers that take care of management frames (IEEE 802.11
+ * authentication and association) internally.
+ */
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc)
+{
+ if (hapd->tkip_countermeasures) {
+ hostapd_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_MICHAEL_MIC_FAILURE);
+ return;
+ }
+
+ hostapd_prune_associations(hapd, sta);
+
+ /* IEEE 802.11F (IAPP) */
+ if (hapd->conf->ieee802_11f)
+ iapp_new_station(hapd->iapp, sta);
+
+ /* Start accounting here, if IEEE 802.1X and WPA are not used.
+ * IEEE 802.1X/WPA code will start accounting after the station has
+ * been authorized. */
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
+ accounting_sta_start(hapd, sta);
+
+ hostapd_wme_sta_config(hapd, sta);
+
+ /* Start IEEE 802.1X authentication process for new stations */
+ ieee802_1x_new_station(hapd, sta);
+ if (reassoc) {
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
+ wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
+ } else
+ wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0)
+ return 1;
+ return 0;
+}
+
+
+static void hostapd_sim_db_cb(void *ctx, void *session_ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0)
+ radius_server_eap_pending_cb(hapd->radius_srv, session_ctx);
+}
+#endif /* EAP_SERVER */
+
+
+/**
+ * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
+ */
+static void handle_term(int sig, void *eloop_ctx, void *signal_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
+ eloop_terminate();
+}
+
+
+static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+ struct wpa_auth_config *wconf)
+{
+ wconf->wpa = conf->wpa;
+ wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
+ wconf->wpa_pairwise = conf->wpa_pairwise;
+ wconf->wpa_group = conf->wpa_group;
+ wconf->wpa_group_rekey = conf->wpa_group_rekey;
+ wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
+ wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
+ wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+ wconf->rsn_pairwise = conf->rsn_pairwise;
+ wconf->rsn_preauth = conf->rsn_preauth;
+ wconf->eapol_version = conf->eapol_version;
+ wconf->peerkey = conf->peerkey;
+ wconf->wme_enabled = conf->wme_enabled;
+ wconf->okc = conf->okc;
+#ifdef CONFIG_IEEE80211W
+ wconf->ieee80211w = conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+ wconf->ssid_len = conf->ssid.ssid_len;
+ if (wconf->ssid_len > SSID_LEN)
+ wconf->ssid_len = SSID_LEN;
+ os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
+ os_memcpy(wconf->mobility_domain, conf->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN);
+ if (conf->nas_identifier &&
+ os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) {
+ wconf->r0_key_holder_len = os_strlen(conf->nas_identifier);
+ os_memcpy(wconf->r0_key_holder, conf->nas_identifier,
+ wconf->r0_key_holder_len);
+ }
+ os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
+ wconf->r0_key_lifetime = conf->r0_key_lifetime;
+ wconf->reassociation_deadline = conf->reassociation_deadline;
+ wconf->r0kh_list = conf->r0kh_list;
+ wconf->r1kh_list = conf->r1kh_list;
+ wconf->pmk_r1_push = conf->pmk_r1_push;
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct hostapd_config *newconf, *oldconf;
+ struct wpa_auth_config wpa_auth_conf;
+
+ newconf = hostapd_config_read(iface->config_fname);
+ if (newconf == NULL)
+ return -1;
+
+ /*
+ * Deauthenticate all stations since the new configuration may not
+ * allow them to use the BSS anymore.
+ */
+ hostapd_flush_old_stations(hapd);
+
+ /* TODO: update dynamic data based on changed configuration
+ * items (e.g., open/close sockets, etc.) */
+ radius_client_flush(hapd->radius, 0);
+
+ oldconf = hapd->iconf;
+ hapd->iconf = newconf;
+ hapd->conf = &newconf->bss[0];
+ iface->conf = newconf;
+
+ if (hostapd_setup_wpa_psk(hapd->conf)) {
+ wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
+ "after reloading configuration");
+ }
+
+ if (hapd->conf->wpa && hapd->wpa_auth == NULL)
+ hostapd_setup_wpa(hapd);
+ else if (hapd->conf->wpa) {
+ hostapd_wpa_auth_conf(&newconf->bss[0], &wpa_auth_conf);
+ wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
+ } else if (hapd->wpa_auth) {
+ wpa_deinit(hapd->wpa_auth);
+ hapd->wpa_auth = NULL;
+ hostapd_set_privacy(hapd, 0);
+ hostapd_setup_encryption(hapd->conf->iface, hapd);
+ }
+
+ ieee802_11_set_beacon(hapd);
+
+ hostapd_config_free(oldconf);
+
+ wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
+
+ return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+/**
+ * handle_reload - SIGHUP handler to reload configuration
+ */
+static void handle_reload(int sig, void *eloop_ctx, void *signal_ctx)
+{
+ struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx;
+ size_t i;
+
+ wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
+ sig);
+
+ for (i = 0; i < hapds->count; i++) {
+ if (hostapd_reload_config(hapds->iface[i]) < 0) {
+ wpa_printf(MSG_WARNING, "Failed to read new "
+ "configuration file - continuing with "
+ "old.");
+ continue;
+ }
+ }
+}
+
+
+#ifdef HOSTAPD_DUMP_STATE
+/**
+ * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
+ */
+static void hostapd_dump_state(struct hostapd_data *hapd)
+{
+ FILE *f;
+ time_t now;
+ struct sta_info *sta;
+ int i;
+ char *buf;
+
+ if (!hapd->conf->dump_log_name) {
+ wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
+ "request");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
+ hapd->conf->dump_log_name);
+ f = fopen(hapd->conf->dump_log_name, "w");
+ if (f == NULL) {
+ wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
+ "writing.", hapd->conf->dump_log_name);
+ return;
+ }
+
+ time(&now);
+ fprintf(f, "hostapd state dump - %s", ctime(&now));
+ fprintf(f, "num_sta=%d num_sta_non_erp=%d "
+ "num_sta_no_short_slot_time=%d\n"
+ "num_sta_no_short_preamble=%d\n",
+ hapd->num_sta, hapd->iface->num_sta_non_erp,
+ hapd->iface->num_sta_no_short_slot_time,
+ hapd->iface->num_sta_no_short_preamble);
+
+ for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+ fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
+
+ fprintf(f,
+ " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+ " capability=0x%x listen_interval=%d\n",
+ sta->aid,
+ sta->flags,
+ (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
+ (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
+ (sta->flags & WLAN_STA_PS ? "[PS]" : ""),
+ (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
+ (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
+ (sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" :
+ ""),
+ (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+ ""),
+ (sta->flags & WLAN_STA_SHORT_PREAMBLE ?
+ "[SHORT_PREAMBLE]" : ""),
+ (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+ (sta->flags & WLAN_STA_WME ? "[WME]" : ""),
+ (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
+ (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
+ (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
+ (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+ sta->capability,
+ sta->listen_interval);
+
+ fprintf(f, " supported_rates=");
+ for (i = 0; i < sta->supported_rates_len; i++)
+ fprintf(f, "%02x ", sta->supported_rates[i]);
+ fprintf(f, "\n");
+
+ fprintf(f,
+ " timeout_next=%s\n",
+ (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
+ (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
+ "DEAUTH")));
+
+ ieee802_1x_dump_state(f, " ", sta);
+ }
+
+ buf = os_malloc(4096);
+ if (buf) {
+ int count = radius_client_get_mib(hapd->radius, buf, 4096);
+ if (count < 0)
+ count = 0;
+ else if (count > 4095)
+ count = 4095;
+ buf[count] = '\0';
+ fprintf(f, "%s", buf);
+
+ count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
+ if (count < 0)
+ count = 0;
+ else if (count > 4095)
+ count = 4095;
+ buf[count] = '\0';
+ fprintf(f, "%s", buf);
+ os_free(buf);
+ }
+ fclose(f);
+}
+#endif /* HOSTAPD_DUMP_STATE */
+
+
+static void handle_dump_state(int sig, void *eloop_ctx, void *signal_ctx)
+{
+#ifdef HOSTAPD_DUMP_STATE
+ struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx;
+ size_t i, j;
+
+ for (i = 0; i < hapds->count; i++) {
+ struct hostapd_iface *hapd_iface = hapds->iface[i];
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_dump_state(hapd_iface->bss[j]);
+ }
+#endif /* HOSTAPD_DUMP_STATE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
+ char *ifname)
+{
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (hostapd_set_encryption(ifname, hapd, "none", NULL, i, NULL,
+ 0, i == 0 ? 1 : 0)) {
+ wpa_printf(MSG_DEBUG, "Failed to clear default "
+ "encryption keys (ifname=%s keyidx=%d)",
+ ifname, i);
+ }
+ }
+#ifdef CONFIG_IEEE80211W
+ if (hapd->conf->ieee80211w) {
+ for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
+ if (hostapd_set_encryption(ifname, hapd, "none", NULL,
+ i, NULL, 0,
+ i == 0 ? 1 : 0)) {
+ wpa_printf(MSG_DEBUG, "Failed to clear "
+ "default mgmt encryption keys "
+ "(ifname=%s keyidx=%d)", ifname, i);
+ }
+ }
+ }
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
+{
+ hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
+ return 0;
+}
+
+
+static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
+{
+ int errors = 0, idx;
+ struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+ idx = ssid->wep.idx;
+ if (ssid->wep.default_len &&
+ hostapd_set_encryption(hapd->conf->iface,
+ hapd, "WEP", NULL, idx,
+ ssid->wep.key[idx],
+ ssid->wep.len[idx],
+ idx == ssid->wep.idx)) {
+ wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
+ errors++;
+ }
+
+ if (ssid->dyn_vlan_keys) {
+ size_t i;
+ for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+ const char *ifname;
+ struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
+ if (key == NULL)
+ continue;
+ ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+ i);
+ if (ifname == NULL)
+ continue;
+
+ idx = key->idx;
+ if (hostapd_set_encryption(ifname, hapd, "WEP", NULL,
+ idx, key->key[idx],
+ key->len[idx],
+ idx == key->idx)) {
+ wpa_printf(MSG_WARNING, "Could not set "
+ "dynamic VLAN WEP encryption.");
+ errors++;
+ }
+ }
+ }
+
+ return errors;
+}
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+ hostapd_ctrl_iface_deinit(hapd);
+
+ os_free(hapd->default_wep_key);
+ hapd->default_wep_key = NULL;
+ iapp_deinit(hapd->iapp);
+ hapd->iapp = NULL;
+ accounting_deinit(hapd);
+ rsn_preauth_iface_deinit(hapd);
+ if (hapd->wpa_auth) {
+ wpa_deinit(hapd->wpa_auth);
+ hapd->wpa_auth = NULL;
+
+ if (hostapd_set_privacy(hapd, 0)) {
+ wpa_printf(MSG_DEBUG, "Could not disable "
+ "PrivacyInvoked for interface %s",
+ hapd->conf->iface);
+ }
+
+ if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
+ wpa_printf(MSG_DEBUG, "Could not remove generic "
+ "information element from interface %s",
+ hapd->conf->iface);
+ }
+ }
+ ieee802_1x_deinit(hapd);
+ vlan_deinit(hapd);
+ hostapd_acl_deinit(hapd);
+ radius_client_deinit(hapd->radius);
+ hapd->radius = NULL;
+ radius_server_deinit(hapd->radius_srv);
+ hapd->radius_srv = NULL;
+
+#ifdef CONFIG_IEEE80211R
+ l2_packet_deinit(hapd->l2);
+#endif /* CONFIG_IEEE80211R */
+
+ hostapd_deinit_wps(hapd);
+
+ hostapd_wireless_event_deinit(hapd);
+
+#ifdef EAP_TLS_FUNCS
+ if (hapd->ssl_ctx) {
+ tls_deinit(hapd->ssl_ctx);
+ hapd->ssl_ctx = NULL;
+ }
+#endif /* EAP_TLS_FUNCS */
+
+#ifdef EAP_SERVER
+ if (hapd->eap_sim_db_priv) {
+ eap_sim_db_deinit(hapd->eap_sim_db_priv);
+ hapd->eap_sim_db_priv = NULL;
+ }
+#endif /* EAP_SERVER */
+
+ if (hapd->interface_added &&
+ hostapd_bss_remove(hapd, hapd->conf->iface)) {
+ wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
+ hapd->conf->iface);
+ }
+}
+
+
+/**
+ * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called before per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
+{
+}
+
+
+/**
+ * hostapd_cleanup_iface - Complete per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called after per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+{
+ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+ iface->hw_features = NULL;
+ os_free(iface->current_rates);
+ iface->current_rates = NULL;
+ ap_list_deinit(iface);
+ hostapd_config_free(iface->conf);
+ iface->conf = NULL;
+
+ os_free(iface->config_fname);
+ os_free(iface->bss);
+ os_free(iface);
+}
+
+
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
+{
+ int i;
+
+ hostapd_broadcast_wep_set(hapd);
+
+ if (hapd->conf->ssid.wep.default_len)
+ return 0;
+
+ for (i = 0; i < 4; i++) {
+ if (hapd->conf->ssid.wep.key[i] &&
+ hostapd_set_encryption(iface, hapd, "WEP", NULL,
+ i, hapd->conf->ssid.wep.key[i],
+ hapd->conf->ssid.wep.len[i],
+ i == hapd->conf->ssid.wep.idx)) {
+ wpa_printf(MSG_WARNING, "Could not set WEP "
+ "encryption.");
+ return -1;
+ }
+ if (hapd->conf->ssid.wep.key[i] &&
+ i == hapd->conf->ssid.wep.idx)
+ hostapd_set_privacy(hapd, 1);
+ }
+
+ return 0;
+}
+
+
+static int hostapd_flush_old_stations(struct hostapd_data *hapd)
+{
+ int ret = 0;
+
+ if (hostapd_drv_none(hapd))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Flushing old station entries");
+ if (hostapd_flush(hapd)) {
+ wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
+ ret = -1;
+ }
+ wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
+ hostapd_deauth_all_stas(hapd);
+
+ return ret;
+}
+
+
+static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
+ logger_level level, const char *txt)
+{
+ struct hostapd_data *hapd = ctx;
+ int hlevel;
+
+ switch (level) {
+ case LOGGER_WARNING:
+ hlevel = HOSTAPD_LEVEL_WARNING;
+ break;
+ case LOGGER_INFO:
+ hlevel = HOSTAPD_LEVEL_INFO;
+ break;
+ case LOGGER_DEBUG:
+ default:
+ hlevel = HOSTAPD_LEVEL_DEBUG;
+ break;
+ }
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
+}
+
+
+static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
+ u16 reason)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
+ "STA " MACSTR " reason %d",
+ __func__, MAC2STR(addr), reason);
+
+ sta = ap_get_sta(hapd, addr);
+ hostapd_sta_deauth(hapd, addr, reason);
+ if (sta == NULL)
+ return;
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+ sta->timeout_next = STA_REMOVE;
+}
+
+
+static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+{
+ struct hostapd_data *hapd = ctx;
+ ieee80211_michael_mic_failure(hapd, addr, 0);
+}
+
+
+static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
+ wpa_eapol_variable var, int value)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (sta == NULL)
+ return;
+ switch (var) {
+ case WPA_EAPOL_portEnabled:
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
+ break;
+ case WPA_EAPOL_portValid:
+ ieee802_1x_notify_port_valid(sta->eapol_sm, value);
+ break;
+ case WPA_EAPOL_authorized:
+ ieee802_1x_set_sta_authorized(hapd, sta, value);
+ break;
+ case WPA_EAPOL_portControl_Auto:
+ if (sta->eapol_sm)
+ sta->eapol_sm->portControl = Auto;
+ break;
+ case WPA_EAPOL_keyRun:
+ if (sta->eapol_sm)
+ sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+ break;
+ case WPA_EAPOL_keyAvailable:
+ if (sta->eapol_sm)
+ sta->eapol_sm->eap_if->eapKeyAvailable =
+ value ? TRUE : FALSE;
+ break;
+ case WPA_EAPOL_keyDone:
+ if (sta->eapol_sm)
+ sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+ break;
+ case WPA_EAPOL_inc_EapolFramesTx:
+ if (sta->eapol_sm)
+ sta->eapol_sm->dot1xAuthEapolFramesTx++;
+ break;
+ }
+}
+
+
+static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
+ wpa_eapol_variable var)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (sta == NULL || sta->eapol_sm == NULL)
+ return -1;
+ switch (var) {
+ case WPA_EAPOL_keyRun:
+ return sta->eapol_sm->keyRun;
+ case WPA_EAPOL_keyAvailable:
+ return sta->eapol_sm->eap_if->eapKeyAvailable;
+ default:
+ return -1;
+ }
+}
+
+
+static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *prev_psk)
+{
+ struct hostapd_data *hapd = ctx;
+ return hostapd_get_psk(hapd->conf, addr, prev_psk);
+}
+
+
+static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
+ size_t *len)
+{
+ struct hostapd_data *hapd = ctx;
+ const u8 *key;
+ size_t keylen;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL)
+ return -1;
+
+ key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
+ if (key == NULL)
+ return -1;
+
+ if (keylen > *len)
+ keylen = *len;
+ os_memcpy(msk, key, keylen);
+ *len = keylen;
+
+ return 0;
+}
+
+
+static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, const char *alg,
+ const u8 *addr, int idx, u8 *key,
+ size_t key_len)
+{
+ struct hostapd_data *hapd = ctx;
+ const char *ifname = hapd->conf->iface;
+
+ if (vlan_id > 0) {
+ ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+ if (ifname == NULL)
+ return -1;
+ }
+
+ return hostapd_set_encryption(ifname, hapd, alg, addr, idx,
+ key, key_len, 1);
+}
+
+
+static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct hostapd_data *hapd = ctx;
+ return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
+}
+
+
+static int hostapd_wpa_auth_get_seqnum_igtk(void *ctx, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct hostapd_data *hapd = ctx;
+ return hostapd_get_seqnum_igtk(hapd->conf->iface, hapd, addr, idx,
+ seq);
+}
+
+
+static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
+ const u8 *data, size_t data_len,
+ int encrypt)
+{
+ struct hostapd_data *hapd = ctx;
+ return hostapd_send_eapol(hapd, addr, data, data_len, encrypt);
+}
+
+
+static int hostapd_wpa_auth_for_each_sta(
+ void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
+ void *cb_ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
+ return 1;
+ }
+ return 0;
+}
+
+
+static int hostapd_wpa_auth_for_each_auth(
+ void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx),
+ void *cb_ctx)
+{
+ struct hostapd_data *ohapd;
+ size_t i, j;
+ struct hapd_interfaces *interfaces = eloop_get_user_data();
+
+ for (i = 0; i < interfaces->count; i++) {
+ for (j = 0; j < interfaces->iface[i]->num_bss; j++) {
+ ohapd = interfaces->iface[i]->bss[j];
+ if (cb(ohapd->wpa_auth, cb_ctx))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
+ const u8 *data, size_t data_len)
+{
+ struct hostapd_data *hapd = ctx;
+
+ if (hapd->driver && hapd->driver->send_ether)
+ return hapd->driver->send_ether(hapd->drv_priv, dst,
+ hapd->own_addr, proto,
+ data, data_len);
+ if (hapd->l2 == NULL)
+ return -1;
+ return l2_packet_send(hapd->l2, dst, proto, data, data_len);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
+ const u8 *data, size_t data_len)
+{
+ struct hostapd_data *hapd = ctx;
+ int res;
+ struct ieee80211_mgmt *m;
+ size_t mlen;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, dst);
+ if (sta == NULL || sta->wpa_sm == NULL)
+ return -1;
+
+ m = os_zalloc(sizeof(*m) + data_len);
+ if (m == NULL)
+ return -1;
+ mlen = ((u8 *) &m->u - (u8 *) m) + data_len;
+ m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(m->da, dst, ETH_ALEN);
+ os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+ os_memcpy(&m->u, data, data_len);
+
+ res = hostapd_send_mgmt_frame(hapd, (u8 *) m, mlen, 0);
+ os_free(m);
+ return res;
+}
+
+
+static struct wpa_state_machine *
+hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_sta_add(hapd, sta_addr);
+ if (sta == NULL)
+ return NULL;
+ if (sta->wpa_sm)
+ return sta->wpa_sm;
+
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
+ if (sta->wpa_sm == NULL) {
+ ap_free_sta(hapd, sta);
+ return NULL;
+ }
+ sta->auth_alg = WLAN_AUTH_FT;
+
+ return sta->wpa_sm;
+}
+
+
+static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ wpa_ft_rrb_rx(hapd->wpa_auth, src_addr, buf, len);
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/**
+ * hostapd_validate_bssid_configuration - Validate BSSID configuration
+ * @iface: Pointer to interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to validate that the configured BSSIDs are valid.
+ */
+static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
+{
+ u8 mask[ETH_ALEN] = { 0 };
+ struct hostapd_data *hapd = iface->bss[0];
+ unsigned int i = iface->conf->num_bss, bits = 0, j;
+ int res;
+
+ if (hostapd_drv_none(hapd))
+ return 0;
+
+ /* Generate BSSID mask that is large enough to cover the BSSIDs. */
+
+ /* Determine the bits necessary to cover the number of BSSIDs. */
+ for (i--; i; i >>= 1)
+ bits++;
+
+ /* Determine the bits necessary to any configured BSSIDs,
+ if they are higher than the number of BSSIDs. */
+ for (j = 0; j < iface->conf->num_bss; j++) {
+ if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0)
+ continue;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ mask[i] |=
+ iface->conf->bss[j].bssid[i] ^
+ hapd->own_addr[i];
+ }
+ }
+
+ for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
+ ;
+ j = 0;
+ if (i < ETH_ALEN) {
+ j = (5 - i) * 8;
+
+ while (mask[i] != 0) {
+ mask[i] >>= 1;
+ j++;
+ }
+ }
+
+ if (bits < j)
+ bits = j;
+
+ if (bits > 40)
+ return -1;
+
+ os_memset(mask, 0xff, ETH_ALEN);
+ j = bits / 8;
+ for (i = 5; i > 5 - j; i--)
+ mask[i] = 0;
+ j = bits % 8;
+ while (j--)
+ mask[i] <<= 1;
+
+ wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
+ (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
+
+ res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
+ if (res == 0)
+ return 0;
+
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
+ MACSTR " for start address " MACSTR ".",
+ MAC2STR(mask), MAC2STR(hapd->own_addr));
+ return -1;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
+ wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
+ " for start address " MACSTR ".",
+ MAC2STR(mask), MAC2STR(hapd->own_addr));
+ wpa_printf(MSG_ERROR, "Start address must be the "
+ "first address in the block (i.e., addr "
+ "AND mask == addr).");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int mac_in_conf(struct hostapd_config *conf, const void *a)
+{
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_setup_wpa(struct hostapd_data *hapd)
+{
+ struct wpa_auth_config _conf;
+ struct wpa_auth_callbacks cb;
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+
+ hostapd_wpa_auth_conf(hapd->conf, &_conf);
+ os_memset(&cb, 0, sizeof(cb));
+ cb.ctx = hapd;
+ cb.logger = hostapd_wpa_auth_logger;
+ cb.disconnect = hostapd_wpa_auth_disconnect;
+ cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+ cb.set_eapol = hostapd_wpa_auth_set_eapol;
+ cb.get_eapol = hostapd_wpa_auth_get_eapol;
+ cb.get_psk = hostapd_wpa_auth_get_psk;
+ cb.get_msk = hostapd_wpa_auth_get_msk;
+ cb.set_key = hostapd_wpa_auth_set_key;
+ cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
+ cb.get_seqnum_igtk = hostapd_wpa_auth_get_seqnum_igtk;
+ cb.send_eapol = hostapd_wpa_auth_send_eapol;
+ cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
+ cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
+ cb.send_ether = hostapd_wpa_auth_send_ether;
+#ifdef CONFIG_IEEE80211R
+ cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
+ cb.add_sta = hostapd_wpa_auth_add_sta;
+#endif /* CONFIG_IEEE80211R */
+ hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
+ if (hapd->wpa_auth == NULL) {
+ wpa_printf(MSG_ERROR, "WPA initialization failed.");
+ return -1;
+ }
+
+ if (hostapd_set_privacy(hapd, 1)) {
+ wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
+ "for interface %s", hapd->conf->iface);
+ return -1;
+ }
+
+ wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
+ if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
+ wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
+ "the kernel driver.");
+ return -1;
+ }
+
+ if (rsn_preauth_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR, "Initialization of RSN "
+ "pre-authentication failed.");
+ return -1;
+ }
+
+ return 0;
+
+}
+
+
+static int hostapd_setup_radius_srv(struct hostapd_data *hapd,
+ struct hostapd_bss_config *conf)
+{
+ struct radius_server_conf srv;
+ os_memset(&srv, 0, sizeof(srv));
+ srv.client_file = conf->radius_server_clients;
+ srv.auth_port = conf->radius_server_auth_port;
+ srv.conf_ctx = conf;
+ srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
+ srv.ssl_ctx = hapd->ssl_ctx;
+ srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
+ srv.eap_fast_a_id = conf->eap_fast_a_id;
+ srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
+ srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
+ srv.eap_fast_prov = conf->eap_fast_prov;
+ srv.pac_key_lifetime = conf->pac_key_lifetime;
+ srv.pac_key_refresh_time = conf->pac_key_refresh_time;
+ srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+ srv.tnc = conf->tnc;
+ srv.wps = hapd->wps;
+ srv.ipv6 = conf->radius_server_ipv6;
+ srv.get_eap_user = hostapd_radius_get_eap_user;
+ srv.eap_req_id_text = conf->eap_req_id_text;
+ srv.eap_req_id_text_len = conf->eap_req_id_text_len;
+
+ hapd->radius_srv = radius_server_init(&srv);
+ if (hapd->radius_srv == NULL) {
+ wpa_printf(MSG_ERROR, "RADIUS server initialization failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * hostapd_setup_bss - Per-BSS setup (initialization)
+ * @hapd: Pointer to BSS data
+ * @first: Whether this BSS is the first BSS of an interface
+ *
+ * This function is used to initialize all per-BSS data structures and
+ * resources. This gets called in a loop for each BSS when an interface is
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
+ int ssid_len, set_ssid;
+
+ if (!first) {
+ if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
+ /* Allocate the next available BSSID. */
+ do {
+ inc_byte_array(hapd->own_addr, ETH_ALEN);
+ } while (mac_in_conf(hapd->iconf, hapd->own_addr));
+ } else {
+ /* Allocate the configured BSSID. */
+ os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+
+ if (hostapd_mac_comp(hapd->own_addr,
+ hapd->iface->bss[0]->own_addr) ==
+ 0) {
+ wpa_printf(MSG_ERROR, "BSS '%s' may not have "
+ "BSSID set to the MAC address of "
+ "the radio", hapd->conf->iface);
+ return -1;
+ }
+ }
+
+ hapd->interface_added = 1;
+ if (hostapd_bss_add(hapd->iface->bss[0], hapd->conf->iface,
+ hapd->own_addr)) {
+ wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
+ MACSTR ")", MAC2STR(hapd->own_addr));
+ return -1;
+ }
+ }
+
+ /*
+ * Fetch the SSID from the system and use it or,
+ * if one was specified in the config file, verify they
+ * match.
+ */
+ ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
+ if (ssid_len < 0) {
+ wpa_printf(MSG_ERROR, "Could not read SSID from system");
+ return -1;
+ }
+ if (conf->ssid.ssid_set) {
+ /*
+ * If SSID is specified in the config file and it differs
+ * from what is being used then force installation of the
+ * new SSID.
+ */
+ set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
+ os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
+ } else {
+ /*
+ * No SSID in the config file; just use the one we got
+ * from the system.
+ */
+ set_ssid = 0;
+ conf->ssid.ssid_len = ssid_len;
+ os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
+ conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
+ }
+
+ if (!hostapd_drv_none(hapd)) {
+ wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+ " and ssid '%s'",
+ hapd->conf->iface, MAC2STR(hapd->own_addr),
+ hapd->conf->ssid.ssid);
+ }
+
+ if (hostapd_setup_wpa_psk(conf)) {
+ wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
+ return -1;
+ }
+
+ /* Set flag for whether SSID is broadcast in beacons */
+ if (hostapd_set_broadcast_ssid(hapd,
+ !!hapd->conf->ignore_broadcast_ssid)) {
+ wpa_printf(MSG_ERROR, "Could not set broadcast SSID flag for "
+ "kernel driver");
+ return -1;
+ }
+
+ if (hostapd_set_dtim_period(hapd, hapd->conf->dtim_period)) {
+ wpa_printf(MSG_ERROR, "Could not set DTIM period for kernel "
+ "driver");
+ return -1;
+ }
+
+ /* Set SSID for the kernel driver (to be used in beacon and probe
+ * response frames) */
+ if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
+ conf->ssid.ssid_len)) {
+ wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
+ return -1;
+ }
+
+ if (wpa_debug_level == MSG_MSGDUMP)
+ conf->radius->msg_dumps = 1;
+ hapd->radius = radius_client_init(hapd, conf->radius);
+ if (hapd->radius == NULL) {
+ wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
+ return -1;
+ }
+
+ if (hostapd_acl_init(hapd)) {
+ wpa_printf(MSG_ERROR, "ACL initialization failed.");
+ return -1;
+ }
+ if (hostapd_init_wps(hapd, conf))
+ return -1;
+
+ if (ieee802_1x_init(hapd)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
+ return -1;
+ }
+
+ if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
+ return -1;
+
+ if (accounting_init(hapd)) {
+ wpa_printf(MSG_ERROR, "Accounting initialization failed.");
+ return -1;
+ }
+
+ if (hapd->conf->ieee802_11f &&
+ (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+ wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
+ "failed.");
+ return -1;
+ }
+
+ if (hostapd_ctrl_iface_init(hapd)) {
+ wpa_printf(MSG_ERROR, "Failed to setup control interface");
+ return -1;
+ }
+
+ if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
+ wpa_printf(MSG_ERROR, "VLAN initialization failed.");
+ return -1;
+ }
+
+#ifdef CONFIG_IEEE80211R
+ if (!hostapd_drv_none(hapd)) {
+ hapd->l2 = l2_packet_init(hapd->conf->iface, NULL, ETH_P_RRB,
+ hostapd_rrb_receive, hapd, 0);
+ if (hapd->l2 == NULL &&
+ (hapd->driver == NULL ||
+ hapd->driver->send_ether == NULL)) {
+ wpa_printf(MSG_ERROR, "Failed to open l2_packet "
+ "interface");
+ return -1;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ ieee802_11_set_beacon(hapd);
+
+ if (conf->radius_server_clients &&
+ hostapd_setup_radius_srv(hapd, conf))
+ return -1;
+
+ return 0;
+}
+
+
+static void hostapd_tx_queue_params(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ int i;
+ struct hostapd_tx_queue_params *p;
+
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ p = &iface->conf->tx_queue[i];
+
+ if (!p->configured)
+ continue;
+
+ if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
+ p->cwmax, p->burst)) {
+ wpa_printf(MSG_DEBUG, "Failed to set TX queue "
+ "parameters for queue %d.", i);
+ /* Continue anyway */
+ }
+ }
+}
+
+
+static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ const struct hostapd_eap_user *eap_user;
+ int i, count;
+
+ eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
+ if (eap_user == NULL)
+ return -1;
+
+ if (user == NULL)
+ return 0;
+
+ os_memset(user, 0, sizeof(*user));
+ count = EAP_USER_MAX_METHODS;
+ if (count > EAP_MAX_METHODS)
+ count = EAP_MAX_METHODS;
+ for (i = 0; i < count; i++) {
+ user->methods[i].vendor = eap_user->methods[i].vendor;
+ user->methods[i].method = eap_user->methods[i].method;
+ }
+
+ if (eap_user->password) {
+ user->password = os_malloc(eap_user->password_len);
+ if (user->password == NULL)
+ return -1;
+ os_memcpy(user->password, eap_user->password,
+ eap_user->password_len);
+ user->password_len = eap_user->password_len;
+ user->password_hash = eap_user->password_hash;
+ }
+ user->force_version = eap_user->force_version;
+ user->ttls_auth = eap_user->ttls_auth;
+
+ return 0;
+}
+
+
+static int setup_interface(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct hostapd_bss_config *conf = hapd->conf;
+ size_t i;
+ char country[4];
+ u8 *b = conf->bssid;
+ int freq;
+ size_t j;
+ int ret = 0;
+ u8 *prev_addr;
+
+ /*
+ * Initialize the driver interface and make sure that all BSSes get
+ * configured with a pointer to this driver interface.
+ */
+ if (b[0] | b[1] | b[2] | b[3] | b[4] | b[5]) {
+ hapd->drv_priv = hostapd_driver_init_bssid(hapd, b);
+ } else {
+ hapd->drv_priv = hostapd_driver_init(hapd);
+ }
+
+ if (hapd->drv_priv == NULL) {
+ wpa_printf(MSG_ERROR, "%s driver initialization failed.",
+ hapd->driver ? hapd->driver->name : "Unknown");
+ hapd->driver = NULL;
+ return -1;
+ }
+ for (i = 0; i < iface->num_bss; i++) {
+ iface->bss[i]->driver = hapd->driver;
+ iface->bss[i]->drv_priv = hapd->drv_priv;
+ }
+
+ if (hostapd_validate_bssid_configuration(iface))
+ return -1;
+
+#ifdef CONFIG_IEEE80211N
+ SET_2BIT_LE16(&iface->ht_op_mode,
+ HT_INFO_OPERATION_MODE_OP_MODE_OFFSET,
+ OP_MODE_PURE);
+#endif /* CONFIG_IEEE80211N */
+
+ if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+ os_memcpy(country, hapd->iconf->country, 3);
+ country[3] = '\0';
+ if (hostapd_set_country(hapd, country) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set country code");
+ return -1;
+ }
+ }
+
+ if (hapd->iconf->ieee80211d &&
+ hostapd_set_ieee80211d(hapd, 1) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set ieee80211d (%d)",
+ hapd->iconf->ieee80211d);
+ return -1;
+ }
+
+ if (hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
+ hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets)) {
+ wpa_printf(MSG_ERROR, "Failed to set bridge_packets for "
+ "kernel driver");
+ return -1;
+ }
+
+ /* TODO: merge with hostapd_driver_init() ? */
+ if (hostapd_wireless_event_init(hapd) < 0)
+ return -1;
+
+ if (hostapd_get_hw_features(iface)) {
+ /* Not all drivers support this yet, so continue without hw
+ * feature data. */
+ } else {
+ int ret = hostapd_select_hw_mode(iface);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Could not select hw_mode and "
+ "channel. (%d)", ret);
+ return -1;
+ }
+ }
+
+ hostapd_flush_old_stations(hapd);
+ hostapd_set_privacy(hapd, 0);
+
+ if (hapd->iconf->channel) {
+ freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+ wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
+ "Frequency: %d MHz",
+ hostapd_hw_mode_txt(hapd->iconf->hw_mode),
+ hapd->iconf->channel, freq);
+
+ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq,
+ hapd->iconf->ieee80211n,
+ hapd->iconf->secondary_channel)) {
+ wpa_printf(MSG_ERROR, "Could not set channel for "
+ "kernel driver");
+ return -1;
+ }
+ }
+
+ hostapd_broadcast_wep_clear(hapd);
+ if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+ return -1;
+
+ hostapd_set_beacon_int(hapd, hapd->iconf->beacon_int);
+ ieee802_11_set_beacon(hapd);
+
+ if (hapd->iconf->rts_threshold > -1 &&
+ hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+ wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
+ "kernel driver");
+ return -1;
+ }
+
+ if (hapd->iconf->fragm_threshold > -1 &&
+ hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+ wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
+ "for kernel driver");
+ return -1;
+ }
+
+ prev_addr = hapd->own_addr;
+
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ if (j)
+ os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+ if (hostapd_setup_bss(hapd, j == 0))
+ return -1;
+ if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+ prev_addr = hapd->own_addr;
+ }
+
+ hostapd_tx_queue_params(iface);
+
+ ap_list_init(iface);
+
+ if (hostapd_driver_commit(hapd) < 0) {
+ wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
+ "configuration", __func__);
+ return -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * hostapd_setup_interface - Setup of an interface
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, -1 on failure
+ *
+ * Initializes the driver interface, validates the configuration,
+ * and sets driver parameters based on the configuration.
+ * Flushes old stations, sets the channel, encryption,
+ * beacons, and WDS links based on the configuration.
+ */
+static int hostapd_setup_interface(struct hostapd_iface *iface)
+{
+ int ret;
+
+ ret = setup_interface(iface);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "%s: Unable to setup interface.",
+ iface->bss[0]->conf->iface);
+ eloop_terminate();
+ return -1;
+ } else if (!hostapd_drv_none(iface->bss[0])) {
+ wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
+ iface->bss[0]->conf->iface);
+ }
+
+ return 0;
+}
+
+
+static void show_version(void)
+{
+ fprintf(stderr,
+ "hostapd v" VERSION_STR "\n"
+ "User space daemon for IEEE 802.11 AP management,\n"
+ "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
+ "Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> "
+ "and contributors\n");
+}
+
+
+static void usage(void)
+{
+ show_version();
+ fprintf(stderr,
+ "\n"
+ "usage: hostapd [-hdBKtv] [-P <PID file>] "
+ "<configuration file(s)>\n"
+ "\n"
+ "options:\n"
+ " -h show this usage\n"
+ " -d show more debug messages (-dd for even more)\n"
+ " -B run daemon in the background\n"
+ " -P PID file\n"
+ " -K include key data in debug messages\n"
+ " -t include timestamps in some debug messages\n"
+ " -v show hostapd version\n");
+
+ exit(1);
+}
+
+
+/**
+ * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
+ * @hapd_iface: Pointer to interface data
+ * @conf: Pointer to per-interface configuration
+ * @bss: Pointer to per-BSS configuration for this BSS
+ * Returns: Pointer to allocated BSS data
+ *
+ * This function is used to allocate per-BSS data structure. This data will be
+ * freed after hostapd_cleanup() is called for it during interface
+ * deinitialization.
+ */
+static struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+ struct hostapd_config *conf,
+ struct hostapd_bss_config *bss)
+{
+ struct hostapd_data *hapd;
+
+ hapd = os_zalloc(sizeof(*hapd));
+ if (hapd == NULL)
+ return NULL;
+
+ hapd->iconf = conf;
+ hapd->conf = bss;
+ hapd->iface = hapd_iface;
+
+ if (hapd->conf->individual_wep_key_len > 0) {
+ /* use key0 in individual key and key1 in broadcast key */
+ hapd->default_wep_key_idx = 1;
+ }
+
+#ifdef EAP_TLS_FUNCS
+ if (hapd->conf->eap_server &&
+ (hapd->conf->ca_cert || hapd->conf->server_cert ||
+ hapd->conf->dh_file)) {
+ struct tls_connection_params params;
+
+ hapd->ssl_ctx = tls_init(NULL);
+ if (hapd->ssl_ctx == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to initialize TLS");
+ goto fail;
+ }
+
+ os_memset(&params, 0, sizeof(params));
+ params.ca_cert = hapd->conf->ca_cert;
+ params.client_cert = hapd->conf->server_cert;
+ params.private_key = hapd->conf->private_key;
+ params.private_key_passwd = hapd->conf->private_key_passwd;
+ params.dh_file = hapd->conf->dh_file;
+
+ if (tls_global_set_params(hapd->ssl_ctx, &params)) {
+ wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
+ goto fail;
+ }
+
+ if (tls_global_set_verify(hapd->ssl_ctx,
+ hapd->conf->check_crl)) {
+ wpa_printf(MSG_ERROR, "Failed to enable check_crl");
+ goto fail;
+ }
+ }
+#endif /* EAP_TLS_FUNCS */
+
+#ifdef EAP_SERVER
+ if (hapd->conf->eap_sim_db) {
+ hapd->eap_sim_db_priv =
+ eap_sim_db_init(hapd->conf->eap_sim_db,
+ hostapd_sim_db_cb, hapd);
+ if (hapd->eap_sim_db_priv == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
+ "database interface");
+ goto fail;
+ }
+ }
+#endif /* EAP_SERVER */
+
+ hapd->driver = hapd->iconf->driver;
+
+ return hapd;
+
+#if defined(EAP_TLS_FUNCS) || defined(EAP_SERVER)
+fail:
+#endif
+ /* TODO: cleanup allocated resources(?) */
+ os_free(hapd);
+ return NULL;
+}
+
+
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+static struct hostapd_iface * hostapd_init(const char *config_file)
+{
+ struct hostapd_iface *hapd_iface = NULL;
+ struct hostapd_config *conf = NULL;
+ struct hostapd_data *hapd;
+ size_t i;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (hapd_iface == NULL)
+ goto fail;
+
+ hapd_iface->config_fname = os_strdup(config_file);
+ if (hapd_iface->config_fname == NULL)
+ goto fail;
+
+ conf = hostapd_config_read(hapd_iface->config_fname);
+ if (conf == NULL)
+ goto fail;
+ hapd_iface->conf = conf;
+
+ hapd_iface->num_bss = conf->num_bss;
+ hapd_iface->bss = os_zalloc(conf->num_bss *
+ sizeof(struct hostapd_data *));
+ if (hapd_iface->bss == NULL)
+ goto fail;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ hapd = hapd_iface->bss[i] =
+ hostapd_alloc_bss_data(hapd_iface, conf,
+ &conf->bss[i]);
+ if (hapd == NULL)
+ goto fail;
+ }
+
+ return hapd_iface;
+
+fail:
+ if (conf)
+ hostapd_config_free(conf);
+ if (hapd_iface) {
+ for (i = 0; hapd_iface->bss && i < hapd_iface->num_bss; i++) {
+ hapd = hapd_iface->bss[i];
+ if (hapd && hapd->ssl_ctx)
+ tls_deinit(hapd->ssl_ctx);
+ }
+
+ os_free(hapd_iface->config_fname);
+ os_free(hapd_iface->bss);
+ os_free(hapd_iface);
+ }
+ return NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct hapd_interfaces interfaces;
+ int ret = 1, k;
+ size_t i, j;
+ int c, debug = 0, daemonize = 0, tnc = 0;
+ const char *pid_file = NULL;
+
+ hostapd_logger_register_cb(hostapd_logger_cb);
+
+ for (;;) {
+ c = getopt(argc, argv, "BdhKP:tv");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'h':
+ usage();
+ break;
+ case 'd':
+ debug++;
+ if (wpa_debug_level > 0)
+ wpa_debug_level--;
+ break;
+ case 'B':
+ daemonize++;
+ break;
+ case 'K':
+ wpa_debug_show_keys++;
+ break;
+ case 'P':
+ pid_file = optarg;
+ break;
+ case 't':
+ wpa_debug_timestamp++;
+ break;
+ case 'v':
+ show_version();
+ exit(1);
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (optind == argc)
+ usage();
+
+ if (eap_server_register_methods()) {
+ wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+ return -1;
+ }
+
+ interfaces.count = argc - optind;
+
+ interfaces.iface = os_malloc(interfaces.count *
+ sizeof(struct hostapd_iface *));
+ if (interfaces.iface == NULL) {
+ wpa_printf(MSG_ERROR, "malloc failed\n");
+ return -1;
+ }
+
+ if (eloop_init(&interfaces)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ return -1;
+ }
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ eloop_register_signal(SIGHUP, handle_reload, NULL);
+ eloop_register_signal(SIGUSR1, handle_dump_state, NULL);
+#endif /* CONFIG_NATIVE_WINDOWS */
+ eloop_register_signal_terminate(handle_term, NULL);
+
+ /* Initialize interfaces */
+ for (i = 0; i < interfaces.count; i++) {
+ wpa_printf(MSG_ERROR, "Configuration file: %s",
+ argv[optind + i]);
+ interfaces.iface[i] = hostapd_init(argv[optind + i]);
+ if (!interfaces.iface[i])
+ goto out;
+ for (k = 0; k < debug; k++) {
+ if (interfaces.iface[i]->bss[0]->conf->
+ logger_stdout_level > 0)
+ interfaces.iface[i]->bss[0]->conf->
+ logger_stdout_level--;
+ }
+
+ ret = hostapd_setup_interface(interfaces.iface[i]);
+ if (ret)
+ goto out;
+
+ for (k = 0; k < (int) interfaces.iface[i]->num_bss; k++) {
+ if (interfaces.iface[i]->bss[0]->conf->tnc)
+ tnc++;
+ }
+ }
+
+#ifdef EAP_TNC
+ if (tnc && tncs_global_init() < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
+ goto out;
+ }
+#endif /* EAP_TNC */
+
+ if (daemonize && os_daemonize(pid_file)) {
+ perror("daemon");
+ goto out;
+ }
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ openlog("hostapd", 0, LOG_DAEMON);
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ eloop_run();
+
+ /* Disconnect associated stations from all interfaces and BSSes */
+ for (i = 0; i < interfaces.count; i++) {
+ for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
+ struct hostapd_data *hapd =
+ interfaces.iface[i]->bss[j];
+ hostapd_free_stas(hapd);
+ hostapd_flush_old_stations(hapd);
+ }
+ }
+
+ ret = 0;
+
+ out:
+ /* Deinitialize all interfaces */
+ for (i = 0; i < interfaces.count; i++) {
+ if (!interfaces.iface[i])
+ continue;
+ hostapd_cleanup_iface_pre(interfaces.iface[i]);
+ for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
+ struct hostapd_data *hapd =
+ interfaces.iface[i]->bss[j];
+ hostapd_cleanup(hapd);
+ if (j == interfaces.iface[i]->num_bss - 1 &&
+ hapd->driver)
+ hostapd_driver_deinit(hapd);
+ }
+ for (j = 0; j < interfaces.iface[i]->num_bss; j++)
+ os_free(interfaces.iface[i]->bss[j]);
+ hostapd_cleanup_iface(interfaces.iface[i]);
+ }
+ os_free(interfaces.iface);
+
+#ifdef EAP_TNC
+ tncs_global_deinit();
+#endif /* EAP_TNC */
+
+ eloop_destroy();
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ closelog();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ eap_server_unregister_methods();
+
+ os_daemonize_terminate(pid_file);
+
+ return ret;
+}
diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf
new file mode 100644
index 0000000..0602cb0
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.conf
@@ -0,0 +1,1024 @@
+##### 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 and nl80211 driver interfaces, 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/none/nl80211/bsd);
+# default: hostap). nl80211 is used with all Linux mac80211 drivers.
+# Use driver=none 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.
+# Set as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+#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
+
+# 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)
+# Please note that some drivers (e.g., madwifi) do not use this value from
+# hostapd and the channel will need to be configuration separately with
+# iwconfig.
+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
+
+# Short Preamble
+# This parameter can be used to enable optional use of short preamble for
+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
+# This applies only to IEEE 802.11b-compatible networks and this should only be
+# enabled if the local hardware supports use of short preamble. If any of the
+# associated STAs do not support short preamble, use of short preamble will be
+# disabled (and enabled when such STAs disassociate) dynamically.
+# 0 = do not allow use of short preamble (default)
+# 1 = allow use of short preamble
+#preamble=1
+
+# 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
+
+# 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
+
+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
+# remain asleep). Default: 65535 (no limit apart from field size)
+#max_listen_interval=100
+
+##### IEEE 802.11n related configuration ######################################
+
+# ieee80211n: Whether IEEE 802.11n (HT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211n=1
+
+# ht_capab: HT capabilities (list of flags)
+# LDPC coding capability: [LDPC] = supported
+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
+# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
+# with secondary channel below the primary channel
+# (20 MHz only if neither is set)
+# Note: There are limits on which channels can be used with HT40- and
+# HT40+. Following table shows the channels that may be available for
+# HT40- and HT40+ use per IEEE 802.11n Annex J:
+# freq HT40- HT40+
+# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan)
+# 5 GHz 40,48,56,64 36,44,52,60
+# (depending on the location, not all of these channels may be available
+# for use)
+# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
+# (SMPS disabled if neither is set)
+# HT-greenfield: [GF] (disabled if not set)
+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
+# Tx STBC: [TX-STBC] (disabled if not set)
+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
+# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
+# disabled if none of these set
+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
+# set)
+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
+# PSMP support: [PSMP] (disabled if not set)
+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
+
+##### 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.
+# You can generate DH parameters file with OpenSSL, e.g.,
+# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
+#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)
+# A-ID indicates the identity of the authority that issues PACs. The A-ID
+# should be unique across all issuing servers. In theory, this is a variable
+# length field, but due to some existing implementations required A-ID to be
+# 16 octets in length, it is strongly recommended to use that length for the
+# field to provided interoperability with deployed peer implementation. This
+# field is configured in hex format.
+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
+
+# EAP-FAST authority identifier information (A-ID-Info)
+# This is a user-friendly name for the A-ID. For example, the enterprise name
+# and server name in a human-readable format. This field is encoded as UTF-8.
+#eap_fast_a_id_info=test server
+
+# Enable/disable different EAP-FAST provisioning modes:
+#0 = provisioning disabled
+#1 = only anonymous provisioning allowed
+#2 = only authenticated provisioning allowed
+#3 = both provisioning modes allowed (default)
+#eap_fast_prov=3
+
+# EAP-FAST PAC-Key lifetime in seconds (hard limit)
+#pac_key_lifetime=604800
+
+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
+# limit). The server will generate a new PAC-Key when this number of seconds
+# (or fewer) of the lifetime remains.
+#pac_key_refresh_time=86400
+
+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
+# (default: 0 = disabled).
+#eap_sim_aka_result_ind=1
+
+# Trusted Network Connect (TNC)
+# If enabled, TNC validation will be required before the peer is allowed to
+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
+# EAP method is enabled, the peer will be allowed to connect without TNC.
+#tnc=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. Optionally, the local MAC ACL list (accept_mac_file) can be
+# used to set static client MAC address to VLAN ID mapping.
+# 0 = disabled (default)
+# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#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. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
+# (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
+
+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
+# PTK to mitigate some attacks against TKIP deficiencies.
+#wpa_ptk_rekey=600
+
+# 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 (MFP) is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+
+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
+# (maximum time to wait for a SA Query response)
+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
+#assoc_sa_query_max_timeout=1000
+
+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
+# (time between two subsequent SA Query requests)
+# dot11AssociationSAQueryRetryTimeout, 1...4294967295
+#assoc_sa_query_retry_timeout=201
+
+
+# okc: Opportunistic Key Caching (aka Proactive Key Caching)
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+# 0 = disabled (default)
+# 1 = enabled
+#okc=1
+
+
+##### 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
+
+
+##### Wi-Fi Protected Setup (WPS) #############################################
+
+# WPS state
+# 0 = WPS disabled (default)
+# 1 = WPS enabled, not configured
+# 2 = WPS enabled, configured
+#wps_state=2
+
+# AP can be configured into a locked state where new WPS Registrar are not
+# accepted, but previously authorized Registrars (including the internal one)
+# can continue to add new Enrollees.
+#ap_setup_locked=1
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# This value is used as the UUID for the internal WPS Registrar. If the AP
+# is also using UPnP, this value should be set to the device's UPnP UUID.
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
+# per-device PSKs is recommended as the more secure option (i.e., make sure to
+# set wpa_psk_file when using WPS with WPA-PSK).
+
+# When an Enrollee requests access to the network with PIN method, the Enrollee
+# PIN will need to be entered for the Registrar. PIN request notifications are
+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
+# text file that could be used, e.g., to populate the AP administration UI with
+# pending PIN requests. If the following variable is set, the PIN requests will
+# be written to the configured file.
+#wps_pin_requests=/var/run/hostapd_wps_pin_requests
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless AP
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=WAP
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+# default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+# 1-0050F204-1 (Computer / PC)
+# 1-0050F204-2 (Computer / Server)
+# 5-0050F204-1 (Storage / NAS)
+# 6-0050F204-1 (Network Infrastructure / AP)
+#device_type=6-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+#config_methods=label display push_button keypad
+
+# Access point PIN for initial configuration and adding Registrars
+# If not set, hostapd will not allow external WPS Registrars to control the
+# access point.
+#ap_pin=12345670
+
+# Skip building of automatic WPS credential
+# This can be used to allow the automatically generated Credential attribute to
+# be replaced with pre-configured Credential(s).
+#skip_cred_build=1
+
+# Additional Credential attribute(s)
+# This option can be used to add pre-configured Credential attributes into M8
+# message when acting as a Registrar. If skip_cred_build=1, this data will also
+# be able to override the Credential attribute that would have otherwise been
+# automatically generated based on network configuration. This configuration
+# option points to an external file that much contain the WPS Credential
+# attribute(s) as binary data.
+#extra_cred=hostapd.cred
+
+# Credential processing
+# 0 = process received credentials internally (default)
+# 1 = do not process received credentials; just pass them over ctrl_iface to
+# external program(s)
+# 2 = process received credentials internally and pass them over ctrl_iface
+# to external program(s)
+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
+# extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
+#wps_cred_processing=0
+
+# AP Settings Attributes for M7
+# By default, hostapd generates the AP Settings Attributes for M7 based on the
+# current configuration. It is possible to override this by providing a file
+# with pre-configured attributes. This is similar to extra_cred file format,
+# but the AP Settings attributes are not encapsulated in a Credential
+# attribute.
+#ap_settings=hostapd.ap_settings
+
+# WPS UPnP interface
+# If set, support for external Registrars is enabled.
+#upnp_iface=br0
+
+# Friendly Name (required for UPnP)
+# Short description for end use. Should be less than 64 characters.
+#friendly_name=WPS Access Point
+
+# Manufacturer URL (optional for UPnP)
+#manufacturer_url=http://www.example.com/
+
+# Model Description (recommended for UPnP)
+# Long description for end user. Should be less than 128 characters.
+#model_description=Wireless Access Point
+
+# Model URL (optional for UPnP)
+#model_url=http://www.example.com/model/
+
+# Universal Product Code (optional for UPnP)
+# 12-digit, all-numeric code that identifies the consumer package.
+#upc=123456789012
+
+##### 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
+# ...
diff --git a/contrib/wpa/hostapd/hostapd.deny b/contrib/wpa/hostapd/hostapd.deny
new file mode 100644
index 0000000..1616678
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.deny
@@ -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
diff --git a/contrib/wpa/hostapd/hostapd.eap_user b/contrib/wpa/hostapd/hostapd.eap_user
new file mode 100644
index 0000000..ac9a5d8
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.eap_user
@@ -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]
diff --git a/contrib/wpa/hostapd/hostapd.h b/contrib/wpa/hostapd/hostapd.h
new file mode 100644
index 0000000..26f30d7
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.h
@@ -0,0 +1,238 @@
+/*
+ * hostapd / Initialization and configuration
+ * Host AP kernel driver
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#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;
+struct upnp_wps_device_sm;
+
+#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;
+
+ 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;
+ struct wps_context *wps;
+
+#ifdef CONFIG_WPS
+ u8 *wps_beacon_ie;
+ size_t wps_beacon_ie_len;
+ u8 *wps_probe_resp_ie;
+ size_t wps_probe_resp_ie_len;
+ unsigned int ap_pin_failures;
+ struct upnp_wps_device_sm *wps_upnp;
+#endif /* CONFIG_WPS */
+};
+
+
+/**
+ * struct hostapd_iface - hostapd per-interface data structure
+ */
+struct hostapd_iface {
+ char *config_fname;
+ struct hostapd_config *conf;
+
+ 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;
+
+ 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 */
+
+ /* Number of HT associated stations that do not support greenfield */
+ int num_sta_ht_no_gf;
+
+ /* Number of associated non-HT stations */
+ int num_sta_no_ht;
+
+ /* Number of HT associated stations 20 MHz */
+ int num_sta_ht_20mhz;
+
+ /* Overlapping BSS information */
+ int olbc_ht;
+
+#ifdef CONFIG_IEEE80211N
+ u16 ht_op_mode;
+#endif /* CONFIG_IEEE80211N */
+};
+
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc);
+int hostapd_reload_config(struct hostapd_iface *iface);
+
+#endif /* HOSTAPD_H */
diff --git a/contrib/wpa/hostapd/hostapd.radius_clients b/contrib/wpa/hostapd/hostapd.radius_clients
new file mode 100644
index 0000000..3980427
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.radius_clients
@@ -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
diff --git a/contrib/wpa/hostapd/hostapd.sim_db b/contrib/wpa/hostapd/hostapd.sim_db
new file mode 100644
index 0000000..01c593d
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.sim_db
@@ -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
diff --git a/contrib/wpa/hostapd/hostapd.vlan b/contrib/wpa/hostapd/hostapd.vlan
new file mode 100644
index 0000000..98254fa
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.vlan
@@ -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#
diff --git a/contrib/wpa/hostapd/hostapd.wpa_psk b/contrib/wpa/hostapd/hostapd.wpa_psk
new file mode 100644
index 0000000..0a9499a
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd.wpa_psk
@@ -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
diff --git a/contrib/wpa/hostapd/hostapd_cli.1 b/contrib/wpa/hostapd/hostapd_cli.1
new file mode 100644
index 0000000..8d6587f
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd_cli.1
@@ -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).
diff --git a/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c
new file mode 100644
index 0000000..2614113
--- /dev/null
+++ b/contrib/wpa/hostapd/hostapd_cli.c
@@ -0,0 +1,673 @@
+/*
+ * hostapd - command line interface for hostapd daemon
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#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-2009, 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"
+#ifdef CONFIG_IEEE80211W
+" sa_query <addr> send SA Query to a station\n"
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+" wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n"
+" wps_pbc indicate button pushed to initiate PBC\n"
+#endif /* CONFIG_WPS */
+" 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 int ping_interval = 5;
+
+
+static void usage(void)
+{
+ fprintf(stderr, "%s\n", hostapd_cli_version);
+ fprintf(stderr,
+ "\n"
+ "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
+ "[-G<ping interval>] \\\n"
+ " [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);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+ if (argc != 1) {
+ printf("Invalid 'sa_query' command - exactly one argument, "
+ "STA address, is required.\n");
+ return -1;
+ }
+ snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+ if (argc != 2) {
+ printf("Invalid 'wps_pin' command - exactly two arguments, "
+ "UUID and PIN, are required.\n");
+ return -1;
+ }
+ snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_PBC");
+}
+#endif /* CONFIG_WPS */
+
+
+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 },
+#ifdef CONFIG_IEEE80211W
+ { "sa_query", hostapd_cli_cmd_sa_query },
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+ { "wps_pin", hostapd_cli_cmd_wps_pin },
+ { "wps_pbc", hostapd_cli_cmd_wps_pbc },
+#endif /* CONFIG_WPS */
+ { "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(ping_interval);
+ 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(ping_interval);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int interactive;
+ int warning_displayed = 0;
+ int c;
+
+ for (;;) {
+ c = getopt(argc, argv, "hG:i:p:v");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'G':
+ ping_interval = atoi(optarg);
+ break;
+ 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;
+}
diff --git a/contrib/wpa/hostapd/hw_features.c b/contrib/wpa/hostapd/hw_features.c
new file mode 100644
index 0000000..f1288e0
--- /dev/null
+++ b/contrib/wpa/hostapd/hw_features.c
@@ -0,0 +1,487 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 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"
+
+#include "hostapd.h"
+#include "hw_features.h"
+#include "driver.h"
+#include "config.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;
+
+ if (hostapd_drv_none(hapd))
+ return -1;
+ 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++) {
+ /*
+ * Disable all channels that are marked not to allow
+ * IBSS operation or active scanning. In addition,
+ * disable all channels that require radar detection,
+ * since that (in addition to full DFS) is not yet
+ * supported.
+ */
+ if (feature->channels[j].flag &
+ (HOSTAPD_CHAN_NO_IBSS |
+ HOSTAPD_CHAN_PASSIVE_SCAN |
+ HOSTAPD_CHAN_RADAR))
+ feature->channels[j].flag |=
+ HOSTAPD_CHAN_DISABLED;
+ if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
+ "chan=%d freq=%d MHz max_tx_power=%d dBm",
+ feature->mode,
+ feature->channels[j].chan,
+ feature->channels[j].freq,
+ feature->channels[j].max_tx_power);
+ }
+ }
+
+ 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;
+}
+
+
+#ifdef CONFIG_IEEE80211N
+static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
+{
+ int sec_chan, ok, j, first;
+ int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ size_t k;
+
+ if (!iface->conf->secondary_channel)
+ return 1; /* HT40 not used */
+
+ sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
+ wpa_printf(MSG_DEBUG, "HT40: control channel: %d "
+ "secondary channel: %d",
+ iface->conf->channel, sec_chan);
+
+ /* Verify that HT40 secondary channel is an allowed 20 MHz
+ * channel */
+ 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_DISABLED) &&
+ chan->chan == sec_chan) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
+ sec_chan);
+ return 0;
+ }
+
+ /*
+ * Verify that HT40 primary,secondary channel pair is allowed per
+ * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
+ * 2.4 GHz rules allow all cases where the secondary channel fits into
+ * the list of allowed channels (already checked above).
+ */
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 1;
+
+ if (iface->conf->secondary_channel > 0)
+ first = iface->conf->channel;
+ else
+ first = sec_chan;
+
+ ok = 0;
+ for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+ if (first == allowed[k]) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+ iface->conf->channel,
+ iface->conf->secondary_channel);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
+{
+ u16 hw = iface->current_mode->ht_capab;
+ u16 conf = iface->conf->ht_capab;
+
+ if (!iface->conf->ieee80211n)
+ return 1;
+
+ if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
+ !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [LDPC]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [HT40*]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
+ (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [SMPS-*]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
+ !(hw & HT_CAP_INFO_GREEN_FIELD)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [GF]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
+ !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [SHORT-GI-20]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
+ !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [SHORT-GI-40]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [TX-STBC]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
+ (hw & HT_CAP_INFO_RX_STBC_MASK)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [RX-STBC*]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_DELAYED_BA) &&
+ !(hw & HT_CAP_INFO_DELAYED_BA)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [DELAYED-BA]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
+ !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [MAX-AMSDU-7935]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
+ !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [DSSS_CCK-40]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [PSMP]");
+ return 0;
+ }
+
+ if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
+ !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured "
+ "HT capability [LSIG-TXOP-PROT]");
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+/**
+ * hostapd_select_hw_mode - Select the hardware mode
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, -1 on failure
+ *
+ * Sets up the hardware mode, channel, rates, and passive scanning
+ * based on the configuration.
+ */
+int hostapd_select_hw_mode(struct hostapd_iface *iface)
+{
+ int i, j, ok, ret;
+
+ 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_DISABLED) &&
+ (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;
+ }
+
+ if (iface->current_mode == NULL) {
+ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Hardware does not support configured channel");
+ return -1;
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (!ieee80211n_allowed_ht40_channel_pair(iface))
+ return -1;
+ if (!ieee80211n_supported_ht_capab(iface))
+ return -1;
+#endif /* CONFIG_IEEE80211N */
+
+ 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.");
+ return -1;
+ }
+
+ 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) {
+ if (ret == -1) {
+ wpa_printf(MSG_DEBUG, "Passive scanning not "
+ "supported");
+ } else {
+ wpa_printf(MSG_ERROR, "Could not set passive "
+ "scanning: %s", strerror(ret));
+ }
+ ret = 0;
+ }
+
+ return ret;
+}
+
+
+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;
+}
diff --git a/contrib/wpa/hostapd/hw_features.h b/contrib/wpa/hostapd/hw_features.h
new file mode 100644
index 0000000..7d43c89
--- /dev/null
+++ b/contrib/wpa/hostapd/hw_features.h
@@ -0,0 +1,62 @@
+/*
+ * 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_DISABLED 0x00000001
+#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
+#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_RADAR 0x00000008
+
+struct hostapd_channel_data {
+ short chan; /* channel number (IEEE 802.11) */
+ short freq; /* frequency in MHz */
+ int flag; /* flag for hostapd use (HOSTAPD_CHAN_*) */
+ u8 max_tx_power; /* maximum transmit power in dBm */
+};
+
+#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;
+ u16 ht_capab;
+};
+
+
+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(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 */
diff --git a/contrib/wpa/hostapd/iapp.c b/contrib/wpa/hostapd/iapp.c
new file mode 100644
index 0000000..6d6dba8
--- /dev/null
+++ b/contrib/wpa/hostapd/iapp.c
@@ -0,0 +1,553 @@
+/*
+ * 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 extending 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]");
+}
+
+
+/**
+ * iapp_new_station - IAPP processing for a new STA
+ * @iapp: IAPP data
+ * @sta: The associated station
+ */
+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;
+}
+
+
+/**
+ * iapp_receive_udp - Process IAPP UDP frames
+ * @sock: File descriptor for the socket
+ * @eloop_ctx: IAPP data (struct iapp_data *)
+ * @sock_ctx: Not used
+ */
+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;
+}
diff --git a/contrib/wpa/hostapd/iapp.h b/contrib/wpa/hostapd/iapp.h
new file mode 100644
index 0000000..86de592
--- /dev/null
+++ b/contrib/wpa/hostapd/iapp.h
@@ -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 */
diff --git a/contrib/wpa/hostapd/ieee802_11.c b/contrib/wpa/hostapd/ieee802_11.c
new file mode 100644
index 0000000..8399d88
--- /dev/null
+++ b/contrib/wpa/hostapd/ieee802_11.c
@@ -0,0 +1,1768 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include <net/if.h>
+
+#include "eloop.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "ieee802_11_auth.h"
+#include "sta_info.h"
+#include "rc4.h"
+#include "ieee802_1x.h"
+#include "wpa.h"
+#include "wme.h"
+#include "ap_list.h"
+#include "accounting.h"
+#include "driver.h"
+#include "mlme.h"
+
+
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ int i, num, count;
+
+ if (hapd->iface->current_rates == NULL)
+ return eid;
+
+ *pos++ = WLAN_EID_SUPP_RATES;
+ num = hapd->iface->num_rates;
+ if (num > 8) {
+ /* rest of the rates are encoded in Extended supported
+ * rates element */
+ num = 8;
+ }
+
+ *pos++ = num;
+ count = 0;
+ for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
+ i++) {
+ count++;
+ *pos = hapd->iface->current_rates[i].rate / 5;
+ if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+ *pos |= 0x80;
+ pos++;
+ }
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ int i, num, count;
+
+ if (hapd->iface->current_rates == NULL)
+ return eid;
+
+ num = hapd->iface->num_rates;
+ if (num <= 8)
+ return eid;
+ num -= 8;
+
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = num;
+ count = 0;
+ for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
+ i++) {
+ count++;
+ if (count <= 8)
+ continue; /* already in SuppRates IE */
+ *pos = hapd->iface->current_rates[i].rate / 5;
+ if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+ *pos |= 0x80;
+ pos++;
+ }
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_ht_capabilities_info(struct hostapd_data *hapd, u8 *eid)
+{
+#ifdef CONFIG_IEEE80211N
+ struct ieee80211_ht_capability *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211n)
+ return eid;
+
+ *pos++ = WLAN_EID_HT_CAP;
+ *pos++ = sizeof(*cap);
+
+ cap = (struct ieee80211_ht_capability *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+ SET_2BIT_U8(&cap->mac_ht_params_info,
+ MAC_HT_PARAM_INFO_MAX_RX_AMPDU_FACTOR_OFFSET,
+ MAX_RX_AMPDU_FACTOR_64KB);
+
+ cap->capabilities_info = host_to_le16(hapd->iconf->ht_capab);
+
+ cap->supported_mcs_set[0] = 0xff;
+ cap->supported_mcs_set[1] = 0xff;
+
+ pos += sizeof(*cap);
+
+ return pos;
+#else /* CONFIG_IEEE80211N */
+ return eid;
+#endif /* CONFIG_IEEE80211N */
+}
+
+
+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+#ifdef CONFIG_IEEE80211N
+ struct ieee80211_ht_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211n)
+ return eid;
+
+ *pos++ = WLAN_EID_HT_OPERATION;
+ *pos++ = sizeof(*oper);
+
+ oper = (struct ieee80211_ht_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ oper->control_chan = hapd->iconf->channel;
+ oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
+ if (hapd->iconf->secondary_channel == 1)
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
+ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+ if (hapd->iconf->secondary_channel == -1)
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+
+ pos += sizeof(*oper);
+
+ return pos;
+#else /* CONFIG_IEEE80211N */
+ return eid;
+#endif /* CONFIG_IEEE80211N */
+}
+
+
+#ifdef CONFIG_IEEE80211N
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+ in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+ however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+ (currently non-GF HT station is considered as non-HT STA also)
+*/
+int hostapd_ht_operation_update(struct hostapd_iface *iface)
+{
+ u16 cur_op_mode, new_op_mode;
+ int op_mode_changes = 0;
+
+ if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
+ __func__, iface->ht_op_mode);
+
+ if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+ && iface->num_sta_ht_no_gf) {
+ iface->ht_op_mode |=
+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ op_mode_changes++;
+ } else if ((iface->ht_op_mode &
+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+ iface->num_sta_ht_no_gf == 0) {
+ iface->ht_op_mode &=
+ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ op_mode_changes++;
+ }
+
+ if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ (iface->num_sta_no_ht || iface->olbc_ht)) {
+ iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ op_mode_changes++;
+ } else if ((iface->ht_op_mode &
+ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
+ iface->ht_op_mode &=
+ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ op_mode_changes++;
+ }
+
+ /* Note: currently we switch to the MIXED op mode if HT non-greenfield
+ * station is associated. Probably it's a theoretical case, since
+ * it looks like all known HT STAs support greenfield.
+ */
+ new_op_mode = 0;
+ if (iface->num_sta_no_ht ||
+ (iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+ new_op_mode = OP_MODE_MIXED;
+ else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+ && iface->num_sta_ht_20mhz)
+ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+ else if (iface->olbc_ht)
+ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+ else
+ new_op_mode = OP_MODE_PURE;
+
+ cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ if (cur_op_mode != new_op_mode) {
+ iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ iface->ht_op_mode |= new_op_mode;
+ op_mode_changes++;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
+ __func__, iface->ht_op_mode, op_mode_changes);
+
+ return op_mode_changes;
+}
+
+#endif /* CONFIG_IEEE80211N */
+
+
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int probe)
+{
+ int capab = WLAN_CAPABILITY_ESS;
+ int privacy;
+
+ if (hapd->iface->num_sta_no_short_preamble == 0 &&
+ hapd->iconf->preamble == SHORT_PREAMBLE)
+ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+ privacy = hapd->conf->ssid.wep.keys_set;
+
+ if (hapd->conf->ieee802_1x &&
+ (hapd->conf->default_wep_key_len ||
+ hapd->conf->individual_wep_key_len))
+ privacy = 1;
+
+ if (hapd->conf->wpa)
+ privacy = 1;
+
+ if (sta) {
+ int policy, def_klen;
+ if (probe && sta->ssid_probe) {
+ policy = sta->ssid_probe->security_policy;
+ def_klen = sta->ssid_probe->wep.default_len;
+ } else {
+ policy = sta->ssid->security_policy;
+ def_klen = sta->ssid->wep.default_len;
+ }
+ privacy = policy != SECURITY_PLAINTEXT;
+ if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
+ privacy = 0;
+ }
+
+ if (privacy)
+ capab |= WLAN_CAPABILITY_PRIVACY;
+
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ hapd->iface->num_sta_no_short_slot_time == 0)
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+ return capab;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *eid)
+{
+ u8 *pos = eid;
+ u32 timeout, tu;
+ struct os_time now, passed;
+
+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+ *pos++ = 5;
+ *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+ os_get_time(&now);
+ os_time_sub(&now, &sta->sa_query_start, &passed);
+ tu = (passed.sec * 1000000 + passed.usec) / 1024;
+ if (hapd->conf->assoc_sa_query_max_timeout > tu)
+ timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+ else
+ timeout = 0;
+ if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+ timeout++; /* add some extra time for local timers */
+ WPA_PUT_LE32(pos, timeout);
+ pos += 4;
+
+ return pos;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
+{
+ int i;
+ if (len > HOSTAPD_MAX_SSID_LEN)
+ len = HOSTAPD_MAX_SSID_LEN;
+ for (i = 0; i < len; i++) {
+ if (ssid[i] >= 32 && ssid[i] < 127)
+ buf[i] = ssid[i];
+ else
+ buf[i] = '.';
+ }
+ buf[len] = '\0';
+}
+
+
+/**
+ * ieee802_11_send_deauth - Send Deauthentication frame
+ * @hapd: hostapd BSS data
+ * @addr: Address of the destination STA
+ * @reason: Reason code for Deauthentication
+ */
+void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason)
+{
+ struct ieee80211_mgmt mgmt;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "deauthenticate - reason %d", reason);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
+ if (hostapd_send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth), 0) < 0)
+ perror("ieee802_11_send_deauth: send");
+}
+
+
+static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
+ u16 auth_transaction, u8 *challenge, int iswep)
+{
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "authentication (shared key, transaction %d)",
+ auth_transaction);
+
+ if (auth_transaction == 1) {
+ if (!sta->challenge) {
+ /* Generate a pseudo-random challenge */
+ u8 key[8];
+ time_t now;
+ int r;
+ sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
+ if (sta->challenge == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ now = time(NULL);
+ r = random();
+ os_memcpy(key, &now, 4);
+ os_memcpy(key + 4, &r, 4);
+ rc4(sta->challenge, WLAN_AUTH_CHALLENGE_LEN,
+ key, sizeof(key));
+ }
+ return 0;
+ }
+
+ if (auth_transaction != 3)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /* Transaction 3 */
+ if (!iswep || !sta->challenge || !challenge ||
+ os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "shared key authentication - invalid "
+ "challenge-response");
+ return WLAN_STATUS_CHALLENGE_FAIL;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "authentication OK (shared key)");
+#ifdef IEEE80211_REQUIRE_AUTH_ACK
+ /* Station will be marked authenticated if it ACKs the
+ * authentication reply. */
+#else
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+#endif
+ os_free(sta->challenge);
+ sta->challenge = NULL;
+
+ return 0;
+}
+
+
+static void send_auth_reply(struct hostapd_data *hapd,
+ const u8 *dst, const u8 *bssid,
+ u16 auth_alg, u16 auth_transaction, u16 resp,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee80211_mgmt *reply;
+ u8 *buf;
+ size_t rlen;
+
+ rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
+ buf = os_zalloc(rlen);
+ if (buf == NULL)
+ return;
+
+ reply = (struct ieee80211_mgmt *) buf;
+ reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ os_memcpy(reply->da, dst, ETH_ALEN);
+ os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(reply->bssid, bssid, ETH_ALEN);
+
+ reply->u.auth.auth_alg = host_to_le16(auth_alg);
+ reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
+ reply->u.auth.status_code = host_to_le16(resp);
+
+ if (ies && ies_len)
+ os_memcpy(reply->u.auth.variable, ies, ies_len);
+
+ wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
+ " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+ MAC2STR(dst), auth_alg, auth_transaction,
+ resp, (unsigned long) ies_len);
+ if (hostapd_send_mgmt_frame(hapd, reply, rlen, 0) < 0)
+ perror("send_auth_reply: send");
+
+ os_free(buf);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
+ u16 auth_transaction, u16 status,
+ const u8 *ies, size_t ies_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
+ status, ies, ies_len);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ return;
+
+ sta = ap_get_sta(hapd, dst);
+ if (sta == NULL)
+ return;
+
+ hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+ sta->flags |= WLAN_STA_AUTH;
+ mlme_authenticate_indication(hapd, sta);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u16 auth_alg, auth_transaction, status_code;
+ u16 resp = WLAN_STATUS_SUCCESS;
+ struct sta_info *sta = NULL;
+ int res;
+ u16 fc;
+ u8 *challenge = NULL;
+ u32 session_timeout, acct_interim_interval;
+ int vlan_id = 0;
+ u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+ size_t resp_ies_len = 0;
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ printf("handle_auth - too short payload (len=%lu)\n",
+ (unsigned long) len);
+ return;
+ }
+
+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+ status_code = le_to_host16(mgmt->u.auth.status_code);
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
+ 2 + WLAN_AUTH_CHALLENGE_LEN &&
+ mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
+ mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
+ challenge = &mgmt->u.auth.variable[2];
+
+ wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
+ "auth_transaction=%d status_code=%d wep=%d%s",
+ MAC2STR(mgmt->sa), auth_alg, auth_transaction,
+ status_code, !!(fc & WLAN_FC_ISWEP),
+ challenge ? " challenge" : "");
+
+ if (hapd->tkip_countermeasures) {
+ resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ goto fail;
+ }
+
+ if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
+ auth_alg == WLAN_AUTH_OPEN) ||
+#ifdef CONFIG_IEEE80211R
+ (hapd->conf->wpa &&
+ (hapd->conf->wpa_key_mgmt &
+ (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
+ auth_alg == WLAN_AUTH_FT) ||
+#endif /* CONFIG_IEEE80211R */
+ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
+ auth_alg == WLAN_AUTH_SHARED_KEY))) {
+ printf("Unsupported authentication algorithm (%d)\n",
+ auth_alg);
+ resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+ goto fail;
+ }
+
+ if (!(auth_transaction == 1 ||
+ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
+ printf("Unknown authentication transaction number (%d)\n",
+ auth_transaction);
+ resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ goto fail;
+ }
+
+ if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+ printf("Station " MACSTR " not allowed to authenticate.\n",
+ MAC2STR(mgmt->sa));
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
+ &session_timeout,
+ &acct_interim_interval, &vlan_id);
+ if (res == HOSTAPD_ACL_REJECT) {
+ printf("Station " MACSTR " not allowed to authenticate.\n",
+ MAC2STR(mgmt->sa));
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (res == HOSTAPD_ACL_PENDING) {
+ wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+ " waiting for an external authentication",
+ MAC2STR(mgmt->sa));
+ /* Authentication code will re-send the authentication frame
+ * after it has received (and cached) information from the
+ * external source. */
+ return;
+ }
+
+ sta = ap_sta_add(hapd, mgmt->sa);
+ if (!sta) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (vlan_id > 0) {
+ if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+ sta->vlan_id) == NULL) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
+ "%d received from RADIUS server",
+ vlan_id);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ sta->vlan_id = vlan_id;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+ }
+
+ sta->flags &= ~WLAN_STA_PREAUTH;
+ ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+
+ if (hapd->conf->radius->acct_interim_interval == 0 &&
+ acct_interim_interval)
+ sta->acct_interim_interval = acct_interim_interval;
+ if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+ else
+ ap_sta_no_session_timeout(hapd, sta);
+
+ switch (auth_alg) {
+ case WLAN_AUTH_OPEN:
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "authentication OK (open system)");
+#ifdef IEEE80211_REQUIRE_AUTH_ACK
+ /* Station will be marked authenticated if it ACKs the
+ * authentication reply. */
+#else
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = WLAN_AUTH_OPEN;
+ mlme_authenticate_indication(hapd, sta);
+#endif
+ break;
+ case WLAN_AUTH_SHARED_KEY:
+ resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
+ fc & WLAN_FC_ISWEP);
+ sta->auth_alg = WLAN_AUTH_SHARED_KEY;
+ mlme_authenticate_indication(hapd, sta);
+ if (sta->challenge && auth_transaction == 1) {
+ resp_ies[0] = WLAN_EID_CHALLENGE;
+ resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
+ os_memcpy(resp_ies + 2, sta->challenge,
+ WLAN_AUTH_CHALLENGE_LEN);
+ resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
+ }
+ break;
+#ifdef CONFIG_IEEE80211R
+ case WLAN_AUTH_FT:
+ sta->auth_alg = WLAN_AUTH_FT;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+ "state machine");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
+ auth_transaction, mgmt->u.auth.variable,
+ len - IEEE80211_HDRLEN -
+ sizeof(mgmt->u.auth),
+ handle_auth_ft_finish, hapd);
+ /* handle_auth_ft_finish() callback will complete auth. */
+ return;
+#endif /* CONFIG_IEEE80211R */
+ }
+
+ fail:
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ auth_transaction + 1, resp, resp_ies, resp_ies_len);
+}
+
+
+static void handle_assoc(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len, int reassoc)
+{
+ u16 capab_info, listen_interval;
+ u16 resp = WLAN_STATUS_SUCCESS;
+ u8 *pos, *wpa_ie;
+ size_t wpa_ie_len;
+ int send_deauth = 0, send_len, left, i;
+ struct sta_info *sta;
+ struct ieee802_11_elems elems;
+ u8 buf[sizeof(struct ieee80211_mgmt) + 512];
+ struct ieee80211_mgmt *reply;
+
+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
+ sizeof(mgmt->u.assoc_req))) {
+ printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+ "\n", reassoc, (unsigned long) len);
+ return;
+ }
+
+ if (reassoc) {
+ capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
+ listen_interval = le_to_host16(
+ mgmt->u.reassoc_req.listen_interval);
+ wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
+ " capab_info=0x%02x listen_interval=%d current_ap="
+ MACSTR,
+ MAC2STR(mgmt->sa), capab_info, listen_interval,
+ MAC2STR(mgmt->u.reassoc_req.current_ap));
+ left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+ pos = mgmt->u.reassoc_req.variable;
+ } else {
+ capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
+ listen_interval = le_to_host16(
+ mgmt->u.assoc_req.listen_interval);
+ wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
+ " capab_info=0x%02x listen_interval=%d",
+ MAC2STR(mgmt->sa), capab_info, listen_interval);
+ left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+ pos = mgmt->u.assoc_req.variable;
+ }
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+#ifdef CONFIG_IEEE80211R
+ if (sta && sta->auth_alg == WLAN_AUTH_FT &&
+ (sta->flags & WLAN_STA_AUTH) == 0) {
+ wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
+ "prior to authentication since it is using "
+ "over-the-DS FT", MAC2STR(mgmt->sa));
+ } else
+#endif /* CONFIG_IEEE80211R */
+ if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
+ printf("STA " MACSTR " trying to associate before "
+ "authentication\n", MAC2STR(mgmt->sa));
+ if (sta) {
+ printf(" sta: addr=" MACSTR " aid=%d flags=0x%04x\n",
+ MAC2STR(sta->addr), sta->aid, sta->flags);
+ }
+ send_deauth = 1;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (hapd->tkip_countermeasures) {
+ resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ goto fail;
+ }
+
+ if (listen_interval > hapd->conf->max_listen_interval) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Too large Listen Interval (%d)",
+ listen_interval);
+ resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
+ goto fail;
+ }
+
+ sta->capability = capab_info;
+ sta->listen_interval = listen_interval;
+
+ /* followed by SSID and Supported rates; and HT capabilities if 802.11n
+ * is used */
+ if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed ||
+ !elems.ssid) {
+ printf("STA " MACSTR " sent invalid association request\n",
+ MAC2STR(sta->addr));
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (elems.ssid_len != hapd->conf->ssid.ssid_len ||
+ os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != 0)
+ {
+ char ssid_txt[33];
+ ieee802_11_print_ssid(ssid_txt, elems.ssid, elems.ssid_len);
+ printf("Station " MACSTR " tried to associate with "
+ "unknown SSID '%s'\n", MAC2STR(sta->addr), ssid_txt);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ sta->flags &= ~WLAN_STA_WME;
+ if (elems.wme && hapd->conf->wme_enabled) {
+ if (hostapd_eid_wme_valid(hapd, elems.wme, elems.wme_len))
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_WPA,
+ HOSTAPD_LEVEL_DEBUG,
+ "invalid WME element in association "
+ "request");
+ else
+ sta->flags |= WLAN_STA_WME;
+ }
+
+ if (!elems.supp_rates) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "No supported rates element in AssocReq");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (elems.supp_rates_len > sizeof(sta->supported_rates)) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Invalid supported rates element length %d",
+ elems.supp_rates_len);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
+ os_memcpy(sta->supported_rates, elems.supp_rates,
+ elems.supp_rates_len);
+ sta->supported_rates_len = elems.supp_rates_len;
+
+ if (elems.ext_supp_rates) {
+ if (elems.supp_rates_len + elems.ext_supp_rates_len >
+ sizeof(sta->supported_rates)) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Invalid supported rates element length"
+ " %d+%d", elems.supp_rates_len,
+ elems.ext_supp_rates_len);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ os_memcpy(sta->supported_rates + elems.supp_rates_len,
+ elems.ext_supp_rates, elems.ext_supp_rates_len);
+ sta->supported_rates_len += elems.ext_supp_rates_len;
+ }
+
+#ifdef CONFIG_IEEE80211N
+ /* save HT capabilities in the sta object */
+ os_memset(&sta->ht_capabilities, 0, sizeof(sta->ht_capabilities));
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capability)) {
+ sta->flags |= WLAN_STA_HT;
+ sta->ht_capabilities.id = WLAN_EID_HT_CAP;
+ sta->ht_capabilities.length =
+ sizeof(struct ieee80211_ht_capability);
+ os_memcpy(&sta->ht_capabilities.data,
+ elems.ht_capabilities,
+ sizeof(struct ieee80211_ht_capability));
+ } else
+ sta->flags &= ~WLAN_STA_HT;
+#endif /* CONFIG_IEEE80211N */
+
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
+ wpa_ie = elems.rsn_ie;
+ wpa_ie_len = elems.rsn_ie_len;
+ } else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
+ elems.wpa_ie) {
+ wpa_ie = elems.wpa_ie;
+ wpa_ie_len = elems.wpa_ie_len;
+ } else {
+ wpa_ie = NULL;
+ wpa_ie_len = 0;
+ }
+#ifdef CONFIG_WPS
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+ if (hapd->conf->wps_state && wpa_ie == NULL) {
+ if (elems.wps_ie) {
+ wpa_printf(MSG_DEBUG, "STA included WPS IE in "
+ "(Re)Association Request - assume WPS is "
+ "used");
+ sta->flags |= WLAN_STA_WPS;
+ wpabuf_free(sta->wps_ie);
+ sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4,
+ elems.wps_ie_len - 4);
+ } else {
+ wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE "
+ "in (Re)Association Request - possible WPS "
+ "use");
+ sta->flags |= WLAN_STA_MAYBE_WPS;
+ }
+ } else
+#endif /* CONFIG_WPS */
+ if (hapd->conf->wpa && wpa_ie == NULL) {
+ printf("STA " MACSTR ": No WPA/RSN IE in association "
+ "request\n", MAC2STR(sta->addr));
+ resp = WLAN_STATUS_INVALID_IE;
+ goto fail;
+ }
+
+ if (hapd->conf->wpa && wpa_ie) {
+ int res;
+ wpa_ie -= 2;
+ wpa_ie_len += 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");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ wpa_ie, wpa_ie_len,
+ elems.mdie, elems.mdie_len);
+ if (res == WPA_INVALID_GROUP)
+ resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ else if (res == WPA_INVALID_PAIRWISE)
+ resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ else if (res == WPA_INVALID_AKMP)
+ resp = WLAN_STATUS_AKMP_NOT_VALID;
+ else if (res == WPA_ALLOC_FAIL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_IEEE80211W
+ else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+#endif /* CONFIG_IEEE80211W */
+ else if (res == WPA_INVALID_MDIE)
+ resp = WLAN_STATUS_INVALID_MDIE;
+ else if (res != WPA_IE_OK)
+ resp = WLAN_STATUS_INVALID_IE;
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+#ifdef CONFIG_IEEE80211W
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA
+ * Query timeout has not been reached. Reject the
+ * association attempt temporarily and start SA Query,
+ * if one is not pending.
+ */
+
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+ goto fail;
+ }
+
+ if (wpa_auth_uses_mfp(sta->wpa_sm))
+ sta->flags |= WLAN_STA_MFP;
+ else
+ sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+ if (sta->auth_alg == WLAN_AUTH_FT) {
+ if (!reassoc) {
+ wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
+ "to use association (not "
+ "re-association) with FT auth_alg",
+ MAC2STR(sta->addr));
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ resp = wpa_ft_validate_reassoc(sta->wpa_sm, pos, left);
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211N
+ if ((sta->flags & WLAN_STA_HT) &&
+ wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
+ wpa_printf(MSG_DEBUG, "HT: " MACSTR " tried to "
+ "use TKIP with HT association",
+ MAC2STR(sta->addr));
+ resp = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ goto fail;
+ }
+#endif /* CONFIG_IEEE80211N */
+ } else
+ wpa_auth_sta_no_wpa(sta->wpa_sm);
+
+ if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ sta->flags |= WLAN_STA_NONERP;
+ for (i = 0; i < sta->supported_rates_len; i++) {
+ if ((sta->supported_rates[i] & 0x7f) > 22) {
+ sta->flags &= ~WLAN_STA_NONERP;
+ break;
+ }
+ }
+ if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
+ sta->nonerp_set = 1;
+ hapd->iface->num_sta_non_erp++;
+ if (hapd->iface->num_sta_non_erp == 1)
+ ieee802_11_set_beacons(hapd->iface);
+ }
+
+ if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
+ !sta->no_short_slot_time_set) {
+ sta->no_short_slot_time_set = 1;
+ 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 == 1)
+ ieee802_11_set_beacons(hapd->iface);
+ }
+
+ if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+ else
+ sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+ if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+ !sta->no_short_preamble_set) {
+ sta->no_short_preamble_set = 1;
+ hapd->iface->num_sta_no_short_preamble++;
+ if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ && hapd->iface->num_sta_no_short_preamble == 1)
+ ieee802_11_set_beacons(hapd->iface);
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (sta->flags & WLAN_STA_HT) {
+ u16 ht_capab = le_to_host16(
+ sta->ht_capabilities.data.capabilities_info);
+ wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities "
+ "Info: 0x%04x", MAC2STR(sta->addr), ht_capab);
+ if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
+ if (!sta->no_ht_gf_set) {
+ sta->no_ht_gf_set = 1;
+ hapd->iface->num_sta_ht_no_gf++;
+ }
+ wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no "
+ "greenfield, num of non-gf stations %d",
+ __func__, MAC2STR(sta->addr),
+ hapd->iface->num_sta_ht_no_gf);
+ }
+ if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
+ if (!sta->ht_20mhz_set) {
+ sta->ht_20mhz_set = 1;
+ hapd->iface->num_sta_ht_20mhz++;
+ }
+ wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, "
+ "num of 20MHz HT STAs %d",
+ __func__, MAC2STR(sta->addr),
+ hapd->iface->num_sta_ht_20mhz);
+ }
+ } else {
+ if (!sta->no_ht_set) {
+ sta->no_ht_set = 1;
+ hapd->iface->num_sta_no_ht++;
+ }
+ if (hapd->iconf->ieee80211n) {
+ wpa_printf(MSG_DEBUG, "%s STA " MACSTR
+ " - no HT, num of non-HT stations %d",
+ __func__, MAC2STR(sta->addr),
+ hapd->iface->num_sta_no_ht);
+ }
+ }
+
+ if (hostapd_ht_operation_update(hapd->iface) > 0)
+ ieee802_11_set_beacons(hapd->iface);
+#endif /* CONFIG_IEEE80211N */
+
+ /* get a unique AID */
+ if (sta->aid > 0) {
+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
+ } else {
+ for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
+ if (hapd->sta_aid[sta->aid - 1] == NULL)
+ break;
+ if (sta->aid > MAX_AID_TABLE_SIZE) {
+ sta->aid = 0;
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ wpa_printf(MSG_ERROR, " no room for more AIDs");
+ goto fail;
+ } else {
+ hapd->sta_aid[sta->aid - 1] = sta;
+ wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
+ }
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "association OK (aid %d)", sta->aid);
+ /* Station will be marked associated, after it acknowledges AssocResp
+ */
+
+#ifdef CONFIG_IEEE80211W
+ if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
+ wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
+ "SA Query procedure", reassoc ? "re" : "");
+ /* TODO: Send a protected Disassociate frame to the STA using
+ * the old key and Reason Code "Previous Authentication no
+ * longer valid". Make sure this is only sent protected since
+ * unprotected frame would be received by the STA that is now
+ * trying to associate.
+ */
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ if (reassoc) {
+ os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
+ ETH_ALEN);
+ }
+
+ if (sta->last_assoc_req)
+ os_free(sta->last_assoc_req);
+ sta->last_assoc_req = os_malloc(len);
+ if (sta->last_assoc_req)
+ os_memcpy(sta->last_assoc_req, mgmt, len);
+
+ /* Make sure that the previously registered inactivity timer will not
+ * remove the STA immediately. */
+ sta->timeout_next = STA_NULLFUNC;
+
+ fail:
+ os_memset(buf, 0, sizeof(buf));
+ reply = (struct ieee80211_mgmt *) buf;
+ reply->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ (send_deauth ? WLAN_FC_STYPE_DEAUTH :
+ (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
+ WLAN_FC_STYPE_ASSOC_RESP)));
+ os_memcpy(reply->da, mgmt->sa, ETH_ALEN);
+ os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(reply->bssid, mgmt->bssid, ETH_ALEN);
+
+ send_len = IEEE80211_HDRLEN;
+ if (send_deauth) {
+ send_len += sizeof(reply->u.deauth);
+ reply->u.deauth.reason_code = host_to_le16(resp);
+ } else {
+ u8 *p;
+ send_len += sizeof(reply->u.assoc_resp);
+ reply->u.assoc_resp.capab_info =
+ host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
+ reply->u.assoc_resp.status_code = host_to_le16(resp);
+ reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
+ | BIT(14) | BIT(15));
+ /* Supported rates */
+ p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
+ /* Extended supported rates */
+ p = hostapd_eid_ext_supp_rates(hapd, p);
+ if (sta->flags & WLAN_STA_WME)
+ p = hostapd_eid_wme(hapd, p);
+
+ p = hostapd_eid_ht_capabilities_info(hapd, p);
+ p = hostapd_eid_ht_operation(hapd, p);
+
+#ifdef CONFIG_IEEE80211R
+ if (resp == WLAN_STATUS_SUCCESS) {
+ /* IEEE 802.11r: Mobility Domain Information, Fast BSS
+ * Transition Information, RSN */
+ p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
+ buf + sizeof(buf) - p,
+ sta->auth_alg);
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+ if (resp == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
+ p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+#endif /* CONFIG_IEEE80211W */
+
+ send_len += p - reply->u.assoc_resp.variable;
+ }
+
+ if (hostapd_send_mgmt_frame(hapd, reply, send_len, 0) < 0)
+ perror("handle_assoc: send");
+}
+
+
+static void handle_disassoc(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct sta_info *sta;
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
+ printf("handle_disassoc - too short payload (len=%lu)\n",
+ (unsigned long) len);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
+ MAC2STR(mgmt->sa),
+ le_to_host16(mgmt->u.disassoc.reason_code));
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (sta == NULL) {
+ printf("Station " MACSTR " trying to disassociate, but it "
+ "is not associated.\n", MAC2STR(mgmt->sa));
+ return;
+ }
+
+ sta->flags &= ~WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "disassociated");
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ /* Stop Accounting and IEEE 802.1X sessions, but leave the STA
+ * authenticated. */
+ accounting_sta_stop(hapd, sta);
+ ieee802_1x_free_station(sta);
+ hostapd_sta_remove(hapd, sta->addr);
+
+ if (sta->timeout_next == STA_NULLFUNC ||
+ sta->timeout_next == STA_DISASSOC) {
+ sta->timeout_next = STA_DEAUTH;
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
+ hapd, sta);
+ }
+
+ mlme_disassociate_indication(
+ hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
+}
+
+
+static void handle_deauth(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct sta_info *sta;
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
+ printf("handle_deauth - too short payload (len=%lu)\n",
+ (unsigned long) len);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR
+ " reason_code=%d",
+ MAC2STR(mgmt->sa),
+ le_to_host16(mgmt->u.deauth.reason_code));
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (sta == NULL) {
+ printf("Station " MACSTR " trying to deauthenticate, but it "
+ "is not authenticated.\n", MAC2STR(mgmt->sa));
+ return;
+ }
+
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+ mlme_deauthenticate_indication(
+ hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_beacon(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct hostapd_frame_info *fi)
+{
+ struct ieee802_11_elems elems;
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
+ printf("handle_beacon - too short payload (len=%lu)\n",
+ (unsigned long) len);
+ return;
+ }
+
+ (void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
+ len - (IEEE80211_HDRLEN +
+ sizeof(mgmt->u.beacon)), &elems,
+ 0);
+
+ ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *trans_id)
+{
+ struct ieee80211_mgmt mgmt;
+ u8 *end;
+
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+ mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+ os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+ end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+ if (hostapd_send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+ perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void hostapd_sa_query_action(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct sta_info *sta;
+ u8 *end;
+ int i;
+
+ end = mgmt->u.action.u.sa_query_resp.trans_id +
+ WLAN_SA_QUERY_TR_ID_LEN;
+ if (((u8 *) mgmt) + len < end) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
+ "frame (len=%lu)", (unsigned long) len);
+ return;
+ }
+
+ if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+ "Action %d", mgmt->u.action.u.sa_query_resp.action);
+ return;
+ }
+
+ /* MLME-SAQuery.confirm */
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (sta == NULL || sta->sa_query_trans_id == NULL) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+ "pending SA Query request found");
+ return;
+ }
+
+ for (i = 0; i < sta->sa_query_count; i++) {
+ if (os_memcmp(sta->sa_query_trans_id +
+ i * WLAN_SA_QUERY_TR_ID_LEN,
+ mgmt->u.action.u.sa_query_resp.trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN) == 0)
+ break;
+ }
+
+ if (i >= sta->sa_query_count) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+ "transaction identifier found");
+ return;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Reply to pending SA Query received");
+ ap_sta_stop_sa_query(hapd, sta);
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+static void handle_action(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ if (len < IEEE80211_HDRLEN + 1) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "handle_action - too short payload (len=%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ switch (mgmt->u.action.category) {
+#ifdef CONFIG_IEEE80211R
+ case WLAN_ACTION_FT:
+ {
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
+ "frame from unassociated STA " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+ len - IEEE80211_HDRLEN))
+ break;
+
+ return;
+ }
+#endif /* CONFIG_IEEE80211R */
+ case WLAN_ACTION_WMM:
+ hostapd_wme_action(hapd, mgmt, len);
+ return;
+#ifdef CONFIG_IEEE80211W
+ case WLAN_ACTION_SA_QUERY:
+ hostapd_sa_query_action(hapd, mgmt, len);
+ return;
+#endif /* CONFIG_IEEE80211W */
+ }
+
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "handle_action - unknown action category %d or invalid "
+ "frame",
+ mgmt->u.action.category);
+ if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
+ !(mgmt->sa[0] & 0x01)) {
+ /*
+ * IEEE 802.11-REVma/D9.0 - 7.3.1.11
+ * Return the Action frame to the source without change
+ * except that MSB of the Category set to 1.
+ */
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
+ "frame back to sender");
+ os_memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category |= 0x80;
+
+ hostapd_send_mgmt_frame(hapd, mgmt, len, 0);
+ }
+}
+
+
+/**
+ * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
+ * @hapd: hostapd BSS data structure (the BSS to which the management frame was
+ * sent to)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @stype: management frame subtype from frame control field
+ * @fi: meta data about received frame (signal level, etc.)
+ *
+ * Process all incoming IEEE 802.11 management frames. This will be called for
+ * each frame received from the kernel driver through wlan#ap interface. In
+ * addition, it can be called to re-inserted pending frames (e.g., when using
+ * external RADIUS server as an MAC ACL).
+ */
+void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype,
+ struct hostapd_frame_info *fi)
+{
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf;
+ int broadcast;
+
+ if (stype == WLAN_FC_STYPE_BEACON) {
+ handle_beacon(hapd, mgmt, len, fi);
+ return;
+ }
+
+ if (fi && fi->passive_scan)
+ return;
+
+ broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
+ mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
+ mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
+
+ if (!broadcast &&
+ os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
+ printf("MGMT: BSSID=" MACSTR " not our address\n",
+ MAC2STR(mgmt->bssid));
+ return;
+ }
+
+
+ if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+ handle_probe_req(hapd, mgmt, len);
+ return;
+ }
+
+ if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "MGMT: DA=" MACSTR " not our address",
+ MAC2STR(mgmt->da));
+ return;
+ }
+
+ switch (stype) {
+ case WLAN_FC_STYPE_AUTH:
+ wpa_printf(MSG_DEBUG, "mgmt::auth");
+ handle_auth(hapd, mgmt, len);
+ break;
+ case WLAN_FC_STYPE_ASSOC_REQ:
+ wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
+ handle_assoc(hapd, mgmt, len, 0);
+ break;
+ case WLAN_FC_STYPE_REASSOC_REQ:
+ wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
+ handle_assoc(hapd, mgmt, len, 1);
+ break;
+ case WLAN_FC_STYPE_DISASSOC:
+ wpa_printf(MSG_DEBUG, "mgmt::disassoc");
+ handle_disassoc(hapd, mgmt, len);
+ break;
+ case WLAN_FC_STYPE_DEAUTH:
+ wpa_printf(MSG_DEBUG, "mgmt::deauth");
+ handle_deauth(hapd, mgmt, len);
+ break;
+ case WLAN_FC_STYPE_ACTION:
+ wpa_printf(MSG_DEBUG, "mgmt::action");
+ handle_action(hapd, mgmt, len);
+ break;
+ default:
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "unknown mgmt frame subtype %d", stype);
+ break;
+ }
+}
+
+
+static void handle_auth_cb(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ u16 auth_alg, auth_transaction, status_code;
+ struct sta_info *sta;
+
+ if (!ok) {
+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "did not acknowledge authentication response");
+ return;
+ }
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ printf("handle_auth_cb - too short payload (len=%lu)\n",
+ (unsigned long) len);
+ return;
+ }
+
+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+ status_code = le_to_host16(mgmt->u.auth.status_code);
+
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ printf("handle_auth_cb: STA " MACSTR " not found\n",
+ MAC2STR(mgmt->da));
+ return;
+ }
+
+ if (status_code == WLAN_STATUS_SUCCESS &&
+ ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
+ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "authenticated");
+ sta->flags |= WLAN_STA_AUTH;
+ }
+}
+
+
+static void handle_assoc_cb(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt,
+ size_t len, int reassoc, int ok)
+{
+ u16 status;
+ struct sta_info *sta;
+ int new_assoc = 1;
+ struct ht_cap_ie *ht_cap = NULL;
+
+ if (!ok) {
+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "did not acknowledge association response");
+ return;
+ }
+
+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+ sizeof(mgmt->u.assoc_resp))) {
+ printf("handle_assoc_cb(reassoc=%d) - too short payload "
+ "(len=%lu)\n", reassoc, (unsigned long) len);
+ return;
+ }
+
+ if (reassoc)
+ status = le_to_host16(mgmt->u.reassoc_resp.status_code);
+ else
+ status = le_to_host16(mgmt->u.assoc_resp.status_code);
+
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ printf("handle_assoc_cb: STA " MACSTR " not found\n",
+ MAC2STR(mgmt->da));
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ /* Stop previous accounting session, if one is started, and allocate
+ * new session id for the new session. */
+ accounting_sta_stop(hapd, sta);
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "associated (aid %d)",
+ sta->aid);
+
+ if (sta->flags & WLAN_STA_ASSOC)
+ new_assoc = 0;
+ sta->flags |= WLAN_STA_ASSOC;
+
+ if (reassoc)
+ mlme_reassociate_indication(hapd, sta);
+ else
+ mlme_associate_indication(hapd, sta);
+
+#ifdef CONFIG_IEEE80211N
+ if (sta->flags & WLAN_STA_HT)
+ ht_cap = &sta->ht_capabilities;
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211W
+ sta->sa_query_timed_out = 0;
+#endif /* CONFIG_IEEE80211W */
+
+ if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid,
+ sta->capability, sta->supported_rates,
+ sta->supported_rates_len, 0, sta->listen_interval,
+ ht_cap))
+ {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ }
+
+ if (sta->eapol_sm == NULL) {
+ /*
+ * This STA does not use RADIUS server for EAP authentication,
+ * so bind it to the selected VLAN interface now, since the
+ * interface selection is not going to change anymore.
+ */
+ ap_sta_bind_vlan(hapd, sta, 0);
+ } else if (sta->vlan_id) {
+ /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
+ ap_sta_bind_vlan(hapd, sta, 0);
+ }
+ if (sta->flags & WLAN_STA_SHORT_PREAMBLE) {
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ WLAN_STA_SHORT_PREAMBLE, ~0);
+ } else {
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ 0, ~WLAN_STA_SHORT_PREAMBLE);
+ }
+
+ if (sta->auth_alg == WLAN_AUTH_FT)
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+ else
+ 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);
+
+ fail:
+ /* Copy of the association request is not needed anymore */
+ if (sta->last_assoc_req) {
+ os_free(sta->last_assoc_req);
+ sta->last_assoc_req = NULL;
+ }
+}
+
+
+/**
+ * ieee802_11_mgmt_cb - Process management frame TX status callback
+ * @hapd: hostapd BSS data structure (the BSS from which the management frame
+ * was sent from)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @stype: management frame subtype from frame control field
+ * @ok: Whether the frame was ACK'ed
+ */
+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
+ u16 stype, int ok)
+{
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf;
+
+ switch (stype) {
+ case WLAN_FC_STYPE_AUTH:
+ wpa_printf(MSG_DEBUG, "mgmt::auth cb");
+ handle_auth_cb(hapd, mgmt, len, ok);
+ break;
+ case WLAN_FC_STYPE_ASSOC_RESP:
+ wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
+ handle_assoc_cb(hapd, mgmt, len, 0, ok);
+ break;
+ case WLAN_FC_STYPE_REASSOC_RESP:
+ wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
+ handle_assoc_cb(hapd, mgmt, len, 1, ok);
+ break;
+ case WLAN_FC_STYPE_PROBE_RESP:
+ wpa_printf(MSG_DEBUG, "mgmt::proberesp cb");
+ break;
+ case WLAN_FC_STYPE_DEAUTH:
+ /* ignore */
+ break;
+ case WLAN_FC_STYPE_ACTION:
+ wpa_printf(MSG_DEBUG, "mgmt::action cb");
+ break;
+ default:
+ printf("unknown mgmt cb frame subtype %d\n", stype);
+ break;
+ }
+}
+
+
+static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ hapd->tkip_countermeasures = 0;
+ hostapd_set_countermeasures(hapd, 0);
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
+}
+
+
+static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
+
+ wpa_auth_countermeasures_start(hapd->wpa_auth);
+ hapd->tkip_countermeasures = 1;
+ hostapd_set_countermeasures(hapd, 1);
+ wpa_gtk_rekey(hapd->wpa_auth);
+ eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+ eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
+ hapd, NULL);
+ for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+ hostapd_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_MICHAEL_MIC_FAILURE);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_AUTHORIZED);
+ hostapd_sta_remove(hapd, sta->addr);
+ }
+}
+
+
+void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
+ int local)
+{
+ time_t now;
+
+ if (addr && local) {
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (sta != NULL) {
+ wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Michael MIC failure detected in "
+ "received frame");
+ mlme_michaelmicfailure_indication(hapd, addr);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "for not associated STA (" MACSTR
+ ") ignored", MAC2STR(addr));
+ return;
+ }
+ }
+
+ time(&now);
+ if (now > hapd->michael_mic_failure + 60) {
+ hapd->michael_mic_failures = 1;
+ } else {
+ hapd->michael_mic_failures++;
+ if (hapd->michael_mic_failures > 1)
+ ieee80211_tkip_countermeasures_start(hapd);
+ }
+ hapd->michael_mic_failure = now;
+}
+
+
+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+ /* TODO */
+ return 0;
+}
+
+
+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ /* TODO */
+ return 0;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa/hostapd/ieee802_11.h b/contrib/wpa/hostapd/ieee802_11.h
new file mode 100644
index 0000000..ca8ef93
--- /dev/null
+++ b/contrib/wpa/hostapd/ieee802_11.h
@@ -0,0 +1,56 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef IEEE802_11_H
+#define IEEE802_11_H
+
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+
+struct hostapd_frame_info {
+ u32 phytype;
+ u32 channel;
+ u32 datarate;
+ u32 ssi_signal;
+
+ unsigned int passive_scan:1;
+};
+
+struct hostapd_iface;
+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);
+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);
+u8 * hostapd_eid_ht_capabilities_info(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
+int hostapd_ht_operation_update(struct hostapd_iface *iface);
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *trans_id);
+
+#endif /* IEEE802_11_H */
diff --git a/contrib/wpa/hostapd/ieee802_11_auth.c b/contrib/wpa/hostapd/ieee802_11_auth.c
new file mode 100644
index 0000000..9aba1fe
--- /dev/null
+++ b/contrib/wpa/hostapd/ieee802_11_auth.c
@@ -0,0 +1,523 @@
+/*
+ * 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.
+ *
+ * Access control list for IEEE 802.11 authentication can uses statically
+ * configured ACL from configuration files or an external RADIUS server.
+ * Results from external RADIUS queries are cached to allow faster
+ * authentication frame processing.
+ */
+
+#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"
+#include "driver.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)
+ if (session_timeout)
+ *session_timeout =
+ entry->session_timeout;
+ if (acct_interim_interval)
+ *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;
+}
+
+
+/**
+ * hostapd_allowed_address - Check whether a specified STA can be authenticated
+ * @hapd: hostapd BSS data
+ * @addr: MAC address of the STA
+ * @msg: Authentication message
+ * @len: Length of msg in octets
+ * @session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
+ * @vlan_id: Buffer for returning VLAN ID
+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ */
+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)
+{
+ if (session_timeout)
+ *session_timeout = 0;
+ if (acct_interim_interval)
+ *acct_interim_interval = 0;
+ if (vlan_id)
+ *vlan_id = 0;
+
+ if (hostapd_maclist_found(hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac, addr, vlan_id))
+ return HOSTAPD_ACL_ACCEPT;
+
+ if (hostapd_maclist_found(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, addr, vlan_id))
+ 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;
+#ifdef CONFIG_DRIVER_RADIUS_ACL
+ hostapd_set_radius_acl_expire(hapd, entry->addr);
+#endif /* CONFIG_DRIVER_RADIUS_ACL */
+ 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;
+ }
+}
+
+
+/**
+ * hostapd_acl_expire - ACL cache expiration callback
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: Not used
+ */
+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);
+}
+
+
+/**
+ * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
+ * was processed here) or RADIUS_RX_UNKNOWN if not.
+ */
+static RadiusRxResult
+hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
+ const 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;
+
+#ifdef CONFIG_DRIVER_RADIUS_ACL
+ hostapd_set_radius_acl_auth(hapd, query->addr, cache->accepted,
+ cache->session_timeout);
+#else /* CONFIG_DRIVER_RADIUS_ACL */
+ /* 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);
+#endif /* CONFIG_DRIVER_RADIUS_ACL */
+
+ done:
+ if (prev == NULL)
+ hapd->acl_queries = query->next;
+ else
+ prev->next = query->next;
+
+ hostapd_acl_query_free(query);
+
+ return RADIUS_RX_PROCESSED;
+}
+
+
+/**
+ * hostapd_acl_init: Initialize IEEE 802.11 ACL
+ * @hapd: hostapd BSS data
+ * Returns: 0 on success, -1 on failure
+ */
+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;
+}
+
+
+/**
+ * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
+ * @hapd: hostapd BSS data
+ */
+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 */
diff --git a/contrib/wpa/hostapd/ieee802_11_auth.h b/contrib/wpa/hostapd/ieee802_11_auth.h
new file mode 100644
index 0000000..0eed825
--- /dev/null
+++ b/contrib/wpa/hostapd/ieee802_11_auth.h
@@ -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 */
diff --git a/contrib/wpa/hostapd/ieee802_1x.c b/contrib/wpa/hostapd/ieee802_1x.c
new file mode 100644
index 0000000..9b096d4
--- /dev/null
+++ b/contrib/wpa/hostapd/ieee802_1x.c
@@ -0,0 +1,2042 @@
+/*
+ * hostapd / IEEE 802.1X-2004 Authenticator
+ * Copyright (c) 2002-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 "hostapd.h"
+#include "ieee802_1x.h"
+#include "accounting.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "eapol_sm.h"
+#include "md5.h"
+#include "rc4.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "wpa.h"
+#include "preauth.h"
+#include "pmksa_cache.h"
+#include "driver.h"
+#include "hw_features.h"
+#include "eap_server/eap.h"
+#include "ieee802_11_defs.h"
+
+
+static void ieee802_1x_finished(struct hostapd_data *hapd,
+ struct sta_info *sta, int success);
+
+
+static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
+ u8 type, const u8 *data, size_t datalen)
+{
+ u8 *buf;
+ struct ieee802_1x_hdr *xhdr;
+ size_t len;
+ int encrypt = 0;
+
+ len = sizeof(*xhdr) + datalen;
+ buf = os_zalloc(len);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "malloc() failed for "
+ "ieee802_1x_send(len=%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ xhdr = (struct ieee802_1x_hdr *) buf;
+ xhdr->version = hapd->conf->eapol_version;
+ xhdr->type = type;
+ xhdr->length = host_to_be16(datalen);
+
+ if (datalen > 0 && data != NULL)
+ os_memcpy(xhdr + 1, data, datalen);
+
+ if (wpa_auth_pairwise_set(sta->wpa_sm))
+ encrypt = 1;
+ if (sta->flags & WLAN_STA_PREAUTH) {
+ rsn_preauth_send(hapd, sta, buf, len);
+ } else {
+ hostapd_send_eapol(hapd, sta->addr, buf, len, encrypt);
+ }
+
+ os_free(buf);
+}
+
+
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+ struct sta_info *sta, int authorized)
+{
+ int res;
+
+ if (sta->flags & WLAN_STA_PREAUTH)
+ return;
+
+ if (authorized) {
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ WLAN_STA_AUTHORIZED, ~0);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "authorizing port");
+ } else {
+ sta->flags &= ~WLAN_STA_AUTHORIZED;
+ res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ 0, ~WLAN_STA_AUTHORIZED);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
+ }
+
+ if (res && errno != ENOENT) {
+ printf("Could not set station " MACSTR " flags for kernel "
+ "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+ }
+
+ if (authorized)
+ accounting_sta_start(hapd, sta);
+}
+
+
+static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ int idx, int broadcast,
+ u8 *key_data, size_t key_len)
+{
+ u8 *buf, *ekey;
+ struct ieee802_1x_hdr *hdr;
+ struct ieee802_1x_eapol_key *key;
+ size_t len, ekey_len;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ len = sizeof(*key) + key_len;
+ buf = os_zalloc(sizeof(*hdr) + len);
+ if (buf == NULL)
+ return;
+
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+ key->type = EAPOL_KEY_TYPE_RC4;
+ key->key_length = htons(key_len);
+ wpa_get_ntp_timestamp(key->replay_counter);
+
+ if (os_get_random(key->key_iv, sizeof(key->key_iv))) {
+ wpa_printf(MSG_ERROR, "Could not get random numbers");
+ os_free(buf);
+ return;
+ }
+
+ key->key_index = idx | (broadcast ? 0 : BIT(7));
+ if (hapd->conf->eapol_key_index_workaround) {
+ /* According to some information, WinXP Supplicant seems to
+ * interpret bit7 as an indication whether the key is to be
+ * activated, so make it possible to enable workaround that
+ * sets this bit for all keys. */
+ key->key_index |= BIT(7);
+ }
+
+ /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
+ * MSK[32..63] is used to sign the message. */
+ if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
+ wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
+ "and signing EAPOL-Key");
+ os_free(buf);
+ return;
+ }
+ os_memcpy((u8 *) (key + 1), key_data, key_len);
+ ekey_len = sizeof(key->key_iv) + 32;
+ ekey = os_malloc(ekey_len);
+ if (ekey == NULL) {
+ wpa_printf(MSG_ERROR, "Could not encrypt key");
+ os_free(buf);
+ return;
+ }
+ os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
+ os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
+ rc4((u8 *) (key + 1), key_len, ekey, ekey_len);
+ os_free(ekey);
+
+ /* This header is needed here for HMAC-MD5, but it will be regenerated
+ * in ieee802_1x_send() */
+ hdr->version = hapd->conf->eapol_version;
+ hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+ hdr->length = host_to_be16(len);
+ hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
+ key->key_signature);
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
+ " (%s index=%d)", MAC2STR(sm->addr),
+ broadcast ? "broadcast" : "unicast", idx);
+ ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
+ if (sta->eapol_sm)
+ sta->eapol_sm->dot1xAuthEapolFramesTx++;
+ os_free(buf);
+}
+
+
+static struct hostapd_wep_keys *
+ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
+{
+ struct hostapd_wep_keys *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (key == NULL)
+ return NULL;
+
+ key->default_len = hapd->conf->default_wep_key_len;
+
+ if (key->idx >= hapd->conf->broadcast_key_idx_max ||
+ key->idx < hapd->conf->broadcast_key_idx_min)
+ key->idx = hapd->conf->broadcast_key_idx_min;
+ else
+ key->idx++;
+
+ if (!key->key[key->idx])
+ key->key[key->idx] = os_malloc(key->default_len);
+ if (key->key[key->idx] == NULL ||
+ os_get_random(key->key[key->idx], key->default_len)) {
+ printf("Could not generate random WEP key (dynamic VLAN).\n");
+ os_free(key->key[key->idx]);
+ key->key[key->idx] = NULL;
+ os_free(key);
+ return NULL;
+ }
+ key->len[key->idx] = key->default_len;
+
+ wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",
+ ifname, key->idx);
+ wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
+ key->key[key->idx], key->len[key->idx]);
+
+ if (hostapd_set_encryption(ifname, hapd, "WEP", NULL, key->idx,
+ key->key[key->idx], key->len[key->idx], 1))
+ printf("Could not set dynamic VLAN WEP encryption key.\n");
+
+ hostapd_set_ieee8021x(ifname, hapd, 1);
+
+ return key;
+}
+
+
+static struct hostapd_wep_keys *
+ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
+ size_t vlan_id)
+{
+ const char *ifname;
+
+ if (vlan_id == 0)
+ return &ssid->wep;
+
+ if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
+ ssid->dyn_vlan_keys[vlan_id])
+ return ssid->dyn_vlan_keys[vlan_id];
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "
+ "state machine for VLAN ID %lu",
+ (unsigned long) vlan_id);
+
+ ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+ if (ifname == NULL) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "
+ "cannot create group key state machine",
+ (unsigned long) vlan_id);
+ return NULL;
+ }
+
+ if (ssid->dyn_vlan_keys == NULL) {
+ int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+ ssid->dyn_vlan_keys = os_zalloc(size);
+ if (ssid->dyn_vlan_keys == NULL)
+ return NULL;
+ ssid->max_dyn_vlan_keys = vlan_id;
+ }
+
+ if (ssid->max_dyn_vlan_keys < vlan_id) {
+ struct hostapd_wep_keys **na;
+ int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+ na = os_realloc(ssid->dyn_vlan_keys, size);
+ if (na == NULL)
+ return NULL;
+ ssid->dyn_vlan_keys = na;
+ os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
+ (vlan_id - ssid->max_dyn_vlan_keys) *
+ sizeof(ssid->dyn_vlan_keys[0]));
+ ssid->max_dyn_vlan_keys = vlan_id;
+ }
+
+ ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
+
+ return ssid->dyn_vlan_keys[vlan_id];
+}
+
+
+void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct hostapd_wep_keys *key = NULL;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ int vlan_id;
+
+ if (sm == NULL || !sm->eap_if->eapKeyData)
+ return;
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
+ MAC2STR(sta->addr));
+
+ vlan_id = sta->vlan_id;
+ if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
+ vlan_id = 0;
+
+ if (vlan_id) {
+ key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
+ if (key && key->key[key->idx])
+ ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
+ key->key[key->idx],
+ key->len[key->idx]);
+ } else if (hapd->default_wep_key) {
+ ieee802_1x_tx_key_one(hapd, sta, hapd->default_wep_key_idx, 1,
+ hapd->default_wep_key,
+ hapd->conf->default_wep_key_len);
+ }
+
+ if (hapd->conf->individual_wep_key_len > 0) {
+ u8 *ikey;
+ ikey = os_malloc(hapd->conf->individual_wep_key_len);
+ if (ikey == NULL ||
+ os_get_random(ikey, hapd->conf->individual_wep_key_len)) {
+ wpa_printf(MSG_ERROR, "Could not generate random "
+ "individual WEP key.");
+ os_free(ikey);
+ return;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
+ ikey, hapd->conf->individual_wep_key_len);
+
+ ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
+ hapd->conf->individual_wep_key_len);
+
+ /* TODO: set encryption in TX callback, i.e., only after STA
+ * has ACKed EAPOL-Key frame */
+ if (hostapd_set_encryption(hapd->conf->iface, hapd, "WEP",
+ sta->addr, 0, ikey,
+ hapd->conf->individual_wep_key_len,
+ 1)) {
+ wpa_printf(MSG_ERROR, "Could not set individual WEP "
+ "encryption.");
+ }
+
+ os_free(ikey);
+ }
+}
+
+
+const char *radius_mode_txt(struct hostapd_data *hapd)
+{
+ if (hapd->iface->current_mode == NULL)
+ return "802.11";
+
+ switch (hapd->iface->current_mode->mode) {
+ case HOSTAPD_MODE_IEEE80211A:
+ return "802.11a";
+ case HOSTAPD_MODE_IEEE80211G:
+ return "802.11g";
+ case HOSTAPD_MODE_IEEE80211B:
+ default:
+ return "802.11b";
+ }
+}
+
+
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ int i;
+ u8 rate = 0;
+
+ for (i = 0; i < sta->supported_rates_len; i++)
+ if ((sta->supported_rates[i] & 0x7f) > rate)
+ rate = sta->supported_rates[i] & 0x7f;
+
+ return rate;
+}
+
+
+static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
+ struct eapol_state_machine *sm,
+ const u8 *eap, size_t len)
+{
+ const u8 *identity;
+ size_t identity_len;
+
+ if (len <= sizeof(struct eap_hdr) ||
+ eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
+ return;
+
+ identity = eap_get_identity(sm->eap, &identity_len);
+ if (identity == NULL)
+ return;
+
+ /* Save station identity for future RADIUS packets */
+ os_free(sm->identity);
+ sm->identity = os_malloc(identity_len + 1);
+ if (sm->identity == NULL) {
+ sm->identity_len = 0;
+ return;
+ }
+
+ os_memcpy(sm->identity, identity, identity_len);
+ sm->identity_len = identity_len;
+ sm->identity[identity_len] = '\0';
+ hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
+ sm->dot1xAuthEapolRespIdFramesRx++;
+}
+
+
+static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *eap, size_t len)
+{
+ struct radius_msg *msg;
+ char buf[128];
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ ieee802_1x_learn_identity(hapd, sm, eap, len);
+
+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
+ "packet");
+
+ sm->radius_identifier = radius_client_get_id(hapd->radius);
+ msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+ sm->radius_identifier);
+ if (msg == NULL) {
+ printf("Could not create net RADIUS packet\n");
+ return;
+ }
+
+ radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+ if (sm->identity &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+ sm->identity, sm->identity_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 (!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);
+ buf[sizeof(buf) - 1] = '\0';
+ 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;
+ }
+
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(sta->addr));
+ buf[sizeof(buf) - 1] = '\0';
+ 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;
+ }
+
+ /* TODO: should probably check MTU from driver config; 2304 is max for
+ * IEEE 802.11, but use 1400 to avoid problems with too large packets
+ */
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+ printf("Could not add Framed-MTU\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;
+ }
+
+ if (sta->flags & WLAN_STA_PREAUTH) {
+ os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
+ sizeof(buf));
+ } else {
+ 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));
+ buf[sizeof(buf) - 1] = '\0';
+ }
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ (u8 *) buf, os_strlen(buf))) {
+ printf("Could not add Connect-Info\n");
+ goto fail;
+ }
+
+ if (eap && !radius_msg_add_eap(msg, eap, len)) {
+ printf("Could not add EAP-Message\n");
+ goto fail;
+ }
+
+ /* State attribute must be copied if and only if this packet is
+ * Access-Request reply to the previous Access-Challenge */
+ if (sm->last_recv_radius && sm->last_recv_radius->hdr->code ==
+ RADIUS_CODE_ACCESS_CHALLENGE) {
+ int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
+ RADIUS_ATTR_STATE);
+ if (res < 0) {
+ printf("Could not copy State attribute from previous "
+ "Access-Challenge\n");
+ goto fail;
+ }
+ if (res > 0) {
+ wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
+ }
+ }
+
+ radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr);
+ return;
+
+ fail:
+ radius_msg_free(msg);
+ os_free(msg);
+}
+
+
+char *eap_type_text(u8 type)
+{
+ switch (type) {
+ case EAP_TYPE_IDENTITY: return "Identity";
+ case EAP_TYPE_NOTIFICATION: return "Notification";
+ case EAP_TYPE_NAK: return "Nak";
+ case EAP_TYPE_MD5: return "MD5-Challenge";
+ case EAP_TYPE_OTP: return "One-Time Password";
+ case EAP_TYPE_GTC: return "Generic Token Card";
+ case EAP_TYPE_TLS: return "TLS";
+ case EAP_TYPE_TTLS: return "TTLS";
+ case EAP_TYPE_PEAP: return "PEAP";
+ case EAP_TYPE_SIM: return "SIM";
+ case EAP_TYPE_FAST: return "FAST";
+ case EAP_TYPE_SAKE: return "SAKE";
+ case EAP_TYPE_PSK: return "PSK";
+ case EAP_TYPE_PAX: return "PAX";
+ default: return "Unknown";
+ }
+}
+
+
+static void handle_eap_response(struct hostapd_data *hapd,
+ struct sta_info *sta, struct eap_hdr *eap,
+ size_t len)
+{
+ u8 type, *data;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ if (sm == NULL)
+ return;
+
+ data = (u8 *) (eap + 1);
+
+ if (len < sizeof(*eap) + 1) {
+ printf("handle_eap_response: too short response data\n");
+ return;
+ }
+
+ sm->eap_type_supp = type = data[0];
+
+ hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
+ "id=%d len=%d) from STA: EAP Response-%s (%d)",
+ eap->code, eap->identifier, be_to_host16(eap->length),
+ eap_type_text(type), type);
+
+ sm->dot1xAuthEapolRespFramesRx++;
+
+ wpabuf_free(sm->eap_if->eapRespData);
+ sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
+ sm->eapolEap = TRUE;
+}
+
+
+/* Process incoming EAP packet from Supplicant */
+static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
+ u8 *buf, size_t len)
+{
+ struct eap_hdr *eap;
+ u16 eap_len;
+
+ if (len < sizeof(*eap)) {
+ printf(" too short EAP packet\n");
+ return;
+ }
+
+ eap = (struct eap_hdr *) buf;
+
+ eap_len = be_to_host16(eap->length);
+ wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
+ eap->code, eap->identifier, eap_len);
+ if (eap_len < sizeof(*eap)) {
+ wpa_printf(MSG_DEBUG, " Invalid EAP length");
+ return;
+ } else if (eap_len > len) {
+ wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP "
+ "packet");
+ return;
+ } else if (eap_len < len) {
+ wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP "
+ "packet", (unsigned long) len - eap_len);
+ }
+
+ switch (eap->code) {
+ case EAP_CODE_REQUEST:
+ wpa_printf(MSG_DEBUG, " (request)");
+ return;
+ case EAP_CODE_RESPONSE:
+ wpa_printf(MSG_DEBUG, " (response)");
+ handle_eap_response(hapd, sta, eap, eap_len);
+ break;
+ case EAP_CODE_SUCCESS:
+ wpa_printf(MSG_DEBUG, " (success)");
+ return;
+ case EAP_CODE_FAILURE:
+ wpa_printf(MSG_DEBUG, " (failure)");
+ return;
+ default:
+ wpa_printf(MSG_DEBUG, " (unknown code)");
+ return;
+ }
+}
+
+
+/**
+ * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
+ * @hapd: hostapd BSS data
+ * @sa: Source address (sender of the EAPOL frame)
+ * @buf: EAPOL frame
+ * @len: Length of buf in octets
+ *
+ * This function is called for each incoming EAPOL frame from the interface
+ */
+void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
+ size_t len)
+{
+ struct sta_info *sta;
+ struct ieee802_1x_hdr *hdr;
+ struct ieee802_1x_eapol_key *key;
+ u16 datalen;
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+ !hapd->conf->wps_state)
+ return;
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
+ (unsigned long) len, MAC2STR(sa));
+ sta = ap_get_sta(hapd, sa);
+ if (!sta) {
+ printf(" no station information available\n");
+ return;
+ }
+
+ if (len < sizeof(*hdr)) {
+ printf(" too short IEEE 802.1X packet\n");
+ return;
+ }
+
+ hdr = (struct ieee802_1x_hdr *) buf;
+ datalen = be_to_host16(hdr->length);
+ wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d",
+ hdr->version, hdr->type, datalen);
+
+ if (len - sizeof(*hdr) < datalen) {
+ printf(" frame too short for this IEEE 802.1X packet\n");
+ if (sta->eapol_sm)
+ sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
+ return;
+ }
+ if (len - sizeof(*hdr) > datalen) {
+ wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after "
+ "IEEE 802.1X packet",
+ (unsigned long) len - sizeof(*hdr) - datalen);
+ }
+
+ if (sta->eapol_sm) {
+ sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
+ sta->eapol_sm->dot1xAuthEapolFramesRx++;
+ }
+
+ key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+ if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
+ hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
+ (key->type == EAPOL_KEY_TYPE_WPA ||
+ key->type == EAPOL_KEY_TYPE_RSN)) {
+ wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
+ sizeof(*hdr) + datalen);
+ return;
+ }
+
+ if ((!hapd->conf->ieee802_1x &&
+ !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) ||
+ wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
+ return;
+
+ if (!sta->eapol_sm) {
+ sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr,
+ sta->flags & WLAN_STA_PREAUTH,
+ sta);
+ if (!sta->eapol_sm)
+ return;
+
+#ifdef CONFIG_WPS
+ if (!hapd->conf->ieee802_1x &&
+ ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
+ WLAN_STA_MAYBE_WPS)) {
+ /*
+ * Delay EAPOL frame transmission until a possible WPS
+ * STA initiates the handshake with EAPOL-Start.
+ */
+ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+ }
+#endif /* CONFIG_WPS */
+
+ sta->eapol_sm->eap_if->portEnabled = TRUE;
+ }
+
+ /* since we support version 1, we can ignore version field and proceed
+ * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
+ /* TODO: actually, we are not version 1 anymore.. However, Version 2
+ * does not change frame contents, so should be ok to process frames
+ * more or less identically. Some changes might be needed for
+ * verification of fields. */
+
+ switch (hdr->type) {
+ case IEEE802_1X_TYPE_EAP_PACKET:
+ handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
+ break;
+
+ case IEEE802_1X_TYPE_EAPOL_START:
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
+ "from STA");
+ sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
+ pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+ if (pmksa) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+ HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
+ "available - ignore it since "
+ "STA sent EAPOL-Start");
+ wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
+ }
+ sta->eapol_sm->eapolStart = TRUE;
+ sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
+ break;
+
+ case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
+ "from STA");
+ sta->acct_terminate_cause =
+ RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ accounting_sta_stop(hapd, sta);
+ sta->eapol_sm->eapolLogoff = TRUE;
+ sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
+ break;
+
+ case IEEE802_1X_TYPE_EAPOL_KEY:
+ wpa_printf(MSG_DEBUG, " EAPOL-Key");
+ if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_DEBUG, " Dropped key data from "
+ "unauthorized Supplicant");
+ break;
+ }
+ break;
+
+ case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+ wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert");
+ /* TODO: implement support for this; show data */
+ break;
+
+ default:
+ wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type");
+ sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
+ break;
+ }
+
+ eapol_auth_step(sta->eapol_sm);
+}
+
+
+/**
+ * ieee802_1x_new_station - Start IEEE 802.1X authentication
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ *
+ * This function is called to start IEEE 802.1X authentication when a new
+ * station completes IEEE 802.11 association.
+ */
+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+ int reassoc = 1;
+ int force_1x = 0;
+
+#ifdef CONFIG_WPS
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+ /*
+ * Need to enable IEEE 802.1X/EAPOL state machines for possible
+ * WPS handshake even if IEEE 802.1X/EAPOL is not used for
+ * authentication in this BSS.
+ */
+ force_1x = 1;
+ }
+#endif /* CONFIG_WPS */
+
+ if ((!force_1x && !hapd->conf->ieee802_1x) ||
+ wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
+ return;
+
+ if (sta->eapol_sm == NULL) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "start authentication");
+ sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr,
+ sta->flags & WLAN_STA_PREAUTH,
+ sta);
+ if (sta->eapol_sm == NULL) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO,
+ "failed to allocate state machine");
+ return;
+ }
+ reassoc = 0;
+ }
+
+#ifdef CONFIG_WPS
+ sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
+ if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
+ /*
+ * Delay EAPOL frame transmission until a possible WPS
+ * initiates the handshake with EAPOL-Start.
+ */
+ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+ }
+#endif /* CONFIG_WPS */
+
+ sta->eapol_sm->eap_if->portEnabled = TRUE;
+
+ pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+ if (pmksa) {
+ int old_vlanid;
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG,
+ "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
+ /* Setup EAPOL state machines to already authenticated state
+ * because of existing PMKSA information in the cache. */
+ sta->eapol_sm->keyRun = TRUE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+ sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+ sta->eapol_sm->authSuccess = TRUE;
+ if (sta->eapol_sm->eap)
+ eap_sm_notify_cached(sta->eapol_sm->eap);
+ old_vlanid = sta->vlan_id;
+ pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+ if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ sta->vlan_id = 0;
+ ap_sta_bind_vlan(hapd, sta, old_vlanid);
+ } else {
+ if (reassoc) {
+ /*
+ * Force EAPOL state machines to start
+ * re-authentication without having to wait for the
+ * Supplicant to send EAPOL-Start.
+ */
+ sta->eapol_sm->reAuthenticate = TRUE;
+ }
+ eapol_auth_step(sta->eapol_sm);
+ }
+}
+
+
+void ieee802_1x_free_radius_class(struct radius_class_data *class)
+{
+ size_t i;
+ if (class == NULL)
+ return;
+ for (i = 0; i < class->count; i++)
+ os_free(class->attr[i].data);
+ os_free(class->attr);
+ class->attr = NULL;
+ class->count = 0;
+}
+
+
+int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
+ const struct radius_class_data *src)
+{
+ size_t i;
+
+ if (src->attr == NULL)
+ return 0;
+
+ dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
+ if (dst->attr == NULL)
+ return -1;
+
+ dst->count = 0;
+
+ for (i = 0; i < src->count; i++) {
+ dst->attr[i].data = os_malloc(src->attr[i].len);
+ if (dst->attr[i].data == NULL)
+ break;
+ dst->count++;
+ os_memcpy(dst->attr[i].data, src->attr[i].data,
+ src->attr[i].len);
+ dst->attr[i].len = src->attr[i].len;
+ }
+
+ return 0;
+}
+
+
+void ieee802_1x_free_station(struct sta_info *sta)
+{
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ sta->eapol_sm = NULL;
+
+ if (sm->last_recv_radius) {
+ radius_msg_free(sm->last_recv_radius);
+ os_free(sm->last_recv_radius);
+ }
+
+ os_free(sm->identity);
+ ieee802_1x_free_radius_class(&sm->radius_class);
+ eapol_auth_free(sm);
+}
+
+
+static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ u8 *eap;
+ size_t len;
+ struct eap_hdr *hdr;
+ int eap_type = -1;
+ char buf[64];
+ struct radius_msg *msg;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL || sm->last_recv_radius == NULL) {
+ if (sm)
+ sm->eap_if->aaaEapNoReq = TRUE;
+ return;
+ }
+
+ msg = sm->last_recv_radius;
+
+ eap = radius_msg_get_eap(msg, &len);
+ if (eap == NULL) {
+ /* RFC 3579, Chap. 2.6.3:
+ * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
+ * attribute */
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_WARNING, "could not extract "
+ "EAP-Message from RADIUS message");
+ sm->eap_if->aaaEapNoReq = TRUE;
+ return;
+ }
+
+ if (len < sizeof(*hdr)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_WARNING, "too short EAP packet "
+ "received from authentication server");
+ os_free(eap);
+ sm->eap_if->aaaEapNoReq = TRUE;
+ return;
+ }
+
+ if (len > sizeof(*hdr))
+ eap_type = eap[sizeof(*hdr)];
+
+ hdr = (struct eap_hdr *) eap;
+ switch (hdr->code) {
+ case EAP_CODE_REQUEST:
+ if (eap_type >= 0)
+ sm->eap_type_authsrv = eap_type;
+ os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
+ eap_type >= 0 ? eap_type_text(eap_type) : "??",
+ eap_type);
+ break;
+ case EAP_CODE_RESPONSE:
+ os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
+ eap_type >= 0 ? eap_type_text(eap_type) : "??",
+ eap_type);
+ break;
+ case EAP_CODE_SUCCESS:
+ os_strlcpy(buf, "EAP Success", sizeof(buf));
+ break;
+ case EAP_CODE_FAILURE:
+ os_strlcpy(buf, "EAP Failure", sizeof(buf));
+ break;
+ default:
+ os_strlcpy(buf, "unknown EAP code", sizeof(buf));
+ break;
+ }
+ buf[sizeof(buf) - 1] = '\0';
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
+ "id=%d len=%d) from RADIUS server: %s",
+ hdr->code, hdr->identifier, be_to_host16(hdr->length),
+ buf);
+ sm->eap_if->aaaEapReq = TRUE;
+
+ wpabuf_free(sm->eap_if->aaaEapReqData);
+ sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len);
+}
+
+
+static void ieee802_1x_get_keys(struct hostapd_data *hapd,
+ struct sta_info *sta, struct radius_msg *msg,
+ struct radius_msg *req,
+ const u8 *shared_secret,
+ size_t shared_secret_len)
+{
+ struct radius_ms_mppe_keys *keys;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ if (sm == NULL)
+ return;
+
+ keys = radius_msg_get_ms_keys(msg, req, shared_secret,
+ shared_secret_len);
+
+ if (keys && keys->send && keys->recv) {
+ size_t len = keys->send_len + keys->recv_len;
+ wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
+ keys->send, keys->send_len);
+ wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
+ keys->recv, keys->recv_len);
+
+ os_free(sm->eap_if->aaaEapKeyData);
+ sm->eap_if->aaaEapKeyData = os_malloc(len);
+ if (sm->eap_if->aaaEapKeyData) {
+ os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
+ keys->recv_len);
+ os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
+ keys->send, keys->send_len);
+ sm->eap_if->aaaEapKeyDataLen = len;
+ sm->eap_if->aaaEapKeyAvailable = TRUE;
+ }
+ }
+
+ if (keys) {
+ os_free(keys->send);
+ os_free(keys->recv);
+ os_free(keys);
+ }
+}
+
+
+static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ u8 *class;
+ size_t class_len;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ int count, i;
+ struct radius_attr_data *nclass;
+ size_t nclass_count;
+
+ if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
+ sm == NULL)
+ return;
+
+ ieee802_1x_free_radius_class(&sm->radius_class);
+ count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
+ if (count <= 0)
+ return;
+
+ nclass = os_zalloc(count * sizeof(struct radius_attr_data));
+ if (nclass == NULL)
+ return;
+
+ nclass_count = 0;
+
+ class = NULL;
+ for (i = 0; i < count; i++) {
+ do {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
+ &class, &class_len,
+ class) < 0) {
+ i = count;
+ break;
+ }
+ } while (class_len < 1);
+
+ nclass[nclass_count].data = os_malloc(class_len);
+ if (nclass[nclass_count].data == NULL)
+ break;
+
+ os_memcpy(nclass[nclass_count].data, class, class_len);
+ nclass[nclass_count].len = class_len;
+ nclass_count++;
+ }
+
+ sm->radius_class.attr = nclass;
+ sm->radius_class.count = nclass_count;
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
+ "attributes for " MACSTR,
+ (unsigned long) sm->radius_class.count,
+ MAC2STR(sta->addr));
+}
+
+
+/* Update sta->identity based on User-Name attribute in Access-Accept */
+static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ u8 *buf, *identity;
+ size_t len;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
+ NULL) < 0)
+ return;
+
+ identity = os_malloc(len + 1);
+ if (identity == NULL)
+ return;
+
+ os_memcpy(identity, buf, len);
+ identity[len] = '\0';
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
+ "User-Name from Access-Accept '%s'",
+ sm->identity ? (char *) sm->identity : "N/A",
+ (char *) identity);
+
+ os_free(sm->identity);
+ sm->identity = identity;
+ sm->identity_len = len;
+}
+
+
+struct sta_id_search {
+ u8 identifier;
+ struct eapol_state_machine *sm;
+};
+
+
+static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ void *ctx)
+{
+ struct sta_id_search *id_search = ctx;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm && sm->radius_identifier >= 0 &&
+ sm->radius_identifier == id_search->identifier) {
+ id_search->sm = sm;
+ return 1;
+ }
+ return 0;
+}
+
+
+static struct eapol_state_machine *
+ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
+{
+ struct sta_id_search id_search;
+ id_search.identifier = identifier;
+ id_search.sm = NULL;
+ ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
+ return id_search.sm;
+}
+
+
+/**
+ * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
+static RadiusRxResult
+ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
+ const u8 *shared_secret, size_t shared_secret_len,
+ void *data)
+{
+ struct hostapd_data *hapd = data;
+ struct sta_info *sta;
+ u32 session_timeout = 0, termination_action, acct_interim_interval;
+ int session_timeout_set, old_vlanid = 0;
+ struct eapol_state_machine *sm;
+ int override_eapReq = 0;
+
+ sm = ieee802_1x_search_radius_identifier(hapd, msg->hdr->identifier);
+ if (sm == NULL) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
+ "station for this RADIUS message");
+ return RADIUS_RX_UNKNOWN;
+ }
+ sta = sm->sta;
+
+ /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
+ * present when packet contains an EAP-Message attribute */
+ if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT &&
+ radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
+ 0) < 0 &&
+ radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
+ "Message-Authenticator since it does not include "
+ "EAP-Message");
+ } else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
+ req, 1)) {
+ printf("Incoming RADIUS packet did not have correct "
+ "Message-Authenticator - dropped\n");
+ return RADIUS_RX_INVALID_AUTHENTICATOR;
+ }
+
+ if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+ msg->hdr->code != RADIUS_CODE_ACCESS_REJECT &&
+ msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
+ printf("Unknown RADIUS message code\n");
+ return RADIUS_RX_UNKNOWN;
+ }
+
+ sm->radius_identifier = -1;
+ wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
+ MAC2STR(sta->addr));
+
+ if (sm->last_recv_radius) {
+ radius_msg_free(sm->last_recv_radius);
+ os_free(sm->last_recv_radius);
+ }
+
+ sm->last_recv_radius = msg;
+
+ session_timeout_set =
+ !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
+ &session_timeout);
+ if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
+ &termination_action))
+ termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
+
+ if (hapd->conf->radius->acct_interim_interval == 0 &&
+ msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
+ &acct_interim_interval) == 0) {
+ if (acct_interim_interval < 60) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO,
+ "ignored too small "
+ "Acct-Interim-Interval %d",
+ acct_interim_interval);
+ } else
+ sta->acct_interim_interval = acct_interim_interval;
+ }
+
+
+ switch (msg->hdr->code) {
+ case RADIUS_CODE_ACCESS_ACCEPT:
+ if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ sta->vlan_id = 0;
+ else {
+ old_vlanid = sta->vlan_id;
+ sta->vlan_id = radius_msg_get_vlanid(msg);
+ }
+ if (sta->vlan_id > 0 &&
+ hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+ sta->vlan_id)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "VLAN ID %d", sta->vlan_id);
+ } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO, "authentication "
+ "server did not include required VLAN "
+ "ID in Access-Accept");
+ break;
+ }
+
+ ap_sta_bind_vlan(hapd, sta, old_vlanid);
+
+ /* RFC 3580, Ch. 3.17 */
+ if (session_timeout_set && termination_action ==
+ RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
+ sm->reAuthPeriod = session_timeout;
+ } else if (session_timeout_set)
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+
+ sm->eap_if->aaaSuccess = TRUE;
+ override_eapReq = 1;
+ ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
+ shared_secret_len);
+ ieee802_1x_store_radius_class(hapd, sta, msg);
+ ieee802_1x_update_sta_identity(hapd, sta, msg);
+ if (sm->eap_if->eapKeyAvailable &&
+ wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
+ session_timeout_set ?
+ (int) session_timeout : -1, sm) == 0) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+ HOSTAPD_LEVEL_DEBUG,
+ "Added PMKSA cache entry");
+ }
+ break;
+ case RADIUS_CODE_ACCESS_REJECT:
+ sm->eap_if->aaaFail = TRUE;
+ override_eapReq = 1;
+ break;
+ case RADIUS_CODE_ACCESS_CHALLENGE:
+ sm->eap_if->aaaEapReq = TRUE;
+ if (session_timeout_set) {
+ /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
+ sm->eap_if->aaaMethodTimeout = session_timeout;
+ hostapd_logger(hapd, sm->addr,
+ HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG,
+ "using EAP timeout of %d seconds (from "
+ "RADIUS)",
+ sm->eap_if->aaaMethodTimeout);
+ } else {
+ /*
+ * Use dynamic retransmission behavior per EAP
+ * specification.
+ */
+ sm->eap_if->aaaMethodTimeout = 0;
+ }
+ break;
+ }
+
+ ieee802_1x_decapsulate_radius(hapd, sta);
+ if (override_eapReq)
+ sm->eap_if->aaaEapReq = FALSE;
+
+ eapol_auth_step(sm);
+
+ return RADIUS_RX_QUEUED;
+}
+
+
+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ if (sm == NULL)
+ return;
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "aborting authentication");
+
+ if (sm->last_recv_radius) {
+ radius_msg_free(sm->last_recv_radius);
+ os_free(sm->last_recv_radius);
+ sm->last_recv_radius = NULL;
+ }
+
+ if (sm->eap_if->eapTimeout) {
+ /*
+ * Disconnect the STA since it did not reply to the last EAP
+ * request and we cannot continue EAP processing (EAP-Failure
+ * could only be sent if the EAP peer actually replied).
+ */
+ sm->eap_if->portEnabled = FALSE;
+ hostapd_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_AUTHORIZED);
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+ sta->timeout_next = STA_REMOVE;
+ }
+}
+
+
+#ifdef HOSTAPD_DUMP_STATE
+static void fprint_char(FILE *f, char c)
+{
+ if (c >= 32 && c < 127)
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, "<%02x>", c);
+}
+
+
+void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta)
+{
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ if (sm == NULL)
+ return;
+
+ fprintf(f, "%sIEEE 802.1X:\n", prefix);
+
+ if (sm->identity) {
+ size_t i;
+ fprintf(f, "%sidentity=", prefix);
+ for (i = 0; i < sm->identity_len; i++)
+ fprint_char(f, sm->identity[i]);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
+ "Supplicant: %d (%s)\n", prefix,
+ sm->eap_type_authsrv, eap_type_text(sm->eap_type_authsrv),
+ sm->eap_type_supp, eap_type_text(sm->eap_type_supp));
+
+ fprintf(f, "%scached_packets=%s\n", prefix,
+ sm->last_recv_radius ? "[RX RADIUS]" : "");
+
+ eapol_auth_dump_state(f, prefix, sm);
+}
+#endif /* HOSTAPD_DUMP_STATE */
+
+
+static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
+{
+ if (hapd->conf->default_wep_key_len < 1)
+ return 0;
+
+ os_free(hapd->default_wep_key);
+ hapd->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
+ if (hapd->default_wep_key == NULL ||
+ os_get_random(hapd->default_wep_key,
+ hapd->conf->default_wep_key_len)) {
+ printf("Could not generate random WEP key.\n");
+ os_free(hapd->default_wep_key);
+ hapd->default_wep_key = NULL;
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
+ hapd->default_wep_key,
+ hapd->conf->default_wep_key_len);
+
+ return 0;
+}
+
+
+static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ if (sta->eapol_sm) {
+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ eapol_auth_step(sta->eapol_sm);
+ }
+ return 0;
+}
+
+
+static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ if (hapd->default_wep_key_idx >= 3)
+ hapd->default_wep_key_idx =
+ hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
+ else
+ hapd->default_wep_key_idx++;
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
+ hapd->default_wep_key_idx);
+
+ if (ieee802_1x_rekey_broadcast(hapd)) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_WARNING, "failed to generate a "
+ "new broadcast key");
+ os_free(hapd->default_wep_key);
+ hapd->default_wep_key = NULL;
+ return;
+ }
+
+ /* TODO: Could setup key for RX here, but change default TX keyid only
+ * after new broadcast key has been sent to all stations. */
+ if (hostapd_set_encryption(hapd->conf->iface, hapd, "WEP", NULL,
+ hapd->default_wep_key_idx,
+ hapd->default_wep_key,
+ hapd->conf->default_wep_key_len, 1)) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_WARNING, "failed to configure a "
+ "new broadcast key");
+ os_free(hapd->default_wep_key);
+ hapd->default_wep_key = NULL;
+ return;
+ }
+
+ ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
+
+ if (hapd->conf->wep_rekeying_period > 0) {
+ eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
+ ieee802_1x_rekey, hapd, NULL);
+ }
+}
+
+
+static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
+ const u8 *data, size_t datalen)
+{
+ ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
+}
+
+
+static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
+ const u8 *data, size_t datalen)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = sta_ctx;
+
+ ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
+}
+
+
+static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
+ int preauth)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = sta_ctx;
+ if (preauth)
+ rsn_preauth_finished(hapd, sta, success);
+ else
+ ieee802_1x_finished(hapd, sta, success);
+}
+
+
+static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct hostapd_eap_user *eap_user;
+ int i, count;
+
+ eap_user = hostapd_get_eap_user(hapd->conf, identity,
+ identity_len, phase2);
+ if (eap_user == NULL)
+ return -1;
+
+ os_memset(user, 0, sizeof(*user));
+ user->phase2 = phase2;
+ count = EAP_USER_MAX_METHODS;
+ if (count > EAP_MAX_METHODS)
+ count = EAP_MAX_METHODS;
+ for (i = 0; i < count; i++) {
+ user->methods[i].vendor = eap_user->methods[i].vendor;
+ user->methods[i].method = eap_user->methods[i].method;
+ }
+
+ if (eap_user->password) {
+ user->password = os_malloc(eap_user->password_len);
+ if (user->password == NULL)
+ return -1;
+ os_memcpy(user->password, eap_user->password,
+ eap_user->password_len);
+ user->password_len = eap_user->password_len;
+ }
+ user->force_version = eap_user->force_version;
+ user->ttls_auth = eap_user->ttls_auth;
+
+ return 0;
+}
+
+
+static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL || sta->eapol_sm == NULL)
+ return 0;
+ return 1;
+}
+
+
+static void ieee802_1x_logger(void *ctx, const u8 *addr,
+ eapol_logger_level level, const char *txt)
+{
+ struct hostapd_data *hapd = ctx;
+ int hlevel;
+
+ switch (level) {
+ case EAPOL_LOGGER_WARNING:
+ hlevel = HOSTAPD_LEVEL_WARNING;
+ break;
+ case EAPOL_LOGGER_INFO:
+ hlevel = HOSTAPD_LEVEL_INFO;
+ break;
+ case EAPOL_LOGGER_DEBUG:
+ default:
+ hlevel = HOSTAPD_LEVEL_DEBUG;
+ break;
+ }
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
+ txt);
+}
+
+
+static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
+ int authorized)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = sta_ctx;
+ ieee802_1x_set_sta_authorized(hapd, sta, authorized);
+}
+
+
+static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = sta_ctx;
+ ieee802_1x_abort_auth(hapd, sta);
+}
+
+
+static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = sta_ctx;
+ ieee802_1x_tx_key(hapd, sta);
+}
+
+
+int ieee802_1x_init(struct hostapd_data *hapd)
+{
+ int i;
+ struct eapol_auth_config conf;
+ struct eapol_auth_cb cb;
+
+ os_memset(&conf, 0, sizeof(conf));
+ conf.hapd = hapd;
+ conf.eap_reauth_period = hapd->conf->eap_reauth_period;
+ conf.wpa = hapd->conf->wpa;
+ conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
+ conf.eap_server = hapd->conf->eap_server;
+ conf.ssl_ctx = hapd->ssl_ctx;
+ conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
+ conf.eap_req_id_text = hapd->conf->eap_req_id_text;
+ conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+ conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
+ conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
+ conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+ conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
+ conf.eap_fast_prov = hapd->conf->eap_fast_prov;
+ conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
+ conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+ conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+ conf.tnc = hapd->conf->tnc;
+ conf.wps = hapd->wps;
+
+ os_memset(&cb, 0, sizeof(cb));
+ cb.eapol_send = ieee802_1x_eapol_send;
+ cb.aaa_send = ieee802_1x_aaa_send;
+ cb.finished = _ieee802_1x_finished;
+ cb.get_eap_user = ieee802_1x_get_eap_user;
+ cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
+ cb.logger = ieee802_1x_logger;
+ cb.set_port_authorized = ieee802_1x_set_port_authorized;
+ cb.abort_auth = _ieee802_1x_abort_auth;
+ cb.tx_key = _ieee802_1x_tx_key;
+
+ hapd->eapol_auth = eapol_auth_init(&conf, &cb);
+ if (hapd->eapol_auth == NULL)
+ return -1;
+
+ if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
+ hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1))
+ return -1;
+
+ if (radius_client_register(hapd->radius, RADIUS_AUTH,
+ ieee802_1x_receive_auth, hapd))
+ return -1;
+
+ if (hapd->conf->default_wep_key_len) {
+ hostapd_set_privacy(hapd, 1);
+
+ for (i = 0; i < 4; i++)
+ hostapd_set_encryption(hapd->conf->iface, hapd,
+ "none", NULL, i, NULL, 0, 0);
+
+ ieee802_1x_rekey(hapd, NULL);
+
+ if (hapd->default_wep_key == NULL)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void ieee802_1x_deinit(struct hostapd_data *hapd)
+{
+ eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+
+ if (hapd->driver != NULL &&
+ (hapd->conf->ieee802_1x || hapd->conf->wpa))
+ hostapd_set_ieee8021x(hapd->conf->iface, hapd, 0);
+
+ eapol_auth_deinit(hapd->eapol_auth);
+ hapd->eapol_auth = NULL;
+}
+
+
+int ieee802_1x_reconfig(struct hostapd_data *hapd,
+ struct hostapd_config *oldconf,
+ struct hostapd_bss_config *oldbss)
+{
+ ieee802_1x_deinit(hapd);
+ return ieee802_1x_init(hapd);
+}
+
+
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+ u8 *buf, size_t len, int ack)
+{
+ struct ieee80211_hdr *hdr;
+ struct ieee802_1x_hdr *xhdr;
+ struct ieee802_1x_eapol_key *key;
+ u8 *pos;
+ const unsigned char rfc1042_hdr[ETH_ALEN] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ if (sta == NULL)
+ return -1;
+ if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
+ return 0;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ pos = (u8 *) (hdr + 1);
+ if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
+ return 0;
+ pos += sizeof(rfc1042_hdr);
+ if (WPA_GET_BE16(pos) != ETH_P_PAE)
+ return 0;
+ pos += 2;
+
+ xhdr = (struct ieee802_1x_hdr *) pos;
+ pos += sizeof(*xhdr);
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
+ "type=%d length=%d - ack=%d",
+ MAC2STR(sta->addr), xhdr->version, xhdr->type,
+ be_to_host16(xhdr->length), ack);
+
+ /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
+ * or Authenticator state machines, but EAPOL-Key packets are not
+ * retransmitted in case of failure. Try to re-sent failed EAPOL-Key
+ * packets couple of times because otherwise STA keys become
+ * unsynchronized with AP. */
+ if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
+ pos + sizeof(*key) <= buf + len) {
+ key = (struct ieee802_1x_eapol_key *) pos;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
+ "frame (%scast index=%d)",
+ key->key_index & BIT(7) ? "uni" : "broad",
+ key->key_index & ~BIT(7));
+ /* TODO: re-send EAPOL-Key couple of times (with short delay
+ * between them?). If all attempt fail, report error and
+ * deauthenticate STA so that it will get new keys when
+ * authenticating again (e.g., after returning in range).
+ * Separate limit/transmit state needed both for unicast and
+ * broadcast keys(?) */
+ }
+ /* TODO: could move unicast key configuration from ieee802_1x_tx_key()
+ * to here and change the key only if the EAPOL-Key packet was Acked.
+ */
+
+ return 1;
+}
+
+
+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
+{
+ if (sm == NULL || sm->identity == NULL)
+ return NULL;
+
+ *len = sm->identity_len;
+ return sm->identity;
+}
+
+
+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+ int idx)
+{
+ if (sm == NULL || sm->radius_class.attr == NULL ||
+ idx >= (int) sm->radius_class.count)
+ return NULL;
+
+ *len = sm->radius_class.attr[idx].len;
+ return sm->radius_class.attr[idx].data;
+}
+
+
+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
+{
+ if (sm == NULL)
+ return NULL;
+
+ *len = sm->eap_if->eapKeyDataLen;
+ return sm->eap_if->eapKeyData;
+}
+
+
+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
+ int enabled)
+{
+ if (sm == NULL)
+ return;
+ sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
+ eapol_auth_step(sm);
+}
+
+
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
+ int valid)
+{
+ if (sm == NULL)
+ return;
+ sm->portValid = valid ? TRUE : FALSE;
+ eapol_auth_step(sm);
+}
+
+
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
+{
+ if (sm == NULL)
+ return;
+ if (pre_auth)
+ sm->flags |= EAPOL_SM_PREAUTH;
+ else
+ sm->flags &= ~EAPOL_SM_PREAUTH;
+}
+
+
+static const char * bool_txt(Boolean bool)
+{
+ return bool ? "TRUE" : "FALSE";
+}
+
+
+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+ /* TODO */
+ return 0;
+}
+
+
+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ int len = 0, ret;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return 0;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "dot1xPaePortNumber=%d\n"
+ "dot1xPaePortProtocolVersion=%d\n"
+ "dot1xPaePortCapabilities=1\n"
+ "dot1xPaePortInitialize=%d\n"
+ "dot1xPaePortReauthenticate=FALSE\n",
+ sta->aid,
+ EAPOL_VERSION,
+ sm->initialize);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ /* dot1xAuthConfigTable */
+ ret = os_snprintf(buf + len, buflen - len,
+ "dot1xAuthPaeState=%d\n"
+ "dot1xAuthBackendAuthState=%d\n"
+ "dot1xAuthAdminControlledDirections=%d\n"
+ "dot1xAuthOperControlledDirections=%d\n"
+ "dot1xAuthAuthControlledPortStatus=%d\n"
+ "dot1xAuthAuthControlledPortControl=%d\n"
+ "dot1xAuthQuietPeriod=%u\n"
+ "dot1xAuthServerTimeout=%u\n"
+ "dot1xAuthReAuthPeriod=%u\n"
+ "dot1xAuthReAuthEnabled=%s\n"
+ "dot1xAuthKeyTxEnabled=%s\n",
+ sm->auth_pae_state + 1,
+ sm->be_auth_state + 1,
+ sm->adminControlledDirections,
+ sm->operControlledDirections,
+ sm->authPortStatus,
+ sm->portControl,
+ sm->quietPeriod,
+ sm->serverTimeout,
+ sm->reAuthPeriod,
+ bool_txt(sm->reAuthEnabled),
+ bool_txt(sm->keyTxEnabled));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ /* dot1xAuthStatsTable */
+ ret = os_snprintf(buf + len, buflen - len,
+ "dot1xAuthEapolFramesRx=%u\n"
+ "dot1xAuthEapolFramesTx=%u\n"
+ "dot1xAuthEapolStartFramesRx=%u\n"
+ "dot1xAuthEapolLogoffFramesRx=%u\n"
+ "dot1xAuthEapolRespIdFramesRx=%u\n"
+ "dot1xAuthEapolRespFramesRx=%u\n"
+ "dot1xAuthEapolReqIdFramesTx=%u\n"
+ "dot1xAuthEapolReqFramesTx=%u\n"
+ "dot1xAuthInvalidEapolFramesRx=%u\n"
+ "dot1xAuthEapLengthErrorFramesRx=%u\n"
+ "dot1xAuthLastEapolFrameVersion=%u\n"
+ "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
+ sm->dot1xAuthEapolFramesRx,
+ sm->dot1xAuthEapolFramesTx,
+ sm->dot1xAuthEapolStartFramesRx,
+ sm->dot1xAuthEapolLogoffFramesRx,
+ sm->dot1xAuthEapolRespIdFramesRx,
+ sm->dot1xAuthEapolRespFramesRx,
+ sm->dot1xAuthEapolReqIdFramesTx,
+ sm->dot1xAuthEapolReqFramesTx,
+ sm->dot1xAuthInvalidEapolFramesRx,
+ sm->dot1xAuthEapLengthErrorFramesRx,
+ sm->dot1xAuthLastEapolFrameVersion,
+ MAC2STR(sm->addr));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ /* dot1xAuthDiagTable */
+ ret = os_snprintf(buf + len, buflen - len,
+ "dot1xAuthEntersConnecting=%u\n"
+ "dot1xAuthEapLogoffsWhileConnecting=%u\n"
+ "dot1xAuthEntersAuthenticating=%u\n"
+ "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
+ "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
+ "dot1xAuthAuthFailWhileAuthenticating=%u\n"
+ "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
+ "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
+ "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
+ "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
+ "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
+ "dot1xAuthBackendResponses=%u\n"
+ "dot1xAuthBackendAccessChallenges=%u\n"
+ "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
+ "dot1xAuthBackendAuthSuccesses=%u\n"
+ "dot1xAuthBackendAuthFails=%u\n",
+ sm->authEntersConnecting,
+ sm->authEapLogoffsWhileConnecting,
+ sm->authEntersAuthenticating,
+ sm->authAuthSuccessesWhileAuthenticating,
+ sm->authAuthTimeoutsWhileAuthenticating,
+ sm->authAuthFailWhileAuthenticating,
+ sm->authAuthEapStartsWhileAuthenticating,
+ sm->authAuthEapLogoffWhileAuthenticating,
+ sm->authAuthReauthsWhileAuthenticated,
+ sm->authAuthEapStartsWhileAuthenticated,
+ sm->authAuthEapLogoffWhileAuthenticated,
+ sm->backendResponses,
+ sm->backendAccessChallenges,
+ sm->backendOtherRequestsToSupplicant,
+ sm->backendAuthSuccesses,
+ sm->backendAuthFails);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ /* dot1xAuthSessionStatsTable */
+ ret = os_snprintf(buf + len, buflen - len,
+ /* TODO: dot1xAuthSessionOctetsRx */
+ /* TODO: dot1xAuthSessionOctetsTx */
+ /* TODO: dot1xAuthSessionFramesRx */
+ /* TODO: dot1xAuthSessionFramesTx */
+ "dot1xAuthSessionId=%08X-%08X\n"
+ "dot1xAuthSessionAuthenticMethod=%d\n"
+ "dot1xAuthSessionTime=%u\n"
+ "dot1xAuthSessionTerminateCause=999\n"
+ "dot1xAuthSessionUserName=%s\n",
+ sta->acct_session_id_hi, sta->acct_session_id_lo,
+ (wpa_key_mgmt_wpa_ieee8021x(
+ wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
+ 1 : 2,
+ (unsigned int) (time(NULL) -
+ sta->acct_session_start),
+ sm->identity);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ return len;
+}
+
+
+static void ieee802_1x_finished(struct hostapd_data *hapd,
+ struct sta_info *sta, int success)
+{
+ const u8 *key;
+ size_t len;
+ /* TODO: get PMKLifetime from WPA parameters */
+ static const int dot11RSNAConfigPMKLifetime = 43200;
+
+ key = ieee802_1x_get_key(sta->eapol_sm, &len);
+ if (success && key && len >= PMK_LEN &&
+ wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
+ sta->eapol_sm) == 0) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+ HOSTAPD_LEVEL_DEBUG,
+ "Added PMKSA cache entry (IEEE 802.1X)");
+ }
+}
diff --git a/contrib/wpa/hostapd/ieee802_1x.h b/contrib/wpa/hostapd/ieee802_1x.h
new file mode 100644
index 0000000..94cff93
--- /dev/null
+++ b/contrib/wpa/hostapd/ieee802_1x.h
@@ -0,0 +1,90 @@
+/*
+ * 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,
+ const struct radius_class_data *src);
+
+const char *radius_mode_txt(struct hostapd_data *hapd);
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+
+#endif /* IEEE802_1X_H */
diff --git a/contrib/wpa/hostapd/logwatch/README b/contrib/wpa/hostapd/logwatch/README
new file mode 100644
index 0000000..3cba511
--- /dev/null
+++ b/contrib/wpa/hostapd/logwatch/README
@@ -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/
diff --git a/contrib/wpa/hostapd/logwatch/hostapd b/contrib/wpa/hostapd/logwatch/hostapd
new file mode 100755
index 0000000..97b24ef
--- /dev/null
+++ b/contrib/wpa/hostapd/logwatch/hostapd
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+#
+# Logwatch script 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
+
+use strict;
+
+my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
+my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
+my $debugcounter = 1;
+
+my %hostapd;
+my @unmatched;
+
+if ($debug >= 5) {
+ print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
+}
+
+while (defined(my $line = <STDIN>)) {
+ if ($debug >= 5) {
+ print STDERR "DEBUG($debugcounter): $line";
+ $debugcounter++;
+ }
+ chomp($line);
+
+ if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
+ unless ($detail == 10) {
+ # collapse association events
+ $details =~ s/^(associated) .*$/$1/i;
+ }
+ $hostapd{$iface}->{$mac}->{$layer}->{$details}++;
+ } else {
+ push @unmatched, "$line\n";
+ }
+}
+
+if (keys %hostapd) {
+ foreach my $iface (sort keys %hostapd) {
+ print "Interface $iface:\n";
+ foreach my $mac (sort keys %{$hostapd{$iface}}) {
+ print " Client MAC Address $mac:\n";
+ foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
+ print " $layer:\n";
+ foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
+ print " $details";
+ my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
+ if ($count > 1) {
+ print ": " . $count . " Times";
+ }
+ print "\n";
+ }
+ }
+ }
+ }
+}
+
+if ($#unmatched >= 0) {
+ print "\n**Unmatched Entries**\n";
+ print @unmatched;
+}
+
+exit(0);
diff --git a/contrib/wpa/hostapd/logwatch/hostapd.conf b/contrib/wpa/hostapd/logwatch/hostapd.conf
new file mode 100644
index 0000000..5bebe6a
--- /dev/null
+++ b/contrib/wpa/hostapd/logwatch/hostapd.conf
@@ -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
diff --git a/contrib/wpa/hostapd/mlme.c b/contrib/wpa/hostapd/mlme.c
new file mode 100644
index 0000000..d883931
--- /dev/null
+++ b/contrib/wpa/hostapd/mlme.c
@@ -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 && !(sta->flags & WLAN_STA_MFP))
+ 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);
+}
diff --git a/contrib/wpa/hostapd/mlme.h b/contrib/wpa/hostapd/mlme.h
new file mode 100644
index 0000000..c77a939
--- /dev/null
+++ b/contrib/wpa/hostapd/mlme.h
@@ -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 */
diff --git a/contrib/wpa/hostapd/nt_password_hash.c b/contrib/wpa/hostapd/nt_password_hash.c
new file mode 100644
index 0000000..9df307d
--- /dev/null
+++ b/contrib/wpa/hostapd/nt_password_hash.c
@@ -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;
+}
diff --git a/contrib/wpa/hostapd/peerkey.c b/contrib/wpa/hostapd/peerkey.c
new file mode 100644
index 0000000..83f3ce5
--- /dev/null
+++ b/contrib/wpa/hostapd/peerkey.c
@@ -0,0 +1,402 @@
+/*
+ * hostapd - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-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 "common.h"
+#include "eloop.h"
+#include "sha1.h"
+#include "sha256.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);
+#ifdef CONFIG_IEEE80211W
+ sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+ smk, PMK_LEN);
+#else /* CONFIG_IEEE80211W */
+ sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+ smk, PMK_LEN);
+#endif /* CONFIG_IEEE80211W */
+
+ 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 */
diff --git a/contrib/wpa/hostapd/pmksa_cache.c b/contrib/wpa/hostapd/pmksa_cache.c
new file mode 100644
index 0000000..5f54a34
--- /dev/null
+++ b/contrib/wpa/hostapd/pmksa_cache.c
@@ -0,0 +1,455 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * 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 "common.h"
+#include "ap.h"
+#include "config.h"
+#include "common.h"
+#include "eloop.h"
+#include "sha1.h"
+#include "sha256.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
+ * @pmkid: Buffer for PMKID
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * 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, int use_sha256)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA256_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+#ifdef CONFIG_IEEE80211W
+ if (use_sha256)
+ hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
+ else
+#endif /* CONFIG_IEEE80211W */
+ 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;
+}
+
+
+static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct rsn_pmksa_cache_entry *pos, *prev;
+
+ /* 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);
+}
+
+
+/**
+ * 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
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * 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, int akmp)
+{
+ struct rsn_pmksa_cache_entry *entry, *pos;
+ 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,
+ wpa_key_mgmt_sha256(akmp));
+ os_get_time(&now);
+ entry->expiration = now.sec;
+ if (session_timeout > 0)
+ entry->expiration += session_timeout;
+ else
+ entry->expiration += dot11RSNAConfigPMKLifetime;
+ entry->akmp = akmp;
+ 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);
+ }
+
+ pmksa_cache_link_entry(pmksa, entry);
+
+ return entry;
+}
+
+
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
+ const struct rsn_pmksa_cache_entry *old_entry,
+ const u8 *aa, const u8 *pmkid)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (entry == NULL)
+ return NULL;
+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+ os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
+ entry->pmk_len = old_entry->pmk_len;
+ entry->expiration = old_entry->expiration;
+ entry->akmp = old_entry->akmp;
+ os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
+ entry->opportunistic = 1;
+ if (old_entry->identity) {
+ entry->identity = os_malloc(old_entry->identity_len);
+ if (entry->identity) {
+ entry->identity_len = old_entry->identity_len;
+ os_memcpy(entry->identity, old_entry->identity,
+ old_entry->identity_len);
+ }
+ }
+ ieee802_1x_copy_radius_class(&entry->radius_class,
+ &old_entry->radius_class);
+ entry->eap_type_authsrv = old_entry->eap_type_authsrv;
+ entry->vlan_id = old_entry->vlan_id;
+ entry->opportunistic = 1;
+
+ pmksa_cache_link_entry(pmksa, entry);
+
+ 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_get_okc - Fetch a PMKSA cache entry using OKC
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: PMKID
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ *
+ * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
+ struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
+ const u8 *pmkid)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ u8 new_pmkid[PMKID_LEN];
+
+ entry = pmksa->pmksa;
+ while (entry) {
+ if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
+ continue;
+ rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
+ wpa_key_mgmt_sha256(entry->akmp));
+ if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ entry = 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;
+}
diff --git a/contrib/wpa/hostapd/pmksa_cache.h b/contrib/wpa/hostapd/pmksa_cache.h
new file mode 100644
index 0000000..6ba2da6
--- /dev/null
+++ b/contrib/wpa/hostapd/pmksa_cache.h
@@ -0,0 +1,62 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * 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.
+ */
+
+#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;
+ int opportunistic;
+};
+
+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_get_okc(
+ struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa,
+ 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, int akmp);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
+ const struct rsn_pmksa_cache_entry *old_entry,
+ const u8 *aa, const u8 *pmkid);
+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, int use_sha256);
+
+#endif /* PMKSA_CACHE_H */
diff --git a/contrib/wpa/hostapd/preauth.c b/contrib/wpa/hostapd/preauth.c
new file mode 100644
index 0000000..36af4e3
--- /dev/null
+++ b/contrib/wpa/hostapd/preauth.c
@@ -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 */
diff --git a/contrib/wpa/hostapd/preauth.h b/contrib/wpa/hostapd/preauth.h
new file mode 100644
index 0000000..5348bee
--- /dev/null
+++ b/contrib/wpa/hostapd/preauth.h
@@ -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 */
diff --git a/contrib/wpa/hostapd/sta_info.c b/contrib/wpa/hostapd/sta_info.c
new file mode 100644
index 0000000..a139ba9
--- /dev/null
+++ b/contrib/wpa/hostapd/sta_info.c
@@ -0,0 +1,711 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "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);
+#ifdef CONFIG_IEEE80211W
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_IEEE80211W */
+
+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++;
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (sta->no_ht_gf_set) {
+ sta->no_ht_gf_set = 0;
+ hapd->iface->num_sta_ht_no_gf--;
+ }
+
+ if (sta->no_ht_set) {
+ sta->no_ht_set = 0;
+ hapd->iface->num_sta_no_ht--;
+ }
+
+ if (sta->ht_20mhz_set) {
+ sta->ht_20mhz_set = 0;
+ hapd->iface->num_sta_ht_20mhz--;
+ }
+
+ if (hostapd_ht_operation_update(hapd->iface) > 0)
+ set_beacon++;
+#endif /* CONFIG_IEEE80211N */
+
+ 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);
+
+#ifdef CONFIG_IEEE80211W
+ os_free(sta->sa_query_trans_id);
+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+#endif /* CONFIG_IEEE80211W */
+
+ wpabuf_free(sta->wps_ie);
+
+ 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);
+ }
+}
+
+
+/**
+ * ap_handle_timer - Per STA timer handler
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: struct sta_info *
+ *
+ * This function is called to check station activity and to remove inactive
+ * stations.
+ */
+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
+ os_memset(&hdr, 0, sizeof(hdr));
+ if (hapd->driver &&
+ os_strcmp(hapd->driver->name, "hostap") == 0) {
+ /*
+ * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+ * but it is apparently not retried so TX Exc events
+ * are not received for it.
+ */
+ hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_DATA);
+ } else {
+ hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_NULLFUNC);
+ }
+
+ 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);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ u32 tu;
+ struct os_time now, passed;
+ os_get_time(&now);
+ os_time_sub(&now, &sta->sa_query_start, &passed);
+ tu = (passed.sec * 1000000 + passed.usec) / 1024;
+ if (hapd->conf->assoc_sa_query_max_timeout < tu) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "association SA Query timed out");
+ sta->sa_query_timed_out = 1;
+ os_free(sta->sa_query_trans_id);
+ sta->sa_query_trans_id = NULL;
+ sta->sa_query_count = 0;
+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+ unsigned int timeout, sec, usec;
+ u8 *trans_id, *nbuf;
+
+ if (sta->sa_query_count > 0 &&
+ ap_check_sa_query_timeout(hapd, sta))
+ return;
+
+ nbuf = os_realloc(sta->sa_query_trans_id,
+ (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
+ if (nbuf == NULL)
+ return;
+ if (sta->sa_query_count == 0) {
+ /* Starting a new SA Query procedure */
+ os_get_time(&sta->sa_query_start);
+ }
+ trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
+ sta->sa_query_trans_id = nbuf;
+ sta->sa_query_count++;
+
+ os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+ timeout = hapd->conf->assoc_sa_query_retry_timeout;
+ sec = ((timeout / 1000) * 1024) / 1000;
+ usec = (timeout % 1000) * 1024;
+ eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "association SA Query attempt %d", sta->sa_query_count);
+
+ ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
+}
+
+
+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ ap_sa_query_timer(hapd, sta);
+}
+
+
+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+ os_free(sta->sa_query_trans_id);
+ sta->sa_query_trans_id = NULL;
+ sta->sa_query_count = 0;
+}
+
+#endif /* CONFIG_IEEE80211W */
diff --git a/contrib/wpa/hostapd/sta_info.h b/contrib/wpa/hostapd/sta_info.h
new file mode 100644
index 0000000..e835970
--- /dev/null
+++ b/contrib/wpa/hostapd/sta_info.h
@@ -0,0 +1,43 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-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.
+ */
+
+#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);
+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+
+#endif /* STA_INFO_H */
diff --git a/contrib/wpa/hostapd/vlan_init.c b/contrib/wpa/hostapd/vlan_init.c
new file mode 100644
index 0000000..87c61e2
--- /dev/null
+++ b/contrib/wpa/hostapd/vlan_init.c
@@ -0,0 +1,826 @@
+/*
+ * 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>
+#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;
+}
diff --git a/contrib/wpa/hostapd/vlan_init.h b/contrib/wpa/hostapd/vlan_init.h
new file mode 100644
index 0000000..cf55ac2
--- /dev/null
+++ b/contrib/wpa/hostapd/vlan_init.h
@@ -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 */
diff --git a/contrib/wpa/hostapd/wired.conf b/contrib/wpa/hostapd/wired.conf
new file mode 100644
index 0000000..956f8c5
--- /dev/null
+++ b/contrib/wpa/hostapd/wired.conf
@@ -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
diff --git a/contrib/wpa/hostapd/wme.c b/contrib/wpa/hostapd/wme.c
new file mode 100644
index 0000000..727ee7e
--- /dev/null
+++ b/contrib/wpa/hostapd/wme.c
@@ -0,0 +1,262 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * 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 "ieee802_11.h"
+#include "wme.h"
+#include "sta_info.h"
+#include "driver.h"
+
+
+/* TODO: maintain separate sequence and fragment numbers for each AC
+ * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
+ * if only WME stations are receiving a certain group */
+
+
+static u8 wme_oui[3] = { 0x00, 0x50, 0xf2 };
+
+
+/* Add WME Parameter Element to Beacon and Probe Response frames. */
+u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ struct wme_parameter_element *wme =
+ (struct wme_parameter_element *) (pos + 2);
+ int e;
+
+ if (!hapd->conf->wme_enabled)
+ return eid;
+ eid[0] = WLAN_EID_VENDOR_SPECIFIC;
+ wme->oui[0] = 0x00;
+ wme->oui[1] = 0x50;
+ wme->oui[2] = 0xf2;
+ wme->oui_type = WME_OUI_TYPE;
+ wme->oui_subtype = WME_OUI_SUBTYPE_PARAMETER_ELEMENT;
+ wme->version = WME_VERSION;
+ wme->acInfo = hapd->parameter_set_count & 0xf;
+
+ /* fill in a parameter set record for each AC */
+ for (e = 0; e < 4; e++) {
+ struct wme_ac_parameter *ac = &wme->ac[e];
+ struct hostapd_wme_ac_params *acp =
+ &hapd->iconf->wme_ac_params[e];
+
+ ac->aifsn = acp->aifs;
+ ac->acm = acp->admission_control_mandatory;
+ ac->aci = e;
+ ac->reserved = 0;
+ ac->eCWmin = acp->cwmin;
+ ac->eCWmax = acp->cwmax;
+ ac->txopLimit = host_to_le16(acp->txopLimit);
+ }
+
+ pos = (u8 *) (wme + 1);
+ eid[1] = pos - eid - 2; /* element length */
+
+ return pos;
+}
+
+
+/* This function is called when a station sends an association request with
+ * WME info element. The function returns zero on success or non-zero on any
+ * error in WME element. eid does not include Element ID and Length octets. */
+int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ struct wme_information_element *wme;
+
+ wpa_hexdump(MSG_MSGDUMP, "WME IE", eid, len);
+
+ if (len < sizeof(struct wme_information_element)) {
+ wpa_printf(MSG_DEBUG, "Too short WME IE (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+
+ wme = (struct wme_information_element *) eid;
+ wpa_printf(MSG_DEBUG, "Validating WME IE: OUI %02x:%02x:%02x "
+ "OUI type %d OUI sub-type %d version %d",
+ wme->oui[0], wme->oui[1], wme->oui[2], wme->oui_type,
+ wme->oui_subtype, wme->version);
+ if (os_memcmp(wme->oui, wme_oui, sizeof(wme_oui)) != 0 ||
+ wme->oui_type != WME_OUI_TYPE ||
+ wme->oui_subtype != WME_OUI_SUBTYPE_INFORMATION_ELEMENT ||
+ wme->version != WME_VERSION) {
+ wpa_printf(MSG_DEBUG, "Unsupported WME IE OUI/Type/Subtype/"
+ "Version");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* This function is called when a station sends an ACK frame for an AssocResp
+ * frame (status=success) and the matching AssocReq contained a WME element.
+ */
+int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ /* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
+ if (sta->flags & WLAN_STA_WME)
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ WLAN_STA_WME, ~0);
+ else
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ 0, ~WLAN_STA_WME);
+
+ return 0;
+}
+
+
+static void wme_send_action(struct hostapd_data *hapd, const u8 *addr,
+ const struct wme_tspec_info_element *tspec,
+ u8 action_code, u8 dialogue_token, u8 status_code)
+{
+ u8 buf[256];
+ struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
+ struct wme_tspec_info_element *t =
+ (struct wme_tspec_info_element *)
+ m->u.action.u.wme_action.variable;
+ int len;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "action response - reason %d", status_code);
+ os_memset(buf, 0, sizeof(buf));
+ m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(m->da, addr, ETH_ALEN);
+ os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+ m->u.action.category = WLAN_ACTION_WMM;
+ m->u.action.u.wme_action.action_code = action_code;
+ m->u.action.u.wme_action.dialog_token = dialogue_token;
+ m->u.action.u.wme_action.status_code = status_code;
+ os_memcpy(t, tspec, sizeof(struct wme_tspec_info_element));
+ len = ((u8 *) (t + 1)) - buf;
+
+ if (hostapd_send_mgmt_frame(hapd, m, len, 0) < 0)
+ perror("wme_send_action: send");
+}
+
+
+/* given frame data payload size in bytes, and data_rate in bits per second
+ * returns time to complete frame exchange */
+/* FIX: should not use floating point types */
+static double wme_frame_exchange_time(int bytes, int data_rate, int encryption,
+ int cts_protection)
+{
+ /* TODO: account for MAC/PHY headers correctly */
+ /* TODO: account for encryption headers */
+ /* TODO: account for WDS headers */
+ /* TODO: account for CTS protection */
+ /* TODO: account for SIFS + ACK at minimum PHY rate */
+ return (bytes + 400) * 8.0 / data_rate;
+}
+
+
+static void wme_setup_request(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt,
+ struct wme_tspec_info_element *tspec, size_t len)
+{
+ /* FIX: should not use floating point types */
+ double medium_time, pps;
+
+ /* TODO: account for airtime and answer no to tspec setup requests
+ * when none left!! */
+
+ pps = (tspec->mean_data_rate / 8.0) / tspec->nominal_msdu_size;
+ medium_time = (tspec->surplus_bandwidth_allowance / 8) * pps *
+ wme_frame_exchange_time(tspec->nominal_msdu_size,
+ tspec->minimum_phy_rate, 0, 0);
+ tspec->medium_time = medium_time * 1000000.0 / 32.0;
+
+ wme_send_action(hapd, mgmt->sa, tspec, WME_ACTION_CODE_SETUP_RESPONSE,
+ mgmt->u.action.u.wme_action.dialog_token,
+ WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED);
+}
+
+
+void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ int action_code;
+ int left = len - IEEE80211_HDRLEN - 4;
+ u8 *pos = ((u8 *) mgmt) + IEEE80211_HDRLEN + 4;
+ struct ieee802_11_elems elems;
+ struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
+
+ /* check that the request comes from a valid station */
+ if (!sta ||
+ (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WME)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_WME)) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "wme action received is not from associated wme"
+ " station");
+ /* TODO: respond with action frame refused status code */
+ return;
+ }
+
+ /* extract the tspec info element */
+ if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "hostapd_wme_action - could not parse wme "
+ "action");
+ /* TODO: respond with action frame invalid parameters status
+ * code */
+ return;
+ }
+
+ if (!elems.wme_tspec ||
+ elems.wme_tspec_len != (sizeof(struct wme_tspec_info_element) - 2))
+ {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "hostapd_wme_action - missing or wrong length "
+ "tspec");
+ /* TODO: respond with action frame invalid parameters status
+ * code */
+ return;
+ }
+
+ /* TODO: check the request is for an AC with ACM set, if not, refuse
+ * request */
+
+ action_code = mgmt->u.action.u.wme_action.action_code;
+ switch (action_code) {
+ case WME_ACTION_CODE_SETUP_REQUEST:
+ wme_setup_request(hapd, mgmt, (struct wme_tspec_info_element *)
+ elems.wme_tspec, len);
+ return;
+#if 0
+ /* TODO: needed for client implementation */
+ case WME_ACTION_CODE_SETUP_RESPONSE:
+ wme_setup_request(hapd, mgmt, len);
+ return;
+ /* TODO: handle station teardown requests */
+ case WME_ACTION_CODE_TEARDOWN:
+ wme_teardown(hapd, mgmt, len);
+ return;
+#endif
+ }
+
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "hostapd_wme_action - unknown action code %d",
+ action_code);
+}
diff --git a/contrib/wpa/hostapd/wme.h b/contrib/wpa/hostapd/wme.h
new file mode 100644
index 0000000..4ee281a
--- /dev/null
+++ b/contrib/wpa/hostapd/wme.h
@@ -0,0 +1,129 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * 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 WME_H
+#define WME_H
+
+#ifdef __linux__
+#include <endian.h>
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#include <sys/types.h>
+#include <sys/endian.h>
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+ * defined(__DragonFly__) */
+
+
+extern inline u16 tsinfo(int tag1d, int contention_based, int direction)
+{
+ return (tag1d << 11) | (contention_based << 7) | (direction << 5) |
+ (tag1d << 1);
+}
+
+
+struct wme_information_element {
+ /* required fields for WME version 1 */
+ u8 oui[3];
+ u8 oui_type;
+ u8 oui_subtype;
+ u8 version;
+ u8 acInfo;
+
+} __attribute__ ((packed));
+
+struct wme_ac_parameter {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* byte 1 */
+ u8 aifsn:4,
+ acm:1,
+ aci:2,
+ reserved:1;
+
+ /* byte 2 */
+ u8 eCWmin:4,
+ eCWmax:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ /* byte 1 */
+ u8 reserved:1,
+ aci:2,
+ acm:1,
+ aifsn:4;
+
+ /* byte 2 */
+ u8 eCWmax:4,
+ eCWmin:4;
+#else
+#error "Please fix <endian.h>"
+#endif
+
+ /* bytes 3 & 4 */
+ le16 txopLimit;
+} __attribute__ ((packed));
+
+struct wme_parameter_element {
+ /* required fields for WME version 1 */
+ u8 oui[3];
+ u8 oui_type;
+ u8 oui_subtype;
+ u8 version;
+ u8 acInfo;
+ u8 reserved;
+ struct wme_ac_parameter ac[4];
+
+} __attribute__ ((packed));
+
+struct wme_tspec_info_element {
+ u8 eid;
+ u8 length;
+ u8 oui[3];
+ u8 oui_type;
+ u8 oui_subtype;
+ u8 version;
+ u16 ts_info;
+ u16 nominal_msdu_size;
+ u16 maximum_msdu_size;
+ u32 minimum_service_interval;
+ u32 maximum_service_interval;
+ u32 inactivity_interval;
+ u32 start_time;
+ u32 minimum_data_rate;
+ u32 mean_data_rate;
+ u32 maximum_burst_size;
+ u32 minimum_phy_rate;
+ u32 peak_data_rate;
+ u32 delay_bound;
+ u16 surplus_bandwidth_allowance;
+ u16 medium_time;
+} __attribute__ ((packed));
+
+
+/* Access Categories */
+enum {
+ WME_AC_BK = 1,
+ WME_AC_BE = 0,
+ WME_AC_VI = 2,
+ WME_AC_VO = 3
+};
+
+struct ieee80211_mgmt;
+
+u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid);
+int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len);
+int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta);
+void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len);
+
+#endif /* WME_H */
diff --git a/contrib/wpa/hostapd/wpa.c b/contrib/wpa/hostapd/wpa.c
new file mode 100644
index 0000000..cf285b6
--- /dev/null
+++ b/contrib/wpa/hostapd/wpa.c
@@ -0,0 +1,2447 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator
+ * 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 "common.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "wpa.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "rc4.h"
+#include "aes_wrap.h"
+#include "crypto.h"
+#include "eloop.h"
+#include "ieee802_11.h"
+#include "pmksa_cache.h"
+#include "state_machine.h"
+#include "wpa_auth_i.h"
+#include "wpa_auth_ie.h"
+
+#define STATE_MACHINE_DATA struct wpa_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "WPA"
+#define STATE_MACHINE_ADDR sm->addr
+
+
+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpa_sm_step(struct wpa_state_machine *sm);
+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
+static void wpa_request_new_ptk(struct wpa_state_machine *sm);
+
+static const u32 dot11RSNAConfigGroupUpdateCount = 4;
+static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
+static const u32 eapol_key_timeout_first = 100; /* ms */
+static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+
+/* TODO: make these configurable */
+static const int dot11RSNAConfigPMKLifetime = 43200;
+static const int dot11RSNAConfigPMKReauthThreshold = 70;
+static const int dot11RSNAConfigSATimeout = 60;
+
+
+static inline void wpa_auth_mic_failure_report(
+ struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+ if (wpa_auth->cb.mic_failure_report)
+ wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+}
+
+
+static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, wpa_eapol_variable var,
+ int value)
+{
+ if (wpa_auth->cb.set_eapol)
+ wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
+}
+
+
+static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, wpa_eapol_variable var)
+{
+ if (wpa_auth->cb.get_eapol == NULL)
+ return -1;
+ return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
+}
+
+
+static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, const u8 *prev_psk)
+{
+ if (wpa_auth->cb.get_psk == NULL)
+ return NULL;
+ return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);
+}
+
+
+static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, u8 *msk, size_t *len)
+{
+ if (wpa_auth->cb.get_msk == NULL)
+ return -1;
+ return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+ int vlan_id,
+ const char *alg, const u8 *addr, int idx,
+ u8 *key, size_t key_len)
+{
+ if (wpa_auth->cb.set_key == NULL)
+ return -1;
+ return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+ key, key_len);
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_auth->cb.get_seqnum == NULL)
+ return -1;
+ return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_auth->cb.get_seqnum_igtk == NULL)
+ return -1;
+ return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static inline int
+wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ const u8 *data, size_t data_len, int encrypt)
+{
+ if (wpa_auth->cb.send_eapol == NULL)
+ return -1;
+ return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
+ encrypt);
+}
+
+
+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+ int (*cb)(struct wpa_state_machine *sm, void *ctx),
+ void *cb_ctx)
+{
+ if (wpa_auth->cb.for_each_sta == NULL)
+ return 0;
+ return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
+ int (*cb)(struct wpa_authenticator *a, void *ctx),
+ void *cb_ctx)
+{
+ if (wpa_auth->cb.for_each_auth == NULL)
+ return 0;
+ return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ logger_level level, const char *txt)
+{
+ if (wpa_auth->cb.logger == NULL)
+ return;
+ wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
+}
+
+
+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ logger_level level, const char *fmt, ...)
+{
+ char *format;
+ int maxlen;
+ va_list ap;
+
+ if (wpa_auth->cb.logger == NULL)
+ return;
+
+ maxlen = os_strlen(fmt) + 100;
+ format = os_malloc(maxlen);
+ if (!format)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(format, maxlen, fmt, ap);
+ va_end(ap);
+
+ wpa_auth_logger(wpa_auth, addr, level, format);
+
+ os_free(format);
+}
+
+
+static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (wpa_auth->cb.disconnect == NULL)
+ return;
+ wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
+static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
+{
+ int ret = 0;
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+ ret = 1;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
+ ret = 1;
+#endif /* CONFIG_IEEE80211W */
+ return ret;
+}
+
+
+static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+
+ if (os_get_random(wpa_auth->group->GMK, WPA_GMK_LEN)) {
+ wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+ "initialization.");
+ } else {
+ wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
+ }
+
+ if (wpa_auth->conf.wpa_gmk_rekey) {
+ eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+ wpa_rekey_gmk, wpa_auth, NULL);
+ }
+}
+
+
+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+ struct wpa_group *group;
+
+ wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
+ for (group = wpa_auth->group; group; group = group->next) {
+ group->GTKReKey = TRUE;
+ do {
+ group->changed = FALSE;
+ wpa_group_sm_step(wpa_auth, group);
+ } while (group->changed);
+ }
+
+ if (wpa_auth->conf.wpa_group_rekey) {
+ eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
+ 0, wpa_rekey_gtk, wpa_auth, NULL);
+ }
+}
+
+
+static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+ struct wpa_state_machine *sm = timeout_ctx;
+
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
+ wpa_request_new_ptk(sm);
+ wpa_sm_step(sm);
+}
+
+
+static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
+{
+ if (sm->pmksa == ctx)
+ sm->pmksa = NULL;
+ return 0;
+}
+
+
+static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+ void *ctx)
+{
+ struct wpa_authenticator *wpa_auth = ctx;
+ wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+ int vlan_id)
+{
+ struct wpa_group *group;
+ u8 buf[ETH_ALEN + 8 + sizeof(group)];
+ u8 rkey[32];
+
+ group = os_zalloc(sizeof(struct wpa_group));
+ if (group == NULL)
+ return NULL;
+
+ group->GTKAuthenticator = TRUE;
+ group->vlan_id = vlan_id;
+
+ switch (wpa_auth->conf.wpa_group) {
+ case WPA_CIPHER_CCMP:
+ group->GTK_len = 16;
+ break;
+ case WPA_CIPHER_TKIP:
+ group->GTK_len = 32;
+ break;
+ case WPA_CIPHER_WEP104:
+ group->GTK_len = 13;
+ break;
+ case WPA_CIPHER_WEP40:
+ group->GTK_len = 5;
+ break;
+ }
+
+ /* Counter = PRF-256(Random number, "Init Counter",
+ * Local MAC Address || Time)
+ */
+ os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
+ wpa_get_ntp_timestamp(buf + ETH_ALEN);
+ os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+ if (os_get_random(rkey, sizeof(rkey)) ||
+ os_get_random(group->GMK, WPA_GMK_LEN)) {
+ wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+ "initialization.");
+ os_free(group);
+ return NULL;
+ }
+
+ sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
+ group->Counter, WPA_NONCE_LEN);
+
+ group->GInit = TRUE;
+ wpa_group_sm_step(wpa_auth, group);
+ group->GInit = FALSE;
+ wpa_group_sm_step(wpa_auth, group);
+
+ return group;
+}
+
+
+/**
+ * wpa_init - Initialize WPA authenticator
+ * @addr: Authenticator address
+ * @conf: Configuration for WPA authenticator
+ * @cb: Callback functions for WPA authenticator
+ * Returns: Pointer to WPA authenticator data or %NULL on failure
+ */
+struct wpa_authenticator * wpa_init(const u8 *addr,
+ struct wpa_auth_config *conf,
+ struct wpa_auth_callbacks *cb)
+{
+ struct wpa_authenticator *wpa_auth;
+
+ wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
+ if (wpa_auth == NULL)
+ return NULL;
+ os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
+ os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+ os_memcpy(&wpa_auth->cb, cb, sizeof(*cb));
+
+ if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+ wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+ os_free(wpa_auth);
+ return NULL;
+ }
+
+ wpa_auth->group = wpa_group_init(wpa_auth, 0);
+ if (wpa_auth->group == NULL) {
+ os_free(wpa_auth->wpa_ie);
+ os_free(wpa_auth);
+ return NULL;
+ }
+
+ wpa_auth->pmksa = pmksa_cache_init(wpa_auth_pmksa_free_cb, wpa_auth);
+ if (wpa_auth->pmksa == NULL) {
+ wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+ os_free(wpa_auth->wpa_ie);
+ os_free(wpa_auth);
+ return NULL;
+ }
+
+#ifdef CONFIG_IEEE80211R
+ wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
+ if (wpa_auth->ft_pmk_cache == NULL) {
+ wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+ os_free(wpa_auth->wpa_ie);
+ pmksa_cache_deinit(wpa_auth->pmksa);
+ os_free(wpa_auth);
+ return NULL;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (wpa_auth->conf.wpa_gmk_rekey) {
+ eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+ wpa_rekey_gmk, wpa_auth, NULL);
+ }
+
+ if (wpa_auth->conf.wpa_group_rekey) {
+ eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
+ wpa_rekey_gtk, wpa_auth, NULL);
+ }
+
+ return wpa_auth;
+}
+
+
+/**
+ * wpa_deinit - Deinitialize WPA authenticator
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ */
+void wpa_deinit(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group, *prev;
+
+ eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+
+#ifdef CONFIG_PEERKEY
+ while (wpa_auth->stsl_negotiations)
+ wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
+#endif /* CONFIG_PEERKEY */
+
+ pmksa_cache_deinit(wpa_auth->pmksa);
+
+#ifdef CONFIG_IEEE80211R
+ wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
+ wpa_auth->ft_pmk_cache = NULL;
+#endif /* CONFIG_IEEE80211R */
+
+ os_free(wpa_auth->wpa_ie);
+
+ group = wpa_auth->group;
+ while (group) {
+ prev = group;
+ group = group->next;
+ os_free(prev);
+ }
+
+ os_free(wpa_auth);
+}
+
+
+/**
+ * wpa_reconfig - Update WPA authenticator configuration
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ * @conf: Configuration for WPA authenticator
+ */
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+ struct wpa_auth_config *conf)
+{
+ if (wpa_auth == NULL)
+ return 0;
+
+ os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+ if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+ wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+ struct wpa_state_machine *sm;
+
+ sm = os_zalloc(sizeof(struct wpa_state_machine));
+ if (sm == NULL)
+ return NULL;
+ os_memcpy(sm->addr, addr, ETH_ALEN);
+
+ sm->wpa_auth = wpa_auth;
+ sm->group = wpa_auth->group;
+
+ return sm;
+}
+
+
+void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm)
+{
+ if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ return;
+
+#ifdef CONFIG_IEEE80211R
+ if (sm->ft_completed) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "FT authentication already completed - do not "
+ "start 4-way handshake");
+ return;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (sm->started) {
+ os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
+ sm->ReAuthenticationRequest = TRUE;
+ wpa_sm_step(sm);
+ return;
+ }
+
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "start authentication");
+ sm->started = 1;
+
+ sm->Init = TRUE;
+ wpa_sm_step(sm);
+ sm->Init = FALSE;
+ sm->AuthenticationRequest = TRUE;
+ wpa_sm_step(sm);
+}
+
+
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
+{
+ /* WPA/RSN was not used - clear WPA state. This is needed if the STA
+ * reassociates back to the same AP while the previous entry for the
+ * STA has not yet been removed. */
+ if (sm == NULL)
+ return;
+
+ sm->wpa_key_mgmt = 0;
+}
+
+
+static void wpa_free_sta_sm(struct wpa_state_machine *sm)
+{
+ os_free(sm->last_rx_eapol_key);
+ os_free(sm->wpa_ie);
+ os_free(sm);
+}
+
+
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return;
+
+ if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "strict rekeying - force GTK rekey since STA "
+ "is leaving");
+ eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
+ NULL);
+ }
+
+ eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ if (sm->in_step_loop) {
+ /* Must not free state machine while wpa_sm_step() is running.
+ * Freeing will be completed in the end of wpa_sm_step(). */
+ wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
+ "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ sm->pending_deinit = 1;
+ } else
+ wpa_free_sta_sm(sm);
+}
+
+
+static void wpa_request_new_ptk(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return;
+
+ sm->PTKRequest = TRUE;
+ sm->PTK_valid = 0;
+}
+
+
+static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
+ const u8 *replay_counter)
+{
+ int i;
+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+ if (!sm->key_replay[i].valid)
+ break;
+ if (os_memcmp(replay_counter, sm->key_replay[i].counter,
+ WPA_REPLAY_COUNTER_LEN) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ u8 *data, size_t data_len)
+{
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ u16 key_info, key_data_length;
+ enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
+ SMK_M1, SMK_M3, SMK_ERROR } msg;
+ char *msgtxt;
+ struct wpa_eapol_ie_parse kde;
+
+ if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ return;
+
+ if (data_len < sizeof(*hdr) + sizeof(*key))
+ return;
+
+ hdr = (struct ieee802_1x_hdr *) data;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ key_info = WPA_GET_BE16(key->key_info);
+ key_data_length = WPA_GET_BE16(key->key_data_length);
+ if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+ wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
+ "key_data overflow (%d > %lu)",
+ key_data_length,
+ (unsigned long) (data_len - sizeof(*hdr) -
+ sizeof(*key)));
+ return;
+ }
+
+ /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
+ * are set */
+
+ if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
+ (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
+ if (key_info & WPA_KEY_INFO_ERROR) {
+ msg = SMK_ERROR;
+ msgtxt = "SMK Error";
+ } else {
+ msg = SMK_M1;
+ msgtxt = "SMK M1";
+ }
+ } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+ msg = SMK_M3;
+ msgtxt = "SMK M3";
+ } else if (key_info & WPA_KEY_INFO_REQUEST) {
+ msg = REQUEST;
+ msgtxt = "Request";
+ } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
+ msg = GROUP_2;
+ msgtxt = "2/2 Group";
+ } else if (key_data_length == 0) {
+ msg = PAIRWISE_4;
+ msgtxt = "4/4 Pairwise";
+ } else {
+ msg = PAIRWISE_2;
+ msgtxt = "2/4 Pairwise";
+ }
+
+ /* TODO: key_info type validation for PeerKey */
+ if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
+ msg == GROUP_2) {
+ u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+ if (sm->pairwise == WPA_CIPHER_CCMP) {
+ if (wpa_use_aes_cmac(sm) &&
+ ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ wpa_auth_logger(wpa_auth, sm->addr,
+ LOGGER_WARNING,
+ "advertised support for "
+ "AES-128-CMAC, but did not "
+ "use it");
+ return;
+ }
+
+ if (!wpa_use_aes_cmac(sm) &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ wpa_auth_logger(wpa_auth, sm->addr,
+ LOGGER_WARNING,
+ "did not use HMAC-SHA1-AES "
+ "with CCMP");
+ return;
+ }
+ }
+ }
+
+ if (key_info & WPA_KEY_INFO_REQUEST) {
+ if (sm->req_replay_counter_used &&
+ os_memcmp(key->replay_counter, sm->req_replay_counter,
+ WPA_REPLAY_COUNTER_LEN) <= 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+ "received EAPOL-Key request with "
+ "replayed counter");
+ return;
+ }
+ }
+
+ if (!(key_info & WPA_KEY_INFO_REQUEST) &&
+ !wpa_replay_counter_valid(sm, key->replay_counter)) {
+ int i;
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key %s with unexpected "
+ "replay counter", msgtxt);
+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+ if (!sm->key_replay[i].valid)
+ break;
+ wpa_hexdump(MSG_DEBUG, "pending replay counter",
+ sm->key_replay[i].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ }
+ wpa_hexdump(MSG_DEBUG, "received replay counter",
+ key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+ return;
+ }
+
+ switch (msg) {
+ case PAIRWISE_2:
+ if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
+ sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key msg 2/4 in "
+ "invalid state (%d) - dropped",
+ sm->wpa_ptk_state);
+ return;
+ }
+ if (sm->wpa_ie == NULL ||
+ sm->wpa_ie_len != key_data_length ||
+ os_memcmp(sm->wpa_ie, key + 1, key_data_length) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "WPA IE from (Re)AssocReq did not "
+ "match with msg 2/4");
+ if (sm->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
+ sm->wpa_ie, sm->wpa_ie_len);
+ }
+ wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
+ (u8 *) (key + 1), key_data_length);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr);
+ return;
+ }
+ break;
+ case PAIRWISE_4:
+ if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
+ !sm->PTK_valid) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key msg 4/4 in "
+ "invalid state (%d) - dropped",
+ sm->wpa_ptk_state);
+ return;
+ }
+ break;
+ case GROUP_2:
+ if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
+ || !sm->PTK_valid) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key msg 2/2 in "
+ "invalid state (%d) - dropped",
+ sm->wpa_ptk_group_state);
+ return;
+ }
+ break;
+#ifdef CONFIG_PEERKEY
+ case SMK_M1:
+ case SMK_M3:
+ case SMK_ERROR:
+ if (!wpa_auth->conf.peerkey) {
+ wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
+ "PeerKey use disabled - ignoring message");
+ return;
+ }
+ if (!sm->PTK_valid) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key msg SMK in "
+ "invalid state - dropped");
+ return;
+ }
+ break;
+#else /* CONFIG_PEERKEY */
+ case SMK_M1:
+ case SMK_M3:
+ case SMK_ERROR:
+ return; /* STSL disabled - ignore SMK messages */
+#endif /* CONFIG_PEERKEY */
+ case REQUEST:
+ break;
+ }
+
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "received EAPOL-Key frame (%s)", msgtxt);
+
+ if (key_info & WPA_KEY_INFO_ACK) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received invalid EAPOL-Key: Key Ack set");
+ return;
+ }
+
+ if (!(key_info & WPA_KEY_INFO_MIC)) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received invalid EAPOL-Key: Key MIC not set");
+ return;
+ }
+
+ sm->MICVerified = FALSE;
+ if (sm->PTK_valid) {
+ if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key with invalid MIC");
+ return;
+ }
+ sm->MICVerified = TRUE;
+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+ }
+
+ if (key_info & WPA_KEY_INFO_REQUEST) {
+ if (sm->MICVerified) {
+ sm->req_replay_counter_used = 1;
+ os_memcpy(sm->req_replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ } else {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key request with "
+ "invalid MIC");
+ return;
+ }
+
+ /*
+ * TODO: should decrypt key data field if encryption was used;
+ * even though MAC address KDE is not normally encrypted,
+ * supplicant is allowed to encrypt it.
+ */
+ if (msg == SMK_ERROR) {
+#ifdef CONFIG_PEERKEY
+ wpa_smk_error(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+ return;
+ } else if (key_info & WPA_KEY_INFO_ERROR) {
+ /* Supplicant reported a Michael MIC error */
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key Error Request "
+ "(STA detected Michael MIC failure)");
+ wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+ sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+ wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+ /* Error report is not a request for a new key
+ * handshake, but since Authenticator may do it, let's
+ * change the keys now anyway. */
+ wpa_request_new_ptk(sm);
+ } else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key Request for new "
+ "4-Way Handshake");
+ wpa_request_new_ptk(sm);
+#ifdef CONFIG_PEERKEY
+ } else if (msg == SMK_M1) {
+ wpa_smk_m1(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+ } else if (key_data_length > 0 &&
+ wpa_parse_kde_ies((const u8 *) (key + 1),
+ key_data_length, &kde) == 0 &&
+ kde.mac_addr) {
+ } else {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key Request for GTK "
+ "rekeying");
+ /* FIX: why was this triggering PTK rekeying for the
+ * STA that requested Group Key rekeying?? */
+ /* wpa_request_new_ptk(sta->wpa_sm); */
+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+ wpa_rekey_gtk(wpa_auth, NULL);
+ }
+ } else {
+ /* Do not allow the same key replay counter to be reused. This
+ * does also invalidate all other pending replay counters if
+ * retransmissions were used, i.e., we will only process one of
+ * the pending replies and ignore rest if more than one is
+ * received. */
+ sm->key_replay[0].valid = FALSE;
+ }
+
+#ifdef CONFIG_PEERKEY
+ if (msg == SMK_M3) {
+ wpa_smk_m3(wpa_auth, sm, key);
+ return;
+ }
+#endif /* CONFIG_PEERKEY */
+
+ os_free(sm->last_rx_eapol_key);
+ sm->last_rx_eapol_key = os_malloc(data_len);
+ if (sm->last_rx_eapol_key == NULL)
+ return;
+ os_memcpy(sm->last_rx_eapol_key, data, data_len);
+ sm->last_rx_eapol_key_len = data_len;
+
+ sm->EAPOLKeyReceived = TRUE;
+ sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
+ sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
+ os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
+ wpa_sm_step(sm);
+}
+
+
+static void wpa_gmk_to_gtk(const u8 *gmk, const u8 *addr, const u8 *gnonce,
+ u8 *gtk, size_t gtk_len)
+{
+ u8 data[ETH_ALEN + WPA_NONCE_LEN];
+
+ /* GTK = PRF-X(GMK, "Group key expansion", AA || GNonce) */
+ os_memcpy(data, addr, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
+
+#ifdef CONFIG_IEEE80211W
+ sha256_prf(gmk, WPA_GMK_LEN, "Group key expansion",
+ data, sizeof(data), gtk, gtk_len);
+#else /* CONFIG_IEEE80211W */
+ sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion",
+ data, sizeof(data), gtk, gtk_len);
+#endif /* CONFIG_IEEE80211W */
+
+ wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
+}
+
+
+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+ struct wpa_state_machine *sm = timeout_ctx;
+
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
+ sm->TimeoutEvt = TRUE;
+ wpa_sm_step(sm);
+}
+
+
+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int key_info,
+ const u8 *key_rsc, const u8 *nonce,
+ const u8 *kde, size_t kde_len,
+ int keyidx, int encr, int force_version)
+{
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ size_t len;
+ int alg;
+ int key_data_len, pad_len = 0;
+ u8 *buf, *pos;
+ int version, pairwise;
+ int i;
+
+ len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+
+ if (force_version)
+ version = force_version;
+ else if (wpa_use_aes_cmac(sm))
+ version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
+ else if (sm->pairwise == WPA_CIPHER_CCMP)
+ version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+ else
+ version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+ pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+
+ wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
+ "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
+ "encr=%d)",
+ version,
+ (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
+ (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
+ (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
+ (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
+ pairwise, (unsigned long) kde_len, keyidx, encr);
+
+ key_data_len = kde_len;
+
+ if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+ version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
+ pad_len = key_data_len % 8;
+ if (pad_len)
+ pad_len = 8 - pad_len;
+ key_data_len += pad_len + 8;
+ }
+
+ len += key_data_len;
+
+ hdr = os_zalloc(len);
+ if (hdr == NULL)
+ return;
+ hdr->version = wpa_auth->conf.eapol_version;
+ hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+ hdr->length = host_to_be16(len - sizeof(*hdr));
+ key = (struct wpa_eapol_key *) (hdr + 1);
+
+ key->type = sm->wpa == WPA_VERSION_WPA2 ?
+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+ key_info |= version;
+ if (encr && sm->wpa == WPA_VERSION_WPA2)
+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+ if (sm->wpa != WPA_VERSION_WPA2)
+ key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
+ WPA_PUT_BE16(key->key_info, key_info);
+
+ alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+ switch (alg) {
+ case WPA_CIPHER_CCMP:
+ WPA_PUT_BE16(key->key_length, 16);
+ break;
+ case WPA_CIPHER_TKIP:
+ WPA_PUT_BE16(key->key_length, 32);
+ break;
+ case WPA_CIPHER_WEP40:
+ WPA_PUT_BE16(key->key_length, 5);
+ break;
+ case WPA_CIPHER_WEP104:
+ WPA_PUT_BE16(key->key_length, 13);
+ break;
+ }
+ if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+ WPA_PUT_BE16(key->key_length, 0);
+
+ /* FIX: STSL: what to use as key_replay_counter? */
+ for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
+ sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
+ os_memcpy(sm->key_replay[i].counter,
+ sm->key_replay[i - 1].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ }
+ inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(key->replay_counter, sm->key_replay[0].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->key_replay[0].valid = TRUE;
+
+ if (nonce)
+ os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
+
+ if (key_rsc)
+ os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
+
+ if (kde && !encr) {
+ os_memcpy(key + 1, kde, kde_len);
+ WPA_PUT_BE16(key->key_data_length, kde_len);
+ } else if (encr && kde) {
+ buf = os_zalloc(key_data_len);
+ if (buf == NULL) {
+ os_free(hdr);
+ return;
+ }
+ pos = buf;
+ os_memcpy(pos, kde, kde_len);
+ pos += kde_len;
+
+ if (pad_len)
+ *pos++ = 0xdd;
+
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
+ buf, key_data_len);
+ if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+ version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
+ (u8 *) (key + 1))) {
+ os_free(hdr);
+ os_free(buf);
+ return;
+ }
+ WPA_PUT_BE16(key->key_data_length, key_data_len);
+ } else {
+ u8 ek[32];
+ os_memcpy(key->key_iv,
+ sm->group->Counter + WPA_NONCE_LEN - 16, 16);
+ inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
+ os_memcpy(ek, key->key_iv, 16);
+ os_memcpy(ek + 16, sm->PTK.kek, 16);
+ os_memcpy(key + 1, buf, key_data_len);
+ rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
+ WPA_PUT_BE16(key->key_data_length, key_data_len);
+ }
+ os_free(buf);
+ }
+
+ if (key_info & WPA_KEY_INFO_MIC) {
+ if (!sm->PTK_valid) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTK not valid when sending EAPOL-Key "
+ "frame");
+ os_free(hdr);
+ return;
+ }
+ wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
+ key->key_mic);
+ }
+
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
+ 1);
+ wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
+ sm->pairwise_set);
+ os_free(hdr);
+}
+
+
+static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int key_info,
+ const u8 *key_rsc, const u8 *nonce,
+ const u8 *kde, size_t kde_len,
+ int keyidx, int encr)
+{
+ int timeout_ms;
+ int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+ int ctr;
+
+ if (sm == NULL)
+ return;
+
+ __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
+ keyidx, encr, 0);
+
+ ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
+ if (ctr == 1)
+ timeout_ms = eapol_key_timeout_first;
+ else
+ timeout_ms = eapol_key_timeout_subseq;
+ eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
+ wpa_send_eapol_timeout, wpa_auth, sm);
+}
+
+
+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+{
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ u16 key_info;
+ int ret = 0;
+ u8 mic[16];
+
+ if (data_len < sizeof(*hdr) + sizeof(*key))
+ return -1;
+
+ hdr = (struct ieee802_1x_hdr *) data;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ key_info = WPA_GET_BE16(key->key_info);
+ os_memcpy(mic, key->key_mic, 16);
+ os_memset(key->key_mic, 0, 16);
+ if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+ data, data_len, key->key_mic) ||
+ os_memcmp(mic, key->key_mic, 16) != 0)
+ ret = -1;
+ os_memcpy(key->key_mic, mic, 16);
+ return ret;
+}
+
+
+void wpa_remove_ptk(struct wpa_state_machine *sm)
+{
+ sm->PTK_valid = FALSE;
+ os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+ wpa_auth_set_key(sm->wpa_auth, 0, "none", sm->addr, 0, (u8 *) "", 0);
+ sm->pairwise_set = FALSE;
+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+}
+
+
+void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
+{
+ int remove_ptk = 1;
+
+ if (sm == NULL)
+ return;
+
+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "event %d notification", event);
+
+ switch (event) {
+ case WPA_AUTH:
+ case WPA_ASSOC:
+ break;
+ case WPA_DEAUTH:
+ case WPA_DISASSOC:
+ sm->DeauthenticationRequest = TRUE;
+ break;
+ case WPA_REAUTH:
+ case WPA_REAUTH_EAPOL:
+ if (sm->GUpdateStationKeys) {
+ /*
+ * Reauthentication cancels the pending group key
+ * update for this STA.
+ */
+ sm->group->GKeyDoneStations--;
+ sm->GUpdateStationKeys = FALSE;
+ sm->PtkGroupInit = TRUE;
+ }
+ sm->ReAuthenticationRequest = TRUE;
+ break;
+ case WPA_ASSOC_FT:
+#ifdef CONFIG_IEEE80211R
+ /* Using FT protocol, not WPA auth state machine */
+ sm->ft_completed = 1;
+ return;
+#else /* CONFIG_IEEE80211R */
+ break;
+#endif /* CONFIG_IEEE80211R */
+ }
+
+#ifdef CONFIG_IEEE80211R
+ sm->ft_completed = 0;
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+ if (sm->mgmt_frame_prot && event == WPA_AUTH)
+ remove_ptk = 0;
+#endif /* CONFIG_IEEE80211W */
+
+ if (remove_ptk) {
+ sm->PTK_valid = FALSE;
+ os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+ if (event != WPA_REAUTH_EAPOL)
+ wpa_remove_ptk(sm);
+ }
+
+ wpa_sm_step(sm);
+}
+
+
+static const char * wpa_alg_txt(int alg)
+{
+ switch (alg) {
+ case WPA_CIPHER_CCMP:
+ return "CCMP";
+ case WPA_CIPHER_TKIP:
+ return "TKIP";
+ case WPA_CIPHER_WEP104:
+ case WPA_CIPHER_WEP40:
+ return "WEP";
+ default:
+ return "";
+ }
+}
+
+
+SM_STATE(WPA_PTK, INITIALIZE)
+{
+ SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
+ if (sm->Init) {
+ /* Init flag is not cleared here, so avoid busy
+ * loop by claiming nothing changed. */
+ sm->changed = FALSE;
+ }
+
+ sm->keycount = 0;
+ if (sm->GUpdateStationKeys)
+ sm->group->GKeyDoneStations--;
+ sm->GUpdateStationKeys = FALSE;
+ if (sm->wpa == WPA_VERSION_WPA)
+ sm->PInitAKeys = FALSE;
+ if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
+ * Local AA > Remote AA)) */) {
+ sm->Pair = TRUE;
+ }
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
+ wpa_remove_ptk(sm);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
+ sm->TimeoutCtr = 0;
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+ WPA_EAPOL_authorized, 0);
+ }
+}
+
+
+SM_STATE(WPA_PTK, DISCONNECT)
+{
+ SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
+ sm->Disconnect = FALSE;
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+}
+
+
+SM_STATE(WPA_PTK, DISCONNECTED)
+{
+ SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
+ sm->DeauthenticationRequest = FALSE;
+}
+
+
+SM_STATE(WPA_PTK, AUTHENTICATION)
+{
+ SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
+ os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+ sm->PTK_valid = FALSE;
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
+ 1);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
+ sm->AuthenticationRequest = FALSE;
+}
+
+
+SM_STATE(WPA_PTK, AUTHENTICATION2)
+{
+ SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
+ os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
+ sm->ReAuthenticationRequest = FALSE;
+ /* IEEE 802.11i does not clear TimeoutCtr here, but this is more
+ * logical place than INITIALIZE since AUTHENTICATION2 can be
+ * re-entered on ReAuthenticationRequest without going through
+ * INITIALIZE. */
+ sm->TimeoutCtr = 0;
+}
+
+
+SM_STATE(WPA_PTK, INITPMK)
+{
+ u8 msk[2 * PMK_LEN];
+ size_t len = 2 * PMK_LEN;
+
+ SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
+#ifdef CONFIG_IEEE80211R
+ sm->xxkey_len = 0;
+#endif /* CONFIG_IEEE80211R */
+ if (sm->pmksa) {
+ wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
+ os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
+ } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
+ wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
+ "(len=%lu)", (unsigned long) len);
+ os_memcpy(sm->PMK, msk, PMK_LEN);
+#ifdef CONFIG_IEEE80211R
+ if (len >= 2 * PMK_LEN) {
+ os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
+ sm->xxkey_len = PMK_LEN;
+ }
+#endif /* CONFIG_IEEE80211R */
+ } else {
+ wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+ }
+
+ sm->req_replay_counter_used = 0;
+ /* IEEE 802.11i does not set keyRun to FALSE, but not doing this
+ * will break reauthentication since EAPOL state machines may not be
+ * get into AUTHENTICATING state that clears keyRun before WPA state
+ * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
+ * state and takes PMK from the previously used AAA Key. This will
+ * eventually fail in 4-Way Handshake because Supplicant uses PMK
+ * derived from the new AAA Key. Setting keyRun = FALSE here seems to
+ * be good workaround for this issue. */
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
+}
+
+
+SM_STATE(WPA_PTK, INITPSK)
+{
+ const u8 *psk;
+ SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
+ psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
+ if (psk) {
+ os_memcpy(sm->PMK, psk, PMK_LEN);
+#ifdef CONFIG_IEEE80211R
+ os_memcpy(sm->xxkey, psk, PMK_LEN);
+ sm->xxkey_len = PMK_LEN;
+#endif /* CONFIG_IEEE80211R */
+ }
+ sm->req_replay_counter_used = 0;
+}
+
+
+SM_STATE(WPA_PTK, PTKSTART)
+{
+ u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
+ size_t pmkid_len = 0;
+
+ SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
+ sm->PTKRequest = FALSE;
+ sm->TimeoutEvt = FALSE;
+
+ sm->TimeoutCtr++;
+ if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ /* No point in sending the EAPOL-Key - we will disconnect
+ * immediately following this. */
+ return;
+ }
+
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "sending 1/4 msg of 4-Way Handshake");
+ /*
+ * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
+ * one possible PSK for this STA.
+ */
+ if (sm->wpa == WPA_VERSION_WPA2 &&
+ wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
+ pmkid = buf;
+ pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+ pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
+ pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
+ RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
+ if (sm->pmksa)
+ os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+ sm->pmksa->pmkid, PMKID_LEN);
+ else {
+ /*
+ * Calculate PMKID since no PMKSA cache entry was
+ * available with pre-calculated PMKID.
+ */
+ rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
+ sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
+ wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+ }
+ }
+ wpa_send_eapol(sm->wpa_auth, sm,
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+ sm->ANonce, pmkid, pmkid_len, 0, 0);
+}
+
+
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+ struct wpa_ptk *ptk)
+{
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+#endif /* CONFIG_IEEE80211R */
+
+ wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+ sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
+ (u8 *) ptk, sizeof(*ptk),
+ wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+
+ return 0;
+}
+
+
+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
+{
+ struct wpa_ptk PTK;
+ int ok = 0;
+ const u8 *pmk = NULL;
+
+ SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
+ sm->EAPOLKeyReceived = FALSE;
+
+ /* WPA with IEEE 802.1X: use the derived PMK from EAP
+ * WPA-PSK: iterate through possible PSKs and select the one matching
+ * the packet */
+ for (;;) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
+ if (pmk == NULL)
+ break;
+ } else
+ pmk = sm->PMK;
+
+ wpa_derive_ptk(sm, pmk, &PTK);
+
+ if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+ sm->last_rx_eapol_key_len) == 0) {
+ ok = 1;
+ break;
+ }
+
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ break;
+ }
+
+ if (!ok) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "invalid MIC in msg 2/4 of 4-Way Handshake");
+ return;
+ }
+
+ eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ /* PSK may have changed from the previous choice, so update
+ * state machine data based on whatever PSK was selected here.
+ */
+ os_memcpy(sm->PMK, pmk, PMK_LEN);
+ }
+
+ sm->MICVerified = TRUE;
+
+ os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+ sm->PTK_valid = TRUE;
+}
+
+
+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
+{
+ SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
+ sm->TimeoutCtr = 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+ if (sm->mgmt_frame_prot) {
+ return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+ }
+
+ return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_igtk_kde igtk;
+ struct wpa_group *gsm = sm->group;
+
+ if (!sm->mgmt_frame_prot)
+ return pos;
+
+ igtk.keyid[0] = gsm->GN_igtk;
+ igtk.keyid[1] = 0;
+ if (wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn)
+ < 0)
+ os_memset(igtk.pn, 0, sizeof(igtk.pn));
+ os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
+ (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+
+ return pos;
+}
+
+#else /* CONFIG_IEEE80211W */
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+ return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+ return pos;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
+{
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+ size_t gtk_len, kde_len;
+ struct wpa_group *gsm = sm->group;
+ u8 *wpa_ie;
+ int wpa_ie_len, secure, keyidx, encr = 0;
+
+ SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
+ sm->TimeoutEvt = FALSE;
+
+ sm->TimeoutCtr++;
+ if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ /* No point in sending the EAPOL-Key - we will disconnect
+ * immediately following this. */
+ return;
+ }
+
+ /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, GTK[GN])
+ */
+ os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+ wpa_ie = sm->wpa_auth->wpa_ie;
+ wpa_ie_len = sm->wpa_auth->wpa_ie_len;
+ if (sm->wpa == WPA_VERSION_WPA &&
+ (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+ /* WPA-only STA, remove RSN IE */
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ wpa_ie_len = wpa_ie[1] + 2;
+ }
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "sending 3/4 msg of 4-Way Handshake");
+ if (sm->wpa == WPA_VERSION_WPA2) {
+ /* WPA2 send GTK in the 4-way handshake */
+ secure = 1;
+ gtk = gsm->GTK[gsm->GN - 1];
+ gtk_len = gsm->GTK_len;
+ keyidx = gsm->GN;
+ _rsc = rsc;
+ encr = 1;
+ } else {
+ /* WPA does not include GTK in msg 3/4 */
+ secure = 0;
+ gtk = NULL;
+ gtk_len = 0;
+ keyidx = 0;
+ _rsc = NULL;
+ }
+
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+ if (gtk)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
+ kde = os_malloc(kde_len);
+ if (kde == NULL)
+ return;
+
+ pos = kde;
+ os_memcpy(pos, wpa_ie, wpa_ie_len);
+ pos += wpa_ie_len;
+ if (gtk) {
+ u8 hdr[2];
+ hdr[0] = keyidx & 0x03;
+ hdr[1] = 0;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+ gtk, gtk_len);
+ }
+ pos = ieee80211w_kde_add(sm, pos);
+
+ wpa_send_eapol(sm->wpa_auth, sm,
+ (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
+ WPA_KEY_INFO_KEY_TYPE,
+ _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ os_free(kde);
+}
+
+
+SM_STATE(WPA_PTK, PTKINITDONE)
+{
+ SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
+ sm->EAPOLKeyReceived = FALSE;
+ if (sm->Pair) {
+ char *alg;
+ int klen;
+ if (sm->pairwise == WPA_CIPHER_TKIP) {
+ alg = "TKIP";
+ klen = 32;
+ } else {
+ alg = "CCMP";
+ klen = 16;
+ }
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+ sm->PTK.tk1, klen)) {
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ return;
+ }
+ /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
+ sm->pairwise_set = TRUE;
+
+ if (sm->wpa_auth->conf.wpa_ptk_rekey) {
+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_register_timeout(sm->wpa_auth->conf.
+ wpa_ptk_rekey, 0, wpa_rekey_ptk,
+ sm->wpa_auth, sm);
+ }
+
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+ WPA_EAPOL_authorized, 1);
+ }
+ }
+
+ if (0 /* IBSS == TRUE */) {
+ sm->keycount++;
+ if (sm->keycount == 2) {
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+ WPA_EAPOL_portValid, 1);
+ }
+ } else {
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
+ 1);
+ }
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+ if (sm->wpa == WPA_VERSION_WPA)
+ sm->PInitAKeys = TRUE;
+ else
+ sm->has_GTK = TRUE;
+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "pairwise key handshake completed (%s)",
+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+
+#ifdef CONFIG_IEEE80211R
+ wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+SM_STEP(WPA_PTK)
+{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+ if (sm->Init)
+ SM_ENTER(WPA_PTK, INITIALIZE);
+ else if (sm->Disconnect
+ /* || FIX: dot11RSNAConfigSALifetime timeout */)
+ SM_ENTER(WPA_PTK, DISCONNECT);
+ else if (sm->DeauthenticationRequest)
+ SM_ENTER(WPA_PTK, DISCONNECTED);
+ else if (sm->AuthenticationRequest)
+ SM_ENTER(WPA_PTK, AUTHENTICATION);
+ else if (sm->ReAuthenticationRequest)
+ SM_ENTER(WPA_PTK, AUTHENTICATION2);
+ else if (sm->PTKRequest)
+ SM_ENTER(WPA_PTK, PTKSTART);
+ else switch (sm->wpa_ptk_state) {
+ case WPA_PTK_INITIALIZE:
+ break;
+ case WPA_PTK_DISCONNECT:
+ SM_ENTER(WPA_PTK, DISCONNECTED);
+ break;
+ case WPA_PTK_DISCONNECTED:
+ SM_ENTER(WPA_PTK, INITIALIZE);
+ break;
+ case WPA_PTK_AUTHENTICATION:
+ SM_ENTER(WPA_PTK, AUTHENTICATION2);
+ break;
+ case WPA_PTK_AUTHENTICATION2:
+ if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+ wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+ WPA_EAPOL_keyRun) > 0)
+ SM_ENTER(WPA_PTK, INITPMK);
+ else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)
+ /* FIX: && 802.1X::keyRun */)
+ SM_ENTER(WPA_PTK, INITPSK);
+ break;
+ case WPA_PTK_INITPMK:
+ if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+ WPA_EAPOL_keyAvailable) > 0)
+ SM_ENTER(WPA_PTK, PTKSTART);
+ else {
+ wpa_auth->dot11RSNA4WayHandshakeFailures++;
+ SM_ENTER(WPA_PTK, DISCONNECT);
+ }
+ break;
+ case WPA_PTK_INITPSK:
+ if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
+ SM_ENTER(WPA_PTK, PTKSTART);
+ else {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "no PSK configured for the STA");
+ wpa_auth->dot11RSNA4WayHandshakeFailures++;
+ SM_ENTER(WPA_PTK, DISCONNECT);
+ }
+ break;
+ case WPA_PTK_PTKSTART:
+ if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+ sm->EAPOLKeyPairwise)
+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+ else if (sm->TimeoutCtr >
+ (int) dot11RSNAConfigPairwiseUpdateCount) {
+ wpa_auth->dot11RSNA4WayHandshakeFailures++;
+ SM_ENTER(WPA_PTK, DISCONNECT);
+ } else if (sm->TimeoutEvt)
+ SM_ENTER(WPA_PTK, PTKSTART);
+ break;
+ case WPA_PTK_PTKCALCNEGOTIATING:
+ if (sm->MICVerified)
+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2);
+ else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+ sm->EAPOLKeyPairwise)
+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+ else if (sm->TimeoutEvt)
+ SM_ENTER(WPA_PTK, PTKSTART);
+ break;
+ case WPA_PTK_PTKCALCNEGOTIATING2:
+ SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
+ break;
+ case WPA_PTK_PTKINITNEGOTIATING:
+ if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+ sm->EAPOLKeyPairwise && sm->MICVerified)
+ SM_ENTER(WPA_PTK, PTKINITDONE);
+ else if (sm->TimeoutCtr >
+ (int) dot11RSNAConfigPairwiseUpdateCount) {
+ wpa_auth->dot11RSNA4WayHandshakeFailures++;
+ SM_ENTER(WPA_PTK, DISCONNECT);
+ } else if (sm->TimeoutEvt)
+ SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
+ break;
+ case WPA_PTK_PTKINITDONE:
+ break;
+ }
+}
+
+
+SM_STATE(WPA_PTK_GROUP, IDLE)
+{
+ SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
+ if (sm->Init) {
+ /* Init flag is not cleared here, so avoid busy
+ * loop by claiming nothing changed. */
+ sm->changed = FALSE;
+ }
+ sm->GTimeoutCtr = 0;
+}
+
+
+SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
+{
+ u8 rsc[WPA_KEY_RSC_LEN];
+ struct wpa_group *gsm = sm->group;
+ u8 *kde, *pos, hdr[2];
+ size_t kde_len;
+
+ SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
+
+ sm->GTimeoutCtr++;
+ if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+ /* No point in sending the EAPOL-Key - we will disconnect
+ * immediately following this. */
+ return;
+ }
+
+ if (sm->wpa == WPA_VERSION_WPA)
+ sm->PInitAKeys = FALSE;
+ sm->TimeoutEvt = FALSE;
+ /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
+ os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+ if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "sending 1/2 msg of Group Key Handshake");
+
+ if (sm->wpa == WPA_VERSION_WPA2) {
+ kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
+ ieee80211w_kde_len(sm);
+ kde = os_malloc(kde_len);
+ if (kde == NULL)
+ return;
+
+ pos = kde;
+ hdr[0] = gsm->GN & 0x03;
+ hdr[1] = 0;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+ gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ pos = ieee80211w_kde_add(sm, pos);
+ } else {
+ kde = gsm->GTK[gsm->GN - 1];
+ pos = kde + gsm->GTK_len;
+ }
+
+ wpa_send_eapol(sm->wpa_auth, sm,
+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ACK |
+ (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
+ rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
+ if (sm->wpa == WPA_VERSION_WPA2)
+ os_free(kde);
+}
+
+
+SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
+{
+ SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
+ sm->EAPOLKeyReceived = FALSE;
+ if (sm->GUpdateStationKeys)
+ sm->group->GKeyDoneStations--;
+ sm->GUpdateStationKeys = FALSE;
+ sm->GTimeoutCtr = 0;
+ /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "group key handshake completed (%s)",
+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+ sm->has_GTK = TRUE;
+}
+
+
+SM_STATE(WPA_PTK_GROUP, KEYERROR)
+{
+ SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
+ if (sm->GUpdateStationKeys)
+ sm->group->GKeyDoneStations--;
+ sm->GUpdateStationKeys = FALSE;
+ sm->Disconnect = TRUE;
+}
+
+
+SM_STEP(WPA_PTK_GROUP)
+{
+ if (sm->Init || sm->PtkGroupInit) {
+ SM_ENTER(WPA_PTK_GROUP, IDLE);
+ sm->PtkGroupInit = FALSE;
+ } else switch (sm->wpa_ptk_group_state) {
+ case WPA_PTK_GROUP_IDLE:
+ if (sm->GUpdateStationKeys ||
+ (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
+ SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
+ break;
+ case WPA_PTK_GROUP_REKEYNEGOTIATING:
+ if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+ !sm->EAPOLKeyPairwise && sm->MICVerified)
+ SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
+ else if (sm->GTimeoutCtr >
+ (int) dot11RSNAConfigGroupUpdateCount)
+ SM_ENTER(WPA_PTK_GROUP, KEYERROR);
+ else if (sm->TimeoutEvt)
+ SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
+ break;
+ case WPA_PTK_GROUP_KEYERROR:
+ SM_ENTER(WPA_PTK_GROUP, IDLE);
+ break;
+ case WPA_PTK_GROUP_REKEYESTABLISHED:
+ SM_ENTER(WPA_PTK_GROUP, IDLE);
+ break;
+ }
+}
+
+
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ int ret = 0;
+
+ /* FIX: is this the correct way of getting GNonce? */
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ wpa_gmk_to_gtk(group->GMK, wpa_auth->addr, group->GNonce,
+ group->GTK[group->GN - 1], group->GTK_len);
+
+#ifdef CONFIG_IEEE80211W
+ if (wpa_auth->conf.ieee80211w != WPA_NO_IEEE80211W) {
+ if (os_get_random(group->IGTK[group->GN_igtk - 4],
+ WPA_IGTK_LEN) < 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to get new random "
+ "IGTK");
+ ret = -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "IGTK",
+ group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ return ret;
+}
+
+
+static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+ "GTK_INIT (VLAN-ID %d)", group->vlan_id);
+ group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+ group->wpa_group_state = WPA_GROUP_GTK_INIT;
+
+ /* GTK[0..N] = 0 */
+ os_memset(group->GTK, 0, sizeof(group->GTK));
+ group->GN = 1;
+ group->GM = 2;
+#ifdef CONFIG_IEEE80211W
+ group->GN_igtk = 4;
+ group->GM_igtk = 5;
+#endif /* CONFIG_IEEE80211W */
+ /* GTK[GN] = CalcGTK() */
+ wpa_gtk_update(wpa_auth, group);
+}
+
+
+static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
+{
+ if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Not in PTKINITDONE; skip Group Key update");
+ return 0;
+ }
+ if (sm->GUpdateStationKeys) {
+ /*
+ * This should not really happen, but just in case, make sure
+ * we do not count the same STA twice in GKeyDoneStations.
+ */
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "GUpdateStationKeys already set - do not "
+ "increment GKeyDoneStations");
+ } else {
+ sm->group->GKeyDoneStations++;
+ sm->GUpdateStationKeys = TRUE;
+ }
+ wpa_sm_step(sm);
+ return 0;
+}
+
+
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ int tmp;
+
+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+ "SETKEYS (VLAN-ID %d)", group->vlan_id);
+ group->changed = TRUE;
+ group->wpa_group_state = WPA_GROUP_SETKEYS;
+ group->GTKReKey = FALSE;
+ tmp = group->GM;
+ group->GM = group->GN;
+ group->GN = tmp;
+#ifdef CONFIG_IEEE80211W
+ tmp = group->GM_igtk;
+ group->GM_igtk = group->GN_igtk;
+ group->GN_igtk = tmp;
+#endif /* CONFIG_IEEE80211W */
+ /* "GKeyDoneStations = GNoStations" is done in more robust way by
+ * counting the STAs that are marked with GUpdateStationKeys instead of
+ * including all STAs that could be in not-yet-completed state. */
+ wpa_gtk_update(wpa_auth, group);
+
+ wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
+ wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
+ group->GKeyDoneStations);
+}
+
+
+static void wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+ "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
+ group->changed = TRUE;
+ group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
+ wpa_auth_set_key(wpa_auth, group->vlan_id,
+ wpa_alg_txt(wpa_auth->conf.wpa_group),
+ NULL, group->GN, group->GTK[group->GN - 1],
+ group->GTK_len);
+
+#ifdef CONFIG_IEEE80211W
+ if (wpa_auth->conf.ieee80211w != WPA_NO_IEEE80211W) {
+ wpa_auth_set_key(wpa_auth, group->vlan_id, "IGTK",
+ NULL, group->GN_igtk,
+ group->IGTK[group->GN_igtk - 4],
+ WPA_IGTK_LEN);
+ }
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ if (group->GInit) {
+ wpa_group_gtk_init(wpa_auth, group);
+ } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
+ group->GTKAuthenticator) {
+ wpa_group_setkeysdone(wpa_auth, group);
+ } else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
+ group->GTKReKey) {
+ wpa_group_setkeys(wpa_auth, group);
+ } else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
+ if (group->GKeyDoneStations == 0)
+ wpa_group_setkeysdone(wpa_auth, group);
+ else if (group->GTKReKey)
+ wpa_group_setkeys(wpa_auth, group);
+ }
+}
+
+
+static void wpa_sm_step(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return;
+
+ if (sm->in_step_loop) {
+ /* This should not happen, but if it does, make sure we do not
+ * end up freeing the state machine too early by exiting the
+ * recursive call. */
+ wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
+ return;
+ }
+
+ sm->in_step_loop = 1;
+ do {
+ if (sm->pending_deinit)
+ break;
+
+ sm->changed = FALSE;
+ sm->wpa_auth->group->changed = FALSE;
+
+ SM_STEP_RUN(WPA_PTK);
+ if (sm->pending_deinit)
+ break;
+ SM_STEP_RUN(WPA_PTK_GROUP);
+ if (sm->pending_deinit)
+ break;
+ wpa_group_sm_step(sm->wpa_auth, sm->group);
+ } while (sm->changed || sm->wpa_auth->group->changed);
+ sm->in_step_loop = 0;
+
+ if (sm->pending_deinit) {
+ wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
+ "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_free_sta_sm(sm);
+ }
+}
+
+
+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_state_machine *sm = eloop_ctx;
+ wpa_sm_step(sm);
+}
+
+
+void wpa_auth_sm_notify(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return;
+ eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
+}
+
+
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
+{
+ int tmp, i;
+ struct wpa_group *group;
+
+ if (wpa_auth == NULL)
+ return;
+
+ group = wpa_auth->group;
+
+ for (i = 0; i < 2; i++) {
+ tmp = group->GM;
+ group->GM = group->GN;
+ group->GN = tmp;
+#ifdef CONFIG_IEEE80211W
+ tmp = group->GM_igtk;
+ group->GM_igtk = group->GN_igtk;
+ group->GN_igtk = tmp;
+#endif /* CONFIG_IEEE80211W */
+ wpa_gtk_update(wpa_auth, group);
+ }
+}
+
+
+static const char * wpa_bool_txt(int bool)
+{
+ return bool ? "TRUE" : "FALSE";
+}
+
+
+static int wpa_cipher_bits(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ return 128;
+ case WPA_CIPHER_TKIP:
+ return 256;
+ case WPA_CIPHER_WEP104:
+ return 104;
+ case WPA_CIPHER_WEP40:
+ return 40;
+ default:
+ return 0;
+ }
+}
+
+
+#define RSN_SUITE "%02x-%02x-%02x-%d"
+#define RSN_SUITE_ARG(s) \
+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
+
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
+{
+ int len = 0, ret;
+ char pmkid_txt[PMKID_LEN * 2 + 1];
+
+ if (wpa_auth == NULL)
+ return len;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "dot11RSNAOptionImplemented=TRUE\n"
+#ifdef CONFIG_RSN_PREAUTH
+ "dot11RSNAPreauthenticationImplemented=TRUE\n"
+#else /* CONFIG_RSN_PREAUTH */
+ "dot11RSNAPreauthenticationImplemented=FALSE\n"
+#endif /* CONFIG_RSN_PREAUTH */
+ "dot11RSNAEnabled=%s\n"
+ "dot11RSNAPreauthenticationEnabled=%s\n",
+ wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
+ wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+ wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
+
+ ret = os_snprintf(
+ buf + len, buflen - len,
+ "dot11RSNAConfigVersion=%u\n"
+ "dot11RSNAConfigPairwiseKeysSupported=9999\n"
+ /* FIX: dot11RSNAConfigGroupCipher */
+ /* FIX: dot11RSNAConfigGroupRekeyMethod */
+ /* FIX: dot11RSNAConfigGroupRekeyTime */
+ /* FIX: dot11RSNAConfigGroupRekeyPackets */
+ "dot11RSNAConfigGroupRekeyStrict=%u\n"
+ "dot11RSNAConfigGroupUpdateCount=%u\n"
+ "dot11RSNAConfigPairwiseUpdateCount=%u\n"
+ "dot11RSNAConfigGroupCipherSize=%u\n"
+ "dot11RSNAConfigPMKLifetime=%u\n"
+ "dot11RSNAConfigPMKReauthThreshold=%u\n"
+ "dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
+ "dot11RSNAConfigSATimeout=%u\n"
+ "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+ "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+ "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+ "dot11RSNAPMKIDUsed=%s\n"
+ "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+ "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+ "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+ "dot11RSNATKIPCounterMeasuresInvoked=%u\n"
+ "dot11RSNA4WayHandshakeFailures=%u\n"
+ "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
+ RSN_VERSION,
+ !!wpa_auth->conf.wpa_strict_rekey,
+ dot11RSNAConfigGroupUpdateCount,
+ dot11RSNAConfigPairwiseUpdateCount,
+ wpa_cipher_bits(wpa_auth->conf.wpa_group),
+ dot11RSNAConfigPMKLifetime,
+ dot11RSNAConfigPMKReauthThreshold,
+ dot11RSNAConfigSATimeout,
+ RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected),
+ RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected),
+ RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
+ pmkid_txt,
+ RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested),
+ RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested),
+ RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
+ wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
+ wpa_auth->dot11RSNA4WayHandshakeFailures);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ /* TODO: dot11RSNAConfigPairwiseCiphersTable */
+ /* TODO: dot11RSNAConfigAuthenticationSuitesTable */
+
+ /* Private MIB */
+ ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
+ wpa_auth->group->wpa_group_state);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ return len;
+}
+
+
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
+{
+ int len = 0, ret;
+ u32 pairwise = 0;
+
+ if (sm == NULL)
+ return 0;
+
+ /* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
+
+ /* dot11RSNAStatsEntry */
+
+ if (sm->wpa == WPA_VERSION_WPA) {
+ if (sm->pairwise == WPA_CIPHER_CCMP)
+ pairwise = WPA_CIPHER_SUITE_CCMP;
+ else if (sm->pairwise == WPA_CIPHER_TKIP)
+ pairwise = WPA_CIPHER_SUITE_TKIP;
+ else if (sm->pairwise == WPA_CIPHER_WEP104)
+ pairwise = WPA_CIPHER_SUITE_WEP104;
+ else if (sm->pairwise == WPA_CIPHER_WEP40)
+ pairwise = WPA_CIPHER_SUITE_WEP40;
+ else if (sm->pairwise == WPA_CIPHER_NONE)
+ pairwise = WPA_CIPHER_SUITE_NONE;
+ } else if (sm->wpa == WPA_VERSION_WPA2) {
+ if (sm->pairwise == WPA_CIPHER_CCMP)
+ pairwise = RSN_CIPHER_SUITE_CCMP;
+ else if (sm->pairwise == WPA_CIPHER_TKIP)
+ pairwise = RSN_CIPHER_SUITE_TKIP;
+ else if (sm->pairwise == WPA_CIPHER_WEP104)
+ pairwise = RSN_CIPHER_SUITE_WEP104;
+ else if (sm->pairwise == WPA_CIPHER_WEP40)
+ pairwise = RSN_CIPHER_SUITE_WEP40;
+ else if (sm->pairwise == WPA_CIPHER_NONE)
+ pairwise = RSN_CIPHER_SUITE_NONE;
+ } else
+ return 0;
+
+ ret = os_snprintf(
+ buf + len, buflen - len,
+ /* TODO: dot11RSNAStatsIndex */
+ "dot11RSNAStatsSTAAddress=" MACSTR "\n"
+ "dot11RSNAStatsVersion=1\n"
+ "dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
+ /* TODO: dot11RSNAStatsTKIPICVErrors */
+ "dot11RSNAStatsTKIPLocalMICFailures=%u\n"
+ "dot11RSNAStatsTKIPRemoveMICFailures=%u\n"
+ /* TODO: dot11RSNAStatsCCMPReplays */
+ /* TODO: dot11RSNAStatsCCMPDecryptErrors */
+ /* TODO: dot11RSNAStatsTKIPReplays */,
+ MAC2STR(sm->addr),
+ RSN_SUITE_ARG(pairwise),
+ sm->dot11RSNAStatsTKIPLocalMICFailures,
+ sm->dot11RSNAStatsTKIPRemoteMICFailures);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ /* Private MIB */
+ ret = os_snprintf(buf + len, buflen - len,
+ "hostapdWPAPTKState=%d\n"
+ "hostapdWPAPTKGroupState=%d\n",
+ sm->wpa_ptk_state,
+ sm->wpa_ptk_group_state);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ return len;
+}
+
+
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
+{
+ if (wpa_auth)
+ wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
+}
+
+
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
+{
+ return sm && sm->pairwise_set;
+}
+
+
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
+{
+ return sm->pairwise;
+}
+
+
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return -1;
+ return sm->wpa_key_mgmt;
+}
+
+
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return sm->wpa;
+}
+
+
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ if (sm == NULL || sm->pmksa != entry)
+ return -1;
+ sm->pmksa = NULL;
+ return 0;
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
+{
+ return sm ? sm->pmksa : NULL;
+}
+
+
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
+{
+ if (sm)
+ sm->dot11RSNAStatsTKIPLocalMICFailures++;
+}
+
+
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
+{
+ if (wpa_auth == NULL)
+ return NULL;
+ *len = wpa_auth->wpa_ie_len;
+ return wpa_auth->wpa_ie;
+}
+
+
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+ int session_timeout, struct eapol_state_machine *eapol)
+{
+ if (sm == NULL || sm->wpa != WPA_VERSION_WPA2)
+ return -1;
+
+ if (pmksa_cache_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+ sm->wpa_auth->addr, sm->addr, session_timeout,
+ eapol, sm->wpa_key_mgmt))
+ return 0;
+
+ return -1;
+}
+
+
+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
+ const u8 *pmk, size_t len, const u8 *sta_addr,
+ int session_timeout,
+ struct eapol_state_machine *eapol)
+{
+ if (wpa_auth == NULL)
+ return -1;
+
+ if (pmksa_cache_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+ sta_addr, session_timeout, eapol,
+ WPA_KEY_MGMT_IEEE8021X))
+ return 0;
+
+ return -1;
+}
+
+
+static struct wpa_group *
+wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+ struct wpa_group *group;
+
+ if (wpa_auth == NULL || wpa_auth->group == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
+ vlan_id);
+ group = wpa_group_init(wpa_auth, vlan_id);
+ if (group == NULL)
+ return NULL;
+
+ group->next = wpa_auth->group->next;
+ wpa_auth->group->next = group;
+
+ return group;
+}
+
+
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
+{
+ struct wpa_group *group;
+
+ if (sm == NULL || sm->wpa_auth == NULL)
+ return 0;
+
+ group = sm->wpa_auth->group;
+ while (group) {
+ if (group->vlan_id == vlan_id)
+ break;
+ group = group->next;
+ }
+
+ if (group == NULL) {
+ group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
+ if (group == NULL)
+ return -1;
+ }
+
+ if (sm->group == group)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
+ "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+
+ sm->group = group;
+ return 0;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/wpa/hostapd/wpa.h b/contrib/wpa/hostapd/wpa.h
new file mode 100644
index 0000000..d353844
--- /dev/null
+++ b/contrib/wpa/hostapd/wpa.h
@@ -0,0 +1,284 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator
+ * 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.
+ */
+
+#ifndef WPA_AUTH_H
+#define WPA_AUTH_H
+
+#include "eapol_common.h"
+#include "wpa_common.h"
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition
+ */
+struct ft_rrb_frame {
+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+ u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */
+ le16 action_length; /* little endian length of action_frame */
+ u8 ap_address[ETH_ALEN];
+ /*
+ * Followed by action_length bytes of FT Action frame (from Category
+ * field to the end of Action Frame body.
+ */
+} STRUCT_PACKED;
+
+#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1
+
+#define FT_PACKET_REQUEST 0
+#define FT_PACKET_RESPONSE 1
+/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
+#define FT_PACKET_R0KH_R1KH_PULL 200
+#define FT_PACKET_R0KH_R1KH_RESP 201
+#define FT_PACKET_R0KH_R1KH_PUSH 202
+
+#ifndef ETH_P_RRB
+#define ETH_P_RRB 0x890D
+#endif /* ETH_P_RRB */
+
+#define FT_R0KH_R1KH_PULL_DATA_LEN 44
+#define FT_R0KH_R1KH_RESP_DATA_LEN 76
+#define FT_R0KH_R1KH_PUSH_DATA_LEN 80
+
+struct ft_r0kh_r1kh_pull_frame {
+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+ u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
+ le16 data_length; /* little endian length of data (44) */
+ u8 ap_address[ETH_ALEN];
+
+ u8 nonce[16];
+ u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 r1kh_id[FT_R1KH_ID_LEN];
+ u8 s1kh_id[ETH_ALEN];
+ u8 pad[4]; /* 8-octet boundary for AES key wrap */
+ u8 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+struct ft_r0kh_r1kh_resp_frame {
+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+ u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
+ le16 data_length; /* little endian length of data (76) */
+ u8 ap_address[ETH_ALEN];
+
+ u8 nonce[16]; /* copied from pull */
+ u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
+ u8 s1kh_id[ETH_ALEN]; /* copied from pull */
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 pad[4]; /* 8-octet boundary for AES key wrap */
+ u8 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+struct ft_r0kh_r1kh_push_frame {
+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+ u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
+ le16 data_length; /* little endian length of data (80) */
+ u8 ap_address[ETH_ALEN];
+
+ /* Encrypted with AES key-wrap */
+ u8 timestamp[4]; /* current time in seconds since unix epoch, little
+ * endian */
+ u8 r1kh_id[FT_R1KH_ID_LEN];
+ u8 s1kh_id[ETH_ALEN];
+ u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+/* per STA state machine data */
+
+struct wpa_authenticator;
+struct wpa_state_machine;
+struct rsn_pmksa_cache_entry;
+struct eapol_state_machine;
+
+
+struct ft_remote_r0kh {
+ struct ft_remote_r0kh *next;
+ u8 addr[ETH_ALEN];
+ u8 id[FT_R0KH_ID_MAX_LEN];
+ size_t id_len;
+ u8 key[16];
+};
+
+
+struct ft_remote_r1kh {
+ struct ft_remote_r1kh *next;
+ u8 addr[ETH_ALEN];
+ u8 id[FT_R1KH_ID_LEN];
+ u8 key[16];
+};
+
+
+struct wpa_auth_config {
+ int wpa;
+ int wpa_key_mgmt;
+ int wpa_pairwise;
+ int wpa_group;
+ int wpa_group_rekey;
+ int wpa_strict_rekey;
+ int wpa_gmk_rekey;
+ int wpa_ptk_rekey;
+ int rsn_pairwise;
+ int rsn_preauth;
+ int eapol_version;
+ int peerkey;
+ int wme_enabled;
+ int okc;
+#ifdef CONFIG_IEEE80211W
+ enum {
+ WPA_NO_IEEE80211W = 0,
+ WPA_IEEE80211W_OPTIONAL = 1,
+ WPA_IEEE80211W_REQUIRED = 2
+ } ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+#define SSID_LEN 32
+ u8 ssid[SSID_LEN];
+ size_t ssid_len;
+ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+ u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
+ size_t r0_key_holder_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 */
+};
+
+typedef enum {
+ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
+} logger_level;
+
+typedef enum {
+ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
+ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
+ WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
+} wpa_eapol_variable;
+
+struct wpa_auth_callbacks {
+ void *ctx;
+ void (*logger)(void *ctx, const u8 *addr, logger_level level,
+ const char *txt);
+ void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
+ void (*mic_failure_report)(void *ctx, const u8 *addr);
+ void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
+ int value);
+ int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
+ const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
+ int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
+ int (*set_key)(void *ctx, int vlan_id, const char *alg, const u8 *addr,
+ int idx, u8 *key, size_t key_len);
+ int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
+ int (*get_seqnum_igtk)(void *ctx, const u8 *addr, int idx, u8 *seq);
+ int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt);
+ int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
+ void *ctx), void *cb_ctx);
+ int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
+ void *ctx), void *cb_ctx);
+ int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
+ size_t data_len);
+#ifdef CONFIG_IEEE80211R
+ struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+ int (*send_ft_action)(void *ctx, const u8 *dst,
+ const u8 *data, size_t data_len);
+#endif /* CONFIG_IEEE80211R */
+};
+
+struct wpa_authenticator * wpa_init(const u8 *addr,
+ struct wpa_auth_config *conf,
+ struct wpa_auth_callbacks *cb);
+void wpa_deinit(struct wpa_authenticator *wpa_auth);
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+ struct wpa_auth_config *conf);
+
+enum {
+ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
+ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
+ WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
+ WPA_INVALID_MDIE, WPA_INVALID_PROTO
+};
+
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *mdie, size_t mdie_len);
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
+void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm);
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ u8 *data, size_t data_len);
+typedef enum {
+ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
+ WPA_REAUTH_EAPOL, WPA_ASSOC_FT
+} wpa_event;
+void wpa_remove_ptk(struct wpa_state_machine *sm);
+void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
+void wpa_auth_sm_notify(struct wpa_state_machine *sm);
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+ struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
+ size_t *len);
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+ int session_timeout, struct eapol_state_machine *eapol);
+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
+ const u8 *pmk, size_t len, const u8 *sta_addr,
+ int session_timeout,
+ struct eapol_state_machine *eapol);
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
+
+#ifdef CONFIG_IEEE80211R
+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
+ size_t max_len, int auth_alg);
+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+ u16 auth_transaction, const u8 *ies, size_t ies_len,
+ void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+ u16 auth_transaction, u16 resp,
+ const u8 *ies, size_t ies_len),
+ void *ctx);
+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+ size_t ies_len);
+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+ const u8 *data, size_t data_len);
+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
+#endif /* CONFIG_IEEE80211R */
+
+#endif /* WPA_AUTH_H */
diff --git a/contrib/wpa/hostapd/wpa_auth_i.h b/contrib/wpa/hostapd/wpa_auth_i.h
new file mode 100644
index 0000000..bcaeda5
--- /dev/null
+++ b/contrib/wpa/hostapd/wpa_auth_i.h
@@ -0,0 +1,221 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
+ * 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.
+ */
+
+#ifndef WPA_AUTH_I_H
+#define WPA_AUTH_I_H
+
+/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
+#define RSNA_MAX_EAPOL_RETRIES 4
+
+struct wpa_group;
+
+struct wpa_stsl_negotiation {
+ struct wpa_stsl_negotiation *next;
+ u8 initiator[ETH_ALEN];
+ u8 peer[ETH_ALEN];
+};
+
+
+struct wpa_state_machine {
+ struct wpa_authenticator *wpa_auth;
+ struct wpa_group *group;
+
+ u8 addr[ETH_ALEN];
+
+ enum {
+ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
+ WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
+ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
+ WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
+ WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
+ } wpa_ptk_state;
+
+ enum {
+ WPA_PTK_GROUP_IDLE = 0,
+ WPA_PTK_GROUP_REKEYNEGOTIATING,
+ WPA_PTK_GROUP_REKEYESTABLISHED,
+ WPA_PTK_GROUP_KEYERROR
+ } wpa_ptk_group_state;
+
+ Boolean Init;
+ Boolean DeauthenticationRequest;
+ Boolean AuthenticationRequest;
+ Boolean ReAuthenticationRequest;
+ Boolean Disconnect;
+ int TimeoutCtr;
+ int GTimeoutCtr;
+ Boolean TimeoutEvt;
+ Boolean EAPOLKeyReceived;
+ Boolean EAPOLKeyPairwise;
+ Boolean EAPOLKeyRequest;
+ Boolean MICVerified;
+ Boolean GUpdateStationKeys;
+ u8 ANonce[WPA_NONCE_LEN];
+ u8 SNonce[WPA_NONCE_LEN];
+ u8 PMK[PMK_LEN];
+ struct wpa_ptk PTK;
+ Boolean PTK_valid;
+ Boolean pairwise_set;
+ int keycount;
+ Boolean Pair;
+ struct {
+ u8 counter[WPA_REPLAY_COUNTER_LEN];
+ Boolean valid;
+ } key_replay[RSNA_MAX_EAPOL_RETRIES];
+ Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
+ Boolean PTKRequest; /* not in IEEE 802.11i state machine */
+ Boolean has_GTK;
+ Boolean PtkGroupInit; /* init request for PTK Group state machine */
+
+ u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
+ size_t last_rx_eapol_key_len;
+
+ unsigned int changed:1;
+ unsigned int in_step_loop:1;
+ unsigned int pending_deinit:1;
+ unsigned int started:1;
+ unsigned int mgmt_frame_prot:1;
+#ifdef CONFIG_IEEE80211R
+ unsigned int ft_completed:1;
+ unsigned int pmk_r1_name_valid:1;
+#endif /* CONFIG_IEEE80211R */
+
+ u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
+ int req_replay_counter_used;
+
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+
+ enum {
+ WPA_VERSION_NO_WPA = 0 /* WPA not used */,
+ WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
+ WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
+ } wpa;
+ int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+ int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ u32 dot11RSNAStatsTKIPLocalMICFailures;
+ u32 dot11RSNAStatsTKIPRemoteMICFailures;
+
+#ifdef CONFIG_IEEE80211R
+ u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+ size_t xxkey_len;
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
+ * Request */
+ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
+ size_t r0kh_id_len;
+#endif /* CONFIG_IEEE80211R */
+};
+
+
+/* per group key state machine data */
+struct wpa_group {
+ struct wpa_group *next;
+ int vlan_id;
+
+ Boolean GInit;
+ int GKeyDoneStations;
+ Boolean GTKReKey;
+ int GTK_len;
+ int GN, GM;
+ Boolean GTKAuthenticator;
+ u8 Counter[WPA_NONCE_LEN];
+
+ enum {
+ WPA_GROUP_GTK_INIT = 0,
+ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
+ } wpa_group_state;
+
+ u8 GMK[WPA_GMK_LEN];
+ u8 GTK[2][WPA_GTK_MAX_LEN];
+ u8 GNonce[WPA_NONCE_LEN];
+ Boolean changed;
+#ifdef CONFIG_IEEE80211W
+ u8 IGTK[2][WPA_IGTK_LEN];
+ int GN_igtk, GM_igtk;
+#endif /* CONFIG_IEEE80211W */
+};
+
+
+struct wpa_ft_pmk_cache;
+
+/* per authenticator data */
+struct wpa_authenticator {
+ struct wpa_group *group;
+
+ unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
+ u32 dot11RSNAAuthenticationSuiteSelected;
+ u32 dot11RSNAPairwiseCipherSelected;
+ u32 dot11RSNAGroupCipherSelected;
+ u8 dot11RSNAPMKIDUsed[PMKID_LEN];
+ u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */
+ u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */
+ u32 dot11RSNAGroupCipherRequested; /* FIX: update */
+ unsigned int dot11RSNATKIPCounterMeasuresInvoked;
+ unsigned int dot11RSNA4WayHandshakeFailures;
+
+ struct wpa_stsl_negotiation *stsl_negotiations;
+
+ struct wpa_auth_config conf;
+ struct wpa_auth_callbacks cb;
+
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+
+ u8 addr[ETH_ALEN];
+
+ struct rsn_pmksa_cache *pmksa;
+ struct wpa_ft_pmk_cache *ft_pmk_cache;
+};
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+ const u8 *pmkid);
+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ logger_level level, const char *txt);
+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ logger_level level, const char *fmt, ...);
+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int key_info,
+ const u8 *key_rsc, const u8 *nonce,
+ const u8 *kde, size_t kde_len,
+ int keyidx, int encr, int force_version);
+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+ int (*cb)(struct wpa_state_machine *sm, void *ctx),
+ void *cb_ctx);
+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
+ int (*cb)(struct wpa_authenticator *a, void *ctx),
+ void *cb_ctx);
+
+#ifdef CONFIG_PEERKEY
+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+ struct wpa_stsl_negotiation *neg);
+void wpa_smk_error(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211R
+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
+ struct wpa_ptk *ptk);
+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
+#endif /* CONFIG_IEEE80211R */
+
+#endif /* WPA_AUTH_I_H */
diff --git a/contrib/wpa/hostapd/wpa_auth_ie.c b/contrib/wpa/hostapd/wpa_auth_ie.c
new file mode 100644
index 0000000..3ac9d67
--- /dev/null
+++ b/contrib/wpa/hostapd/wpa_auth_ie.c
@@ -0,0 +1,864 @@
+/*
+ * hostapd - WPA/RSN IE and KDE definitions
+ * 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 "common.h"
+#include "config.h"
+#include "ieee802_11.h"
+#include "eapol_sm.h"
+#include "wpa.h"
+#include "pmksa_cache.h"
+#include "wpa_auth_ie.h"
+#include "wpa_auth_i.h"
+
+
+static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ struct wpa_ie_hdr *hdr;
+ int num_suites;
+ u8 *pos, *count;
+
+ hdr = (struct wpa_ie_hdr *) buf;
+ hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
+ RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
+ WPA_PUT_LE16(hdr->version, WPA_VERSION);
+ pos = (u8 *) (hdr + 1);
+
+ if (conf->wpa_group == WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+ } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+ } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
+ } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
+ } else {
+ wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+ conf->wpa_group);
+ return -1;
+ }
+ pos += WPA_SELECTOR_LEN;
+
+ num_suites = 0;
+ count = pos;
+ pos += 2;
+
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ if (num_suites == 0) {
+ wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+ conf->wpa_pairwise);
+ return -1;
+ }
+ WPA_PUT_LE16(count, num_suites);
+
+ num_suites = 0;
+ count = pos;
+ pos += 2;
+
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ if (num_suites == 0) {
+ wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+ WPA_PUT_LE16(count, num_suites);
+
+ /* WPA Capabilities; use defaults, so no need to include it */
+
+ hdr->len = (pos - buf) - 2;
+
+ return pos - buf;
+}
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+ const u8 *pmkid)
+{
+ struct rsn_ie_hdr *hdr;
+ int num_suites;
+ u8 *pos, *count;
+ u16 capab;
+
+ hdr = (struct rsn_ie_hdr *) buf;
+ hdr->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+
+ if (conf->wpa_group == WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+ } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
+ } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
+ } else {
+ wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+ conf->wpa_group);
+ return -1;
+ }
+ pos += RSN_SELECTOR_LEN;
+
+ num_suites = 0;
+ count = pos;
+ pos += 2;
+
+ if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ if (num_suites == 0) {
+ wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+ conf->rsn_pairwise);
+ return -1;
+ }
+ WPA_PUT_LE16(count, num_suites);
+
+ num_suites = 0;
+ count = pos;
+ pos += 2;
+
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ if (num_suites == 0) {
+ wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+ WPA_PUT_LE16(count, num_suites);
+
+ /* RSN Capabilities */
+ capab = 0;
+ if (conf->rsn_preauth)
+ capab |= WPA_CAPABILITY_PREAUTH;
+ if (conf->peerkey)
+ capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
+ if (conf->wme_enabled) {
+ /* 4 PTKSA replay counters when using WME */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+#ifdef CONFIG_IEEE80211W
+ if (conf->ieee80211w != WPA_NO_IEEE80211W) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (conf->ieee80211w == IEEE80211W_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#endif /* CONFIG_IEEE80211W */
+ WPA_PUT_LE16(pos, capab);
+ pos += 2;
+
+ if (pmkid) {
+ if (pos + 2 + PMKID_LEN > buf + len)
+ return -1;
+ /* PMKID Count */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ os_memcpy(pos, pmkid, PMKID_LEN);
+ pos += PMKID_LEN;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ if (conf->ieee80211w != WPA_NO_IEEE80211W) {
+ if (pos + 2 + 4 > buf + len)
+ return -1;
+ if (pmkid == NULL) {
+ /* PMKID Count */
+ WPA_PUT_LE16(pos, 0);
+ pos += 2;
+ }
+
+ /* Management Group Cipher Suite */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+ pos += RSN_SELECTOR_LEN;
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ hdr->len = (pos - buf) - 2;
+
+ return pos - buf;
+}
+
+
+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
+{
+ u8 *pos, buf[128];
+ int res;
+
+ pos = buf;
+
+ if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
+ res = wpa_write_rsn_ie(&wpa_auth->conf,
+ pos, buf + sizeof(buf) - pos, NULL);
+ if (res < 0)
+ return res;
+ pos += res;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (wpa_auth->conf.wpa_key_mgmt &
+ (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
+ res = wpa_write_mdie(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
+ }
+#endif /* CONFIG_IEEE80211R */
+ if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
+ res = wpa_write_wpa_ie(&wpa_auth->conf,
+ pos, buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
+ }
+
+ os_free(wpa_auth->wpa_ie);
+ wpa_auth->wpa_ie = os_malloc(pos - buf);
+ if (wpa_auth->wpa_ie == NULL)
+ return -1;
+ os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
+ wpa_auth->wpa_ie_len = pos - buf;
+
+ return 0;
+}
+
+
+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
+ const u8 *data2, size_t data2_len)
+{
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
+ RSN_SELECTOR_PUT(pos, kde);
+ pos += RSN_SELECTOR_LEN;
+ os_memcpy(pos, data, data_len);
+ pos += data_len;
+ if (data2) {
+ os_memcpy(pos, data2, data2_len);
+ pos += data2_len;
+ }
+ return pos;
+}
+
+
+static int wpa_selector_to_bitfield(const u8 *s)
+{
+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
+ return WPA_CIPHER_NONE;
+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
+ return WPA_CIPHER_WEP40;
+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
+ return WPA_CIPHER_TKIP;
+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
+ return WPA_CIPHER_CCMP;
+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
+ return WPA_CIPHER_WEP104;
+ return 0;
+}
+
+
+static int wpa_key_mgmt_to_bitfield(const u8 *s)
+{
+ if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
+ return WPA_KEY_MGMT_IEEE8021X;
+ if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+ return WPA_KEY_MGMT_PSK;
+ if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
+ return WPA_KEY_MGMT_WPA_NONE;
+ return 0;
+}
+
+
+static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+ struct wpa_ie_data *data)
+{
+ const struct wpa_ie_hdr *hdr;
+ const u8 *pos;
+ int left;
+ int i, count;
+
+ os_memset(data, 0, sizeof(*data));
+ data->pairwise_cipher = WPA_CIPHER_TKIP;
+ data->group_cipher = WPA_CIPHER_TKIP;
+ data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ data->mgmt_group_cipher = 0;
+
+ if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
+ return -1;
+
+ hdr = (const struct wpa_ie_hdr *) wpa_ie;
+
+ if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
+ hdr->len != wpa_ie_len - 2 ||
+ RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
+ WPA_GET_LE16(hdr->version) != WPA_VERSION) {
+ return -2;
+ }
+
+ pos = (const u8 *) (hdr + 1);
+ left = wpa_ie_len - sizeof(*hdr);
+
+ if (left >= WPA_SELECTOR_LEN) {
+ data->group_cipher = wpa_selector_to_bitfield(pos);
+ pos += WPA_SELECTOR_LEN;
+ left -= WPA_SELECTOR_LEN;
+ } else if (left > 0)
+ return -3;
+
+ if (left >= 2) {
+ data->pairwise_cipher = 0;
+ count = WPA_GET_LE16(pos);
+ pos += 2;
+ left -= 2;
+ if (count == 0 || left < count * WPA_SELECTOR_LEN)
+ return -4;
+ for (i = 0; i < count; i++) {
+ data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
+ pos += WPA_SELECTOR_LEN;
+ left -= WPA_SELECTOR_LEN;
+ }
+ } else if (left == 1)
+ return -5;
+
+ if (left >= 2) {
+ data->key_mgmt = 0;
+ count = WPA_GET_LE16(pos);
+ pos += 2;
+ left -= 2;
+ if (count == 0 || left < count * WPA_SELECTOR_LEN)
+ return -6;
+ for (i = 0; i < count; i++) {
+ data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
+ pos += WPA_SELECTOR_LEN;
+ left -= WPA_SELECTOR_LEN;
+ }
+ } else if (left == 1)
+ return -7;
+
+ if (left >= 2) {
+ data->capabilities = WPA_GET_LE16(pos);
+ pos += 2;
+ left -= 2;
+ }
+
+ if (left > 0) {
+ return -8;
+ }
+
+ return 0;
+}
+
+
+struct wpa_auth_okc_iter_data {
+ struct rsn_pmksa_cache_entry *pmksa;
+ const u8 *aa;
+ const u8 *spa;
+ const u8 *pmkid;
+};
+
+
+static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
+{
+ struct wpa_auth_okc_iter_data *data = ctx;
+ data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
+ data->pmkid);
+ if (data->pmksa)
+ return 1;
+ return 0;
+}
+
+
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *mdie, size_t mdie_len)
+{
+ struct wpa_ie_data data;
+ int ciphers, key_mgmt, res, version;
+ u32 selector;
+ size_t i;
+ const u8 *pmkid = NULL;
+
+ if (wpa_auth == NULL || sm == NULL)
+ return WPA_NOT_ENABLED;
+
+ if (wpa_ie == NULL || wpa_ie_len < 1)
+ return WPA_INVALID_IE;
+
+ if (wpa_ie[0] == WLAN_EID_RSN)
+ version = WPA_PROTO_RSN;
+ else
+ version = WPA_PROTO_WPA;
+
+ if (!(wpa_auth->conf.wpa & version)) {
+ wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
+ version, MAC2STR(sm->addr));
+ return WPA_INVALID_PROTO;
+ }
+
+ if (version == WPA_PROTO_RSN) {
+ res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+
+ selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ if (0) {
+ }
+#ifdef CONFIG_IEEE80211R
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+ selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
+ selector = RSN_AUTH_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+ selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+ else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+ selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
+ selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
+
+ selector = RSN_CIPHER_SUITE_CCMP;
+ if (data.pairwise_cipher & WPA_CIPHER_CCMP)
+ selector = RSN_CIPHER_SUITE_CCMP;
+ else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
+ selector = RSN_CIPHER_SUITE_TKIP;
+ else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
+ selector = RSN_CIPHER_SUITE_WEP104;
+ else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
+ selector = RSN_CIPHER_SUITE_WEP40;
+ else if (data.pairwise_cipher & WPA_CIPHER_NONE)
+ selector = RSN_CIPHER_SUITE_NONE;
+ wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
+
+ selector = RSN_CIPHER_SUITE_CCMP;
+ if (data.group_cipher & WPA_CIPHER_CCMP)
+ selector = RSN_CIPHER_SUITE_CCMP;
+ else if (data.group_cipher & WPA_CIPHER_TKIP)
+ selector = RSN_CIPHER_SUITE_TKIP;
+ else if (data.group_cipher & WPA_CIPHER_WEP104)
+ selector = RSN_CIPHER_SUITE_WEP104;
+ else if (data.group_cipher & WPA_CIPHER_WEP40)
+ selector = RSN_CIPHER_SUITE_WEP40;
+ else if (data.group_cipher & WPA_CIPHER_NONE)
+ selector = RSN_CIPHER_SUITE_NONE;
+ wpa_auth->dot11RSNAGroupCipherSelected = selector;
+ } else {
+ res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
+
+ selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+ selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
+ selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
+
+ selector = WPA_CIPHER_SUITE_TKIP;
+ if (data.pairwise_cipher & WPA_CIPHER_CCMP)
+ selector = WPA_CIPHER_SUITE_CCMP;
+ else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
+ selector = WPA_CIPHER_SUITE_TKIP;
+ else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
+ selector = WPA_CIPHER_SUITE_WEP104;
+ else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
+ selector = WPA_CIPHER_SUITE_WEP40;
+ else if (data.pairwise_cipher & WPA_CIPHER_NONE)
+ selector = WPA_CIPHER_SUITE_NONE;
+ wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
+
+ selector = WPA_CIPHER_SUITE_TKIP;
+ if (data.group_cipher & WPA_CIPHER_CCMP)
+ selector = WPA_CIPHER_SUITE_CCMP;
+ else if (data.group_cipher & WPA_CIPHER_TKIP)
+ selector = WPA_CIPHER_SUITE_TKIP;
+ else if (data.group_cipher & WPA_CIPHER_WEP104)
+ selector = WPA_CIPHER_SUITE_WEP104;
+ else if (data.group_cipher & WPA_CIPHER_WEP40)
+ selector = WPA_CIPHER_SUITE_WEP40;
+ else if (data.group_cipher & WPA_CIPHER_NONE)
+ selector = WPA_CIPHER_SUITE_NONE;
+ wpa_auth->dot11RSNAGroupCipherSelected = selector;
+ }
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
+ MACSTR " (res=%d)", MAC2STR(sm->addr), res);
+ wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
+ return WPA_INVALID_IE;
+ }
+
+ if (data.group_cipher != wpa_auth->conf.wpa_group) {
+ wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
+ MACSTR, data.group_cipher, MAC2STR(sm->addr));
+ return WPA_INVALID_GROUP;
+ }
+
+ key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
+ if (!key_mgmt) {
+ wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
+ MACSTR, data.key_mgmt, MAC2STR(sm->addr));
+ return WPA_INVALID_AKMP;
+ }
+ if (0) {
+ }
+#ifdef CONFIG_IEEE80211R
+ else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+ else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+ else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ else
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+ if (version == WPA_PROTO_RSN)
+ ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
+ else
+ ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
+ if (!ciphers) {
+ wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
+ "from " MACSTR,
+ version == WPA_PROTO_RSN ? "RSN" : "WPA",
+ data.pairwise_cipher, MAC2STR(sm->addr));
+ return WPA_INVALID_PAIRWISE;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ if (wpa_auth->conf.ieee80211w == WPA_IEEE80211W_REQUIRED) {
+ if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_DEBUG, "Management frame protection "
+ "required, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+
+ if (ciphers & WPA_CIPHER_TKIP) {
+ wpa_printf(MSG_DEBUG, "Management frame protection "
+ "cannot use TKIP");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+
+ if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+ wpa_printf(MSG_DEBUG, "Unsupported management group "
+ "cipher %d", data.mgmt_group_cipher);
+ return WPA_INVALID_MGMT_GROUP_CIPHER;
+ }
+ }
+
+ if (wpa_auth->conf.ieee80211w == WPA_NO_IEEE80211W ||
+ !(data.capabilities & WPA_CAPABILITY_MFPC))
+ sm->mgmt_frame_prot = 0;
+ else
+ sm->mgmt_frame_prot = 1;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
+ wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
+ "MDIE not included");
+ return WPA_INVALID_MDIE;
+ }
+ if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
+ "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
+ return WPA_INVALID_MDIE;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (ciphers & WPA_CIPHER_CCMP)
+ sm->pairwise = WPA_CIPHER_CCMP;
+ else
+ sm->pairwise = WPA_CIPHER_TKIP;
+
+ /* TODO: clear WPA/WPA2 state if STA changes from one to another */
+ if (wpa_ie[0] == WLAN_EID_RSN)
+ sm->wpa = WPA_VERSION_WPA2;
+ else
+ sm->wpa = WPA_VERSION_WPA;
+
+ sm->pmksa = NULL;
+ for (i = 0; i < data.num_pmkid; i++) {
+ wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
+ &data.pmkid[i * PMKID_LEN], PMKID_LEN);
+ sm->pmksa = pmksa_cache_get(wpa_auth->pmksa, sm->addr,
+ &data.pmkid[i * PMKID_LEN]);
+ if (sm->pmksa) {
+ pmkid = sm->pmksa->pmkid;
+ break;
+ }
+ }
+ for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
+ i < data.num_pmkid; i++) {
+ struct wpa_auth_okc_iter_data idata;
+ idata.pmksa = NULL;
+ idata.aa = wpa_auth->addr;
+ idata.spa = sm->addr;
+ idata.pmkid = &data.pmkid[i * PMKID_LEN];
+ wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
+ if (idata.pmksa) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "OKC match for PMKID");
+ sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
+ idata.pmksa,
+ wpa_auth->addr,
+ idata.pmkid);
+ pmkid = idata.pmkid;
+ break;
+ }
+ }
+ if (sm->pmksa) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PMKID found from PMKSA cache "
+ "eap_type=%d vlan_id=%d",
+ sm->pmksa->eap_type_authsrv,
+ sm->pmksa->vlan_id);
+ os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
+ }
+
+ if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
+ os_free(sm->wpa_ie);
+ sm->wpa_ie = os_malloc(wpa_ie_len);
+ if (sm->wpa_ie == NULL)
+ return WPA_ALLOC_FAIL;
+ }
+ os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
+ sm->wpa_ie_len = wpa_ie_len;
+
+ return WPA_IE_OK;
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (pos[1] == 0)
+ return 1;
+
+ if (pos[1] >= 6 &&
+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+ pos[2 + WPA_SELECTOR_LEN] == 1 &&
+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ ie->wpa_ie = pos;
+ ie->wpa_ie_len = pos[1] + 2;
+ return 0;
+ }
+
+ if (pos + 1 + RSN_SELECTOR_LEN < end &&
+ pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+#ifdef CONFIG_PEERKEY
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
+ ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
+ ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+ ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
+ ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+ ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
+ ie->error = pos + 2 + RSN_SELECTOR_LEN;
+ ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211W
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+ const u8 *pos, *end;
+ int ret = 0;
+
+ os_memset(ie, 0, sizeof(*ie));
+ for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+ if (pos[0] == 0xdd &&
+ ((pos == buf + len - 1) || pos[1] == 0)) {
+ /* Ignore padding */
+ break;
+ }
+ if (pos + 2 + pos[1] > end) {
+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+ "underflow (ie=%d len=%d pos=%d)",
+ pos[0], pos[1], (int) (pos - buf));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
+ buf, len);
+ ret = -1;
+ break;
+ }
+ if (*pos == WLAN_EID_RSN) {
+ ie->rsn_ie = pos;
+ ie->rsn_ie_len = pos[1] + 2;
+#ifdef CONFIG_IEEE80211R
+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+ ie->mdie = pos;
+ ie->mdie_len = pos[1] + 2;
+#endif /* CONFIG_IEEE80211R */
+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+ ret = wpa_parse_generic(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+ "Key Data IE", pos, 2 + pos[1]);
+ }
+ }
+
+ return ret;
+}
+
+
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
+{
+ return sm ? sm->mgmt_frame_prot : 0;
+}
diff --git a/contrib/wpa/hostapd/wpa_auth_ie.h b/contrib/wpa/hostapd/wpa_auth_ie.h
new file mode 100644
index 0000000..9968d2d
--- /dev/null
+++ b/contrib/wpa/hostapd/wpa_auth_ie.h
@@ -0,0 +1,54 @@
+/*
+ * hostapd - WPA/RSN IE and KDE definitions
+ * 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.
+ */
+
+#ifndef WPA_AUTH_IE_H
+#define WPA_AUTH_IE_H
+
+struct wpa_eapol_ie_parse {
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ const u8 *rsn_ie;
+ size_t rsn_ie_len;
+ const u8 *pmkid;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *mac_addr;
+ size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+ const u8 *smk;
+ size_t smk_len;
+ const u8 *nonce;
+ size_t nonce_len;
+ const u8 *lifetime;
+ size_t lifetime_len;
+ const u8 *error;
+ size_t error_len;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+ const u8 *igtk;
+ size_t igtk_len;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+ const u8 *mdie;
+ size_t mdie_len;
+#endif /* CONFIG_IEEE80211R */
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len,
+ struct wpa_eapol_ie_parse *ie);
+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
+ const u8 *data2, size_t data2_len);
+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
+
+#endif /* WPA_AUTH_IE_H */
diff --git a/contrib/wpa/hostapd/wpa_ft.c b/contrib/wpa/hostapd/wpa_ft.c
new file mode 100644
index 0000000..9cf6713
--- /dev/null
+++ b/contrib/wpa/hostapd/wpa_ft.c
@@ -0,0 +1,1499 @@
+/*
+ * hostapd - IEEE 802.11r - Fast BSS Transition
+ * 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"
+
+#include "common.h"
+#include "config.h"
+#include "wpa.h"
+#include "aes_wrap.h"
+#include "ieee802_11.h"
+#include "defs.h"
+#include "wpa_auth_i.h"
+#include "wpa_auth_ie.h"
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
+ const u8 *data, size_t data_len)
+{
+ if (wpa_auth->cb.send_ether == NULL)
+ return -1;
+ return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
+ data, data_len);
+}
+
+
+static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
+ const u8 *dst, const u8 *data, size_t data_len)
+{
+ if (wpa_auth->cb.send_ft_action == NULL)
+ return -1;
+ return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
+ data, data_len);
+}
+
+
+static struct wpa_state_machine *
+wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+ if (wpa_auth->cb.add_sta == NULL)
+ return NULL;
+ return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
+}
+
+
+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+ u8 capab;
+ if (len < 2 + sizeof(struct rsn_mdie))
+ return -1;
+
+ *pos++ = WLAN_EID_MOBILITY_DOMAIN;
+ *pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
+ os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
+ pos += MOBILITY_DOMAIN_ID_LEN;
+ capab = RSN_FT_CAPAB_FT_OVER_DS;
+ *pos++ = capab;
+
+ return pos - buf;
+}
+
+
+static int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
+ size_t r0kh_id_len,
+ const u8 *anonce, const u8 *snonce,
+ u8 *buf, size_t len, const u8 *subelem,
+ size_t subelem_len)
+{
+ u8 *pos = buf, *ielen;
+ struct rsn_ftie *hdr;
+
+ if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
+ subelem_len)
+ return -1;
+
+ *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
+ ielen = pos++;
+
+ hdr = (struct rsn_ftie *) pos;
+ os_memset(hdr, 0, sizeof(*hdr));
+ pos += sizeof(*hdr);
+ WPA_PUT_LE16(hdr->mic_control, 0);
+ if (anonce)
+ os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+ if (snonce)
+ os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+
+ /* Optional Parameters */
+ *pos++ = FTIE_SUBELEM_R1KH_ID;
+ *pos++ = FT_R1KH_ID_LEN;
+ os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
+ pos += FT_R1KH_ID_LEN;
+
+ if (r0kh_id) {
+ *pos++ = FTIE_SUBELEM_R0KH_ID;
+ *pos++ = r0kh_id_len;
+ os_memcpy(pos, r0kh_id, r0kh_id_len);
+ pos += r0kh_id_len;
+ }
+
+ if (subelem) {
+ os_memcpy(pos, subelem, subelem_len);
+ pos += subelem_len;
+ }
+
+ *ielen = pos - buf - 2;
+
+ return pos - buf;
+}
+
+
+struct wpa_ft_pmk_r0_sa {
+ struct wpa_ft_pmk_r0_sa *next;
+ u8 pmk_r0[PMK_LEN];
+ u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 spa[ETH_ALEN];
+ /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+ int pmk_r1_pushed;
+};
+
+struct wpa_ft_pmk_r1_sa {
+ struct wpa_ft_pmk_r1_sa *next;
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 spa[ETH_ALEN];
+ /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+};
+
+struct wpa_ft_pmk_cache {
+ struct wpa_ft_pmk_r0_sa *pmk_r0;
+ struct wpa_ft_pmk_r1_sa *pmk_r1;
+};
+
+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
+{
+ struct wpa_ft_pmk_cache *cache;
+
+ cache = os_zalloc(sizeof(*cache));
+
+ return cache;
+}
+
+
+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
+{
+ struct wpa_ft_pmk_r0_sa *r0, *r0prev;
+ struct wpa_ft_pmk_r1_sa *r1, *r1prev;
+
+ r0 = cache->pmk_r0;
+ while (r0) {
+ r0prev = r0;
+ r0 = r0->next;
+ os_memset(r0prev->pmk_r0, 0, PMK_LEN);
+ os_free(r0prev);
+ }
+
+ r1 = cache->pmk_r1;
+ while (r1) {
+ r1prev = r1;
+ r1 = r1->next;
+ os_memset(r1prev->pmk_r1, 0, PMK_LEN);
+ os_free(r1prev);
+ }
+
+ os_free(cache);
+}
+
+
+static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r0,
+ const u8 *pmk_r0_name)
+{
+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ struct wpa_ft_pmk_r0_sa *r0;
+
+ /* TODO: add expiration and limit on number of entries in cache */
+
+ r0 = os_zalloc(sizeof(*r0));
+ if (r0 == NULL)
+ return -1;
+
+ os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
+ os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
+ os_memcpy(r0->spa, spa, ETH_ALEN);
+
+ r0->next = cache->pmk_r0;
+ cache->pmk_r0 = r0;
+
+ return 0;
+}
+
+
+static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r0_name,
+ u8 *pmk_r0)
+{
+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ struct wpa_ft_pmk_r0_sa *r0;
+
+ r0 = cache->pmk_r0;
+ while (r0) {
+ if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
+ os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
+ == 0) {
+ os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
+ return 0;
+ }
+
+ r0 = r0->next;
+ }
+
+ return -1;
+}
+
+
+static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1,
+ const u8 *pmk_r1_name)
+{
+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ struct wpa_ft_pmk_r1_sa *r1;
+
+ /* TODO: add expiration and limit on number of entries in cache */
+
+ r1 = os_zalloc(sizeof(*r1));
+ if (r1 == NULL)
+ return -1;
+
+ os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
+ os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+ os_memcpy(r1->spa, spa, ETH_ALEN);
+
+ r1->next = cache->pmk_r1;
+ cache->pmk_r1 = r1;
+
+ return 0;
+}
+
+
+static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1)
+{
+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ struct wpa_ft_pmk_r1_sa *r1;
+
+ r1 = cache->pmk_r1;
+ while (r1) {
+ if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
+ os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
+ == 0) {
+ os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
+ return 0;
+ }
+
+ r1 = r1->next;
+ }
+
+ return -1;
+}
+
+
+static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *s1kh_id, const u8 *r0kh_id,
+ size_t r0kh_id_len, const u8 *pmk_r0_name)
+{
+ struct ft_remote_r0kh *r0kh;
+ struct ft_r0kh_r1kh_pull_frame frame, f;
+
+ r0kh = wpa_auth->conf.r0kh_list;
+ while (r0kh) {
+ if (r0kh->id_len == r0kh_id_len &&
+ os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
+ break;
+ r0kh = r0kh->next;
+ }
+ if (r0kh == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
+ "address " MACSTR, MAC2STR(r0kh->addr));
+
+ os_memset(&frame, 0, sizeof(frame));
+ frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+ frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
+ frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
+ os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+
+ /* aes_wrap() does not support inplace encryption, so use a temporary
+ * buffer for the data. */
+ if (os_get_random(f.nonce, sizeof(f.nonce))) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+ "nonce");
+ return -1;
+ }
+ os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
+ os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+ os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+
+ if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+ f.nonce, frame.nonce) < 0)
+ return -1;
+
+ wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
+
+ return 0;
+}
+
+
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
+ struct wpa_ptk *ptk)
+{
+ u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+ const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
+ const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
+ size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
+ const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
+ const u8 *ssid = sm->wpa_auth->conf.ssid;
+ size_t ssid_len = sm->wpa_auth->conf.ssid_len;
+
+
+ if (sm->xxkey_len == 0) {
+ wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
+ "derivation");
+ return -1;
+ }
+
+ wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+ r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name);
+
+ wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, pmk_r1_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_name);
+
+ wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, pmk_r1_name,
+ (u8 *) ptk, sizeof(*ptk), ptk_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk));
+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+ return 0;
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_auth->cb.get_seqnum == NULL)
+ return -1;
+ return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_auth->cb.get_seqnum_igtk == NULL)
+ return -1;
+ return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len, pad_len;
+ const u8 *key;
+ size_t key_len;
+ u8 keybuf[32];
+
+ key_len = gsm->GTK_len;
+ if (key_len > sizeof(keybuf))
+ return NULL;
+
+ /*
+ * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
+ * than 16 bytes.
+ */
+ pad_len = key_len % 8;
+ if (pad_len)
+ pad_len = 8 - pad_len;
+ if (key_len + pad_len < 16)
+ pad_len += 8;
+ if (pad_len) {
+ os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ os_memset(keybuf + key_len, 0, pad_len);
+ keybuf[key_len] = 0xdd;
+ key_len += pad_len;
+ key = keybuf;
+ } else
+ key = gsm->GTK[gsm->GN - 1];
+
+ /*
+ * Sub-elem ID[1] | Length[1] | Key Info[1] | Key Length[1] | RSC[8] |
+ * Key[5..32].
+ */
+ subelem_len = 12 + key_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ subelem[0] = FTIE_SUBELEM_GTK;
+ subelem[1] = 10 + key_len + 8;
+ subelem[2] = gsm->GN & 0x03; /* Key ID in B0-B1 of Key Info */
+ subelem[3] = gsm->GTK_len;
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 4);
+ if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 12)) {
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem, *pos;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+
+ /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
+ * Key[16+8] */
+ subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ pos = subelem;
+ *pos++ = FTIE_SUBELEM_IGTK;
+ *pos++ = subelem_len - 2;
+ WPA_PUT_LE16(pos, gsm->GN_igtk);
+ pos += 2;
+ wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
+ pos += 6;
+ *pos++ = WPA_IGTK_LEN;
+ if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+ gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
+ size_t max_len, int auth_alg)
+{
+ u8 *end, *mdie, *ftie, *rsnie, *r0kh_id, *subelem = NULL;
+ size_t mdie_len, ftie_len, rsnie_len, r0kh_id_len, subelem_len = 0;
+ int res;
+ struct wpa_auth_config *conf;
+ struct rsn_ftie *_ftie;
+
+ if (sm == NULL)
+ return pos;
+
+ conf = &sm->wpa_auth->conf;
+
+ if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+ sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
+ return pos;
+
+ end = pos + max_len;
+
+ /* RSN */
+ res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
+ if (res < 0)
+ return pos;
+ rsnie = pos;
+ rsnie_len = res;
+ pos += res;
+
+ /* Mobility Domain Information */
+ res = wpa_write_mdie(conf, pos, end - pos);
+ if (res < 0)
+ return pos;
+ mdie = pos;
+ mdie_len = res;
+ pos += res;
+
+ /* Fast BSS Transition Information */
+ if (auth_alg == WLAN_AUTH_FT) {
+ subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+ r0kh_id = sm->r0kh_id;
+ r0kh_id_len = sm->r0kh_id_len;
+#ifdef CONFIG_IEEE80211W
+ if (sm->mgmt_frame_prot) {
+ u8 *igtk;
+ size_t igtk_len;
+ u8 *nbuf;
+ igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
+ if (igtk == NULL) {
+ os_free(subelem);
+ return pos;
+ }
+ nbuf = os_realloc(subelem, subelem_len + igtk_len);
+ if (nbuf == NULL) {
+ os_free(subelem);
+ os_free(igtk);
+ return pos;
+ }
+ subelem = nbuf;
+ os_memcpy(subelem + subelem_len, igtk, igtk_len);
+ subelem_len += igtk_len;
+ os_free(igtk);
+ }
+#endif /* CONFIG_IEEE80211W */
+ } else {
+ r0kh_id = conf->r0_key_holder;
+ r0kh_id_len = conf->r0_key_holder_len;
+ }
+ res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, NULL, NULL, pos,
+ end - pos, subelem, subelem_len);
+ os_free(subelem);
+ if (res < 0)
+ return pos;
+ ftie = pos;
+ ftie_len = res;
+ pos += res;
+
+ _ftie = (struct rsn_ftie *) (ftie + 2);
+ _ftie->mic_control[1] = 3; /* Information element count */
+ if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+ mdie, mdie_len, ftie, ftie_len,
+ rsnie, rsnie_len, NULL, 0, _ftie->mic) < 0)
+ wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+
+ return pos;
+}
+
+
+struct wpa_ft_ies {
+ const u8 *mdie;
+ size_t mdie_len;
+ const u8 *ftie;
+ size_t ftie_len;
+ const u8 *r1kh_id;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *r0kh_id;
+ size_t r0kh_id_len;
+ const u8 *rsn;
+ size_t rsn_len;
+ const u8 *rsn_pmkid;
+};
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+ struct wpa_ft_ies *parse)
+{
+ const u8 *end, *pos;
+
+ parse->ftie = ie;
+ parse->ftie_len = ie_len;
+
+ pos = ie + sizeof(struct rsn_ftie);
+ end = ie + ie_len;
+
+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+ switch (pos[0]) {
+ case FTIE_SUBELEM_R1KH_ID:
+ if (pos[1] != FT_R1KH_ID_LEN) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+ "length in FTIE: %d", pos[1]);
+ return -1;
+ }
+ parse->r1kh_id = pos + 2;
+ break;
+ case FTIE_SUBELEM_GTK:
+ parse->gtk = pos + 2;
+ parse->gtk_len = pos[1];
+ break;
+ case FTIE_SUBELEM_R0KH_ID:
+ if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+ "length in FTIE: %d", pos[1]);
+ return -1;
+ }
+ parse->r0kh_id = pos + 2;
+ parse->r0kh_id_len = pos[1];
+ break;
+ }
+
+ pos += 2 + pos[1];
+ }
+
+ return 0;
+}
+
+
+static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+ struct wpa_ft_ies *parse)
+{
+ const u8 *end, *pos;
+ struct wpa_ie_data data;
+ int ret;
+
+ os_memset(parse, 0, sizeof(*parse));
+ if (ies == NULL)
+ return 0;
+
+ pos = ies;
+ end = ies + ies_len;
+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+ switch (pos[0]) {
+ case WLAN_EID_RSN:
+ parse->rsn = pos + 2;
+ parse->rsn_len = pos[1];
+ ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+ parse->rsn_len + 2,
+ &data);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+ "RSN IE: %d", ret);
+ return -1;
+ }
+ if (data.num_pmkid == 1 && data.pmkid)
+ parse->rsn_pmkid = data.pmkid;
+ break;
+ case WLAN_EID_MOBILITY_DOMAIN:
+ parse->mdie = pos + 2;
+ parse->mdie_len = pos[1];
+ break;
+ case WLAN_EID_FAST_BSS_TRANSITION:
+ if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+ return -1;
+ break;
+ }
+
+ pos += 2 + pos[1];
+ }
+
+ return 0;
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+ int vlan_id,
+ const char *alg, const u8 *addr, int idx,
+ u8 *key, size_t key_len)
+{
+ if (wpa_auth->cb.set_key == NULL)
+ return -1;
+ return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+ key, key_len);
+}
+
+
+static void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+{
+ char *alg;
+ int klen;
+
+ /* MLME-SETKEYS.request(PTK) */
+ if (sm->pairwise == WPA_CIPHER_TKIP) {
+ alg = "TKIP";
+ klen = 32;
+ } else if (sm->pairwise == WPA_CIPHER_CCMP) {
+ alg = "CCMP";
+ klen = 16;
+ } else
+ return;
+
+ /* FIX: add STA entry to kernel/driver here? The set_key will fail
+ * most likely without this.. At the moment, STA entry is added only
+ * after association has been completed. Alternatively, could
+ * re-configure PTK at that point(?).
+ */
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+ sm->PTK.tk1, klen))
+ return;
+
+ /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
+ sm->pairwise_set = TRUE;
+}
+
+
+static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
+ const u8 *ies, size_t ies_len,
+ u8 **resp_ies, size_t *resp_ies_len)
+{
+ struct rsn_mdie *mdie;
+ struct rsn_ftie *ftie;
+ u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+ struct wpa_auth_config *conf;
+ struct wpa_ft_ies parse;
+ size_t buflen;
+ int ret;
+ u8 *pos, *end;
+
+ *resp_ies = NULL;
+ *resp_ies_len = 0;
+
+ sm->pmk_r1_name_valid = 0;
+ conf = &sm->wpa_auth->conf;
+
+ wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
+ ies, ies_len);
+
+ if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ mdie = (struct rsn_mdie *) parse.mdie;
+ if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+ os_memcmp(mdie->mobility_domain,
+ sm->wpa_auth->conf.mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+ return WLAN_STATUS_INVALID_MDIE;
+ }
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+
+ if (parse.r0kh_id == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
+ parse.r0kh_id, parse.r0kh_id_len);
+ os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
+ sm->r0kh_id_len = parse.r0kh_id_len;
+
+ if (parse.rsn_pmkid == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
+ parse.rsn_pmkid, WPA_PMK_NAME_LEN);
+ wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+ sm->wpa_auth->conf.r1_key_holder, sm->addr,
+ pmk_r1_name);
+ wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
+ pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1) <
+ 0) {
+ if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
+ sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Did not have matching "
+ "PMK-R1 and unknown R0KH-ID");
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+
+ /*
+ * TODO: Should return "status pending" (and the caller should
+ * not send out response now). The real response will be sent
+ * once the response from R0KH is received.
+ */
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
+ sm->pmk_r1_name_valid = 1;
+ os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ if (os_get_random(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+ "ANonce");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+ sm->SNonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
+ sm->ANonce, WPA_NONCE_LEN);
+
+ wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, pmk_r1_name,
+ (u8 *) &sm->PTK, sizeof(sm->PTK), ptk_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
+ (u8 *) &sm->PTK, sizeof(sm->PTK));
+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+ wpa_ft_install_ptk(sm);
+
+ buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+ 2 + FT_R1KH_ID_LEN + 200;
+ *resp_ies = os_zalloc(buflen);
+ if (*resp_ies == NULL) {
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ pos = *resp_ies;
+ end = *resp_ies + buflen;
+
+ ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
+ if (ret < 0) {
+ os_free(*resp_ies);
+ *resp_ies = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ pos += ret;
+
+ ret = wpa_write_mdie(conf, pos, end - pos);
+ if (ret < 0) {
+ os_free(*resp_ies);
+ *resp_ies = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ pos += ret;
+
+ ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
+ sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+ if (ret < 0) {
+ os_free(*resp_ies);
+ *resp_ies = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ pos += ret;
+
+ *resp_ies_len = pos - *resp_ies;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+ u16 auth_transaction, const u8 *ies, size_t ies_len,
+ void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+ u16 auth_transaction, u16 status,
+ const u8 *ies, size_t ies_len),
+ void *ctx)
+{
+ u16 status;
+ u8 *resp_ies;
+ size_t resp_ies_len;
+
+ if (sm == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
+ "WPA SM not available");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
+ " BSSID=" MACSTR " transaction=%d",
+ MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
+ status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
+ &resp_ies_len);
+
+ wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
+ " auth_transaction=%d status=%d",
+ MAC2STR(sm->addr), auth_transaction + 1, status);
+ wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
+ cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
+ resp_ies, resp_ies_len);
+ os_free(resp_ies);
+}
+
+
+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+ size_t ies_len)
+{
+ struct wpa_ft_ies parse;
+ struct rsn_mdie *mdie;
+ struct rsn_ftie *ftie;
+ u8 mic[16];
+
+ if (sm == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
+
+ if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (parse.rsn == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (parse.rsn_pmkid == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+
+ if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+ {
+ wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
+ "with the PMKR1Name derived from auth request");
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+
+ mdie = (struct rsn_mdie *) parse.mdie;
+ if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+ os_memcmp(mdie->mobility_domain,
+ sm->wpa_auth->conf.mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+ return WLAN_STATUS_INVALID_MDIE;
+ }
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ /*
+ * Assume that MDIE, FTIE, and RSN IE are protected and that there is
+ * no RIC, so total of 3 protected IEs.
+ */
+ if (ftie->mic_control[1] != 3) {
+ wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in FTIE (%d)",
+ ftie->mic_control[1]);
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+ parse.mdie - 2, parse.mdie_len + 2,
+ parse.ftie - 2, parse.ftie_len + 2,
+ parse.rsn - 2, parse.rsn_len + 2, NULL, 0,
+ mic) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
+{
+ const u8 *sta_addr, *target_ap;
+ const u8 *ies;
+ size_t ies_len;
+ u8 action;
+ struct ft_rrb_frame *frame;
+
+ if (sm == NULL)
+ return -1;
+
+ /*
+ * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
+ * FT Request action frame body[variable]
+ */
+
+ if (len < 14) {
+ wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
+ "(len=%lu)", (unsigned long) len);
+ return -1;
+ }
+
+ action = data[1];
+ sta_addr = data + 2;
+ target_ap = data + 8;
+ ies = data + 14;
+ ies_len = len - 14;
+
+ wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
+ " Target AP=" MACSTR " Action=%d)",
+ MAC2STR(sta_addr), MAC2STR(target_ap), action);
+
+ if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
+ "STA=" MACSTR " STA-Address=" MACSTR,
+ MAC2STR(sm->addr), MAC2STR(sta_addr));
+ return -1;
+ }
+
+ /*
+ * Do some sanity checking on the target AP address (not own and not
+ * broadcast. This could be extended to filter based on a list of known
+ * APs in the MD (if such a list were configured).
+ */
+ if ((target_ap[0] & 0x01) ||
+ os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
+ "frame");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
+
+ /* RRB - Forward action frame to the target AP */
+ frame = os_malloc(sizeof(*frame) + len);
+ frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+ frame->packet_type = FT_PACKET_REQUEST;
+ frame->action_length = host_to_le16(len);
+ os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
+ os_memcpy(frame + 1, data, len);
+
+ wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
+ sizeof(*frame) + len);
+ os_free(frame);
+
+ return 0;
+}
+
+
+static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
+ const u8 *current_ap, const u8 *sta_addr,
+ const u8 *body, size_t len)
+{
+ struct wpa_state_machine *sm;
+ u16 status;
+ u8 *resp_ies, *pos;
+ size_t resp_ies_len, rlen;
+ struct ft_rrb_frame *frame;
+
+ sm = wpa_ft_add_sta(wpa_auth, sta_addr);
+ if (sm == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
+ "RRB Request");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
+
+ status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
+ &resp_ies_len);
+
+ wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
+ " CurrentAP=" MACSTR " status=%d",
+ MAC2STR(sm->addr), MAC2STR(current_ap), status);
+ wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
+
+ /* RRB - Forward action frame response to the Current AP */
+
+ /*
+ * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
+ * Status_Code[2] FT Request action frame body[variable]
+ */
+ rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
+
+ frame = os_malloc(sizeof(*frame) + rlen);
+ frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+ frame->packet_type = FT_PACKET_RESPONSE;
+ frame->action_length = host_to_le16(rlen);
+ os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
+ pos = (u8 *) (frame + 1);
+ *pos++ = WLAN_ACTION_FT;
+ *pos++ = 2; /* Action: Response */
+ os_memcpy(pos, sta_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ WPA_PUT_LE16(pos, status);
+ pos += 2;
+ if (resp_ies) {
+ os_memcpy(pos, resp_ies, resp_ies_len);
+ os_free(resp_ies);
+ }
+
+ wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
+ sizeof(*frame) + rlen);
+ os_free(frame);
+
+ return 0;
+}
+
+
+static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *data, size_t data_len)
+{
+ struct ft_r0kh_r1kh_pull_frame *frame, f;
+ struct ft_remote_r1kh *r1kh;
+ struct ft_r0kh_r1kh_resp_frame resp, r;
+ u8 pmk_r0[PMK_LEN];
+
+ wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
+
+ if (data_len < sizeof(*frame))
+ return -1;
+
+ r1kh = wpa_auth->conf.r1kh_list;
+ while (r1kh) {
+ if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ r1kh = r1kh->next;
+ }
+ if (r1kh == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
+ "PMK-R1 pull source address " MACSTR,
+ MAC2STR(src_addr));
+ return -1;
+ }
+
+ frame = (struct ft_r0kh_r1kh_pull_frame *) data;
+ /* aes_unwrap() does not support inplace decryption, so use a temporary
+ * buffer for the data. */
+ if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+ frame->nonce, f.nonce) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
+ "request from " MACSTR, MAC2STR(src_addr));
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+ f.nonce, sizeof(f.nonce));
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
+ f.pmk_r0_name, WPA_PMK_NAME_LEN);
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+ MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+
+ os_memset(&resp, 0, sizeof(resp));
+ resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+ resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
+ resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
+ os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
+
+ /* aes_wrap() does not support inplace encryption, so use a temporary
+ * buffer for the data. */
+ os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
+ os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
+ os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
+ if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
+ "PMK-R1 pull");
+ return -1;
+ }
+
+ wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+ r.pmk_r1, r.pmk_r1_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+
+ if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+ r.nonce, resp.nonce) < 0) {
+ os_memset(pmk_r0, 0, PMK_LEN);
+ return -1;
+ }
+
+ os_memset(pmk_r0, 0, PMK_LEN);
+
+ wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
+
+ return 0;
+}
+
+
+static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *data, size_t data_len)
+{
+ struct ft_r0kh_r1kh_resp_frame *frame, f;
+ struct ft_remote_r0kh *r0kh;
+
+ wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
+
+ if (data_len < sizeof(*frame))
+ return -1;
+
+ r0kh = wpa_auth->conf.r0kh_list;
+ while (r0kh) {
+ if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ r0kh = r0kh->next;
+ }
+ if (r0kh == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
+ "PMK-R0 pull response source address " MACSTR,
+ MAC2STR(src_addr));
+ return -1;
+ }
+
+ frame = (struct ft_r0kh_r1kh_resp_frame *) data;
+ /* aes_unwrap() does not support inplace decryption, so use a temporary
+ * buffer for the data. */
+ if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+ frame->nonce, f.nonce) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
+ "response from " MACSTR, MAC2STR(src_addr));
+ return -1;
+ }
+
+ if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
+ != 0) {
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
+ "matching R1KH-ID");
+ return -1;
+ }
+
+ /* TODO: verify that <nonce,s1kh_id> matches with a pending request
+ * and call this requests callback function to finish request
+ * processing */
+
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+ f.nonce, sizeof(f.nonce));
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+ MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
+ f.pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
+ f.pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name);
+ os_memset(f.pmk_r1, 0, PMK_LEN);
+
+ return 0;
+}
+
+
+static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr,
+ const u8 *data, size_t data_len)
+{
+ struct ft_r0kh_r1kh_push_frame *frame, f;
+ struct ft_remote_r0kh *r0kh;
+ struct os_time now;
+ os_time_t tsend;
+
+ wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
+
+ if (data_len < sizeof(*frame))
+ return -1;
+
+ r0kh = wpa_auth->conf.r0kh_list;
+ while (r0kh) {
+ if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ r0kh = r0kh->next;
+ }
+ if (r0kh == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
+ "PMK-R0 push source address " MACSTR,
+ MAC2STR(src_addr));
+ return -1;
+ }
+
+ frame = (struct ft_r0kh_r1kh_push_frame *) data;
+ /* aes_unwrap() does not support inplace decryption, so use a temporary
+ * buffer for the data. */
+ if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+ frame->timestamp, f.timestamp) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
+ MACSTR, MAC2STR(src_addr));
+ return -1;
+ }
+
+ os_get_time(&now);
+ tsend = WPA_GET_LE32(f.timestamp);
+ if ((now.sec > tsend && now.sec - tsend > 60) ||
+ (now.sec < tsend && tsend - now.sec > 60)) {
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
+ "timestamp: sender time %d own time %d\n",
+ (int) tsend, (int) now.sec);
+ return -1;
+ }
+
+ if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
+ != 0) {
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
+ "R1KH-ID (received " MACSTR " own " MACSTR ")",
+ MAC2STR(f.r1kh_id),
+ MAC2STR(wpa_auth->conf.r1_key_holder));
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
+ MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
+ f.pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
+ f.pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name);
+ os_memset(f.pmk_r1, 0, PMK_LEN);
+
+ return 0;
+}
+
+
+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+ const u8 *data, size_t data_len)
+{
+ struct ft_rrb_frame *frame;
+ u16 alen;
+ const u8 *pos, *end, *start;
+ u8 action;
+ const u8 *sta_addr, *target_ap_addr;
+
+ wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
+ MAC2STR(src_addr));
+
+ if (data_len < sizeof(*frame)) {
+ wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
+ (unsigned long) data_len);
+ return -1;
+ }
+
+ pos = data;
+ frame = (struct ft_rrb_frame *) pos;
+ pos += sizeof(*frame);
+
+ alen = le_to_host16(frame->action_length);
+ wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
+ "action_length=%d ap_address=" MACSTR,
+ frame->frame_type, frame->packet_type, alen,
+ MAC2STR(frame->ap_address));
+
+ if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
+ /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
+ wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
+ "unrecognized type %d", frame->frame_type);
+ return -1;
+ }
+
+ if (alen > data_len - sizeof(*frame)) {
+ wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
+ "frame");
+ return -1;
+ }
+
+ if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
+ return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
+ if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
+ return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
+ if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
+ return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
+
+ if (alen < 1 + 1 + 2 * ETH_ALEN) {
+ wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
+ "room for Action Frame body); alen=%lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ start = pos;
+ end = pos + alen;
+
+ if (*pos != WLAN_ACTION_FT) {
+ wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
+ "%d", *pos);
+ return -1;
+ }
+
+ pos++;
+ action = *pos++;
+ sta_addr = pos;
+ pos += ETH_ALEN;
+ target_ap_addr = pos;
+ pos += ETH_ALEN;
+ wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
+ MACSTR " target_ap_addr=" MACSTR,
+ action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
+
+ if (frame->packet_type == FT_PACKET_REQUEST) {
+ wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
+
+ if (action != 1) {
+ wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
+ "RRB Request", action);
+ return -1;
+ }
+
+ if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
+ "RRB Request does not match with own "
+ "address");
+ return -1;
+ }
+
+ if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
+ sta_addr, pos, end - pos) < 0)
+ return -1;
+ } else if (frame->packet_type == FT_PACKET_RESPONSE) {
+ u16 status_code;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
+ "code in RRB Response");
+ return -1;
+ }
+ status_code = WPA_GET_LE16(pos);
+ pos += 2;
+
+ wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
+ "(status_code=%d)", status_code);
+
+ if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
+ "packet_type %d", frame->packet_type);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+ struct wpa_ft_pmk_r0_sa *pmk_r0,
+ struct ft_remote_r1kh *r1kh,
+ const u8 *s1kh_id)
+{
+ struct ft_r0kh_r1kh_push_frame frame, f;
+ struct os_time now;
+
+ os_memset(&frame, 0, sizeof(frame));
+ frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+ frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
+ frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
+ os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+
+ /* aes_wrap() does not support inplace encryption, so use a temporary
+ * buffer for the data. */
+ os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
+ os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+ os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
+ wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
+ s1kh_id, f.pmk_r1, f.pmk_r1_name);
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+ os_get_time(&now);
+ WPA_PUT_LE32(f.timestamp, now.sec);
+ if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+ f.timestamp, frame.timestamp) < 0)
+ return;
+
+ wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+}
+
+
+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+ struct wpa_ft_pmk_r0_sa *r0;
+ struct ft_remote_r1kh *r1kh;
+
+ if (!wpa_auth->conf.pmk_r1_push)
+ return;
+
+ r0 = wpa_auth->ft_pmk_cache->pmk_r0;
+ while (r0) {
+ if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+ break;
+ r0 = r0->next;
+ }
+
+ if (r0 == NULL || r0->pmk_r1_pushed)
+ return;
+ r0->pmk_r1_pushed = 1;
+
+ wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
+ "for STA " MACSTR, MAC2STR(addr));
+
+ r1kh = wpa_auth->conf.r1kh_list;
+ while (r1kh) {
+ wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr);
+ r1kh = r1kh->next;
+ }
+}
+
+#endif /* CONFIG_IEEE80211R */
diff --git a/contrib/wpa/hostapd/wps_hostapd.c b/contrib/wpa/hostapd/wps_hostapd.c
new file mode 100644
index 0000000..a824c16
--- /dev/null
+++ b/contrib/wpa/hostapd/wps_hostapd.c
@@ -0,0 +1,998 @@
+/*
+ * hostapd / WPS integration
+ * 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"
+
+#include "hostapd.h"
+#include "driver.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "wpa_ctrl.h"
+#include "ieee802_11_defs.h"
+#include "sta_info.h"
+#include "eapol_sm.h"
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+#include "wps/wps_dev_attr.h"
+#include "wps_hostapd.h"
+
+
+#ifdef CONFIG_WPS_UPNP
+#include "wps/wps_upnp.h"
+static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
+ struct wps_context *wps);
+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
+#endif /* CONFIG_WPS_UPNP */
+
+
+static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+ size_t psk_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct hostapd_wpa_psk *p;
+ struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+ wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
+ MACSTR, MAC2STR(mac_addr));
+ wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
+
+ if (psk_len != PMK_LEN) {
+ wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
+ (unsigned long) psk_len);
+ return -1;
+ }
+
+ /* Add the new PSK to runtime PSK list */
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return -1;
+ os_memcpy(p->addr, mac_addr, ETH_ALEN);
+ os_memcpy(p->psk, psk, PMK_LEN);
+
+ p->next = ssid->wpa_psk;
+ ssid->wpa_psk = p;
+
+ if (ssid->wpa_psk_file) {
+ FILE *f;
+ char hex[PMK_LEN * 2 + 1];
+ /* Add the new PSK to PSK list file */
+ f = fopen(ssid->wpa_psk_file, "a");
+ if (f == NULL) {
+ wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
+ "'%s'", ssid->wpa_psk_file);
+ return -1;
+ }
+
+ wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
+ fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+ fclose(f);
+ }
+
+ return 0;
+}
+
+
+static int hostapd_wps_set_ie_cb(void *ctx, const u8 *beacon_ie,
+ size_t beacon_ie_len, const u8 *probe_resp_ie,
+ size_t probe_resp_ie_len)
+{
+ struct hostapd_data *hapd = ctx;
+
+ os_free(hapd->wps_beacon_ie);
+ if (beacon_ie_len == 0) {
+ hapd->wps_beacon_ie = NULL;
+ hapd->wps_beacon_ie_len = 0;
+ } else {
+ hapd->wps_beacon_ie = os_malloc(beacon_ie_len);
+ if (hapd->wps_beacon_ie == NULL) {
+ hapd->wps_beacon_ie_len = 0;
+ return -1;
+ }
+ os_memcpy(hapd->wps_beacon_ie, beacon_ie, beacon_ie_len);
+ hapd->wps_beacon_ie_len = beacon_ie_len;
+ }
+ hostapd_set_wps_beacon_ie(hapd, hapd->wps_beacon_ie,
+ hapd->wps_beacon_ie_len);
+
+ os_free(hapd->wps_probe_resp_ie);
+ if (probe_resp_ie_len == 0) {
+ hapd->wps_probe_resp_ie = NULL;
+ hapd->wps_probe_resp_ie_len = 0;
+ } else {
+ hapd->wps_probe_resp_ie = os_malloc(probe_resp_ie_len);
+ if (hapd->wps_probe_resp_ie == NULL) {
+ hapd->wps_probe_resp_ie_len = 0;
+ return -1;
+ }
+ os_memcpy(hapd->wps_probe_resp_ie, probe_resp_ie,
+ probe_resp_ie_len);
+ hapd->wps_probe_resp_ie_len = probe_resp_ie_len;
+ }
+ hostapd_set_wps_probe_resp_ie(hapd, hapd->wps_probe_resp_ie,
+ hapd->wps_probe_resp_ie_len);
+
+ return 0;
+}
+
+
+static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
+ const struct wps_device_data *dev)
+{
+ struct hostapd_data *hapd = ctx;
+ char uuid[40], txt[400];
+ int len;
+ if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+ return;
+ wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
+ len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
+ "%s " MACSTR " [%s|%s|%s|%s|%s|%d-%08X-%d]",
+ uuid, MAC2STR(dev->mac_addr), dev->device_name,
+ dev->manufacturer, dev->model_name,
+ dev->model_number, dev->serial_number,
+ dev->categ, dev->oui, dev->sub_categ);
+ if (len > 0 && len < (int) sizeof(txt))
+ wpa_msg(hapd, MSG_INFO, "%s", txt);
+
+ if (hapd->conf->wps_pin_requests) {
+ FILE *f;
+ struct os_time t;
+ f = fopen(hapd->conf->wps_pin_requests, "a");
+ if (f == NULL)
+ return;
+ os_get_time(&t);
+ fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
+ "\t%d-%08X-%d\n",
+ t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
+ dev->manufacturer, dev->model_name, dev->model_number,
+ dev->serial_number,
+ dev->categ, dev->oui, dev->sub_categ);
+ fclose(f);
+ }
+}
+
+
+static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
+ const u8 *uuid_e)
+{
+ struct hostapd_data *hapd = ctx;
+ char uuid[40];
+ if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+ return;
+ wpa_msg(hapd, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
+ MAC2STR(mac_addr), uuid);
+}
+
+
+static int str_starts(const char *str, const char *start)
+{
+ return os_strncmp(str, start, os_strlen(start)) == 0;
+}
+
+
+static void wps_reload_config(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_iface *iface = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
+ if (hostapd_reload_config(iface) < 0) {
+ wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
+ "configuration");
+ }
+}
+
+
+static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+{
+ struct hostapd_data *hapd = ctx;
+ FILE *oconf, *nconf;
+ size_t len, i;
+ char *tmp_fname;
+ char buf[1024];
+ int multi_bss;
+ int wpa;
+
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
+ cred->cred_attr, cred->cred_attr_len);
+
+ wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
+ wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
+ cred->auth_type);
+ wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
+ wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+ cred->key, cred->key_len);
+ wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
+ MAC2STR(cred->mac_addr));
+
+ if ((hapd->conf->wps_cred_processing == 1 ||
+ hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
+ size_t blen = cred->cred_attr_len * 2 + 1;
+ char *buf = os_malloc(blen);
+ if (buf) {
+ wpa_snprintf_hex(buf, blen,
+ cred->cred_attr, cred->cred_attr_len);
+ wpa_msg(hapd, MSG_INFO, "%s%s",
+ WPS_EVENT_NEW_AP_SETTINGS, buf);
+ os_free(buf);
+ }
+ } else
+ wpa_msg(hapd, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
+
+ if (hapd->conf->wps_cred_processing == 1)
+ return 0;
+
+ len = os_strlen(hapd->iface->config_fname) + 5;
+ tmp_fname = os_malloc(len);
+ if (tmp_fname == NULL)
+ return -1;
+ os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
+
+ oconf = fopen(hapd->iface->config_fname, "r");
+ if (oconf == NULL) {
+ wpa_printf(MSG_WARNING, "WPS: Could not open current "
+ "configuration file");
+ os_free(tmp_fname);
+ return -1;
+ }
+
+ nconf = fopen(tmp_fname, "w");
+ if (nconf == NULL) {
+ wpa_printf(MSG_WARNING, "WPS: Could not write updated "
+ "configuration file");
+ os_free(tmp_fname);
+ fclose(oconf);
+ return -1;
+ }
+
+ fprintf(nconf, "# WPS configuration - START\n");
+
+ fprintf(nconf, "wps_state=2\n");
+
+ fprintf(nconf, "ssid=");
+ for (i = 0; i < cred->ssid_len; i++)
+ fputc(cred->ssid[i], nconf);
+ fprintf(nconf, "\n");
+
+ if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+ (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+ wpa = 3;
+ else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+ wpa = 2;
+ else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ wpa = 1;
+ else
+ wpa = 0;
+
+ if (wpa) {
+ char *prefix;
+ fprintf(nconf, "wpa=%d\n", wpa);
+
+ fprintf(nconf, "wpa_key_mgmt=");
+ prefix = "";
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
+ fprintf(nconf, "WPA-EAP");
+ prefix = " ";
+ }
+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+ fprintf(nconf, "%sWPA-PSK", prefix);
+ fprintf(nconf, "\n");
+
+ fprintf(nconf, "wpa_pairwise=");
+ prefix = "";
+ if (cred->encr_type & WPS_ENCR_AES) {
+ fprintf(nconf, "CCMP");
+ prefix = " ";
+ }
+ if (cred->encr_type & WPS_ENCR_TKIP) {
+ fprintf(nconf, "%sTKIP", prefix);
+ }
+ fprintf(nconf, "\n");
+
+ if (cred->key_len >= 8 && cred->key_len < 64) {
+ fprintf(nconf, "wpa_passphrase=");
+ for (i = 0; i < cred->key_len; i++)
+ fputc(cred->key[i], nconf);
+ fprintf(nconf, "\n");
+ } else if (cred->key_len == 64) {
+ fprintf(nconf, "wpa_psk=");
+ for (i = 0; i < cred->key_len; i++)
+ fputc(cred->key[i], nconf);
+ fprintf(nconf, "\n");
+ } else {
+ wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
+ "for WPA/WPA2",
+ (unsigned long) cred->key_len);
+ }
+
+ fprintf(nconf, "auth_algs=1\n");
+ } else {
+ if ((cred->auth_type & WPS_AUTH_OPEN) &&
+ (cred->auth_type & WPS_AUTH_SHARED))
+ fprintf(nconf, "auth_algs=3\n");
+ else if (cred->auth_type & WPS_AUTH_SHARED)
+ fprintf(nconf, "auth_algs=2\n");
+ else
+ fprintf(nconf, "auth_algs=1\n");
+
+ if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx < 4) {
+ fprintf(nconf, "wep_default_key=%d\n", cred->key_idx);
+ fprintf(nconf, "wep_key%d=", cred->key_idx);
+ if (cred->key_len != 10 && cred->key_len != 26)
+ fputc('"', nconf);
+ for (i = 0; i < cred->key_len; i++)
+ fputc(cred->key[i], nconf);
+ if (cred->key_len != 10 && cred->key_len != 26)
+ fputc('"', nconf);
+ fprintf(nconf, "\n");
+ }
+ }
+
+ fprintf(nconf, "# WPS configuration - END\n");
+
+ multi_bss = 0;
+ while (fgets(buf, sizeof(buf), oconf)) {
+ if (os_strncmp(buf, "bss=", 4) == 0)
+ multi_bss = 1;
+ if (!multi_bss &&
+ (str_starts(buf, "ssid=") ||
+ str_starts(buf, "auth_algs=") ||
+ str_starts(buf, "wps_state=") ||
+ str_starts(buf, "wpa=") ||
+ str_starts(buf, "wpa_psk=") ||
+ str_starts(buf, "wpa_pairwise=") ||
+ str_starts(buf, "rsn_pairwise=") ||
+ str_starts(buf, "wpa_key_mgmt=") ||
+ str_starts(buf, "wpa_passphrase="))) {
+ fprintf(nconf, "#WPS# %s", buf);
+ } else
+ fprintf(nconf, "%s", buf);
+ }
+
+ fclose(nconf);
+ fclose(oconf);
+
+ if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
+ wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
+ "configuration file: %s", strerror(errno));
+ os_free(tmp_fname);
+ return -1;
+ }
+
+ os_free(tmp_fname);
+
+ /* Schedule configuration reload after short period of time to allow
+ * EAP-WSC to be finished.
+ */
+ eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+ NULL);
+
+ /* TODO: dualband AP may need to update multiple configuration files */
+
+ wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
+
+ return 0;
+}
+
+
+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
+ struct wps_event_pwd_auth_fail *data)
+{
+ FILE *f;
+
+ if (!data->enrollee)
+ return;
+
+ /*
+ * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
+ * if this happens multiple times.
+ */
+ hapd->ap_pin_failures++;
+ if (hapd->ap_pin_failures < 4)
+ return;
+
+ wpa_msg(hapd, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
+ hapd->wps->ap_setup_locked = 1;
+
+ wps_registrar_update_ie(hapd->wps->registrar);
+
+ if (hapd->conf->wps_cred_processing == 1)
+ return;
+
+ f = fopen(hapd->iface->config_fname, "a");
+ if (f == NULL) {
+ wpa_printf(MSG_WARNING, "WPS: Could not append to the current "
+ "configuration file");
+ return;
+ }
+
+ fprintf(f, "# WPS AP Setup Locked based on possible attack\n");
+ fprintf(f, "ap_setup_locked=1\n");
+ fclose(f);
+
+ /* TODO: dualband AP may need to update multiple configuration files */
+
+ wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
+}
+
+
+static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
+ union wps_event_data *data)
+{
+ struct hostapd_data *hapd = ctx;
+
+ if (event == WPS_EV_PWD_AUTH_FAIL)
+ hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
+}
+
+
+static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
+{
+ os_free(hapd->wps_beacon_ie);
+ hapd->wps_beacon_ie = NULL;
+ hapd->wps_beacon_ie_len = 0;
+ hostapd_set_wps_beacon_ie(hapd, NULL, 0);
+
+ os_free(hapd->wps_probe_resp_ie);
+ hapd->wps_probe_resp_ie = NULL;
+ hapd->wps_probe_resp_ie_len = 0;
+ hostapd_set_wps_probe_resp_ie(hapd, NULL, 0);
+}
+
+
+int hostapd_init_wps(struct hostapd_data *hapd,
+ struct hostapd_bss_config *conf)
+{
+ struct wps_context *wps;
+ struct wps_registrar_config cfg;
+
+ if (conf->wps_state == 0) {
+ hostapd_wps_clear_ies(hapd);
+ return 0;
+ }
+
+ wps = os_zalloc(sizeof(*wps));
+ if (wps == NULL)
+ return -1;
+
+ wps->cred_cb = hostapd_wps_cred_cb;
+ wps->event_cb = hostapd_wps_event_cb;
+ wps->cb_ctx = hapd;
+
+ os_memset(&cfg, 0, sizeof(cfg));
+ wps->wps_state = hapd->conf->wps_state;
+ wps->ap_setup_locked = hapd->conf->ap_setup_locked;
+ if (is_nil_uuid(hapd->conf->uuid)) {
+ uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
+ wps->uuid, UUID_LEN);
+ } else
+ os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
+ wps->ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
+ wps->ap = 1;
+ os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
+ wps->dev.device_name = hapd->conf->device_name ?
+ os_strdup(hapd->conf->device_name) : NULL;
+ wps->dev.manufacturer = hapd->conf->manufacturer ?
+ os_strdup(hapd->conf->manufacturer) : NULL;
+ wps->dev.model_name = hapd->conf->model_name ?
+ os_strdup(hapd->conf->model_name) : NULL;
+ wps->dev.model_number = hapd->conf->model_number ?
+ os_strdup(hapd->conf->model_number) : NULL;
+ wps->dev.serial_number = hapd->conf->serial_number ?
+ os_strdup(hapd->conf->serial_number) : NULL;
+ if (hapd->conf->config_methods) {
+ char *m = hapd->conf->config_methods;
+ if (os_strstr(m, "label"))
+ wps->config_methods |= WPS_CONFIG_LABEL;
+ if (os_strstr(m, "display"))
+ wps->config_methods |= WPS_CONFIG_DISPLAY;
+ if (os_strstr(m, "push_button"))
+ wps->config_methods |= WPS_CONFIG_PUSHBUTTON;
+ if (os_strstr(m, "keypad"))
+ wps->config_methods |= WPS_CONFIG_KEYPAD;
+ }
+ if (hapd->conf->device_type) {
+ char *pos;
+ u8 oui[4];
+ /* <categ>-<OUI>-<subcateg> */
+ wps->dev.categ = atoi(hapd->conf->device_type);
+ pos = os_strchr(hapd->conf->device_type, '-');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+ os_free(wps);
+ return -1;
+ }
+ pos++;
+ if (hexstr2bin(pos, oui, 4)) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI");
+ os_free(wps);
+ return -1;
+ }
+ wps->dev.oui = WPA_GET_BE32(oui);
+ pos = os_strchr(pos, '-');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+ os_free(wps);
+ return -1;
+ }
+ pos++;
+ wps->dev.sub_categ = atoi(pos);
+ }
+ wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
+ wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+ WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+
+ if (conf->wpa & WPA_PROTO_RSN) {
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+ wps->auth_types |= WPS_AUTH_WPA2PSK;
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+ wps->auth_types |= WPS_AUTH_WPA2;
+
+ if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
+ wps->encr_types |= WPS_ENCR_AES;
+ if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
+ wps->encr_types |= WPS_ENCR_TKIP;
+ }
+
+ if (conf->wpa & WPA_PROTO_WPA) {
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+ wps->auth_types |= WPS_AUTH_WPAPSK;
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+ wps->auth_types |= WPS_AUTH_WPA;
+
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ wps->encr_types |= WPS_ENCR_AES;
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ wps->encr_types |= WPS_ENCR_TKIP;
+ }
+
+ if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
+ wps->encr_types |= WPS_ENCR_NONE;
+ wps->auth_types |= WPS_AUTH_OPEN;
+ } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
+ wps->encr_types |= WPS_ENCR_WEP;
+ if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
+ wps->auth_types |= WPS_AUTH_OPEN;
+ if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
+ wps->auth_types |= WPS_AUTH_SHARED;
+ } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
+ wps->auth_types |= WPS_AUTH_OPEN;
+ if (conf->default_wep_key_len)
+ wps->encr_types |= WPS_ENCR_WEP;
+ else
+ wps->encr_types |= WPS_ENCR_NONE;
+ }
+
+ if (conf->ssid.wpa_psk_file) {
+ /* Use per-device PSKs */
+ } else if (conf->ssid.wpa_passphrase) {
+ wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+ wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+ } else if (conf->ssid.wpa_psk) {
+ wps->network_key = os_malloc(2 * PMK_LEN + 1);
+ if (wps->network_key == NULL) {
+ os_free(wps);
+ return -1;
+ }
+ wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+ conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->network_key_len = 2 * PMK_LEN;
+ } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+ wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+ if (wps->network_key == NULL) {
+ os_free(wps);
+ return -1;
+ }
+ os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+ conf->ssid.wep.len[0]);
+ wps->network_key_len = conf->ssid.wep.len[0];
+ }
+
+ if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
+ /* Override parameters to enable security by default */
+ wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
+ wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+ }
+
+ wps->ap_settings = conf->ap_settings;
+ wps->ap_settings_len = conf->ap_settings_len;
+
+ cfg.new_psk_cb = hostapd_wps_new_psk_cb;
+ cfg.set_ie_cb = hostapd_wps_set_ie_cb;
+ cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
+ cfg.reg_success_cb = hostapd_wps_reg_success_cb;
+ cfg.cb_ctx = hapd;
+ cfg.skip_cred_build = conf->skip_cred_build;
+ cfg.extra_cred = conf->extra_cred;
+ cfg.extra_cred_len = conf->extra_cred_len;
+ cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
+ conf->skip_cred_build;
+
+ wps->registrar = wps_registrar_init(wps, &cfg);
+ if (wps->registrar == NULL) {
+ printf("Failed to initialize WPS Registrar\n");
+ os_free(wps->network_key);
+ os_free(wps);
+ return -1;
+ }
+
+#ifdef CONFIG_WPS_UPNP
+ wps->friendly_name = hapd->conf->friendly_name;
+ wps->manufacturer_url = hapd->conf->manufacturer_url;
+ wps->model_description = hapd->conf->model_description;
+ wps->model_url = hapd->conf->model_url;
+ wps->upc = hapd->conf->upc;
+
+ if (hostapd_wps_upnp_init(hapd, wps) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
+ wps_registrar_deinit(wps->registrar);
+ os_free(wps->network_key);
+ os_free(wps);
+ return -1;
+ }
+#endif /* CONFIG_WPS_UPNP */
+
+ hapd->wps = wps;
+
+ return 0;
+}
+
+
+void hostapd_deinit_wps(struct hostapd_data *hapd)
+{
+ if (hapd->wps == NULL)
+ return;
+#ifdef CONFIG_WPS_UPNP
+ hostapd_wps_upnp_deinit(hapd);
+#endif /* CONFIG_WPS_UPNP */
+ wps_registrar_deinit(hapd->wps->registrar);
+ os_free(hapd->wps->network_key);
+ wps_device_data_free(&hapd->wps->dev);
+ wps_free_pending_msgs(hapd->wps->upnp_msgs);
+ os_free(hapd->wps);
+ hapd->wps = NULL;
+ hostapd_wps_clear_ies(hapd);
+}
+
+
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
+ const char *pin)
+{
+ u8 u[UUID_LEN];
+ int any = 0;
+
+ if (hapd->wps == NULL)
+ return -1;
+ if (os_strcmp(uuid, "any") == 0)
+ any = 1;
+ else if (uuid_str2bin(uuid, u))
+ return -1;
+ return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
+ (const u8 *) pin, os_strlen(pin));
+}
+
+
+int hostapd_wps_button_pushed(struct hostapd_data *hapd)
+{
+ if (hapd->wps == NULL)
+ return -1;
+ return wps_registrar_button_pushed(hapd->wps->registrar);
+}
+
+
+void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *ie, size_t ie_len)
+{
+ struct wpabuf *wps_ie;
+ const u8 *end, *pos, *wps;
+
+ if (hapd->wps == NULL)
+ return;
+
+ pos = ie;
+ end = ie + ie_len;
+ wps = NULL;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ return;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ WPA_GET_BE32(&pos[2]) == WPS_DEV_OUI_WFA) {
+ wps = pos;
+ break;
+ }
+ pos += 2 + pos[1];
+ }
+
+ if (wps == NULL)
+ return; /* No WPS IE in Probe Request */
+
+ wps_ie = wpabuf_alloc(ie_len);
+ if (wps_ie == NULL)
+ return;
+
+ /* There may be multiple WPS IEs in the message, so need to concatenate
+ * their WPS Data fields */
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ WPA_GET_BE32(&pos[2]) == WPS_DEV_OUI_WFA)
+ wpabuf_put_data(wps_ie, pos + 6, pos[1] - 4);
+ pos += 2 + pos[1];
+ }
+
+ if (wpabuf_len(wps_ie) > 0) {
+ wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
+#ifdef CONFIG_WPS_UPNP
+ /* FIX: what exactly should be included in the WLANEvent?
+ * WPS attributes? Full ProbeReq frame? */
+ upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr,
+ UPNP_WPS_WLANEVENT_TYPE_PROBE,
+ wps_ie);
+#endif /* CONFIG_WPS_UPNP */
+ }
+
+ wpabuf_free(wps_ie);
+}
+
+
+#ifdef CONFIG_WPS_UPNP
+
+static struct wpabuf *
+hostapd_rx_req_get_device_info(void *priv, struct upnp_wps_peer *peer)
+{
+ struct hostapd_data *hapd = priv;
+ struct wps_config cfg;
+ struct wps_data *wps;
+ enum wsc_op_code op_code;
+ struct wpabuf *m1;
+
+ /*
+ * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
+ * registration over UPnP with the AP acting as an Enrollee. It should
+ * be noted that this is frequently used just to get the device data,
+ * i.e., there may not be any intent to actually complete the
+ * registration.
+ */
+
+ if (peer->wps)
+ wps_deinit(peer->wps);
+
+ os_memset(&cfg, 0, sizeof(cfg));
+ cfg.wps = hapd->wps;
+ cfg.pin = (u8 *) hapd->conf->ap_pin;
+ cfg.pin_len = os_strlen(hapd->conf->ap_pin);
+ wps = wps_init(&cfg);
+ if (wps == NULL)
+ return NULL;
+
+ m1 = wps_get_msg(wps, &op_code);
+ if (m1 == NULL) {
+ wps_deinit(wps);
+ return NULL;
+ }
+
+ peer->wps = wps;
+
+ return m1;
+}
+
+
+static struct wpabuf *
+hostapd_rx_req_put_message(void *priv, struct upnp_wps_peer *peer,
+ const struct wpabuf *msg)
+{
+ enum wps_process_res res;
+ enum wsc_op_code op_code;
+
+ /* PutMessage: msg = InMessage, return OutMessage */
+ res = wps_process_msg(peer->wps, WSC_UPnP, msg);
+ if (res == WPS_FAILURE)
+ return NULL;
+ return wps_get_msg(peer->wps, &op_code);
+}
+
+
+static struct wpabuf *
+hostapd_rx_req_get_ap_settings(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return NULL;
+}
+
+
+static int hostapd_rx_req_set_ap_settings(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_rx_req_del_ap_settings(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static struct wpabuf *
+hostapd_rx_req_get_sta_settings(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return NULL;
+}
+
+
+static int hostapd_rx_req_set_sta_settings(void *priv,
+ const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_rx_req_del_sta_settings(void *priv,
+ const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_rx_req_put_wlan_response(
+ void *priv, enum upnp_wps_wlanevent_type ev_type,
+ const u8 *mac_addr, const struct wpabuf *msg,
+ enum wps_msg_type msg_type)
+{
+ struct hostapd_data *hapd = priv;
+ struct sta_info *sta;
+ struct upnp_pending_message *p;
+
+ wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
+ MACSTR, ev_type, MAC2STR(mac_addr));
+ wpa_hexdump_ascii(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
+ wpabuf_head(msg), wpabuf_len(msg));
+ if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
+ "PutWLANResponse WLANEventType %d", ev_type);
+ return -1;
+ }
+
+ /*
+ * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
+ * server implementation for delivery to the peer.
+ */
+
+ sta = ap_get_sta(hapd, mac_addr);
+ if (!sta) {
+ /*
+ * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
+ * Pick STA that is in an ongoing WPS registration without
+ * checking the MAC address.
+ */
+ wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
+ "on NewWLANEventMAC; try wildcard match");
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
+ break;
+ }
+ }
+
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
+ return 0;
+ }
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return -1;
+ os_memcpy(p->addr, sta->addr, ETH_ALEN);
+ p->msg = wpabuf_dup(msg);
+ p->type = msg_type;
+ p->next = hapd->wps->upnp_msgs;
+ hapd->wps->upnp_msgs = p;
+
+ return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
+}
+
+
+static int hostapd_rx_req_set_selected_registrar(void *priv,
+ const struct wpabuf *msg)
+{
+ struct hostapd_data *hapd = priv;
+ return wps_registrar_set_selected_registrar(hapd->wps->registrar, msg);
+}
+
+
+static int hostapd_rx_req_reboot_ap(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_rx_req_reset_ap(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_rx_req_reboot_sta(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_rx_req_reset_sta(void *priv, const struct wpabuf *msg)
+{
+ wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
+ return -1;
+}
+
+
+static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
+ struct wps_context *wps)
+{
+ struct upnp_wps_device_ctx *ctx;
+
+ if (!hapd->conf->upnp_iface)
+ return 0;
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return -1;
+
+ ctx->rx_req_get_device_info = hostapd_rx_req_get_device_info;
+ ctx->rx_req_put_message = hostapd_rx_req_put_message;
+ ctx->rx_req_get_ap_settings = hostapd_rx_req_get_ap_settings;
+ ctx->rx_req_set_ap_settings = hostapd_rx_req_set_ap_settings;
+ ctx->rx_req_del_ap_settings = hostapd_rx_req_del_ap_settings;
+ ctx->rx_req_get_sta_settings = hostapd_rx_req_get_sta_settings;
+ ctx->rx_req_set_sta_settings = hostapd_rx_req_set_sta_settings;
+ ctx->rx_req_del_sta_settings = hostapd_rx_req_del_sta_settings;
+ ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
+ ctx->rx_req_set_selected_registrar =
+ hostapd_rx_req_set_selected_registrar;
+ ctx->rx_req_reboot_ap = hostapd_rx_req_reboot_ap;
+ ctx->rx_req_reset_ap = hostapd_rx_req_reset_ap;
+ ctx->rx_req_reboot_sta = hostapd_rx_req_reboot_sta;
+ ctx->rx_req_reset_sta = hostapd_rx_req_reset_sta;
+
+ hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd);
+ if (hapd->wps_upnp == NULL) {
+ os_free(ctx);
+ return -1;
+ }
+ wps->wps_upnp = hapd->wps_upnp;
+
+ if (upnp_wps_device_start(hapd->wps_upnp, hapd->conf->upnp_iface)) {
+ upnp_wps_device_deinit(hapd->wps_upnp);
+ hapd->wps_upnp = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
+{
+ upnp_wps_device_deinit(hapd->wps_upnp);
+}
+
+#endif /* CONFIG_WPS_UPNP */
diff --git a/contrib/wpa/hostapd/wps_hostapd.h b/contrib/wpa/hostapd/wps_hostapd.h
new file mode 100644
index 0000000..6615c62a
--- /dev/null
+++ b/contrib/wpa/hostapd/wps_hostapd.h
@@ -0,0 +1,48 @@
+/*
+ * hostapd / WPS integration
+ * 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.
+ */
+
+#ifndef WPS_HOSTAPD_H
+#define WPS_HOSTAPD_H
+
+#ifdef CONFIG_WPS
+
+int hostapd_init_wps(struct hostapd_data *hapd,
+ struct hostapd_bss_config *conf);
+void hostapd_deinit_wps(struct hostapd_data *hapd);
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
+ const char *pin);
+int hostapd_wps_button_pushed(struct hostapd_data *hapd);
+void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *ie, size_t ie_len);
+
+#else /* CONFIG_WPS */
+
+static inline int hostapd_init_wps(struct hostapd_data *hapd,
+ struct hostapd_bss_config *conf)
+{
+ return 0;
+}
+
+static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_wps_probe_req_rx(struct hostapd_data *hapd,
+ const u8 *addr,
+ const u8 *ie, size_t ie_len)
+{
+}
+#endif /* CONFIG_WPS */
+
+#endif /* WPS_HOSTAPD_H */
OpenPOWER on IntegriCloud