diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog deleted file mode 100644 index 18af4b176b9b..000000000000 --- a/hostapd/ChangeLog +++ /dev/null @@ -1,597 +0,0 @@ -ChangeLog for hostapd - -2010-01-12 - v0.6.10 - * fixed SHA-256 based key derivation function to match with the - standard when using CCMP (for IEEE 802.11r and IEEE 802.11w) - (note: this breaks interoperability with previous version) [Bug 307] - * fixed WPS selected registrar expiration for internal PIN registrar - * disable PMTU discovery for RADIUS packets - * fixed WPS UPnP SSDP on 32-bit targets - * fixed WPS AP reconfiguration with drivers that do not use hostapd - MLME - * fixed RSN parameter setting for multi-BSS case - * added WPS workarounds for known interoperability issues with broken, - deployed implementation - * update IEEE 802.11w implementation to match with the published - standard - * fixed OpCode when proxying WSC_ACK or WSC_NACK from WPS ER - * fixed proxying of WSC_NACK to WPS ER - * fixed compilation with newer GnuTLS versions - * added support for defining timeout for WPS PINs - * fixed WPS Probe Request processing to handle missing required - attribute - * fixed PKCS#12 use with OpenSSL 1.0.0 - -2009-03-23 - v0.6.9 - * driver_nl80211: fixed STA accounting data collection (TX/RX bytes - reported correctly; TX/RX packets not yet available from kernel) - * fixed EAPOL/EAP reauthentication when using an external RADIUS - authentication server - * driver_prism54: fixed segmentation fault on initialization - * fixed TNC with EAP-TTLS - * fixed IEEE 802.11r key derivation function to match with the standard - (note: this breaks interoperability with previous version) [Bug 303] - -2009-02-15 - v0.6.8 - * increased hostapd_cli ping interval to 5 seconds and made this - configurable with a new command line options (-G) - * 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= 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 ' 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 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 ') - * 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/hostapd/Makefile b/hostapd/Makefile deleted file mode 100644 index 3b3d7feb58c0..000000000000 --- a/hostapd/Makefile +++ /dev/null @@ -1,635 +0,0 @@ -ifndef CC -CC=gcc -endif - -ifndef CFLAGS -CFLAGS = -MMD -O2 -Wall -g -endif - -# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -# a file (undefine it, if you want to save in binary size) -CFLAGS += -DHOSTAPD_DUMP_STATE - -CFLAGS += -I../src -CFLAGS += -I../src/crypto -CFLAGS += -I../src/utils -CFLAGS += -I../src/common - -# Uncomment following line and set the path to your kernel tree include -# directory if your C library does not include all header files. -# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include - --include .config - -ifndef CONFIG_OS -ifdef CONFIG_NATIVE_WINDOWS -CONFIG_OS=win32 -else -CONFIG_OS=unix -endif -endif - -ifeq ($(CONFIG_OS), internal) -CFLAGS += -DOS_NO_C_LIB_DEFINES -endif - -ifdef CONFIG_NATIVE_WINDOWS -CFLAGS += -DCONFIG_NATIVE_WINDOWS -LIBS += -lws2_32 -endif - -OBJS = hostapd.o ieee802_1x.o eapol_sm.o \ - ieee802_11.o config.o ieee802_11_auth.o accounting.o \ - sta_info.o wpa.o ctrl_iface.o \ - drivers.o preauth.o pmksa_cache.o beacon.o \ - hw_features.o wme.o ap_list.o \ - mlme.o vlan_init.o wpa_auth_ie.o - -OBJS += ../src/utils/eloop.o -OBJS += ../src/utils/common.o -OBJS += ../src/utils/wpa_debug.o -OBJS += ../src/utils/wpabuf.o -OBJS += ../src/utils/os_$(CONFIG_OS).o -OBJS += ../src/utils/ip_addr.o - -OBJS += ../src/common/ieee802_11_common.o -OBJS += ../src/common/wpa_common.o - -OBJS += ../src/radius/radius.o -OBJS += ../src/radius/radius_client.o - -OBJS += ../src/crypto/md5.o -OBJS += ../src/crypto/rc4.o -OBJS += ../src/crypto/md4.o -OBJS += ../src/crypto/sha1.o -OBJS += ../src/crypto/des.o -OBJS += ../src/crypto/aes_wrap.o -OBJS += ../src/crypto/aes.o - -HOBJS=../src/hlr_auc_gw/hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/hlr_auc_gw/milenage.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o - -CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX - -ifdef CONFIG_IAPP -CFLAGS += -DCONFIG_IAPP -OBJS += iapp.o -endif - -ifdef CONFIG_RSN_PREAUTH -CFLAGS += -DCONFIG_RSN_PREAUTH -CONFIG_L2_PACKET=y -endif - -ifdef CONFIG_PEERKEY -CFLAGS += -DCONFIG_PEERKEY -OBJS += peerkey.o -endif - -ifdef CONFIG_IEEE80211W -CFLAGS += -DCONFIG_IEEE80211W -NEED_SHA256=y -endif - -ifdef CONFIG_IEEE80211R -CFLAGS += -DCONFIG_IEEE80211R -OBJS += wpa_ft.o -NEED_SHA256=y -endif - -ifdef CONFIG_IEEE80211N -CFLAGS += -DCONFIG_IEEE80211N -endif - -ifdef CONFIG_DRIVER_HOSTAP -CFLAGS += -DCONFIG_DRIVER_HOSTAP -OBJS += driver_hostap.o -endif - -ifdef CONFIG_DRIVER_WIRED -CFLAGS += -DCONFIG_DRIVER_WIRED -OBJS += driver_wired.o -endif - -ifdef CONFIG_DRIVER_MADWIFI -CFLAGS += -DCONFIG_DRIVER_MADWIFI -OBJS += driver_madwifi.o -CONFIG_L2_PACKET=y -endif - -ifdef CONFIG_DRIVER_ATHEROS -CFLAGS += -DCONFIG_DRIVER_ATHEROS -OBJS += driver_atheros.o -CONFIG_L2_PACKET=y -endif - -ifdef CONFIG_DRIVER_PRISM54 -CFLAGS += -DCONFIG_DRIVER_PRISM54 -OBJS += driver_prism54.o -endif - -ifdef CONFIG_DRIVER_NL80211 -CFLAGS += -DCONFIG_DRIVER_NL80211 -OBJS += driver_nl80211.o radiotap.o -LIBS += -lnl -ifdef CONFIG_LIBNL20 -LIBS += -lnl-genl -CFLAGS += -DCONFIG_LIBNL20 -endif -endif - -ifdef CONFIG_DRIVER_BSD -CFLAGS += -DCONFIG_DRIVER_BSD -OBJS += driver_bsd.o -CONFIG_L2_PACKET=y -CONFIG_DNET_PCAP=y -CONFIG_L2_FREEBSD=y -endif - -ifdef CONFIG_DRIVER_TEST -CFLAGS += -DCONFIG_DRIVER_TEST -OBJS += driver_test.o -endif - -ifdef CONFIG_DRIVER_NONE -CFLAGS += -DCONFIG_DRIVER_NONE -OBJS += driver_none.o -endif - -ifdef CONFIG_L2_PACKET -ifdef CONFIG_DNET_PCAP -ifdef CONFIG_L2_FREEBSD -LIBS += -lpcap -OBJS += ../src/l2_packet/l2_packet_freebsd.o -else -LIBS += -ldnet -lpcap -OBJS += ../src/l2_packet/l2_packet_pcap.o -endif -else -OBJS += ../src/l2_packet/l2_packet_linux.o -endif -else -OBJS += ../src/l2_packet/l2_packet_none.o -endif - - -ifdef CONFIG_EAP_MD5 -CFLAGS += -DEAP_MD5 -OBJS += ../src/eap_server/eap_md5.o -CHAP=y -endif - -ifdef CONFIG_EAP_TLS -CFLAGS += -DEAP_TLS -OBJS += ../src/eap_server/eap_tls.o -TLS_FUNCS=y -endif - -ifdef CONFIG_EAP_PEAP -CFLAGS += -DEAP_PEAP -OBJS += ../src/eap_server/eap_peap.o -OBJS += ../src/eap_common/eap_peap_common.o -TLS_FUNCS=y -CONFIG_EAP_MSCHAPV2=y -endif - -ifdef CONFIG_EAP_TTLS -CFLAGS += -DEAP_TTLS -OBJS += ../src/eap_server/eap_ttls.o -TLS_FUNCS=y -CHAP=y -endif - -ifdef CONFIG_EAP_MSCHAPV2 -CFLAGS += -DEAP_MSCHAPv2 -OBJS += ../src/eap_server/eap_mschapv2.o -MS_FUNCS=y -endif - -ifdef CONFIG_EAP_GTC -CFLAGS += -DEAP_GTC -OBJS += ../src/eap_server/eap_gtc.o -endif - -ifdef CONFIG_EAP_SIM -CFLAGS += -DEAP_SIM -OBJS += ../src/eap_server/eap_sim.o -CONFIG_EAP_SIM_COMMON=y -endif - -ifdef CONFIG_EAP_AKA -CFLAGS += -DEAP_AKA -OBJS += ../src/eap_server/eap_aka.o -CONFIG_EAP_SIM_COMMON=y -NEED_SHA256=y -endif - -ifdef CONFIG_EAP_AKA_PRIME -CFLAGS += -DEAP_AKA_PRIME -endif - -ifdef CONFIG_EAP_SIM_COMMON -OBJS += ../src/eap_common/eap_sim_common.o -# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be -# replaced with another file implementating the interface specified in -# eap_sim_db.h. -OBJS += ../src/eap_server/eap_sim_db.o -NEED_FIPS186_2_PRF=y -endif - -ifdef CONFIG_EAP_PAX -CFLAGS += -DEAP_PAX -OBJS += ../src/eap_server/eap_pax.o ../src/eap_common/eap_pax_common.o -endif - -ifdef CONFIG_EAP_PSK -CFLAGS += -DEAP_PSK -OBJS += ../src/eap_server/eap_psk.o ../src/eap_common/eap_psk_common.o -endif - -ifdef CONFIG_EAP_SAKE -CFLAGS += -DEAP_SAKE -OBJS += ../src/eap_server/eap_sake.o ../src/eap_common/eap_sake_common.o -endif - -ifdef CONFIG_EAP_GPSK -CFLAGS += -DEAP_GPSK -OBJS += ../src/eap_server/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o -ifdef CONFIG_EAP_GPSK_SHA256 -CFLAGS += -DEAP_GPSK_SHA256 -endif -NEED_SHA256=y -endif - -ifdef CONFIG_EAP_VENDOR_TEST -CFLAGS += -DEAP_VENDOR_TEST -OBJS += ../src/eap_server/eap_vendor_test.o -endif - -ifdef CONFIG_EAP_FAST -CFLAGS += -DEAP_FAST -OBJS += ../src/eap_server/eap_fast.o -OBJS += ../src/eap_common/eap_fast_common.o -TLS_FUNCS=y -NEED_T_PRF=y -endif - -ifdef CONFIG_WPS -CFLAGS += -DCONFIG_WPS -DEAP_WSC -OBJS += ../src/utils/uuid.o -OBJS += wps_hostapd.o -OBJS += ../src/eap_server/eap_wsc.o ../src/eap_common/eap_wsc_common.o -OBJS += ../src/wps/wps.o -OBJS += ../src/wps/wps_common.o -OBJS += ../src/wps/wps_attr_parse.o -OBJS += ../src/wps/wps_attr_build.o -OBJS += ../src/wps/wps_attr_process.o -OBJS += ../src/wps/wps_dev_attr.o -OBJS += ../src/wps/wps_enrollee.o -OBJS += ../src/wps/wps_registrar.o -NEED_DH_GROUPS=y -NEED_SHA256=y -NEED_CRYPTO=y -NEED_BASE64=y - -ifdef CONFIG_WPS_UPNP -CFLAGS += -DCONFIG_WPS_UPNP -OBJS += ../src/wps/wps_upnp.o -OBJS += ../src/wps/wps_upnp_ssdp.o -OBJS += ../src/wps/wps_upnp_web.o -OBJS += ../src/wps/wps_upnp_event.o -OBJS += ../src/wps/httpread.o -endif - -endif - -ifdef CONFIG_EAP_IKEV2 -CFLAGS += -DEAP_IKEV2 -OBJS += ../src/eap_server/eap_ikev2.o ../src/eap_server/ikev2.o -OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o -NEED_DH_GROUPS=y -NEED_DH_GROUPS_ALL=y -endif - -ifdef CONFIG_EAP_TNC -CFLAGS += -DEAP_TNC -OBJS += ../src/eap_server/eap_tnc.o -OBJS += ../src/eap_server/tncs.o -NEED_BASE64=y -ifndef CONFIG_DRIVER_BSD -LIBS += -ldl -endif -endif - -# Basic EAP functionality is needed for EAPOL -OBJS += ../src/eap_server/eap.o -OBJS += ../src/eap_common/eap_common.o -OBJS += ../src/eap_server/eap_methods.o -OBJS += ../src/eap_server/eap_identity.o - -ifdef CONFIG_EAP -CFLAGS += -DEAP_SERVER -endif - -ifndef CONFIG_TLS -CONFIG_TLS=openssl -endif - -ifeq ($(CONFIG_TLS), internal) -ifndef CONFIG_CRYPTO -CONFIG_CRYPTO=internal -endif -endif -ifeq ($(CONFIG_CRYPTO), libtomcrypt) -CFLAGS += -DCONFIG_INTERNAL_X509 -endif -ifeq ($(CONFIG_CRYPTO), internal) -CFLAGS += -DCONFIG_INTERNAL_X509 -endif - - -ifdef TLS_FUNCS -# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) -CFLAGS += -DEAP_TLS_FUNCS -OBJS += ../src/eap_server/eap_tls_common.o -NEED_TLS_PRF=y -ifeq ($(CONFIG_TLS), openssl) -OBJS += ../src/crypto/tls_openssl.o -LIBS += -lssl -lcrypto -LIBS_p += -lcrypto -LIBS_h += -lcrypto -endif -ifeq ($(CONFIG_TLS), gnutls) -OBJS += ../src/crypto/tls_gnutls.o -LIBS += -lgnutls -lgcrypt -lgpg-error -LIBS_p += -lgcrypt -LIBS_h += -lgcrypt -endif -ifdef CONFIG_GNUTLS_EXTRA -CFLAGS += -DCONFIG_GNUTLS_EXTRA -LIBS += -lgnutls-extra -endif -ifeq ($(CONFIG_TLS), internal) -OBJS += ../src/crypto/tls_internal.o -OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o -OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_server.o -OBJS += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o -OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o -OBJS_p += ../src/tls/asn1.o -OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o -NEED_BASE64=y -CFLAGS += -DCONFIG_TLS_INTERNAL -CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER -ifeq ($(CONFIG_CRYPTO), internal) -ifdef CONFIG_INTERNAL_LIBTOMMATH -CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH -else -LIBS += -ltommath -LIBS_p += -ltommath -endif -endif -ifeq ($(CONFIG_CRYPTO), libtomcrypt) -LIBS += -ltomcrypt -ltfm -LIBS_p += -ltomcrypt -ltfm -endif -endif -NEED_CRYPTO=y -else -OBJS += ../src/crypto/tls_none.o -endif - -ifdef CONFIG_PKCS12 -CFLAGS += -DPKCS12_FUNCS -endif - -ifdef MS_FUNCS -OBJS += ../src/crypto/ms_funcs.o -NEED_CRYPTO=y -endif - -ifdef CHAP -OBJS += ../src/eap_common/chap.o -endif - -ifdef NEED_CRYPTO -ifndef TLS_FUNCS -ifeq ($(CONFIG_TLS), openssl) -LIBS += -lcrypto -LIBS_p += -lcrypto -LIBS_h += -lcrypto -endif -ifeq ($(CONFIG_TLS), gnutls) -LIBS += -lgcrypt -LIBS_p += -lgcrypt -LIBS_h += -lgcrypt -endif -ifeq ($(CONFIG_TLS), internal) -ifeq ($(CONFIG_CRYPTO), libtomcrypt) -LIBS += -ltomcrypt -ltfm -LIBS_p += -ltomcrypt -ltfm -endif -endif -endif -ifeq ($(CONFIG_TLS), openssl) -OBJS += ../src/crypto/crypto_openssl.o -OBJS_p += ../src/crypto/crypto_openssl.o -HOBJS += ../src/crypto/crypto_openssl.o -CONFIG_INTERNAL_SHA256=y -endif -ifeq ($(CONFIG_TLS), gnutls) -OBJS += ../src/crypto/crypto_gnutls.o -OBJS_p += ../src/crypto/crypto_gnutls.o -HOBJS += ../src/crypto/crypto_gnutls.o -CONFIG_INTERNAL_SHA256=y -endif -ifeq ($(CONFIG_TLS), internal) -ifeq ($(CONFIG_CRYPTO), libtomcrypt) -OBJS += ../src/crypto/crypto_libtomcrypt.o -OBJS_p += ../src/crypto/crypto_libtomcrypt.o -CONFIG_INTERNAL_SHA256=y -endif -ifeq ($(CONFIG_CRYPTO), internal) -OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o -OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o -CFLAGS += -DCONFIG_CRYPTO_INTERNAL -ifdef CONFIG_INTERNAL_LIBTOMMATH -CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH -ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST -CFLAGS += -DLTM_FAST -endif -else -LIBS += -ltommath -LIBS_p += -ltommath -endif -CONFIG_INTERNAL_AES=y -CONFIG_INTERNAL_DES=y -CONFIG_INTERNAL_SHA1=y -CONFIG_INTERNAL_MD4=y -CONFIG_INTERNAL_MD5=y -CONFIG_INTERNAL_SHA256=y -endif -endif -else -CONFIG_INTERNAL_AES=y -CONFIG_INTERNAL_SHA1=y -CONFIG_INTERNAL_MD5=y -CONFIG_INTERNAL_SHA256=y -endif - -ifdef CONFIG_INTERNAL_AES -CFLAGS += -DINTERNAL_AES -endif -ifdef CONFIG_INTERNAL_SHA1 -CFLAGS += -DINTERNAL_SHA1 -endif -ifdef CONFIG_INTERNAL_SHA256 -CFLAGS += -DINTERNAL_SHA256 -endif -ifdef CONFIG_INTERNAL_MD5 -CFLAGS += -DINTERNAL_MD5 -endif -ifdef CONFIG_INTERNAL_MD4 -CFLAGS += -DINTERNAL_MD4 -endif -ifdef CONFIG_INTERNAL_DES -CFLAGS += -DINTERNAL_DES -endif - -ifdef NEED_SHA256 -OBJS += ../src/crypto/sha256.o -endif - -ifdef NEED_DH_GROUPS -OBJS += ../src/crypto/dh_groups.o -ifdef NEED_DH_GROUPS_ALL -CFLAGS += -DALL_DH_GROUPS -endif -endif - -ifndef NEED_FIPS186_2_PRF -CFLAGS += -DCONFIG_NO_FIPS186_2_PRF -endif - -ifndef NEED_T_PRF -CFLAGS += -DCONFIG_NO_T_PRF -endif - -ifndef NEED_TLS_PRF -CFLAGS += -DCONFIG_NO_TLS_PRF -endif - -ifdef CONFIG_RADIUS_SERVER -CFLAGS += -DRADIUS_SERVER -OBJS += ../src/radius/radius_server.o -endif - -ifdef CONFIG_IPV6 -CFLAGS += -DCONFIG_IPV6 -endif - -ifdef CONFIG_DRIVER_RADIUS_ACL -CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL -endif - -ifdef CONFIG_FULL_DYNAMIC_VLAN -# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges -# and vlan interfaces for the vlan feature. -CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN -endif - -ifdef NEED_BASE64 -OBJS += ../src/utils/base64.o -endif - -ifdef CONFIG_NO_STDOUT_DEBUG -CFLAGS += -DCONFIG_NO_STDOUT_DEBUG -endif - -ifdef CONFIG_NO_AES_EXTRAS -CFLAGS += -DCONFIG_NO_AES_UNWRAP -CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1 -CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC -CFLAGS += -DCONFIG_NO_AES_DECRYPT -CFLAGS += -DCONFIG_NO_AES_ENCRYPT_BLOCK -endif - -ALL=hostapd hostapd_cli - -all: verify_config $(ALL) - -Q=@ -E=echo -ifeq ($(V), 1) -Q= -E=true -endif - -%.o: %.c - $(Q)$(CC) -c -o $@ $(CFLAGS) $< - @$(E) " CC " $< - -verify_config: - @if [ ! -r .config ]; then \ - echo 'Building hostapd requires a configuration file'; \ - echo '(.config). See README for more instructions. You can'; \ - echo 'run "cp defconfig .config" to create an example'; \ - echo 'configuration.'; \ - exit 1; \ - fi - -install: all - for i in $(ALL); do cp $$i /usr/local/bin/$$i; done - -hostapd: $(OBJS) - $(CC) -o hostapd $(OBJS) $(LIBS) - -OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o -hostapd_cli: $(OBJS_c) - $(CC) -o hostapd_cli $(OBJS_c) - -NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o ../src/crypto/sha1.o ../src/crypto/rc4.o ../src/crypto/md5.o -NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o -ifdef TLS_FUNCS -LIBS_n += -lcrypto -endif - -nt_password_hash: $(NOBJS) - $(CC) -o nt_password_hash $(NOBJS) $(LIBS_n) - -hlr_auc_gw: $(HOBJS) - $(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h) - -clean: - $(MAKE) -C ../src clean - rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw - rm -f *.d - -%.eps: %.fig - fig2dev -L eps $*.fig $*.eps - -%.png: %.fig - fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \ - > $*.png - -docs-pics: doc/hostapd.png doc/hostapd.eps - -docs: docs-pics - (cd ..; doxygen hostapd/doc/doxygen.full; cd hostapd) - $(MAKE) -C doc/latex - cp doc/latex/refman.pdf hostapd-devel.pdf - -docs-fast: docs-pics - (cd ..; doxygen hostapd/doc/doxygen.fast; cd hostapd) - -clean-docs: - rm -rf doc/latex doc/html - rm -f doc/hostapd.{eps,png} hostapd-devel.pdf - -TEST_SRC_MILENAGE = ../src/hlr_auc_gw/milenage.c ../src/crypto/aes_wrap.c ../src/crypto/aes.c ../src/utils/common.c ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).c -test-milenage: $(TEST_SRC_MILENAGE) - $(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \ - -DTEST_MAIN_MILENAGE -I. -DINTERNAL_AES \ - -I../src/crypto -I../src/utils - ./test-milenage - rm test-milenage - --include $(OBJS:%.o=%.d) diff --git a/hostapd/README b/hostapd/README deleted file mode 100644 index eb9aa4815b4f..000000000000 --- a/hostapd/README +++ /dev/null @@ -1,390 +0,0 @@ -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 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) - - 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 (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/hostapd/README-WPS b/hostapd/README-WPS deleted file mode 100644 index e0e370b5bc8f..000000000000 --- a/hostapd/README-WPS +++ /dev/null @@ -1,239 +0,0 @@ -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 - -To reduce likelihood of PIN being used with other devices or of -forgetting an active PIN available for potential attackers, expiration -time can be set for the new PIN: - -hostapd_cli wps_pin any 12345670 300 - - -After this, the Enrollee can connect to the AP again and complete WPS -negotiation. At that point, a new, random WPA PSK is generated for the -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 -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 -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/hostapd/config.c b/hostapd/config.c deleted file mode 100644 index 692b1a412e02..000000000000 --- a/hostapd/config.c +++ /dev/null @@ -1,2622 +0,0 @@ -/* - * hostapd / Configuration file - * Copyright (c) 2003-2008, Jouni Malinen - * 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 -#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 = 4, aCWmax = 10; - const struct hostapd_wmm_ac_params ac_bk = - { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ - const struct hostapd_wmm_ac_params ac_be = - { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ - const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ - { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 }; - const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ - { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 }; - - conf = os_zalloc(sizeof(*conf)); - bss = os_zalloc(sizeof(*bss)); - 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->wmm_ac_params[0] = ac_be; - conf->wmm_ac_params[1] = ac_bk; - conf->wmm_ac_params[2] = ac_vi; - conf->wmm_ac_params[3] = ac_vo; - -#ifdef CONFIG_IEEE80211N - conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED; -#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_wmm_ac(struct hostapd_config *conf, char *name, - char *val) -{ - int num, v; - char *pos; - struct hostapd_wmm_ac_params *ac; - - /* skip 'wme_ac_' or 'wmm_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 WMM name '%s'", pos); - return -1; - } - - ac = &conf->wmm_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->txop_limit = 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 wmm_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 j; - /* clear to get error below if setting is invalid */ - conf->driver = NULL; - for (j = 0; hostapd_drivers[j]; j++) { - if (os_strcmp(pos, hostapd_drivers[j]->name) == - 0) { - conf->driver = hostapd_drivers[j]; - 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 || - os_strcmp(buf, "wmm_enabled") == 0) { - bss->wmm_enabled = atoi(pos); - } else if (os_strncmp(buf, "wme_ac_", 7) == 0 || - os_strncmp(buf, "wmm_ac_", 7) == 0) { - if (hostapd_config_wmm_ac(conf, buf, pos)) { - wpa_printf(MSG_ERROR, "Line %d: invalid WMM " - "ac item", line); - errors++; - } - } 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); - - for (i = 0; i < conf->num_bss; i++) { - bss = &conf->bss[i]; - - if (bss->individual_wep_key_len == 0) { - /* individual keys are not use; can use key idx0 for - * broadcast keys */ - bss->broadcast_key_idx_min = 0; - } - - /* Select group cipher based on the enabled pairwise cipher - * suites */ - pairwise = 0; - if (bss->wpa & 1) - pairwise |= bss->wpa_pairwise; - if (bss->wpa & 2) { - if (bss->rsn_pairwise == 0) - bss->rsn_pairwise = bss->wpa_pairwise; - pairwise |= bss->rsn_pairwise; - } - if (pairwise & WPA_CIPHER_TKIP) - bss->wpa_group = WPA_CIPHER_TKIP; - else - bss->wpa_group = WPA_CIPHER_CCMP; - - bss->radius->auth_server = bss->radius->auth_servers; - bss->radius->acct_server = bss->radius->acct_servers; - - 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->supported_rates); - os_free(conf->basic_rates); - - 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/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c deleted file mode 100644 index 9dec7247cdd7..000000000000 --- a/hostapd/ctrl_iface.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004-2008, Jouni Malinen - * - * 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 -#include -#include - -#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 - offsetof(struct sockaddr_un, sun_path)); - 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 - offsetof(struct sockaddr_un, sun_path)) - == 0) { - if (prev == NULL) - hapd->ctrl_dst = dst->next; - else - prev->next = dst->next; - os_free(dst); - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - 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 - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - 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, ' '); - char *timeout_txt; - int timeout; - - if (pin == NULL) - return -1; - *pin++ = '\0'; - - timeout_txt = os_strchr(pin, ' '); - if (timeout_txt) { - *timeout_txt++ = '\0'; - timeout = atoi(timeout_txt); - } else - timeout = 0; - - return hostapd_wps_add_pin(hapd, txt, pin, timeout); -} -#endif /* CONFIG_WPS */ - - -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)); -#ifdef __FreeBSD__ - addr.sun_len = sizeof(addr); -#endif /* __FreeBSD__ */ - addr.sun_family = AF_UNIX; - fname = hostapd_ctrl_iface_path(hapd); - if (fname == NULL) - goto fail; - os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", - strerror(errno)); - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" - " allow connections - assuming it was left" - "over from forced program termination"); - if (unlink(fname) < 0) { - perror("unlink[ctrl_iface]"); - wpa_printf(MSG_ERROR, "Could not unlink " - "existing ctrl_iface socket '%s'", - fname); - goto fail; - } - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < - 0) { - perror("bind(PF_UNIX)"); - goto fail; - } - wpa_printf(MSG_DEBUG, "Successfully replaced leftover " - "ctrl_iface socket '%s'", fname); - } else { - wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " - "be in use - cannot override it"); - wpa_printf(MSG_INFO, "Delete '%s' manually if it is " - "not used anymore", fname); - os_free(fname); - fname = NULL; - goto fail; - } - } - - if (hapd->conf->ctrl_interface_gid_set && - 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 - - offsetof(struct sockaddr_un, sun_path)); - msg.msg_name = &dst->addr; - msg.msg_namelen = dst->addrlen; - if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { - int _errno = errno; - wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " - "%d - %s", - idx, errno, strerror(errno)); - dst->errors++; - if (dst->errors > 10 || _errno == ENOENT) { - hostapd_ctrl_iface_detach( - hapd, &dst->addr, - dst->addrlen); - } - } else - dst->errors = 0; - } - idx++; - dst = next; - } -} - -#endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/hostapd/defconfig b/hostapd/defconfig deleted file mode 100644 index 96a023d2e65d..000000000000 --- a/hostapd/defconfig +++ /dev/null @@ -1,144 +0,0 @@ -# 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/hostapd/doc/code_structure.doxygen b/hostapd/doc/code_structure.doxygen deleted file mode 100644 index fdcf725b5d7f..000000000000 --- a/hostapd/doc/code_structure.doxygen +++ /dev/null @@ -1,5 +0,0 @@ -/** -\page code_structure Structure of the source code - - -*/ diff --git a/hostapd/doc/ctrl_iface.doxygen b/hostapd/doc/ctrl_iface.doxygen deleted file mode 100644 index 76cfc6a6b79c..000000000000 --- a/hostapd/doc/ctrl_iface.doxygen +++ /dev/null @@ -1,66 +0,0 @@ -/** -\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/hostapd/doc/doxygen.fast b/hostapd/doc/doxygen.fast deleted file mode 100644 index 650c73d817f4..000000000000 --- a/hostapd/doc/doxygen.fast +++ /dev/null @@ -1,238 +0,0 @@ -# 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/hostapd/doc/doxygen.full b/hostapd/doc/doxygen.full deleted file mode 100644 index f8c49bff7074..000000000000 --- a/hostapd/doc/doxygen.full +++ /dev/null @@ -1,238 +0,0 @@ -# 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/hostapd/doc/driver_wrapper.doxygen b/hostapd/doc/driver_wrapper.doxygen deleted file mode 100644 index 0ad196f2d6b6..000000000000 --- a/hostapd/doc/driver_wrapper.doxygen +++ /dev/null @@ -1,20 +0,0 @@ -/** -\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/hostapd/doc/eap.doxygen b/hostapd/doc/eap.doxygen deleted file mode 100644 index f0f135aa9598..000000000000 --- a/hostapd/doc/eap.doxygen +++ /dev/null @@ -1,56 +0,0 @@ -/** -\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_.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/hostapd/doc/hostapd.fig b/hostapd/doc/hostapd.fig deleted file mode 100644 index af3f0be19a9b..000000000000 --- a/hostapd/doc/hostapd.fig +++ /dev/null @@ -1,264 +0,0 @@ -#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/hostapd/doc/kerneldoc2doxygen.pl b/hostapd/doc/kerneldoc2doxygen.pl deleted file mode 100755 index 68835a1ddd31..000000000000 --- a/hostapd/doc/kerneldoc2doxygen.pl +++ /dev/null @@ -1,129 +0,0 @@ -#!/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 -# -# 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 -# Copyright (C) 2005 Jouni Malinen -# (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/hostapd/doc/mainpage.doxygen b/hostapd/doc/mainpage.doxygen deleted file mode 100644 index 7cf95de584af..000000000000 --- a/hostapd/doc/mainpage.doxygen +++ /dev/null @@ -1,52 +0,0 @@ -/** -\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 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/hostapd/doc/porting.doxygen b/hostapd/doc/porting.doxygen deleted file mode 100644 index 0621791c0be0..000000000000 --- a/hostapd/doc/porting.doxygen +++ /dev/null @@ -1,5 +0,0 @@ -/** -\page porting Porting to different target boards and operating systems - - -*/ diff --git a/hostapd/driver.h b/hostapd/driver.h deleted file mode 100644 index 45f546087302..000000000000 --- a/hostapd/driver.h +++ /dev/null @@ -1,798 +0,0 @@ -/* - * hostapd - driver interface definition - * Copyright (c) 2002-2007, Jouni Malinen - * 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(¶ms, 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, ¶ms); - } - - 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/hostapd/driver_bsd.c b/hostapd/driver_bsd.c deleted file mode 100644 index 43d57d9091d3..000000000000 --- a/hostapd/driver_bsd.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * hostapd / Driver interaction with BSD net80211 layer - * Copyright (c) 2004, Sam Leffler - * Copyright (c) 2004, 2Wire, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" -#include - -#include - -#include -#include -#include - -/* - * Avoid conflicts with hostapd definitions by undefining couple of defines - * from net80211 header files. - */ -#undef RSN_VERSION -#undef WPA_VERSION -#undef WPA_OUI_TYPE -#undef WME_OUI_TYPE - -#include "hostapd.h" -#include "driver.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "sta_info.h" -#include "l2_packet/l2_packet.h" - -#include "eapol_sm.h" -#include "wpa.h" -#include "radius/radius.h" -#include "ieee802_11.h" -#include "common.h" - -struct bsd_driver_data { - struct hostapd_data *hapd; /* back pointer */ - - char iface[IFNAMSIZ + 1]; - struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ - int ioctl_sock; /* socket for ioctl() use */ - int wext_sock; /* socket for wireless events */ -}; - -static int bsd_sta_deauth(void *priv, const u8 *addr, int reason_code); - -static int -set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) -{ - struct ieee80211req ireq; - - memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ); - ireq.i_type = op; - ireq.i_len = arg_len; - ireq.i_data = (void *) arg; - - if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) { - perror("ioctl[SIOCS80211]"); - return -1; - } - return 0; -} - -static int -get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) -{ - struct ieee80211req ireq; - - memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ); - ireq.i_type = op; - ireq.i_len = arg_len; - ireq.i_data = arg; - - if (ioctl(drv->ioctl_sock, SIOCG80211, &ireq) < 0) { - perror("ioctl[SIOCG80211]"); - return -1; - } - return ireq.i_len; -} - -static int -set80211param(struct bsd_driver_data *drv, int op, int arg) -{ - struct ieee80211req ireq; - - memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ); - ireq.i_type = op; - ireq.i_val = arg; - - if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) { - perror("ioctl[SIOCS80211]"); - return -1; - } - return 0; -} - -static const char * -ether_sprintf(const u8 *addr) -{ - static char buf[sizeof(MACSTR)]; - - if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); - return buf; -} - -/* - * Configure WPA parameters. - */ -static int -bsd_configure_wpa(struct bsd_driver_data *drv) -{ - static const char *ciphernames[] = - { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - int v; - - switch (conf->wpa_group) { - case WPA_CIPHER_CCMP: - v = IEEE80211_CIPHER_AES_CCM; - break; - case WPA_CIPHER_TKIP: - v = IEEE80211_CIPHER_TKIP; - break; - case WPA_CIPHER_WEP104: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_WEP40: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_NONE: - v = IEEE80211_CIPHER_NONE; - break; - default: - printf("Unknown group key cipher %u\n", - conf->wpa_group); - return -1; - } - wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", - __func__, ciphernames[v], v); - if (set80211param(drv, IEEE80211_IOC_MCASTCIPHER, v)) { - printf("Unable to set group key cipher to %u (%s)\n", - v, ciphernames[v]); - return -1; - } - if (v == IEEE80211_CIPHER_WEP) { - /* key length is done only for specific ciphers */ - v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); - if (set80211param(drv, IEEE80211_IOC_MCASTKEYLEN, v)) { - printf("Unable to set group key length to %u\n", v); - return -1; - } - } - - v = 0; - if (conf->wpa_pairwise & WPA_CIPHER_CCMP) - v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) - v |= 1<wpa_pairwise & WPA_CIPHER_NONE) - v |= 1<wpa_key_mgmt); - if (set80211param(drv, IEEE80211_IOC_KEYMGTALGS, conf->wpa_key_mgmt)) { - printf("Unable to set key management algorithms to 0x%x\n", - conf->wpa_key_mgmt); - return -1; - } - - v = 0; - if (conf->rsn_preauth) - v |= BIT(0); - wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", - __func__, conf->rsn_preauth); - if (set80211param(drv, IEEE80211_IOC_RSNCAPS, v)) { - printf("Unable to set RSN capabilities to 0x%x\n", v); - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, conf->wpa); - if (set80211param(drv, IEEE80211_IOC_WPA, conf->wpa)) { - printf("Unable to set WPA to %u\n", conf->wpa); - return -1; - } - return 0; -} - - -static int -bsd_set_iface_flags(void *priv, int dev_up) -{ - struct bsd_driver_data *drv = priv; - struct ifreq ifr; - - wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up); - - if (drv->ioctl_sock < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - if (dev_up) { - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - ifr.ifr_mtu = HOSTAPD_MTU; - if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { - perror("ioctl[SIOCSIFMTU]"); - printf("Setting MTU failed - trying to survive with " - "current value\n"); - } - } - - return 0; -} - -static int -bsd_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct bsd_driver_data *drv = priv; - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - if (!enabled) { - /* XXX restore state */ - return set80211param(priv, IEEE80211_IOC_AUTHMODE, - IEEE80211_AUTH_AUTO); - } - if (!conf->wpa && !conf->ieee802_1x) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); - return -1; - } - if (conf->wpa && bsd_configure_wpa(drv) != 0) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); - return -1; - } - if (set80211param(priv, IEEE80211_IOC_AUTHMODE, - (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); - return -1; - } - return bsd_set_iface_flags(priv, 1); -} - -static int -bsd_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct bsd_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - return set80211param(drv, IEEE80211_IOC_PRIVACY, enabled); -} - -static int -bsd_set_sta_authorized(void *priv, const u8 *addr, int authorized) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - - wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", - __func__, ether_sprintf(addr), authorized); - - if (authorized) - mlme.im_op = IEEE80211_MLME_AUTHORIZE; - else - mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; - mlme.im_reason = 0; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); -} - -static int -bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, - int flags_and) -{ - /* For now, only support setting Authorized flag */ - if (flags_or & WLAN_STA_AUTHORIZED) - return bsd_set_sta_authorized(priv, addr, 1); - if (!(flags_and & WLAN_STA_AUTHORIZED)) - return bsd_set_sta_authorized(priv, addr, 0); - return 0; -} - -static int -bsd_del_key(void *priv, const u8 *addr, int key_idx) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_del_key wk; - - wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", - __func__, ether_sprintf(addr), key_idx); - - memset(&wk, 0, sizeof(wk)); - if (addr != NULL) { - memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ - } else { - wk.idk_keyix = key_idx; - } - - return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); -} - -static int -bsd_set_key(const char *ifname, void *priv, const char *alg, - const u8 *addr, int key_idx, - const u8 *key, size_t key_len, int txkey) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_key wk; - u_int8_t cipher; - - if (strcmp(alg, "none") == 0) - return bsd_del_key(drv, addr, key_idx); - - wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d", - __func__, alg, ether_sprintf(addr), key_idx); - - if (strcmp(alg, "WEP") == 0) - cipher = IEEE80211_CIPHER_WEP; - else if (strcmp(alg, "TKIP") == 0) - cipher = IEEE80211_CIPHER_TKIP; - else if (strcmp(alg, "CCMP") == 0) - cipher = IEEE80211_CIPHER_AES_CCM; - else { - printf("%s: unknown/unsupported algorithm %s\n", - __func__, alg); - return -1; - } - - if (key_len > sizeof(wk.ik_keydata)) { - printf("%s: key length %d too big\n", __func__, key_len); - return -3; - } - - memset(&wk, 0, sizeof(wk)); - wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; - if (addr == NULL) { - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - wk.ik_keyix = key_idx; - wk.ik_flags |= IEEE80211_KEY_DEFAULT; - } else { - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = IEEE80211_KEYIX_NONE; - } - wk.ik_keylen = key_len; - memcpy(wk.ik_keydata, key, key_len); - - return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); -} - - -static int -bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_key wk; - - wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", - __func__, ether_sprintf(addr), idx); - - memset(&wk, 0, sizeof(wk)); - if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = idx; - - if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { - printf("Failed to get encryption.\n"); - return -1; - } - -#ifdef WORDS_BIGENDIAN - { - /* - * wk.ik_keytsc is in host byte order (big endian), need to - * swap it to match with the byte order used in WPA. - */ - int i; - u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); - for (i = 0; i < WPA_KEY_RSC_LEN; i++) { - seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; - } - } -#else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -#endif /* WORDS_BIGENDIAN */ - return 0; -} - - -static int -bsd_flush(void *priv) -{ - u8 allsta[IEEE80211_ADDR_LEN]; - - memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return bsd_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE); -} - - -static int -bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_sta_stats stats; - - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); - if (get80211var(drv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) { - /* XXX? do packets counts include non-data frames? */ - data->rx_packets = stats.is_stats.ns_rx_data; - data->rx_bytes = stats.is_stats.ns_rx_bytes; - data->tx_packets = stats.is_stats.ns_tx_data; - data->tx_bytes = stats.is_stats.ns_tx_bytes; - } - return 0; -} - -static int -bsd_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len) -{ - /* - * Do nothing; we setup parameters at startup that define the - * contents of the beacon information element. - */ - return 0; -} - -static int -bsd_sta_deauth(void *priv, const u8 *addr, int reason_code) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DEAUTH; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); -} - -static int -bsd_sta_disassoc(void *priv, const u8 *addr, int reason_code) -{ - struct bsd_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DISASSOC; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); -} - -static int -bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -{ - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - struct sta_info *sta; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deassociated"); - - sta = ap_get_sta(hapd, addr); - if (sta != NULL) { - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - if (conf->wpa) - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); - } - return 0; -} - -static int -bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -{ - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - struct sta_info *sta; - struct ieee80211req_wpaie ie; - int new_assoc, ielen, res; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "associated"); - - sta = ap_sta_add(hapd, addr); - if (sta == NULL) - return -1; - /* - * Fetch and validate any negotiated WPA/RSN parameters. - */ - if (conf->wpa) { - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); - if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { - printf("Failed to get WPA/RSN information element.\n"); - return -1; /* XXX not right */ - } - ielen = ie.wpa_ie[1]; - if (ielen == 0) { - printf("No WPA/RSN information element for station!\n"); - return -1; /* XXX not right */ - } - ielen += 2; - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, - sta->addr); - if (sta->wpa_sm == NULL) { - printf("Failed to initialize WPA state machine\n"); - return -1; - } - res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, - ie.wpa_ie, ielen, NULL, 0); - if (res != WPA_IE_OK) { - printf("WPA/RSN information element rejected? " - "(res %u)\n", res); - return -1; - } - } - - /* - * Now that the internal station state is setup - * kick the authenticator into action. - */ - new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - hostapd_new_assoc_sta(hapd, sta, !new_assoc); - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - return 0; -} - -#include -#include - -static void -bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) -{ - struct bsd_driver_data *drv = ctx; - struct hostapd_data *hapd = drv->hapd; - char buf[2048]; - struct if_announcemsghdr *ifan; - struct rt_msghdr *rtm; - struct ieee80211_michael_event *mic; - struct ieee80211_join_event *join; - struct ieee80211_leave_event *leave; - int n; - - n = read(sock, buf, sizeof(buf)); - if (n < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("read(PF_ROUTE)"); - return; - } - - rtm = (struct rt_msghdr *) buf; - if (rtm->rtm_version != RTM_VERSION) { - wpa_printf(MSG_DEBUG, "Routing message version %d not " - "understood\n", rtm->rtm_version); - return; - } - ifan = (struct if_announcemsghdr *) rtm; - switch (rtm->rtm_type) { - case RTM_IEEE80211: - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - case RTM_IEEE80211_DISASSOC: - case RTM_IEEE80211_SCAN: - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - bsd_del_sta(drv, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - ieee80211_michael_mic_failure(hapd, mic->iev_src, 1); - break; - } - break; - } -} - -static int -bsd_wireless_event_init(void *priv) -{ - struct bsd_driver_data *drv = priv; - int s; - - drv->wext_sock = -1; - - s = socket(PF_ROUTE, SOCK_RAW, 0); - if (s < 0) { - perror("socket(PF_ROUTE,SOCK_RAW)"); - return -1; - } - eloop_register_read_sock(s, bsd_wireless_event_receive, drv, NULL); - drv->wext_sock = s; - - return 0; -} - -static void -bsd_wireless_event_deinit(void *priv) -{ - struct bsd_driver_data *drv = priv; - - if (drv != NULL) { - if (drv->wext_sock < 0) - return; - eloop_unregister_read_sock(drv->wext_sock); - close(drv->wext_sock); - } -} - - -static int -bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr) -{ - struct bsd_driver_data *drv = priv; - unsigned char buf[3000]; - unsigned char *bp = buf; - struct l2_ethhdr *eth; - size_t len; - int status; - - /* - * Prepend the Etherent header. If the caller left us - * space at the front we could just insert it but since - * we don't know we copy to a local buffer. Given the frequency - * and size of frames this probably doesn't matter. - */ - len = data_len + sizeof(struct l2_ethhdr); - if (len > sizeof(buf)) { - bp = malloc(len); - if (bp == NULL) { - printf("EAPOL frame discarded, cannot malloc temp " - "buffer of size %u!\n", len); - return -1; - } - } - eth = (struct l2_ethhdr *) bp; - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, own_addr, ETH_ALEN); - eth->h_proto = htons(ETH_P_EAPOL); - memcpy(eth+1, data, data_len); - - wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); - - status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); - - if (bp != buf) - free(bp); - return status; -} - -static void -handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -{ - struct bsd_driver_data *drv = ctx; - struct hostapd_data *hapd = drv->hapd; - struct sta_info *sta; - - sta = ap_get_sta(hapd, src_addr); - if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { - printf("Data frame from not associated STA %s\n", - ether_sprintf(src_addr)); - /* XXX cannot happen */ - return; - } - ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr), - len - sizeof(struct l2_ethhdr)); -} - -static int -bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len) -{ - struct bsd_driver_data *drv = priv; - int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len); - - wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf); - - return ssid_len; -} - -static int -bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len) -{ - struct bsd_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, len, buf); - - return set80211var(drv, IEEE80211_IOC_SSID, buf, len); -} - -static void * -bsd_init(struct hostapd_data *hapd) -{ - struct bsd_driver_data *drv; - - drv = os_zalloc(sizeof(struct bsd_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for bsd driver data\n"); - goto bad; - } - - drv->hapd = hapd; - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - goto bad; - } - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); - - drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, - handle_read, drv, 1); - if (drv->sock_xmit == NULL) - goto bad; - if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr)) - goto bad; - - bsd_set_iface_flags(drv, 0); /* mark down during setup */ - - return drv; -bad: - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv != NULL) - free(drv); - return NULL; -} - - -static void -bsd_deinit(void *priv) -{ - struct bsd_driver_data *drv = priv; - - (void) bsd_set_iface_flags(drv, 0); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - free(drv); -} - -const struct wpa_driver_ops wpa_driver_bsd_ops = { - .name = "bsd", - .init = bsd_init, - .deinit = bsd_deinit, - .set_ieee8021x = bsd_set_ieee8021x, - .set_privacy = bsd_set_privacy, - .set_encryption = bsd_set_key, - .get_seqnum = bsd_get_seqnum, - .flush = bsd_flush, - .set_generic_elem = bsd_set_opt_ie, - .wireless_event_init = bsd_wireless_event_init, - .wireless_event_deinit = bsd_wireless_event_deinit, - .sta_set_flags = bsd_sta_set_flags, - .read_sta_data = bsd_read_sta_driver_data, - .send_eapol = bsd_send_eapol, - .sta_disassoc = bsd_sta_disassoc, - .sta_deauth = bsd_sta_deauth, - .set_ssid = bsd_set_ssid, - .get_ssid = bsd_get_ssid, -}; diff --git a/hostapd/driver_hostap.c b/hostapd/driver_hostap.c deleted file mode 100644 index ceff0998919c..000000000000 --- a/hostapd/driver_hostap.c +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * hostapd / Kernel driver communication with Linux Host AP driver - * Copyright (c) 2002-2007, Jouni Malinen - * - * 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 - -#ifdef USE_KERNEL_HEADERS -/* compat-wireless does not include linux/compiler.h to define __user, so - * define it here */ -#ifndef __user -#define __user -#endif /* __user */ -#include -#include -#include /* The L2 protocols */ -#include -#include -#else /* USE_KERNEL_HEADERS */ -#include -#include -#include "wireless_copy.h" -#endif /* USE_KERNEL_HEADERS */ - -#include "hostapd.h" -#include "driver.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "priv_netlink.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "hostap_common.h" -#include "hw_features.h" - - -struct hostap_driver_data { - struct hostapd_data *hapd; - - char iface[IFNAMSIZ + 1]; - int sock; /* raw packet socket for driver access */ - int ioctl_sock; /* socket for ioctl() use */ - int wext_sock; /* socket for wireless events */ - - int we_version; - - u8 *generic_ie; - size_t generic_ie_len; - u8 *wps_ie; - size_t wps_ie_len; -}; - - -static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, - int len); -static int hostap_set_iface_flags(void *priv, int dev_up); - -static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len, - u16 stype) -{ - struct ieee80211_hdr *hdr; - u16 fc, ethertype; - u8 *pos, *sa; - size_t left; - struct sta_info *sta; - - if (len < sizeof(struct ieee80211_hdr)) - return; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) { - printf("Not ToDS data frame (fc=0x%04x)\n", fc); - return; - } - - sa = hdr->addr2; - sta = ap_get_sta(hapd, sa); - if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { - printf("Data frame from not associated STA " MACSTR "\n", - MAC2STR(sa)); - if (sta && (sta->flags & WLAN_STA_AUTH)) - hostapd_sta_disassoc( - hapd, sa, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - else - hostapd_sta_deauth( - hapd, sa, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - return; - } - - pos = (u8 *) (hdr + 1); - left = len - sizeof(*hdr); - - if (left < sizeof(rfc1042_header)) { - printf("Too short data frame\n"); - return; - } - - if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) { - printf("Data frame with no RFC1042 header\n"); - return; - } - pos += sizeof(rfc1042_header); - left -= sizeof(rfc1042_header); - - if (left < 2) { - printf("No ethertype in data frame\n"); - return; - } - - ethertype = WPA_GET_BE16(pos); - pos += 2; - left -= 2; - switch (ethertype) { - case ETH_P_PAE: - ieee802_1x_receive(hapd, sa, pos, left); - break; - - default: - printf("Unknown ethertype 0x%04x in data frame\n", ethertype); - break; - } -} - - -static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len, - int ok) -{ - struct ieee80211_hdr *hdr; - u16 fc, type, stype; - struct sta_info *sta; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - case WLAN_FC_TYPE_MGMT: - wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s", - ok ? "ACK" : "fail"); - ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); - break; - case WLAN_FC_TYPE_CTRL: - wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s", - ok ? "ACK" : "fail"); - break; - case WLAN_FC_TYPE_DATA: - wpa_printf(MSG_DEBUG, "DATA (TX callback) %s", - ok ? "ACK" : "fail"); - sta = ap_get_sta(hapd, hdr->addr1); - if (sta && sta->flags & WLAN_STA_PENDING_POLL) { - wpa_printf(MSG_DEBUG, "STA " MACSTR - " %s pending activity poll", - MAC2STR(sta->addr), - ok ? "ACKed" : "did not ACK"); - if (ok) - sta->flags &= ~WLAN_STA_PENDING_POLL; - } - if (sta) - ieee802_1x_tx_status(hapd, sta, buf, len, ok); - break; - default: - printf("unknown TX callback frame type %d\n", type); - break; - } -} - - -static void handle_frame(struct hostapd_data *hapd, u8 *buf, size_t len) -{ - struct ieee80211_hdr *hdr; - u16 fc, extra_len, type, stype; - unsigned char *extra = NULL; - size_t data_len = len; - int ver; - - /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass - * these to user space */ - if (len < 24) { - wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)", - (unsigned long) len); - return; - } - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) { - wpa_hexdump(MSG_MSGDUMP, "Received management frame", - buf, len); - } - - ver = fc & WLAN_FC_PVER; - - /* protocol version 3 is reserved for indicating extra data after the - * payload, version 2 for indicating ACKed frame (TX callbacks), and - * version 1 for indicating failed frame (no ACK, TX callbacks) */ - if (ver == 3) { - u8 *pos = buf + len - 2; - extra_len = WPA_GET_LE16(pos); - printf("extra data in frame (elen=%d)\n", extra_len); - if ((size_t) extra_len + 2 > len) { - printf(" extra data overflow\n"); - return; - } - len -= extra_len + 2; - extra = buf + len; - } else if (ver == 1 || ver == 2) { - handle_tx_callback(hapd, buf, data_len, ver == 2 ? 1 : 0); - return; - } else if (ver != 0) { - printf("unknown protocol version %d\n", ver); - return; - } - - switch (type) { - case WLAN_FC_TYPE_MGMT: - if (stype != WLAN_FC_STYPE_BEACON) - wpa_printf(MSG_MSGDUMP, "MGMT"); - ieee802_11_mgmt(hapd, buf, data_len, stype, NULL); - break; - case WLAN_FC_TYPE_CTRL: - wpa_printf(MSG_DEBUG, "CTRL"); - break; - case WLAN_FC_TYPE_DATA: - wpa_printf(MSG_DEBUG, "DATA"); - handle_data(hapd, buf, data_len, stype); - break; - default: - wpa_printf(MSG_DEBUG, "unknown frame type %d", type); - break; - } -} - - -static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; - int len; - unsigned char buf[3000]; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - handle_frame(hapd, buf, len); -} - - -static int hostap_init_sockets(struct hostap_driver_data *drv) -{ - struct ifreq ifr; - struct sockaddr_ll addr; - - drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - return -1; - } - - if (eloop_register_read_sock(drv->sock, handle_read, drv->hapd, NULL)) - { - printf("Could not register read socket\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); - if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - return -1; - } - - if (hostap_set_iface_flags(drv, 1)) { - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - return -1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - return -1; - } - memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - return 0; -} - - -static int hostap_send_mgmt_frame(void *priv, const void *msg, size_t len, - int flags) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; - int res; - - /* Request TX callback */ - hdr->frame_control |= host_to_le16(BIT(1)); - res = send(drv->sock, msg, len, flags); - hdr->frame_control &= ~host_to_le16(BIT(1)); - - return res; -} - - -static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_hdr *hdr; - size_t len; - u8 *pos; - int res; - - len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for hostapd_send_data(len=%lu)\n", - (unsigned long) len); - return -1; - } - - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); - hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); - if (encrypt) - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); - memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); - memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); - memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - - pos = (u8 *) (hdr + 1); - memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); - pos += sizeof(rfc1042_header); - *((u16 *) pos) = htons(ETH_P_PAE); - pos += 2; - memcpy(pos, data, data_len); - - res = hostap_send_mgmt_frame(drv, (u8 *) hdr, len, 0); - free(hdr); - - if (res < 0) { - perror("hostapd_send_eapol: send"); - printf("hostapd_send_eapol - packet len: %lu - failed\n", - (unsigned long) len); - } - - return res; -} - - -static int hostap_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - param.u.set_flags_sta.flags_or = flags_or; - param.u.set_flags_sta.flags_and = flags_and; - return hostapd_ioctl(drv, ¶m, sizeof(param)); -} - - -static int hostap_set_iface_flags(void *priv, int dev_up) -{ - struct hostap_driver_data *drv = priv; - struct ifreq ifr; - - if (drv->ioctl_sock < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - if (dev_up) { - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface); - ifr.ifr_mtu = HOSTAPD_MTU; - if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { - perror("ioctl[SIOCSIFMTU]"); - printf("Setting MTU failed - trying to survive with " - "current value\n"); - } - } - - return 0; -} - - -static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, - int len) -{ - struct hostap_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) param; - iwr.u.data.length = len; - - if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { - perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); - return -1; - } - - return 0; -} - - -static int hostap_set_encryption(const char *ifname, void *priv, - const char *alg, const u8 *addr, - int idx, const u8 *key, size_t key_len, - int txkey) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param *param; - u8 *buf; - size_t blen; - int ret = 0; - - blen = sizeof(*param) + key_len; - buf = os_zalloc(blen); - if (buf == NULL) - return -1; - - param = (struct prism2_hostapd_param *) buf; - param->cmd = PRISM2_SET_ENCRYPTION; - if (addr == NULL) - memset(param->sta_addr, 0xff, ETH_ALEN); - else - memcpy(param->sta_addr, addr, ETH_ALEN); - os_strlcpy((char *) param->u.crypt.alg, alg, - HOSTAP_CRYPT_ALG_NAME_LEN); - param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; - param->u.crypt.idx = idx; - param->u.crypt.key_len = key_len; - memcpy((u8 *) (param + 1), key, key_len); - - if (hostapd_ioctl(drv, param, blen)) { - printf("Failed to set encryption.\n"); - ret = -1; - } - free(buf); - - return ret; -} - - -static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, - int idx, u8 *seq) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param *param; - u8 *buf; - size_t blen; - int ret = 0; - - blen = sizeof(*param) + 32; - buf = os_zalloc(blen); - if (buf == NULL) - return -1; - - param = (struct prism2_hostapd_param *) buf; - param->cmd = PRISM2_GET_ENCRYPTION; - if (addr == NULL) - memset(param->sta_addr, 0xff, ETH_ALEN); - else - memcpy(param->sta_addr, addr, ETH_ALEN); - param->u.crypt.idx = idx; - - if (hostapd_ioctl(drv, param, blen)) { - printf("Failed to get encryption.\n"); - ret = -1; - } else { - memcpy(seq, param->u.crypt.seq, 8); - } - free(buf); - - return ret; -} - - -static int hostap_ioctl_prism2param(void *priv, int param, int value) -{ - struct hostap_driver_data *drv = priv; - struct iwreq iwr; - int *i; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - i = (int *) iwr.u.name; - *i++ = param; - *i++ = value; - - if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { - perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); - return -1; - } - - return 0; -} - - -static int hostap_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct hostap_driver_data *drv = priv; - - /* enable kernel driver support for IEEE 802.1X */ - if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) { - printf("Could not setup IEEE 802.1X support in kernel driver." - "\n"); - return -1; - } - - if (!enabled) - return 0; - - /* use host driver implementation of encryption to allow - * individual keys and passing plaintext EAPOL frames */ - if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) || - hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) { - printf("Could not setup host-based encryption in kernel " - "driver.\n"); - return -1; - } - - return 0; -} - - -static int hostap_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct hostap_drvier_data *drv = priv; - - return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, - enabled); -} - - -static int hostap_set_ssid(const char *ifname, void *priv, const u8 *buf, - int len) -{ - struct hostap_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len + 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } - - return 0; -} - - -static int hostap_flush(void *priv) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_FLUSH; - return hostapd_ioctl(drv, ¶m, sizeof(param)); -} - - -static int hostap_read_sta_data(void *priv, - struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - char buf[1024], line[128], *pos; - FILE *f; - unsigned long val; - - memset(data, 0, sizeof(*data)); - snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR, - drv->iface, MAC2STR(addr)); - - f = fopen(buf, "r"); - if (!f) - return -1; - /* Need to read proc file with in one piece, so use large enough - * buffer. */ - setbuffer(f, buf, sizeof(buf)); - - while (fgets(line, sizeof(line), f)) { - pos = strchr(line, '='); - if (!pos) - continue; - *pos++ = '\0'; - val = strtoul(pos, NULL, 10); - if (strcmp(line, "rx_packets") == 0) - data->rx_packets = val; - else if (strcmp(line, "tx_packets") == 0) - data->tx_packets = val; - else if (strcmp(line, "rx_bytes") == 0) - data->rx_bytes = val; - else if (strcmp(line, "tx_bytes") == 0) - data->tx_bytes = val; - } - - fclose(f); - - return 0; -} - - -static int hostap_sta_add(const char *ifname, void *priv, const u8 *addr, - u16 aid, u16 capability, u8 *supp_rates, - size_t supp_rates_len, int flags, - u16 listen_interval) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - int tx_supp_rates = 0; - size_t i; - -#define WLAN_RATE_1M BIT(0) -#define WLAN_RATE_2M BIT(1) -#define WLAN_RATE_5M5 BIT(2) -#define WLAN_RATE_11M BIT(3) - - for (i = 0; i < supp_rates_len; i++) { - if ((supp_rates[i] & 0x7f) == 2) - tx_supp_rates |= WLAN_RATE_1M; - if ((supp_rates[i] & 0x7f) == 4) - tx_supp_rates |= WLAN_RATE_2M; - if ((supp_rates[i] & 0x7f) == 11) - tx_supp_rates |= WLAN_RATE_5M5; - if ((supp_rates[i] & 0x7f) == 22) - tx_supp_rates |= WLAN_RATE_11M; - } - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_ADD_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - param.u.add_sta.aid = aid; - param.u.add_sta.capability = capability; - param.u.add_sta.tx_supp_rates = tx_supp_rates; - return hostapd_ioctl(drv, ¶m, sizeof(param)); -} - - -static int hostap_sta_remove(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED); - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_REMOVE_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - printf("Could not remove station from kernel driver.\n"); - return -1; - } - return 0; -} - - -static int hostap_get_inact_sec(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - return -1; - } - - return param.u.get_info_sta.inactive_sec; -} - - -static int hostap_sta_clear_stats(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - return -1; - } - - return 0; -} - - -static int hostap_set_assoc_ap(void *priv, const u8 *addr) -{ - struct hostap_driver_data *drv = priv; - struct prism2_hostapd_param param; - - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) - return -1; - - return 0; -} - - -static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv) -{ - struct prism2_hostapd_param *param; - int res; - size_t blen, elem_len; - - elem_len = drv->generic_ie_len + drv->wps_ie_len; - blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len; - if (blen < sizeof(*param)) - blen = sizeof(*param); - - param = os_zalloc(blen); - if (param == NULL) - return -1; - - param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; - param->u.generic_elem.len = elem_len; - if (drv->generic_ie) { - os_memcpy(param->u.generic_elem.data, drv->generic_ie, - drv->generic_ie_len); - } - if (drv->wps_ie) { - os_memcpy(¶m->u.generic_elem.data[drv->generic_ie_len], - drv->wps_ie, drv->wps_ie_len); - } - wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE", - param->u.generic_elem.data, elem_len); - res = hostapd_ioctl(drv, param, blen); - - os_free(param); - - return res; -} - - -static int hostap_set_generic_elem(const char *ifname, void *priv, - const u8 *elem, size_t elem_len) -{ - struct hostap_driver_data *drv = priv; - - os_free(drv->generic_ie); - drv->generic_ie = NULL; - drv->generic_ie_len = 0; - if (elem) { - drv->generic_ie = os_malloc(elem_len); - if (drv->generic_ie == NULL) - return -1; - os_memcpy(drv->generic_ie, elem, elem_len); - drv->generic_ie_len = elem_len; - } - - return hostapd_ioctl_set_generic_elem(drv); -} - - -static int hostap_set_wps_beacon_ie(const char *ifname, void *priv, - const u8 *ie, size_t len) -{ - /* Host AP driver supports only one set of extra IEs, so we need to - * use the ProbeResp IEs also for Beacon frames since they include more - * information. */ - return 0; -} - - -static int hostap_set_wps_probe_resp_ie(const char *ifname, void *priv, - const u8 *ie, size_t len) -{ - struct hostap_driver_data *drv = priv; - - os_free(drv->wps_ie); - drv->wps_ie = NULL; - drv->wps_ie_len = 0; - if (ie) { - drv->wps_ie = os_malloc(len); - if (drv->wps_ie == NULL) - return -1; - os_memcpy(drv->wps_ie, ie, len); - drv->wps_ie_len = len; - } - - return hostapd_ioctl_set_generic_elem(drv); -} - - -static void -hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv, - char *custom) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - ieee80211_michael_mic_failure(drv->hapd, addr, 1); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } -} - - -static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - if (drv->we_version > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM)) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - hostapd_wireless_event_wireless_custom(drv, buf); - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void hostapd_wireless_event_rtm_newlink(struct hostap_driver_data *drv, - struct nlmsghdr *h, int len) -{ - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; - - if (len < (int) sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - /* TODO: use ifi->ifi_index to filter out wireless events from other - * interfaces */ - - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - hostapd_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void hostapd_wireless_event_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - char buf[256]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - struct hostap_driver_data *drv = eloop_ctx; - - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - printf("Malformed netlink message: " - "len=%d left=%d plen=%d\n", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - hostapd_wireless_event_rtm_newlink(drv, h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - printf("%d extra bytes in the end of netlink message\n", left); - } -} - - -static int hostap_get_we_version(struct hostap_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - free(range); - return 0; -} - - -static int hostap_wireless_event_init(void *priv) -{ - struct hostap_driver_data *drv = priv; - int s; - struct sockaddr_nl local; - - hostap_get_we_version(drv); - - drv->wext_sock = -1; - - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - return -1; - } - - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - eloop_register_read_sock(s, hostapd_wireless_event_receive, drv, - NULL); - drv->wext_sock = s; - - return 0; -} - - -static void hostap_wireless_event_deinit(void *priv) -{ - struct hostap_driver_data *drv = priv; - if (drv->wext_sock < 0) - return; - eloop_unregister_read_sock(drv->wext_sock); - close(drv->wext_sock); -} - - -static void * hostap_init(struct hostapd_data *hapd) -{ - struct hostap_driver_data *drv; - - drv = os_zalloc(sizeof(struct hostap_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for hostapd driver data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->ioctl_sock = drv->sock = -1; - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - free(drv); - return NULL; - } - - if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) { - printf("Could not enable hostapd mode for interface %s\n", - drv->iface); - close(drv->ioctl_sock); - free(drv); - return NULL; - } - - if (hostap_init_sockets(drv)) { - close(drv->ioctl_sock); - free(drv); - return NULL; - } - - return drv; -} - - -static void hostap_driver_deinit(void *priv) -{ - struct hostap_driver_data *drv = priv; - - (void) hostap_set_iface_flags(drv, 0); - (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0); - (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0); - - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - - if (drv->sock >= 0) - close(drv->sock); - - os_free(drv->generic_ie); - os_free(drv->wps_ie); - - free(drv); -} - - -static int hostap_sta_deauth(void *priv, const u8 *addr, int reason) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); - memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); - mgmt.u.deauth.reason_code = host_to_le16(reason); - return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0); -} - - -static int hostap_sta_disassoc(void *priv, const u8 *addr, int reason) -{ - struct hostap_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); - memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); - mgmt.u.disassoc.reason_code = host_to_le16(reason); - return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0); -} - - -static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, - u16 *num_modes, - u16 *flags) -{ - struct hostapd_hw_modes *mode; - int i, clen, rlen; - const short chan2freq[14] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 - }; - - mode = os_zalloc(sizeof(struct hostapd_hw_modes)); - if (mode == NULL) - return NULL; - - *num_modes = 1; - *flags = 0; - - mode->mode = HOSTAPD_MODE_IEEE80211B; - mode->num_channels = 14; - mode->num_rates = 4; - - clen = mode->num_channels * sizeof(struct hostapd_channel_data); - rlen = mode->num_rates * sizeof(struct hostapd_rate_data); - - mode->channels = os_zalloc(clen); - mode->rates = os_zalloc(rlen); - if (mode->channels == NULL || mode->rates == NULL) { - hostapd_free_hw_features(mode, *num_modes); - return NULL; - } - - for (i = 0; i < 14; i++) { - mode->channels[i].chan = i + 1; - mode->channels[i].freq = chan2freq[i]; - /* TODO: Get allowed channel list from the driver */ - if (i >= 11) - mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; - } - - mode->rates[0].rate = 10; - mode->rates[0].flags = HOSTAPD_RATE_CCK; - mode->rates[1].rate = 20; - mode->rates[1].flags = HOSTAPD_RATE_CCK; - mode->rates[2].rate = 55; - mode->rates[2].flags = HOSTAPD_RATE_CCK; - mode->rates[3].rate = 110; - mode->rates[3].flags = HOSTAPD_RATE_CCK; - - return mode; -} - - -const struct wpa_driver_ops wpa_driver_hostap_ops = { - .name = "hostap", - .init = hostap_init, - .deinit = hostap_driver_deinit, - .wireless_event_init = hostap_wireless_event_init, - .wireless_event_deinit = hostap_wireless_event_deinit, - .set_ieee8021x = hostap_set_ieee8021x, - .set_privacy = hostap_set_privacy, - .set_encryption = hostap_set_encryption, - .get_seqnum = hostap_get_seqnum, - .flush = hostap_flush, - .set_generic_elem = hostap_set_generic_elem, - .read_sta_data = hostap_read_sta_data, - .send_eapol = hostap_send_eapol, - .sta_set_flags = hostap_sta_set_flags, - .sta_deauth = hostap_sta_deauth, - .sta_disassoc = hostap_sta_disassoc, - .sta_remove = hostap_sta_remove, - .set_ssid = hostap_set_ssid, - .send_mgmt_frame = hostap_send_mgmt_frame, - .set_assoc_ap = hostap_set_assoc_ap, - .sta_add = hostap_sta_add, - .get_inact_sec = hostap_get_inact_sec, - .sta_clear_stats = hostap_sta_clear_stats, - .get_hw_feature_data = hostap_get_hw_feature_data, - .set_wps_beacon_ie = hostap_set_wps_beacon_ie, - .set_wps_probe_resp_ie = hostap_set_wps_probe_resp_ie, -}; diff --git a/hostapd/driver_madwifi.c b/hostapd/driver_madwifi.c deleted file mode 100644 index 4083fda29b23..000000000000 --- a/hostapd/driver_madwifi.c +++ /dev/null @@ -1,1483 +0,0 @@ -/* - * hostapd / Driver interaction with MADWIFI 802.11 driver - * Copyright (c) 2004, Sam Leffler - * Copyright (c) 2004, Video54 Technologies - * Copyright (c) 2005-2007, Jouni Malinen - * - * 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 -#include - -#include -#include -#ifdef WME_NUM_AC -/* Assume this is built against BSD branch of madwifi driver. */ -#define MADWIFI_BSD -#include -#endif /* WME_NUM_AC */ -#include -#include - -#ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME -#include - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW 0x0019 -#endif -#endif /* IEEE80211_IOCTL_FILTERFRAME */ -#endif /* CONFIG_WPS */ - -/* - * Avoid conflicts with hostapd definitions by undefining couple of defines - * from madwifi header files. - */ -#undef RSN_VERSION -#undef WPA_VERSION -#undef WPA_OUI_TYPE -#undef WME_OUI_TYPE - - -#ifdef IEEE80211_IOCTL_SETWMMPARAMS -/* Assume this is built against madwifi-ng */ -#define MADWIFI_NG -#endif /* IEEE80211_IOCTL_SETWMMPARAMS */ - -#include "wireless_copy.h" - -#include "hostapd.h" -#include "driver.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "priv_netlink.h" -#include "sta_info.h" -#include "l2_packet/l2_packet.h" - -#include "wpa.h" -#include "radius/radius.h" -#include "ieee802_11.h" -#include "accounting.h" -#include "common.h" -#include "wps_hostapd.h" - - -struct madwifi_driver_data { - struct hostapd_data *hapd; /* back pointer */ - - char iface[IFNAMSIZ + 1]; - int ifindex; - struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ - struct l2_packet_data *sock_recv; /* raw packet recv socket */ - int ioctl_sock; /* socket for ioctl() use */ - int wext_sock; /* socket for wireless events */ - int we_version; - u8 acct_mac[ETH_ALEN]; - struct hostap_sta_driver_data acct_data; - - struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ -}; - -static int madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code); - -static int -set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) -{ - struct iwreq iwr; - int do_inline = len < IFNAMSIZ; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -#ifdef IEEE80211_IOCTL_FILTERFRAME - /* FILTERFRAME must be NOT inline, regardless of size. */ - if (op == IEEE80211_IOCTL_FILTERFRAME) - do_inline = 0; -#endif /* IEEE80211_IOCTL_FILTERFRAME */ - if (op == IEEE80211_IOCTL_SET_APPIEBUF) - do_inline = 0; - if (do_inline) { - /* - * Argument data fits inline; put it there. - */ - memcpy(iwr.u.name, data, len); - } else { - /* - * Argument data too big for inline transfer; setup a - * parameter block instead; the kernel will transfer - * the data for the driver. - */ - iwr.u.data.pointer = data; - iwr.u.data.length = len; - } - - if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { -#ifdef MADWIFI_NG - int first = IEEE80211_IOCTL_SETPARAM; - static const char *opnames[] = { - "ioctl[IEEE80211_IOCTL_SETPARAM]", - "ioctl[IEEE80211_IOCTL_GETPARAM]", - "ioctl[IEEE80211_IOCTL_SETMODE]", - "ioctl[IEEE80211_IOCTL_GETMODE]", - "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]", - "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]", - "ioctl[IEEE80211_IOCTL_SETCHANLIST]", - "ioctl[IEEE80211_IOCTL_GETCHANLIST]", - "ioctl[IEEE80211_IOCTL_CHANSWITCH]", - "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]", - "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", - "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]", - "ioctl[IEEE80211_IOCTL_FILTERFRAME]", - "ioctl[IEEE80211_IOCTL_GETCHANINFO]", - "ioctl[IEEE80211_IOCTL_SETOPTIE]", - "ioctl[IEEE80211_IOCTL_GETOPTIE]", - "ioctl[IEEE80211_IOCTL_SETMLME]", - NULL, - "ioctl[IEEE80211_IOCTL_SETKEY]", - NULL, - "ioctl[IEEE80211_IOCTL_DELKEY]", - NULL, - "ioctl[IEEE80211_IOCTL_ADDMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_DELMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_WDSMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_WDSDELMAC]", - NULL, - "ioctl[IEEE80211_IOCTL_KICKMAC]", - }; -#else /* MADWIFI_NG */ - int first = IEEE80211_IOCTL_SETPARAM; - static const char *opnames[] = { - "ioctl[IEEE80211_IOCTL_SETPARAM]", - "ioctl[IEEE80211_IOCTL_GETPARAM]", - "ioctl[IEEE80211_IOCTL_SETKEY]", - "ioctl[SIOCIWFIRSTPRIV+3]", - "ioctl[IEEE80211_IOCTL_DELKEY]", - "ioctl[SIOCIWFIRSTPRIV+5]", - "ioctl[IEEE80211_IOCTL_SETMLME]", - "ioctl[SIOCIWFIRSTPRIV+7]", - "ioctl[IEEE80211_IOCTL_SETOPTIE]", - "ioctl[IEEE80211_IOCTL_GETOPTIE]", - "ioctl[IEEE80211_IOCTL_ADDMAC]", - "ioctl[SIOCIWFIRSTPRIV+11]", - "ioctl[IEEE80211_IOCTL_DELMAC]", - "ioctl[SIOCIWFIRSTPRIV+13]", - "ioctl[IEEE80211_IOCTL_CHANLIST]", - "ioctl[SIOCIWFIRSTPRIV+15]", - "ioctl[IEEE80211_IOCTL_GETRSN]", - "ioctl[SIOCIWFIRSTPRIV+17]", - "ioctl[IEEE80211_IOCTL_GETKEY]", - }; -#endif /* MADWIFI_NG */ - int idx = op - first; - if (first <= op && - idx < (int) (sizeof(opnames) / sizeof(opnames[0])) && - opnames[idx]) - perror(opnames[idx]); - else - perror("ioctl[unknown???]"); - return -1; - } - return 0; -} - -static int -set80211param(struct madwifi_driver_data *drv, int op, int arg) -{ - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.mode = op; - memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); - - if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { - perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); - wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d " - "arg %d)", __func__, op, arg); - return -1; - } - return 0; -} - -static const char * -ether_sprintf(const u8 *addr) -{ - static char buf[sizeof(MACSTR)]; - - if (addr != NULL) - snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); - else - snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); - return buf; -} - -/* - * Configure WPA parameters. - */ -static int -madwifi_configure_wpa(struct madwifi_driver_data *drv) -{ - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - int v; - - switch (conf->wpa_group) { - case WPA_CIPHER_CCMP: - v = IEEE80211_CIPHER_AES_CCM; - break; - case WPA_CIPHER_TKIP: - v = IEEE80211_CIPHER_TKIP; - break; - case WPA_CIPHER_WEP104: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_WEP40: - v = IEEE80211_CIPHER_WEP; - break; - case WPA_CIPHER_NONE: - v = IEEE80211_CIPHER_NONE; - break; - default: - wpa_printf(MSG_ERROR, "Unknown group key cipher %u", - conf->wpa_group); - return -1; - } - wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); - if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { - printf("Unable to set group key cipher to %u\n", v); - return -1; - } - if (v == IEEE80211_CIPHER_WEP) { - /* key length is done only for specific ciphers */ - v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); - if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { - printf("Unable to set group key length to %u\n", v); - return -1; - } - } - - v = 0; - if (conf->wpa_pairwise & WPA_CIPHER_CCMP) - v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) - v |= 1<wpa_pairwise & WPA_CIPHER_NONE) - v |= 1<wpa_key_mgmt); - if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, conf->wpa_key_mgmt)) { - printf("Unable to set key management algorithms to 0x%x\n", - conf->wpa_key_mgmt); - return -1; - } - - v = 0; - if (conf->rsn_preauth) - v |= BIT(0); - wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", - __func__, conf->rsn_preauth); - if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { - printf("Unable to set RSN capabilities to 0x%x\n", v); - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, conf->wpa); - if (set80211param(drv, IEEE80211_PARAM_WPA, conf->wpa)) { - printf("Unable to set WPA to %u\n", conf->wpa); - return -1; - } - return 0; -} - - -static int -madwifi_set_iface_flags(void *priv, int dev_up) -{ - struct madwifi_driver_data *drv = priv; - struct ifreq ifr; - - wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up); - - if (drv->ioctl_sock < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - if (dev_up) { - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - ifr.ifr_mtu = HOSTAPD_MTU; - if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { - perror("ioctl[SIOCSIFMTU]"); - printf("Setting MTU failed - trying to survive with " - "current value\n"); - } - } - - return 0; -} - -static int -madwifi_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct madwifi_driver_data *drv = priv; - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - if (!enabled) { - /* XXX restore state */ - return set80211param(priv, IEEE80211_PARAM_AUTHMODE, - IEEE80211_AUTH_AUTO); - } - if (!conf->wpa && !conf->ieee802_1x) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); - return -1; - } - if (conf->wpa && madwifi_configure_wpa(drv) != 0) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); - return -1; - } - if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, - (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, - HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); - return -1; - } - - return 0; -} - -static int -madwifi_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct madwifi_driver_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); -} - -static int -madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", - __func__, ether_sprintf(addr), authorized); - - if (authorized) - mlme.im_op = IEEE80211_MLME_AUTHORIZE; - else - mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; - mlme.im_reason = 0; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, - __func__, authorized ? "" : "un", MAC2STR(addr)); - } - - return ret; -} - -static int -madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags, - int flags_or, int flags_and) -{ - /* For now, only support setting Authorized flag */ - if (flags_or & WLAN_STA_AUTHORIZED) - return madwifi_set_sta_authorized(priv, addr, 1); - if (!(flags_and & WLAN_STA_AUTHORIZED)) - return madwifi_set_sta_authorized(priv, addr, 0); - return 0; -} - -static int -madwifi_del_key(void *priv, const u8 *addr, int key_idx) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_del_key wk; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", - __func__, ether_sprintf(addr), key_idx); - - memset(&wk, 0, sizeof(wk)); - if (addr != NULL) { - memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; - } else { - wk.idk_keyix = key_idx; - } - - ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" - " key_idx %d)", __func__, ether_sprintf(addr), - key_idx); - } - - return ret; -} - -static int -madwifi_set_key(const char *ifname, void *priv, const char *alg, - const u8 *addr, int key_idx, - const u8 *key, size_t key_len, int txkey) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_key wk; - u_int8_t cipher; - int ret; - - if (strcmp(alg, "none") == 0) - return madwifi_del_key(drv, addr, key_idx); - - wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d", - __func__, alg, ether_sprintf(addr), key_idx); - - if (strcmp(alg, "WEP") == 0) - cipher = IEEE80211_CIPHER_WEP; - else if (strcmp(alg, "TKIP") == 0) - cipher = IEEE80211_CIPHER_TKIP; - else if (strcmp(alg, "CCMP") == 0) - cipher = IEEE80211_CIPHER_AES_CCM; - else { - printf("%s: unknown/unsupported algorithm %s\n", - __func__, alg); - return -1; - } - - if (key_len > sizeof(wk.ik_keydata)) { - printf("%s: key length %lu too big\n", __func__, - (unsigned long) key_len); - return -3; - } - - memset(&wk, 0, sizeof(wk)); - wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; - if (addr == NULL) { - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - wk.ik_keyix = key_idx; - wk.ik_flags |= IEEE80211_KEY_DEFAULT; - } else { - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = IEEE80211_KEYIX_NONE; - } - wk.ik_keylen = key_len; - memcpy(wk.ik_keydata, key, key_len); - - ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" - " key_idx %d alg '%s' key_len %lu txkey %d)", - __func__, ether_sprintf(wk.ik_macaddr), key_idx, - alg, (unsigned long) key_len, txkey); - } - - return ret; -} - - -static int -madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_key wk; - - wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", - __func__, ether_sprintf(addr), idx); - - memset(&wk, 0, sizeof(wk)); - if (addr == NULL) - memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); - else - memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - wk.ik_keyix = idx; - - if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { - wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " - "(addr " MACSTR " key_idx %d)", - __func__, MAC2STR(wk.ik_macaddr), idx); - return -1; - } - -#ifdef WORDS_BIGENDIAN - { - /* - * wk.ik_keytsc is in host byte order (big endian), need to - * swap it to match with the byte order used in WPA. - */ - int i; - u8 tmp[WPA_KEY_RSC_LEN]; - memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); - for (i = 0; i < WPA_KEY_RSC_LEN; i++) { - seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; - } - } -#else /* WORDS_BIGENDIAN */ - memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -#endif /* WORDS_BIGENDIAN */ - return 0; -} - - -static int -madwifi_flush(void *priv) -{ -#ifdef MADWIFI_BSD - u8 allsta[IEEE80211_ADDR_LEN]; - memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return madwifi_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE); -#else /* MADWIFI_BSD */ - return 0; /* XXX */ -#endif /* MADWIFI_BSD */ -} - - -static int -madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct madwifi_driver_data *drv = priv; - -#ifdef MADWIFI_BSD - struct ieee80211req_sta_stats stats; - - memset(data, 0, sizeof(*data)); - - /* - * Fetch statistics for station from the system. - */ - memset(&stats, 0, sizeof(stats)); - memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); - if (set80211priv(drv, -#ifdef MADWIFI_NG - IEEE80211_IOCTL_STA_STATS, -#else /* MADWIFI_NG */ - IEEE80211_IOCTL_GETSTASTATS, -#endif /* MADWIFI_NG */ - &stats, sizeof(stats))) { - wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " - MACSTR ")", __func__, MAC2STR(addr)); - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - memcpy(data, &drv->acct_data, sizeof(*data)); - return 0; - } - - printf("Failed to get station stats information element.\n"); - return -1; - } - - data->rx_packets = stats.is_stats.ns_rx_data; - data->rx_bytes = stats.is_stats.ns_rx_bytes; - data->tx_packets = stats.is_stats.ns_tx_data; - data->tx_bytes = stats.is_stats.ns_tx_bytes; - return 0; - -#else /* MADWIFI_BSD */ - - char buf[1024], line[128], *pos; - FILE *f; - unsigned long val; - - memset(data, 0, sizeof(*data)); - snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR, - drv->iface, MAC2STR(addr)); - - f = fopen(buf, "r"); - if (!f) { - if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0) - return -1; - memcpy(data, &drv->acct_data, sizeof(*data)); - return 0; - } - /* Need to read proc file with in one piece, so use large enough - * buffer. */ - setbuffer(f, buf, sizeof(buf)); - - while (fgets(line, sizeof(line), f)) { - pos = strchr(line, '='); - if (!pos) - continue; - *pos++ = '\0'; - val = strtoul(pos, NULL, 10); - if (strcmp(line, "rx_packets") == 0) - data->rx_packets = val; - else if (strcmp(line, "tx_packets") == 0) - data->tx_packets = val; - else if (strcmp(line, "rx_bytes") == 0) - data->rx_bytes = val; - else if (strcmp(line, "tx_bytes") == 0) - data->tx_bytes = val; - } - - fclose(f); - - return 0; -#endif /* MADWIFI_BSD */ -} - - -static int -madwifi_sta_clear_stats(void *priv, const u8 *addr) -{ -#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS) - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); - - mlme.im_op = IEEE80211_MLME_CLEAR_STATS; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, - sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " - MACSTR ")", __func__, MAC2STR(addr)); - } - - return ret; -#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ - return 0; /* FIX */ -#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ -} - - -static int -madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len) -{ - /* - * Do nothing; we setup parameters at startup that define the - * contents of the beacon information element. - */ - return 0; -} - -static int -madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DEAUTH; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR - " reason %d)", - __func__, MAC2STR(addr), reason_code); - } - - return ret; -} - -static int -madwifi_sta_disassoc(void *priv, const u8 *addr, int reason_code) -{ - struct madwifi_driver_data *drv = priv; - struct ieee80211req_mlme mlme; - int ret; - - wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", - __func__, ether_sprintf(addr), reason_code); - - mlme.im_op = IEEE80211_MLME_DISASSOC; - mlme.im_reason = reason_code; - memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " - MACSTR " reason %d)", - __func__, MAC2STR(addr), reason_code); - } - - return ret; -} - -#ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME -static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, - size_t len) -{ - struct madwifi_driver_data *drv = ctx; - const struct ieee80211_mgmt *mgmt; - const u8 *end, *ie; - u16 fc; - size_t ie_len; - - /* Send Probe Request information to WPS processing */ - - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) - return; - mgmt = (const struct ieee80211_mgmt *) buf; - - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || - WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) - return; - - end = buf + len; - ie = mgmt->u.probe_req.variable; - ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); - - hostapd_wps_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len); -} -#endif /* IEEE80211_IOCTL_FILTERFRAME */ -#endif /* CONFIG_WPS */ - -static int madwifi_receive_probe_req(struct madwifi_driver_data *drv) -{ - int ret = 0; -#ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME - struct ieee80211req_set_filter filt; - - wpa_printf(MSG_DEBUG, "%s Enter", __func__); - filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ; - - ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, - sizeof(struct ieee80211req_set_filter)); - if (ret) - return ret; - - drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, - madwifi_raw_receive, drv, 1); - if (drv->sock_raw == NULL) - return -1; -#endif /* IEEE80211_IOCTL_FILTERFRAME */ -#endif /* CONFIG_WPS */ - return ret; -} - -static int -madwifi_del_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -{ - struct hostapd_data *hapd = drv->hapd; - struct sta_info *sta; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated"); - - sta = ap_get_sta(hapd, addr); - if (sta != NULL) { - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); - } - return 0; -} - -#ifdef CONFIG_WPS -static int -madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) -{ - struct madwifi_driver_data *drv = priv; - u8 buf[256]; - struct ieee80211req_getset_appiebuf *beac_ie; - - wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, - (unsigned long) len); - - beac_ie = (struct ieee80211req_getset_appiebuf *) buf; - beac_ie->app_frmtype = frametype; - beac_ie->app_buflen = len; - memcpy(&(beac_ie->app_buf[0]), ie, len); - - return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, - sizeof(struct ieee80211req_getset_appiebuf) + len); -} - -static int -madwifi_set_wps_beacon_ie(const char *ifname, void *priv, const u8 *ie, - size_t len) -{ - return madwifi_set_wps_ie(priv, ie, len, IEEE80211_APPIE_FRAME_BEACON); -} - -static int -madwifi_set_wps_probe_resp_ie(const char *ifname, void *priv, const u8 *ie, - size_t len) -{ - return madwifi_set_wps_ie(priv, ie, len, - IEEE80211_APPIE_FRAME_PROBE_RESP); -} -#else /* CONFIG_WPS */ -#define madwifi_set_wps_beacon_ie NULL -#define madwifi_set_wps_probe_resp_ie NULL -#endif /* CONFIG_WPS */ - -static int -madwifi_process_wpa_ie(struct madwifi_driver_data *drv, struct sta_info *sta) -{ - struct hostapd_data *hapd = drv->hapd; - struct ieee80211req_wpaie ie; - int ielen, res; - u8 *iebuf; - - /* - * Fetch negotiated WPA/RSN parameters from the system. - */ - memset(&ie, 0, sizeof(ie)); - memcpy(ie.wpa_macaddr, sta->addr, IEEE80211_ADDR_LEN); - if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { - wpa_printf(MSG_ERROR, "%s: Failed to get WPA/RSN IE", - __func__); - printf("Failed to get WPA/RSN information element.\n"); - return -1; /* XXX not right */ - } - wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE", - ie.wpa_ie, IEEE80211_MAX_OPT_IE); - iebuf = ie.wpa_ie; - /* madwifi seems to return some random data if WPA/RSN IE is not set. - * Assume the IE was not included if the IE type is unknown. */ - if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) - iebuf[1] = 0; -#ifdef MADWIFI_NG - wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE", - ie.rsn_ie, IEEE80211_MAX_OPT_IE); - if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { - /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not - * set. This is needed for WPA2. */ - iebuf = ie.rsn_ie; - if (iebuf[0] != WLAN_EID_RSN) - iebuf[1] = 0; - } -#endif /* MADWIFI_NG */ - ielen = iebuf[1]; - if (ielen == 0) { -#ifdef CONFIG_WPS - if (hapd->conf->wps_state) { - wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE " - "in (Re)Association Request - possible WPS " - "use"); - sta->flags |= WLAN_STA_MAYBE_WPS; - return 0; - } -#endif /* CONFIG_WPS */ - printf("No WPA/RSN information element for station!?\n"); - return -1; /* XXX not right */ - } - ielen += 2; - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); - if (sta->wpa_sm == NULL) { - printf("Failed to initialize WPA state machine\n"); - return -1; - } - res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, - iebuf, ielen, NULL, 0); - if (res != WPA_IE_OK) { - printf("WPA/RSN information element rejected? (res %u)\n", res); - return -1; - } - return 0; -} - -static int -madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -{ - struct hostapd_data *hapd = drv->hapd; - struct sta_info *sta; - int new_assoc; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "associated"); - - sta = ap_get_sta(hapd, addr); - if (sta) { - accounting_sta_stop(hapd, sta); - } else { - sta = ap_sta_add(hapd, addr); - if (sta == NULL) - return -1; - } - - if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { - /* Cached accounting data is not valid anymore. */ - memset(drv->acct_mac, 0, ETH_ALEN); - memset(&drv->acct_data, 0, sizeof(drv->acct_data)); - } - - if (hapd->conf->wpa) { - if (madwifi_process_wpa_ie(drv, sta)) - return -1; - } - - /* - * Now that the internal station state is setup - * kick the authenticator into action. - */ - new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - hostapd_new_assoc_sta(hapd, sta, !new_assoc); - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - return 0; -} - -static void -madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, - char *custom) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - ieee80211_michael_mic_failure(drv->hapd, addr, 1); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { - char *key, *value; - u32 val; - key = custom; - while ((key = strchr(key, '\n')) != NULL) { - key++; - value = strchr(key, '='); - if (value == NULL) - continue; - *value++ = '\0'; - val = strtoul(value, NULL, 10); - if (strcmp(key, "mac") == 0) - hwaddr_aton(value, drv->acct_mac); - else if (strcmp(key, "rx_packets") == 0) - drv->acct_data.rx_packets = val; - else if (strcmp(key, "tx_packets") == 0) - drv->acct_data.tx_packets = val; - else if (strcmp(key, "rx_bytes") == 0) - drv->acct_data.rx_bytes = val; - else if (strcmp(key, "tx_bytes") == 0) - drv->acct_data.tx_bytes = val; - key = value; - } - } -} - -static void -madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - if (drv->we_version > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM)) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVEXPIRED: - madwifi_del_sta(drv, (u8 *) iwe->u.addr.sa_data); - break; - case IWEVREGISTERED: - madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data); - break; - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; /* XXX */ - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - madwifi_wireless_event_wireless_custom(drv, buf); - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void -madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv, - struct nlmsghdr *h, int len) -{ - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; - - if (len < (int) sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - if (ifi->ifi_index != drv->ifindex) - return; - - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - madwifi_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void -madwifi_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - char buf[256]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - struct madwifi_driver_data *drv = eloop_ctx; - - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - printf("Malformed netlink message: " - "len=%d left=%d plen=%d\n", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - madwifi_wireless_event_rtm_newlink(drv, h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - printf("%d extra bytes in the end of netlink message\n", left); - } -} - - -static int -madwifi_get_we_version(struct madwifi_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - free(range); - return 0; -} - - -static int -madwifi_wireless_event_init(void *priv) -{ - struct madwifi_driver_data *drv = priv; - int s; - struct sockaddr_nl local; - - madwifi_get_we_version(drv); - - drv->wext_sock = -1; - - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - return -1; - } - - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - eloop_register_read_sock(s, madwifi_wireless_event_receive, drv, NULL); - drv->wext_sock = s; - - return 0; -} - - -static void -madwifi_wireless_event_deinit(void *priv) -{ - struct madwifi_driver_data *drv = priv; - - if (drv != NULL) { - if (drv->wext_sock < 0) - return; - eloop_unregister_read_sock(drv->wext_sock); - close(drv->wext_sock); - } -} - - -static int -madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr) -{ - struct madwifi_driver_data *drv = priv; - unsigned char buf[3000]; - unsigned char *bp = buf; - struct l2_ethhdr *eth; - size_t len; - int status; - - /* - * Prepend the Ethernet header. If the caller left us - * space at the front we could just insert it but since - * we don't know we copy to a local buffer. Given the frequency - * and size of frames this probably doesn't matter. - */ - len = data_len + sizeof(struct l2_ethhdr); - if (len > sizeof(buf)) { - bp = malloc(len); - if (bp == NULL) { - printf("EAPOL frame discarded, cannot malloc temp " - "buffer of size %lu!\n", (unsigned long) len); - return -1; - } - } - eth = (struct l2_ethhdr *) bp; - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, own_addr, ETH_ALEN); - eth->h_proto = htons(ETH_P_EAPOL); - memcpy(eth+1, data, data_len); - - wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); - - status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); - - if (bp != buf) - free(bp); - return status; -} - -static void -handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -{ - struct madwifi_driver_data *drv = ctx; - struct hostapd_data *hapd = drv->hapd; - struct sta_info *sta; - - sta = ap_get_sta(hapd, src_addr); - if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { - printf("Data frame from not associated STA %s\n", - ether_sprintf(src_addr)); - /* XXX cannot happen */ - return; - } - ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr), - len - sizeof(struct l2_ethhdr)); -} - -static void * -madwifi_init(struct hostapd_data *hapd) -{ - struct madwifi_driver_data *drv; - struct ifreq ifr; - struct iwreq iwr; - - drv = os_zalloc(sizeof(struct madwifi_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for madwifi driver data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - goto bad; - } - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - goto bad; - } - drv->ifindex = ifr.ifr_ifindex; - - drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, - handle_read, drv, 1); - if (drv->sock_xmit == NULL) - goto bad; - if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr)) - goto bad; - if (hapd->conf->bridge[0] != '\0') { - wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", - hapd->conf->bridge); - drv->sock_recv = l2_packet_init(hapd->conf->bridge, NULL, - ETH_P_EAPOL, handle_read, drv, - 1); - if (drv->sock_recv == NULL) - goto bad; - } else - drv->sock_recv = drv->sock_xmit; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - - iwr.u.mode = IW_MODE_MASTER; - - if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { - perror("ioctl[SIOCSIWMODE]"); - printf("Could not set interface to master mode!\n"); - goto bad; - } - - madwifi_set_iface_flags(drv, 0); /* mark down during setup */ - madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */ - - madwifi_receive_probe_req(drv); - - return drv; -bad: - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv != NULL) - free(drv); - return NULL; -} - - -static void -madwifi_deinit(void *priv) -{ - struct madwifi_driver_data *drv = priv; - - (void) madwifi_set_iface_flags(drv, 0); - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) - l2_packet_deinit(drv->sock_recv); - if (drv->sock_xmit != NULL) - l2_packet_deinit(drv->sock_xmit); - if (drv->sock_raw) - l2_packet_deinit(drv->sock_raw); - free(drv); -} - -static int -madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len) -{ - struct madwifi_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len + 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } - return 0; -} - -static int -madwifi_get_ssid(const char *ifname, void *priv, u8 *buf, int len) -{ - struct madwifi_driver_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len; - - if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); - ret = -1; - } else - ret = iwr.u.essid.length; - - return ret; -} - -static int -madwifi_set_countermeasures(void *priv, int enabled) -{ - struct madwifi_driver_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); -} - -static int -madwifi_commit(void *priv) -{ - return madwifi_set_iface_flags(priv, 1); -} - -const struct wpa_driver_ops wpa_driver_madwifi_ops = { - .name = "madwifi", - .init = madwifi_init, - .deinit = madwifi_deinit, - .set_ieee8021x = madwifi_set_ieee8021x, - .set_privacy = madwifi_set_privacy, - .set_encryption = madwifi_set_key, - .get_seqnum = madwifi_get_seqnum, - .flush = madwifi_flush, - .set_generic_elem = madwifi_set_opt_ie, - .wireless_event_init = madwifi_wireless_event_init, - .wireless_event_deinit = madwifi_wireless_event_deinit, - .sta_set_flags = madwifi_sta_set_flags, - .read_sta_data = madwifi_read_sta_driver_data, - .send_eapol = madwifi_send_eapol, - .sta_disassoc = madwifi_sta_disassoc, - .sta_deauth = madwifi_sta_deauth, - .set_ssid = madwifi_set_ssid, - .get_ssid = madwifi_get_ssid, - .set_countermeasures = madwifi_set_countermeasures, - .sta_clear_stats = madwifi_sta_clear_stats, - .commit = madwifi_commit, - .set_wps_beacon_ie = madwifi_set_wps_beacon_ie, - .set_wps_probe_resp_ie = madwifi_set_wps_probe_resp_ie, -}; diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c deleted file mode 100644 index 4599e99eadcd..000000000000 --- a/hostapd/driver_nl80211.c +++ /dev/null @@ -1,2708 +0,0 @@ -/* - * hostapd / Kernel driver communication via nl80211 - * Copyright (c) 2002-2007, Jouni Malinen - * Copyright (c) 2003-2004, Instant802 Networks, Inc. - * Copyright (c) 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2007, Johannes Berg - * - * 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 -#include -#include -#include -#include -#include -#include "nl80211_copy.h" -#include -#include -#include "wireless_copy.h" -#include -#include - -#include "hostapd.h" -#include "driver.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "hw_features.h" -#include "mlme.h" -#include "radiotap.h" -#include "radiotap_iter.h" - -#ifdef CONFIG_LIBNL20 -/* libnl 2.0 compatibility code */ -#define nl_handle_alloc_cb nl_socket_alloc_cb -#define nl_handle_destroy nl_socket_free -#endif /* CONFIG_LIBNL20 */ - -enum ieee80211_msg_type { - ieee80211_msg_normal = 0, - ieee80211_msg_tx_callback_ack = 1, - ieee80211_msg_tx_callback_fail = 2, -}; - -struct i802_driver_data { - struct hostapd_data *hapd; - - char iface[IFNAMSIZ + 1]; - int bridge; - int ioctl_sock; /* socket for ioctl() use */ - int wext_sock; /* socket for wireless events */ - int eapol_sock; /* socket for EAPOL frames */ - int monitor_sock; /* socket for monitor */ - int monitor_ifidx; - - int default_if_indices[16]; - int *if_indices; - int num_if_indices; - - int we_version; - struct nl_handle *nl_handle; - struct nl_cache *nl_cache; - struct nl_cb *nl_cb; - struct genl_family *nl80211; - int dtim_period, beacon_int; - unsigned int beacon_set:1; - unsigned int ieee802_1x_active:1; - - int last_freq; - int last_freq_ht; -}; - - -static void add_ifidx(struct i802_driver_data *drv, int ifidx) -{ - int i; - int *old; - - for (i = 0; i < drv->num_if_indices; i++) { - if (drv->if_indices[i] == 0) { - drv->if_indices[i] = ifidx; - return; - } - } - - if (drv->if_indices != drv->default_if_indices) - old = drv->if_indices; - else - old = NULL; - - drv->if_indices = realloc(old, - sizeof(int) * (drv->num_if_indices + 1)); - if (!drv->if_indices) { - if (!old) - drv->if_indices = drv->default_if_indices; - else - drv->if_indices = old; - wpa_printf(MSG_ERROR, "Failed to reallocate memory for " - "interfaces"); - wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); - return; - } - drv->if_indices[drv->num_if_indices] = ifidx; - drv->num_if_indices++; -} - - -static void del_ifidx(struct i802_driver_data *drv, int ifidx) -{ - int i; - - for (i = 0; i < drv->num_if_indices; i++) { - if (drv->if_indices[i] == ifidx) { - drv->if_indices[i] = 0; - break; - } - } -} - - -static int have_ifidx(struct i802_driver_data *drv, int ifidx) -{ - int i; - - if (ifidx == drv->bridge) - return 1; - - for (i = 0; i < drv->num_if_indices; i++) - if (drv->if_indices[i] == ifidx) - return 1; - - return 0; -} - - -/* nl80211 code */ -static int ack_handler(struct nl_msg *msg, void *arg) -{ - int *err = arg; - *err = 0; - return NL_STOP; -} - -static int finish_handler(struct nl_msg *msg, void *arg) -{ - int *ret = arg; - *ret = 0; - return NL_SKIP; -} - -static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, - void *arg) -{ - int *ret = arg; - *ret = err->error; - return NL_SKIP; -} - -static int send_and_recv_msgs(struct i802_driver_data *drv, - struct nl_msg *msg, - int (*valid_handler)(struct nl_msg *, void *), - void *valid_data) -{ - struct nl_cb *cb; - int err = -ENOMEM; - - cb = nl_cb_clone(drv->nl_cb); - if (!cb) - goto out; - - err = nl_send_auto_complete(drv->nl_handle, msg); - if (err < 0) - goto out; - - err = 1; - - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); - - if (valid_handler) - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, - valid_handler, valid_data); - - while (err > 0) - nl_recvmsgs(drv->nl_handle, cb); - out: - nl_cb_put(cb); - nlmsg_free(msg); - return err; -} - -static int hostapd_set_iface_flags(struct i802_driver_data *drv, - const char *ifname, int dev_up) -{ - struct ifreq ifr; - - if (drv->ioctl_sock < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)", - drv->iface); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - return 0; -} - - -static int nl_set_encr(int ifindex, struct i802_driver_data *drv, - const char *alg, const u8 *addr, int idx, const u8 *key, - size_t key_len, int txkey) -{ - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - if (strcmp(alg, "none") == 0) { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_KEY, 0); - } else { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_KEY, 0); - NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); - if (strcmp(alg, "WEP") == 0) { - if (key_len == 5) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - 0x000FAC01); - else - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - 0x000FAC05); - } else if (strcmp(alg, "TKIP") == 0) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); - else if (strcmp(alg, "CCMP") == 0) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); - else if (strcmp(alg, "IGTK") == 0) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06); - else { - wpa_printf(MSG_ERROR, "%s: Unsupported encryption " - "algorithm '%s'", __func__, alg); - nlmsg_free(msg); - return -1; - } - } - - if (addr) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == -ENOENT) - ret = 0; - - /* - * If we failed or don't need to set the default TX key (below), - * we're done here. - */ - if (ret || !txkey || addr) - return ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_KEY, 0); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - if (strcmp(alg, "IGTK") == 0) - NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); - else - NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == -ENOENT) - ret = 0; - return ret; - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_encryption(const char *iface, void *priv, const char *alg, - const u8 *addr, int idx, const u8 *key, - size_t key_len, int txkey) -{ - struct i802_driver_data *drv = priv; - int ret; - - ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, idx, key, - key_len, txkey); - if (ret < 0) - return ret; - - return ret; -} - - -static inline int min_int(int a, int b) -{ - if (a < b) - return a; - return b; -} - - -static int get_key_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - /* - * TODO: validate the key index and mac address! - * Otherwise, there's a race condition as soon as - * the kernel starts sending key notifications. - */ - - if (tb[NL80211_ATTR_KEY_SEQ]) - memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), - min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); - return NL_SKIP; -} - - -static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, - int idx, u8 *seq) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_KEY, 0); - - if (addr) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - memset(seq, 0, 6); - - return send_and_recv_msgs(drv, msg, get_key_handler, seq); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, - int mode) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - u8 rates[NL80211_MAX_SUPP_RATES]; - u8 rates_len = 0; - int i; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); - - for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) - rates[rates_len++] = basic_rates[i] / 5; - - NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); - - /* TODO: multi-BSS support */ - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_send_frame(void *priv, const void *data, size_t len, - int encrypt, int flags) -{ - __u8 rtap_hdr[] = { - 0x00, 0x00, /* radiotap version */ - 0x0e, 0x00, /* radiotap length */ - 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ - IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ - 0x00, /* padding */ - 0x00, 0x00, /* RX and TX flags to indicate that */ - 0x00, 0x00, /* this is the injected frame directly */ - }; - struct i802_driver_data *drv = priv; - struct iovec iov[2] = { - { - .iov_base = &rtap_hdr, - .iov_len = sizeof(rtap_hdr), - }, - { - .iov_base = (void*)data, - .iov_len = len, - } - }; - struct msghdr msg = { - .msg_name = NULL, - .msg_namelen = 0, - .msg_iov = iov, - .msg_iovlen = 2, - .msg_control = NULL, - .msg_controllen = 0, - .msg_flags = 0, - }; - - if (encrypt) - rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; - - return sendmsg(drv->monitor_sock, &msg, flags); -} - -static int i802_send_mgmt_frame(void *priv, const void *data, size_t len, - int flags) -{ - struct ieee80211_mgmt *mgmt; - int do_not_encrypt = 0; - u16 fc; - - mgmt = (struct ieee80211_mgmt *) data; - fc = le_to_host16(mgmt->frame_control); - - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { - /* - * Only one of the authentication frame types is encrypted. - * In order for static WEP encryption to work properly (i.e., - * to not encrypt the frame), we need to tell mac80211 about - * the frames that must not be encrypted. - */ - u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); - u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); - if (auth_alg == WLAN_AUTH_OPEN || - (auth_alg == WLAN_AUTH_SHARED_KEY && auth_trans != 3)) - do_not_encrypt = 1; - } - - return i802_send_frame(priv, data, len, !do_not_encrypt, flags); -} - -/* Set kernel driver on given frequency (MHz) */ -static int i802_set_freq2(void *priv, struct hostapd_freq_params *freq) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - drv->last_freq = freq->freq; - drv->last_freq_ht = freq->ht_enabled; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_WIPHY, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq); - if (freq->ht_enabled) { - switch (freq->sec_channel_offset) { - case -1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40MINUS); - break; - case 1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40PLUS); - break; - default: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT20); - break; - } - } - - if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) - return 0; - nla_put_failure: - return -1; -} - - -static int i802_set_rts(void *priv, int rts) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - iwr.u.rts.value = rts; - iwr.u.rts.fixed = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) { - perror("ioctl[SIOCSIWRTS]"); - return -1; - } - - return 0; -} - - -static int i802_get_rts(void *priv, int *rts) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) { - perror("ioctl[SIOCGIWRTS]"); - return -1; - } - - *rts = iwr.u.rts.value; - - return 0; -} - - -static int i802_set_frag(void *priv, int frag) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - iwr.u.frag.value = frag; - iwr.u.frag.fixed = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCSIWFRAG]"); - return -1; - } - - return 0; -} - - -static int i802_get_frag(void *priv, int *frag) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG]"); - return -1; - } - - *frag = iwr.u.frag.value; - - return 0; -} - - -static int i802_set_retry(void *priv, int short_retry, int long_retry) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - iwr.u.retry.value = short_retry; - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - if (ioctl(drv->ioctl_sock, SIOCSIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCSIWRETRY(short)]"); - return -1; - } - - iwr.u.retry.value = long_retry; - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - if (ioctl(drv->ioctl_sock, SIOCSIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCSIWRETRY(long)]"); - return -1; - } - - return 0; -} - - -static int i802_get_retry(void *priv, int *short_retry, int *long_retry) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG(short)]"); - return -1; - } - *short_retry = iwr.u.retry.value; - - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG(long)]"); - return -1; - } - *long_retry = iwr.u.retry.value; - - return 0; -} - - -static int i802_flush(void *priv) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); - - /* - * XXX: FIX! this needs to flush all VLANs too - */ - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int get_sta_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct hostap_sta_driver_data *data = arg; - struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; - static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { - [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, - }; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - /* - * TODO: validate the interface and mac address! - * Otherwise, there's a race condition as soon as - * the kernel starts sending station notifications. - */ - - if (!tb[NL80211_ATTR_STA_INFO]) { - wpa_printf(MSG_DEBUG, "sta stats missing!"); - return NL_SKIP; - } - if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], - stats_policy)) { - wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); - return NL_SKIP; - } - - if (stats[NL80211_STA_INFO_INACTIVE_TIME]) - data->inactive_msec = - nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); - if (stats[NL80211_STA_INFO_RX_BYTES]) - data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); - if (stats[NL80211_STA_INFO_TX_BYTES]) - data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); - if (stats[NL80211_STA_INFO_RX_PACKETS]) - data->rx_packets = - nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); - if (stats[NL80211_STA_INFO_TX_PACKETS]) - data->tx_packets = - nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); - - return NL_SKIP; -} - -static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - os_memset(data, 0, sizeof(*data)); - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_STATION, 0); - - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - return send_and_recv_msgs(drv, msg, get_sta_handler, data); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr) -{ - struct i802_driver_data *drv = priv; - struct ieee80211_hdr *hdr; - size_t len; - u8 *pos; - int res; -#if 0 /* FIX */ - int qos = sta->flags & WLAN_STA_WME; -#else - int qos = 0; -#endif - - len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + - data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for i802_send_data(len=%lu)\n", - (unsigned long) len); - return -1; - } - - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); - hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); - if (encrypt) - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); -#if 0 /* To be enabled if qos determination is added above */ - if (qos) { - hdr->frame_control |= - host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); - } -#endif - - memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); - memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); - memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - pos = (u8 *) (hdr + 1); - -#if 0 /* To be enabled if qos determination is added above */ - if (qos) { - /* add an empty QoS header if needed */ - pos[0] = 0; - pos[1] = 0; - pos += 2; - } -#endif - - memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); - pos += sizeof(rfc1042_header); - WPA_PUT_BE16(pos, ETH_P_PAE); - pos += 2; - memcpy(pos, data, data_len); - - res = i802_send_frame(drv, (u8 *) hdr, len, encrypt, 0); - free(hdr); - - if (res < 0) { - perror("i802_send_eapol: send"); - printf("i802_send_eapol - packet len: %lu - failed\n", - (unsigned long) len); - } - - return res; -} - - -static int i802_sta_add2(const char *ifname, void *priv, - struct hostapd_sta_add_params *params) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -ENOBUFS; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, - params->supp_rates); - NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, - params->listen_interval); - -#ifdef CONFIG_IEEE80211N - if (params->ht_capabilities) { - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, - params->ht_capabilities->length, - ¶ms->ht_capabilities->data); - } -#endif /* CONFIG_IEEE80211N */ - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) - wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION " - "result: %d (%s)", ret, strerror(-ret)); - if (ret == -EEXIST) - ret = 0; - nla_put_failure: - return ret; -} - - -static int i802_sta_remove(void *priv, const u8 *addr) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == -ENOENT) - return 0; - return ret; - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg, *flags = NULL; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - flags = nlmsg_alloc(); - if (!flags) { - nlmsg_free(msg); - return -ENOMEM; - } - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); - - if (total_flags & WLAN_STA_WMM) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); - - if (total_flags & WLAN_STA_SHORT_PREAMBLE) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); - - if (total_flags & WLAN_STA_MFP) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); - - if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) - goto nla_put_failure; - - nlmsg_free(flags); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - nlmsg_free(flags); - return -ENOBUFS; -} - - -static int i802_set_regulatory_domain(void *priv, unsigned int rd) -{ - return -1; -} - - -static int i802_set_tx_queue_params(void *priv, int queue, int aifs, - int cw_min, int cw_max, int burst_time) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - struct nlattr *txq, *params; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_WIPHY, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); - if (!txq) - goto nla_put_failure; - - /* We are only sending parameters for a single TXQ at a time */ - params = nla_nest_start(msg, 1); - if (!params) - goto nla_put_failure; - - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, queue); - /* Burst time is configured in units of 0.1 msec and TXOP parameter in - * 32 usec, so need to convert the value here. */ - NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); - NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); - NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); - NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); - - nla_nest_end(msg, params); - - nla_nest_end(msg, txq); - - if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) - return 0; - nla_put_failure: - return -1; -} - - -static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx) -{ - struct nl_msg *msg; - - /* stop listening for EAPOL on this interface */ - del_ifidx(drv, ifidx); - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); - - if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) - return; - nla_put_failure: - printf("Failed to remove interface.\n"); -} - - -static int nl80211_create_iface(struct i802_driver_data *drv, - const char *ifname, - enum nl80211_iftype iftype, - const u8 *addr) -{ - struct nl_msg *msg, *flags = NULL; - int ifidx; - struct ifreq ifreq; - struct iwreq iwr; - int ret = -ENOBUFS; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->hapd->conf->iface)); - NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); - - if (iftype == NL80211_IFTYPE_MONITOR) { - int err; - - flags = nlmsg_alloc(); - if (!flags) - goto nla_put_failure; - - NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); - - err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); - - nlmsg_free(flags); - - if (err) - goto nla_put_failure; - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - nla_put_failure: - printf("Failed to create interface %s.\n", ifname); - return ret; - } - - ifidx = if_nametoindex(ifname); - - if (ifidx <= 0) - return -1; - - /* start listening for EAPOL on this interface */ - add_ifidx(drv, ifidx); - - if (addr) { - switch (iftype) { - case NL80211_IFTYPE_AP: - os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ); - memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN); - ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER; - - if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) { - nl80211_remove_iface(drv, ifidx); - return -1; - } - break; - case NL80211_IFTYPE_WDS: - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); - iwr.u.addr.sa_family = ARPHRD_ETHER; - memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN); - if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr)) - return -1; - break; - default: - /* nothing */ - break; - } - } - - return ifidx; -} - - -static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid) -{ - int ifidx; - - /* - * The kernel supports that when the low-level driver does, - * but we currently don't because we need per-BSS data that - * currently we can't handle easily. - */ - return -1; - - ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid); - if (ifidx < 0) - return -1; - if (hostapd_set_iface_flags(priv, ifname, 1)) { - nl80211_remove_iface(priv, ifidx); - return -1; - } - return 0; -} - - -static int i802_bss_remove(void *priv, const char *ifname) -{ - nl80211_remove_iface(priv, if_nametoindex(ifname)); - return 0; -} - - -static int i802_set_beacon(const char *iface, void *priv, - u8 *head, size_t head_len, - u8 *tail, size_t tail_len) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - u8 cmd = NL80211_CMD_NEW_BEACON; - int ret; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - if (drv->beacon_set) - cmd = NL80211_CMD_SET_BEACON; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, cmd, 0); - NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); - NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int); - - if (!drv->dtim_period) - drv->dtim_period = 2; - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (!ret) - drv->beacon_set = 1; - return ret; - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_del_beacon(struct i802_driver_data *drv) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct i802_driver_data *drv = priv; - - /* - * FIXME: This needs to be per interface (BSS) - */ - drv->ieee802_1x_active = enabled; - return 0; -} - - -static int i802_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - - os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); - iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED; - iwr.u.param.value = enabled; - - ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr); - - /* ignore errors, the kernel/driver might not care */ - return 0; -} - - -static int i802_set_internal_bridge(void *priv, int value) -{ - return -1; -} - - -static int i802_set_beacon_int(void *priv, int value) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - drv->beacon_int = value; - - if (!drv->beacon_set) - return 0; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_dtim_period(const char *iface, void *priv, int value) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - drv->dtim_period = value; - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_bss(void *priv, int cts, int preamble, int slot) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_BSS, 0); - - if (cts >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); - if (preamble >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); - if (slot >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); - - /* TODO: multi-BSS support */ - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_cts_protect(void *priv, int value) -{ - return i802_set_bss(priv, value, -1, -1); -} - - -static int i802_set_preamble(void *priv, int value) -{ - return i802_set_bss(priv, -1, value, -1); -} - - -static int i802_set_short_slot_time(void *priv, int value) -{ - return i802_set_bss(priv, -1, -1, value); -} - - -static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type) -{ - switch (type) { - case HOSTAPD_IF_VLAN: - return NL80211_IFTYPE_AP_VLAN; - case HOSTAPD_IF_WDS: - return NL80211_IFTYPE_WDS; - } - return -1; -} - - -static int i802_if_add(const char *iface, void *priv, - enum hostapd_driver_if_type type, char *ifname, - const u8 *addr) -{ - if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0) - return -1; - return 0; -} - - -static int i802_if_update(void *priv, enum hostapd_driver_if_type type, - char *ifname, const u8 *addr) -{ - /* unused at the moment */ - return -1; -} - - -static int i802_if_remove(void *priv, enum hostapd_driver_if_type type, - const char *ifname, const u8 *addr) -{ - nl80211_remove_iface(priv, if_nametoindex(ifname)); - return 0; -} - - -struct phy_info_arg { - u16 *num_modes; - struct hostapd_hw_modes *modes; -}; - -static int phy_info_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct phy_info_arg *phy_info = arg; - - struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, - }; - - struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; - static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { - [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, - [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, - }; - - struct nlattr *nl_band; - struct nlattr *nl_freq; - struct nlattr *nl_rate; - int rem_band, rem_freq, rem_rate; - struct hostapd_hw_modes *mode; - int idx, mode_is_set; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) - return NL_SKIP; - - nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { - mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); - if (!mode) - return NL_SKIP; - phy_info->modes = mode; - - mode_is_set = 0; - - mode = &phy_info->modes[*(phy_info->num_modes)]; - memset(mode, 0, sizeof(*mode)); - *(phy_info->num_modes) += 1; - - nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), - nla_len(nl_band), NULL); - - if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { - mode->ht_capab = nla_get_u16( - tb_band[NL80211_BAND_ATTR_HT_CAPA]); - } - - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), - nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - mode->num_channels++; - } - - mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data)); - if (!mode->channels) - return NL_SKIP; - - idx = 0; - - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), - nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - - mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - mode->channels[idx].flag = 0; - - if (!mode_is_set) { - /* crude heuristic */ - if (mode->channels[idx].freq < 4000) - mode->mode = HOSTAPD_MODE_IEEE80211B; - else - mode->mode = HOSTAPD_MODE_IEEE80211A; - mode_is_set = 1; - } - - /* crude heuristic */ - if (mode->channels[idx].freq < 4000) - if (mode->channels[idx].freq == 2484) - mode->channels[idx].chan = 14; - else - mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; - else - mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; - - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - mode->channels[idx].flag |= - HOSTAPD_CHAN_DISABLED; - if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) - mode->channels[idx].flag |= - HOSTAPD_CHAN_PASSIVE_SCAN; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) - mode->channels[idx].flag |= - HOSTAPD_CHAN_NO_IBSS; - if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) - mode->channels[idx].flag |= - HOSTAPD_CHAN_RADAR; - - if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && - !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - mode->channels[idx].max_tx_power = - nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100; - - idx++; - } - - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), - nla_len(nl_rate), rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - mode->num_rates++; - } - - mode->rates = calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); - if (!mode->rates) - return NL_SKIP; - - idx = 0; - - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), - nla_len(nl_rate), rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - mode->rates[idx].rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); - - /* crude heuristic */ - if (mode->mode == HOSTAPD_MODE_IEEE80211B && - mode->rates[idx].rate > 200) - mode->mode = HOSTAPD_MODE_IEEE80211G; - - if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) - mode->rates[idx].flags |= HOSTAPD_RATE_PREAMBLE2; - - idx++; - } - } - - return NL_SKIP; -} - -static struct hostapd_hw_modes *i802_add_11b(struct hostapd_hw_modes *modes, - u16 *num_modes) -{ - u16 m; - struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; - int i, mode11g_idx = -1; - - /* If only 802.11g mode is included, use it to construct matching - * 802.11b mode data. */ - - for (m = 0; m < *num_modes; m++) { - if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) - return modes; /* 802.11b already included */ - if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) - mode11g_idx = m; - } - - if (mode11g_idx < 0) - return modes; /* 2.4 GHz band not supported at all */ - - nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes)); - if (nmodes == NULL) - return modes; /* Could not add 802.11b mode */ - - mode = &nmodes[*num_modes]; - os_memset(mode, 0, sizeof(*mode)); - (*num_modes)++; - modes = nmodes; - - mode->mode = HOSTAPD_MODE_IEEE80211B; - - mode11g = &modes[mode11g_idx]; - mode->num_channels = mode11g->num_channels; - mode->channels = os_malloc(mode11g->num_channels * - sizeof(struct hostapd_channel_data)); - if (mode->channels == NULL) { - (*num_modes)--; - return modes; /* Could not add 802.11b mode */ - } - os_memcpy(mode->channels, mode11g->channels, - mode11g->num_channels * sizeof(struct hostapd_channel_data)); - - mode->num_rates = 0; - mode->rates = os_malloc(4 * sizeof(struct hostapd_rate_data)); - if (mode->rates == NULL) { - os_free(mode->channels); - (*num_modes)--; - return modes; /* Could not add 802.11b mode */ - } - - for (i = 0; i < mode11g->num_rates; i++) { - if (mode11g->rates[i].rate > 110 || - mode11g->rates[i].flags & - (HOSTAPD_RATE_ERP | HOSTAPD_RATE_OFDM)) - continue; - mode->rates[mode->num_rates] = mode11g->rates[i]; - mode->num_rates++; - if (mode->num_rates == 4) - break; - } - - if (mode->num_rates == 0) { - os_free(mode->channels); - os_free(mode->rates); - (*num_modes)--; - return modes; /* No 802.11b rates */ - } - - wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g " - "information"); - - return modes; -} - -static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv, - u16 *num_modes, - u16 *flags) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - struct phy_info_arg result = { - .num_modes = num_modes, - .modes = NULL, - }; - - *num_modes = 0; - *flags = 0; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) - return i802_add_11b(result.modes, num_modes); - nla_put_failure: - return NULL; -} - - -static int i802_set_sta_vlan(void *priv, const u8 *addr, - const char *ifname, int vlan_id) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(ifname)); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static int i802_set_country(void *priv, const char *country) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - char alpha2[3]; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_REQ_SET_REG, 0); - - alpha2[0] = country[0]; - alpha2[1] = country[1]; - alpha2[2] = '\0'; - NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2); - - return send_and_recv_msgs(drv, msg, NULL, NULL); - nla_put_failure: - return -ENOBUFS; -} - - -static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta) -{ - struct sta_info *sta; - - sta = ap_get_sta(hapd, ta); - if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { - printf("Data/PS-poll frame from not associated STA " - MACSTR "\n", MAC2STR(ta)); - if (sta && (sta->flags & WLAN_STA_AUTH)) - hostapd_sta_disassoc( - hapd, ta, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - else - hostapd_sta_deauth( - hapd, ta, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - } -} - - -static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len, - int ok) -{ - struct ieee80211_hdr *hdr; - u16 fc, type, stype; - struct sta_info *sta; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - case WLAN_FC_TYPE_MGMT: - wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s", - ok ? "ACK" : "fail"); - ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); - break; - case WLAN_FC_TYPE_CTRL: - wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s", - ok ? "ACK" : "fail"); - break; - case WLAN_FC_TYPE_DATA: - sta = ap_get_sta(hapd, hdr->addr1); - if (sta && sta->flags & WLAN_STA_PENDING_POLL) { - wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " - "activity poll", MAC2STR(sta->addr), - ok ? "ACKed" : "did not ACK"); - if (ok) - sta->flags &= ~WLAN_STA_PENDING_POLL; - } - if (sta) - ieee802_1x_tx_status(hapd, sta, buf, len, ok); - break; - default: - printf("unknown TX callback frame type %d\n", type); - break; - } -} - - -static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len, - struct hostapd_frame_info *hfi, - enum ieee80211_msg_type msg_type) -{ - struct ieee80211_hdr *hdr; - u16 fc, type, stype; - size_t data_len = len; - struct hostapd_data *hapd = NULL; - int broadcast_bssid = 0; - size_t i; - u8 *bssid; - - /* - * PS-Poll frames are 16 bytes. All other frames are - * 24 bytes or longer. - */ - if (len < 16) - return; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - case WLAN_FC_TYPE_DATA: - if (len < 24) - return; - switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { - case WLAN_FC_TODS: - bssid = hdr->addr1; - break; - case WLAN_FC_FROMDS: - bssid = hdr->addr2; - break; - default: - /* discard */ - return; - } - break; - case WLAN_FC_TYPE_CTRL: - /* discard non-ps-poll frames */ - if (stype != WLAN_FC_STYPE_PSPOLL) - return; - bssid = hdr->addr1; - break; - case WLAN_FC_TYPE_MGMT: - bssid = hdr->addr3; - break; - default: - /* discard */ - return; - } - - /* find interface frame belongs to */ - for (i = 0; i < iface->num_bss; i++) { - if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) { - hapd = iface->bss[i]; - break; - } - } - - if (hapd == NULL) { - hapd = iface->bss[0]; - - if (bssid[0] != 0xff || bssid[1] != 0xff || - bssid[2] != 0xff || bssid[3] != 0xff || - bssid[4] != 0xff || bssid[5] != 0xff) { - /* - * Unknown BSSID - drop frame if this is not from - * passive scanning or a beacon (at least ProbeReq - * frames to other APs may be allowed through RX - * filtering in the wlan hw/driver) - */ - if ((type != WLAN_FC_TYPE_MGMT || - stype != WLAN_FC_STYPE_BEACON)) - return; - } else - broadcast_bssid = 1; - } - - switch (msg_type) { - case ieee80211_msg_normal: - /* continue processing */ - break; - case ieee80211_msg_tx_callback_ack: - handle_tx_callback(hapd, buf, data_len, 1); - return; - case ieee80211_msg_tx_callback_fail: - handle_tx_callback(hapd, buf, data_len, 0); - return; - } - - switch (type) { - case WLAN_FC_TYPE_MGMT: - if (stype != WLAN_FC_STYPE_BEACON && - stype != WLAN_FC_STYPE_PROBE_REQ) - wpa_printf(MSG_MSGDUMP, "MGMT"); - if (broadcast_bssid) { - for (i = 0; i < iface->num_bss; i++) - ieee802_11_mgmt(iface->bss[i], buf, data_len, - stype, hfi); - } else - ieee802_11_mgmt(hapd, buf, data_len, stype, hfi); - break; - case WLAN_FC_TYPE_CTRL: - /* can only get here with PS-Poll frames */ - wpa_printf(MSG_DEBUG, "CTRL"); - handle_unknown_sta(hapd, hdr->addr2); - break; - case WLAN_FC_TYPE_DATA: - handle_unknown_sta(hapd, hdr->addr2); - break; - } -} - - -static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct i802_driver_data *drv = eloop_ctx; - struct hostapd_data *hapd = drv->hapd; - struct sockaddr_ll lladdr; - unsigned char buf[3000]; - int len; - socklen_t fromlen = sizeof(lladdr); - - len = recvfrom(sock, buf, sizeof(buf), 0, - (struct sockaddr *)&lladdr, &fromlen); - if (len < 0) { - perror("recv"); - return; - } - - if (have_ifidx(drv, lladdr.sll_ifindex)) - ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len); -} - - -static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct i802_driver_data *drv = eloop_ctx; - int len; - unsigned char buf[3000]; - struct hostapd_data *hapd = drv->hapd; - struct ieee80211_radiotap_iterator iter; - int ret; - struct hostapd_frame_info hfi; - int injected = 0, failed = 0, msg_type, rxflags = 0; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { - printf("received invalid radiotap frame\n"); - return; - } - - memset(&hfi, 0, sizeof(hfi)); - - while (1) { - ret = ieee80211_radiotap_iterator_next(&iter); - if (ret == -ENOENT) - break; - if (ret) { - printf("received invalid radiotap frame (%d)\n", ret); - return; - } - switch (iter.this_arg_index) { - case IEEE80211_RADIOTAP_FLAGS: - if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) - len -= 4; - break; - case IEEE80211_RADIOTAP_RX_FLAGS: - rxflags = 1; - break; - case IEEE80211_RADIOTAP_TX_FLAGS: - injected = 1; - failed = le_to_host16((*(uint16_t *) iter.this_arg)) & - IEEE80211_RADIOTAP_F_TX_FAIL; - break; - case IEEE80211_RADIOTAP_DATA_RETRIES: - break; - case IEEE80211_RADIOTAP_CHANNEL: - /* TODO convert from freq/flags to channel number - hfi.channel = XXX; - hfi.phytype = XXX; - */ - break; - case IEEE80211_RADIOTAP_RATE: - hfi.datarate = *iter.this_arg * 5; - break; - case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - hfi.ssi_signal = *iter.this_arg; - break; - } - } - - if (rxflags && injected) - return; - - if (!injected) - msg_type = ieee80211_msg_normal; - else if (failed) - msg_type = ieee80211_msg_tx_callback_fail; - else - msg_type = ieee80211_msg_tx_callback_ack; - - handle_frame(hapd->iface, buf + iter.max_length, - len - iter.max_length, &hfi, msg_type); -} - - -/* - * we post-process the filter code later and rewrite - * this to the offset to the last instruction - */ -#define PASS 0xFF -#define FAIL 0xFE - -static struct sock_filter msock_filter_insns[] = { - /* - * do a little-endian load of the radiotap length field - */ - /* load lower byte into A */ - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), - /* put it into X (== index register) */ - BPF_STMT(BPF_MISC| BPF_TAX, 0), - /* load upper byte into A */ - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), - /* left-shift it by 8 */ - BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), - /* or with X */ - BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), - /* put result into X */ - BPF_STMT(BPF_MISC| BPF_TAX, 0), - - /* - * Allow management frames through, this also gives us those - * management frames that we sent ourselves with status - */ - /* load the lower byte of the IEEE 802.11 frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off frame type and version */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), - /* accept frame if it's both 0, fall through otherwise */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), - - /* - * TODO: add a bit to radiotap RX flags that indicates - * that the sending station is not associated, then - * add a filter here that filters on our DA and that flag - * to allow us to deauth frames to that bad station. - * - * Not a regression -- we didn't do it before either. - */ - -#if 0 - /* - * drop non-data frames, WDS frames - */ - /* load the lower byte of the frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off QoS bit */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), - /* drop non-data frames */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), - /* load the upper byte of the frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off toDS/fromDS */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), - /* drop WDS frames */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, FAIL, 0), -#endif - - /* - * add header length to index - */ - /* load the lower byte of the frame control field */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), - /* mask off QoS bit */ - BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), - /* right shift it by 6 to give 0 or 2 */ - BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), - /* add data frame header length */ - BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), - /* add index, was start of 802.11 header */ - BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), - /* move to index, now start of LL header */ - BPF_STMT(BPF_MISC | BPF_TAX, 0), - - /* - * Accept empty data frames, we use those for - * polling activity. - */ - BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), - - /* - * Accept EAPOL frames - */ - BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), - BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), - - /* keep these last two statements or change the code below */ - /* return 0 == "DROP" */ - BPF_STMT(BPF_RET | BPF_K, 0), - /* return ~0 == "keep all" */ - BPF_STMT(BPF_RET | BPF_K, ~0), -}; - -static struct sock_fprog msock_filter = { - .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]), - .filter = msock_filter_insns, -}; - - -static int add_monitor_filter(int s) -{ - int idx; - - /* rewrite all PASS/FAIL jump offsets */ - for (idx = 0; idx < msock_filter.len; idx++) { - struct sock_filter *insn = &msock_filter_insns[idx]; - - if (BPF_CLASS(insn->code) == BPF_JMP) { - if (insn->code == (BPF_JMP|BPF_JA)) { - if (insn->k == PASS) - insn->k = msock_filter.len - idx - 2; - else if (insn->k == FAIL) - insn->k = msock_filter.len - idx - 3; - } - - if (insn->jt == PASS) - insn->jt = msock_filter.len - idx - 2; - else if (insn->jt == FAIL) - insn->jt = msock_filter.len - idx - 3; - - if (insn->jf == PASS) - insn->jf = msock_filter.len - idx - 2; - else if (insn->jf == FAIL) - insn->jf = msock_filter.len - idx - 3; - } - } - - if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, - &msock_filter, sizeof(msock_filter))) { - perror("SO_ATTACH_FILTER"); - return -1; - } - - return 0; -} - - -static int nl80211_create_monitor_interface(struct i802_driver_data *drv) -{ - char buf[IFNAMSIZ]; - struct sockaddr_ll ll; - int optval; - socklen_t optlen; - - snprintf(buf, IFNAMSIZ, "mon.%s", drv->iface); - buf[IFNAMSIZ - 1] = '\0'; - - drv->monitor_ifidx = - nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL); - - if (drv->monitor_ifidx < 0) - return -1; - - if (hostapd_set_iface_flags(drv, buf, 1)) - goto error; - - memset(&ll, 0, sizeof(ll)); - ll.sll_family = AF_PACKET; - ll.sll_ifindex = drv->monitor_ifidx; - drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->monitor_sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - goto error; - } - - if (add_monitor_filter(drv->monitor_sock)) { - wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " - "interface; do filtering in user space"); - /* This works, but will cost in performance. */ - } - - if (bind(drv->monitor_sock, (struct sockaddr *) &ll, - sizeof(ll)) < 0) { - perror("monitor socket bind"); - goto error; - } - - optlen = sizeof(optval); - optval = 20; - if (setsockopt - (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { - perror("Failed to set socket priority"); - goto error; - } - - if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, - drv, NULL)) { - printf("Could not register monitor read socket\n"); - goto error; - } - - return 0; - error: - nl80211_remove_iface(drv, drv->monitor_ifidx); - return -1; -} - - -static int nl80211_set_master_mode(struct i802_driver_data *drv, - const char *ifname) -{ - struct nl_msg *msg; - int ret = -ENOBUFS; - - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(ifname)); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (!ret) - return 0; - nla_put_failure: - wpa_printf(MSG_ERROR, "Failed to set interface %s to master " - "mode.", ifname); - return ret; -} - - -static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid) -{ - struct ifreq ifr; - struct sockaddr_ll addr; - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - return -1; - } - - /* start listening for EAPOL on the default AP interface */ - add_ifidx(drv, if_nametoindex(drv->iface)); - - if (hostapd_set_iface_flags(drv, drv->iface, 0)) - return -1; - - if (bssid) { - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN); - ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; - - if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) { - perror("ioctl(SIOCSIFHWADDR)"); - return -1; - } - } - - /* - * initialise generic netlink and nl80211 - */ - drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!drv->nl_cb) { - printf("Failed to allocate netlink callbacks.\n"); - return -1; - } - - drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb); - if (!drv->nl_handle) { - printf("Failed to allocate netlink handle.\n"); - return -1; - } - - if (genl_connect(drv->nl_handle)) { - printf("Failed to connect to generic netlink.\n"); - return -1; - } - -#ifdef CONFIG_LIBNL20 - if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) { - printf("Failed to allocate generic netlink cache.\n"); - return -1; - } -#else /* CONFIG_LIBNL20 */ - drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); - if (!drv->nl_cache) { - printf("Failed to allocate generic netlink cache.\n"); - return -1; - } -#endif /* CONFIG_LIBNL20 */ - - drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); - if (!drv->nl80211) { - printf("nl80211 not found.\n"); - return -1; - } - - /* Initialise a monitor interface */ - if (nl80211_create_monitor_interface(drv)) - return -1; - - if (nl80211_set_master_mode(drv, drv->iface)) - goto fail1; - - if (hostapd_set_iface_flags(drv, drv->iface, 1)) - goto fail1; - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); - if (drv->eapol_sock < 0) { - perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); - goto fail1; - } - - if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) - { - printf("Could not register read socket for eapol\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - goto fail1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - goto fail1; - } - memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - return 0; - -fail1: - nl80211_remove_iface(drv, drv->monitor_ifidx); - return -1; -} - - -static int i802_get_inact_sec(void *priv, const u8 *addr) -{ - struct hostap_sta_driver_data data; - int ret; - - data.inactive_msec = (unsigned long) -1; - ret = i802_read_sta_data(priv, &data, addr); - if (ret || data.inactive_msec == (unsigned long) -1) - return -1; - return data.inactive_msec / 1000; -} - - -static int i802_sta_clear_stats(void *priv, const u8 *addr) -{ -#if 0 - /* TODO */ -#endif - return 0; -} - - -static void -hostapd_wireless_event_wireless_custom(struct i802_driver_data *drv, - char *custom) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - ieee80211_michael_mic_failure(drv->hapd, addr, 1); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } -} - - -static void hostapd_wireless_event_wireless(struct i802_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - if (drv->we_version > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM)) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - hostapd_wireless_event_wireless_custom(drv, buf); - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv, - struct nlmsghdr *h, int len) -{ - struct ifinfomsg *ifi; - int attrlen, _nlmsg_len, rta_len; - struct rtattr *attr; - - if (len < (int) sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - /* TODO: use ifi->ifi_index to filter out wireless events from other - * interfaces */ - - _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - _nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len); - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - hostapd_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void hostapd_wireless_event_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - char buf[256]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - struct i802_driver_data *drv = eloop_ctx; - - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - printf("Malformed netlink message: " - "len=%d left=%d plen=%d\n", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - hostapd_wireless_event_rtm_newlink(drv, h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - printf("%d extra bytes in the end of netlink message\n", left); - } -} - - -static int hostap_get_we_version(struct i802_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - free(range); - return 0; -} - - -static int i802_wireless_event_init(void *priv) -{ - struct i802_driver_data *drv = priv; - int s; - struct sockaddr_nl local; - - hostap_get_we_version(drv); - - drv->wext_sock = -1; - - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - return -1; - } - - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - eloop_register_read_sock(s, hostapd_wireless_event_receive, drv, - NULL); - drv->wext_sock = s; - - return 0; -} - - -static void i802_wireless_event_deinit(void *priv) -{ - struct i802_driver_data *drv = priv; - if (drv->wext_sock < 0) - return; - eloop_unregister_read_sock(drv->wext_sock); - close(drv->wext_sock); -} - - -static int i802_sta_deauth(void *priv, const u8 *addr, int reason) -{ - struct i802_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); - memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); - mgmt.u.deauth.reason_code = host_to_le16(reason); - return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0); -} - - -static int i802_sta_disassoc(void *priv, const u8 *addr, int reason) -{ - struct i802_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); - memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); - mgmt.u.disassoc.reason_code = host_to_le16(reason); - return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0); -} - - -static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid) -{ - struct i802_driver_data *drv; - - drv = os_zalloc(sizeof(struct i802_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for i802 driver data\n"); - return NULL; - } - - drv->hapd = hapd; - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); - - drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); - drv->if_indices = drv->default_if_indices; - drv->bridge = if_nametoindex(hapd->conf->bridge); - - if (i802_init_sockets(drv, bssid)) - goto failed; - - return drv; - -failed: - free(drv); - return NULL; -} - - -static void *i802_init(struct hostapd_data *hapd) -{ - return i802_init_bssid(hapd, NULL); -} - - -static void i802_deinit(void *priv) -{ - struct i802_driver_data *drv = priv; - - if (drv->last_freq_ht) { - /* Clear HT flags from the driver */ - struct hostapd_freq_params freq; - os_memset(&freq, 0, sizeof(freq)); - freq.freq = drv->last_freq; - i802_set_freq2(priv, &freq); - } - - i802_del_beacon(drv); - - /* remove monitor interface */ - nl80211_remove_iface(drv, drv->monitor_ifidx); - - (void) hostapd_set_iface_flags(drv, drv->iface, 0); - - if (drv->monitor_sock >= 0) { - eloop_unregister_read_sock(drv->monitor_sock); - close(drv->monitor_sock); - } - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv->eapol_sock >= 0) { - eloop_unregister_read_sock(drv->eapol_sock); - close(drv->eapol_sock); - } - - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl_handle_destroy(drv->nl_handle); - nl_cb_put(drv->nl_cb); - - if (drv->if_indices != drv->default_if_indices) - free(drv->if_indices); - - free(drv); -} - - -const struct wpa_driver_ops wpa_driver_nl80211_ops = { - .name = "nl80211", - .init = i802_init, - .init_bssid = i802_init_bssid, - .deinit = i802_deinit, - .wireless_event_init = i802_wireless_event_init, - .wireless_event_deinit = i802_wireless_event_deinit, - .set_ieee8021x = i802_set_ieee8021x, - .set_privacy = i802_set_privacy, - .set_encryption = i802_set_encryption, - .get_seqnum = i802_get_seqnum, - .flush = i802_flush, - .read_sta_data = i802_read_sta_data, - .send_eapol = i802_send_eapol, - .sta_set_flags = i802_sta_set_flags, - .sta_deauth = i802_sta_deauth, - .sta_disassoc = i802_sta_disassoc, - .sta_remove = i802_sta_remove, - .send_mgmt_frame = i802_send_mgmt_frame, - .sta_add2 = i802_sta_add2, - .get_inact_sec = i802_get_inact_sec, - .sta_clear_stats = i802_sta_clear_stats, - .set_freq2 = i802_set_freq2, - .set_rts = i802_set_rts, - .get_rts = i802_get_rts, - .set_frag = i802_set_frag, - .get_frag = i802_get_frag, - .set_retry = i802_set_retry, - .get_retry = i802_get_retry, - .set_rate_sets = i802_set_rate_sets, - .set_regulatory_domain = i802_set_regulatory_domain, - .set_beacon = i802_set_beacon, - .set_internal_bridge = i802_set_internal_bridge, - .set_beacon_int = i802_set_beacon_int, - .set_dtim_period = i802_set_dtim_period, - .set_cts_protect = i802_set_cts_protect, - .set_preamble = i802_set_preamble, - .set_short_slot_time = i802_set_short_slot_time, - .set_tx_queue_params = i802_set_tx_queue_params, - .bss_add = i802_bss_add, - .bss_remove = i802_bss_remove, - .if_add = i802_if_add, - .if_update = i802_if_update, - .if_remove = i802_if_remove, - .get_hw_feature_data = i802_get_hw_feature_data, - .set_sta_vlan = i802_set_sta_vlan, - .set_country = i802_set_country, -}; diff --git a/hostapd/driver_prism54.c b/hostapd/driver_prism54.c deleted file mode 100644 index 4e2189aeb5f6..000000000000 --- a/hostapd/driver_prism54.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * hostapd / Driver interaction with Prism54 PIMFOR interface - * Copyright (c) 2004, Bell Kin - * based on hostap driver.c, ieee802_11.c - * Copyright (c) 2002-2007, Jouni Malinen - * - * 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 -#include - -#ifdef USE_KERNEL_HEADERS -/* compat-wireless does not include linux/compiler.h to define __user, so - * define it here */ -#ifndef __user -#define __user -#endif /* __user */ -#include -#include -#include /* The L2 protocols */ -#include -#include -#else /* USE_KERNEL_HEADERS */ -#include -#include -#include "wireless_copy.h" -#endif /* USE_KERNEL_HEADERS */ - -#include "hostapd.h" -#include "driver.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "ieee802_11.h" -#include "prism54.h" -#include "wpa.h" -#include "radius/radius.h" -#include "sta_info.h" -#include "accounting.h" - -const int PIM_BUF_SIZE = 4096; - -struct prism54_driver_data { - struct hostapd_data *hapd; - char iface[IFNAMSIZ + 1]; - int sock; /* raw packet socket for 802.3 access */ - int pim_sock; /* socket for pimfor packet */ - char macs[2007][6]; -}; - - -static int mac_id_refresh(struct prism54_driver_data *data, int id, char *mac) -{ - if (id < 0 || id > 2006) { - return -1; - } - memcpy(&data->macs[id][0], mac, ETH_ALEN); - return 0; -} - - -static char * mac_id_get(struct prism54_driver_data *data, int id) -{ - if (id < 0 || id > 2006) { - return NULL; - } - return &data->macs[id][0]; -} - - -/* wait for a specific pimfor, timeout in 10ms resolution */ -/* pim_sock must be non-block to prevent dead lock from no response */ -/* or same response type in series */ -static int prism54_waitpim(void *priv, unsigned long oid, void *buf, int len, - int timeout) -{ - struct prism54_driver_data *drv = priv; - struct timeval tv, stv, ctv; - fd_set pfd; - int rlen; - pimdev_hdr *pkt; - - pkt = malloc(8192); - if (pkt == NULL) - return -1; - - FD_ZERO(&pfd); - gettimeofday(&stv, NULL); - do { - FD_SET(drv->pim_sock, &pfd); - tv.tv_sec = 0; - tv.tv_usec = 10000; - if (select(drv->pim_sock + 1, &pfd, NULL, NULL, &tv)) { - rlen = recv(drv->pim_sock, pkt, 8192, 0); - if (rlen > 0) { - if (pkt->oid == htonl(oid)) { - if (rlen <= len) { - if (buf != NULL) { - memcpy(buf, pkt, rlen); - } - free(pkt); - return rlen; - } else { - printf("buffer too small\n"); - free(pkt); - return -1; - } - } else { - gettimeofday(&ctv, NULL); - continue; - } - } - } - gettimeofday(&ctv, NULL); - } while (((ctv.tv_sec - stv.tv_sec) * 100 + - (ctv.tv_usec - stv.tv_usec) / 10000) > timeout); - free(pkt); - return 0; -} - - -/* send an eapol packet */ -static int prism54_send_eapol(void *priv, const u8 *addr, - const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr) -{ - struct prism54_driver_data *drv = priv; - ieee802_3_hdr *hdr; - size_t len; - u8 *pos; - int res; - - len = sizeof(*hdr) + data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for prism54_send_data(len=%lu)\n", - (unsigned long) len); - return -1; - } - - memcpy(&hdr->da[0], addr, ETH_ALEN); - memcpy(&hdr->sa[0], own_addr, ETH_ALEN); - hdr->type = htons(ETH_P_PAE); - pos = (u8 *) (hdr + 1); - memcpy(pos, data, data_len); - - res = send(drv->sock, hdr, len, 0); - free(hdr); - - if (res < 0) { - perror("hostapd_send_eapol: send"); - printf("hostapd_send_eapol - packet len: %lu - failed\n", - (unsigned long) len); - } - - return res; -} - - -/* open data channel(auth-1) or eapol only(unauth-0) */ -static int prism54_set_sta_authorized(void *priv, const u8 *addr, - int authorized) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - char *pos; - - hdr = malloc(sizeof(*hdr) + ETH_ALEN); - if (hdr == NULL) - return -1; - hdr->op = htonl(PIMOP_SET); - if (authorized) { - hdr->oid = htonl(DOT11_OID_EAPAUTHSTA); - } else { - hdr->oid = htonl(DOT11_OID_EAPUNAUTHSTA); - } - pos = (char *) (hdr + 1); - memcpy(pos, addr, ETH_ALEN); - send(drv->pim_sock, hdr, sizeof(*hdr) + ETH_ALEN, 0); - prism54_waitpim(priv, hdr->oid, hdr, sizeof(*hdr) + ETH_ALEN, 10); - free(hdr); - return 0; -} - - -static int -prism54_sta_set_flags(void *priv, const u8 *addr, int total_flags, - int flags_or, int flags_and) -{ - /* For now, only support setting Authorized flag */ - if (flags_or & WLAN_STA_AUTHORIZED) - return prism54_set_sta_authorized(priv, addr, 1); - if (flags_and & WLAN_STA_AUTHORIZED) - return prism54_set_sta_authorized(priv, addr, 0); - return 0; -} - - -/* set per station key */ -static int prism54_set_encryption(const char *ifname, void *priv, - const char *alg, const u8 *addr, - int idx, const u8 *key, size_t key_len, - int txkey) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - struct obj_stakey *keys; - u8 *buf; - size_t blen; - int ret = 0; - - blen = sizeof(struct obj_stakey) + sizeof(pimdev_hdr); - hdr = malloc(blen); - if (hdr == NULL) { - printf("memory low\n"); - return -1; - } - keys = (struct obj_stakey *) &hdr[1]; - if (!addr) { - memset(&keys->address[0], 0xff, ETH_ALEN); - } else { - memcpy(&keys->address[0], addr, ETH_ALEN); - } - if (!strcmp(alg, "WEP")) { - keys->type = DOT11_PRIV_WEP; - } else if (!strcmp(alg, "TKIP")) { - keys->type = DOT11_PRIV_TKIP; - } else if (!strcmp(alg, "none")) { - /* the only way to clear the key is to deauth it */ - /* and prism54 is capable to receive unencrypted packet */ - /* so we do nothing here */ - free(hdr); - return 0; - } else { - printf("bad auth type: %s\n", alg); - } - buf = (u8 *) &keys->key[0]; - keys->length = key_len; - keys->keyid = idx; - keys->options = htons(DOT11_STAKEY_OPTION_DEFAULTKEY); - keys->reserved = 0; - - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_STAKEY); - - memcpy(buf, key, key_len); - - ret = send(drv->pim_sock, hdr, blen, 0); - if (ret < 0) { - free(hdr); - return ret; - } - prism54_waitpim(priv, hdr->oid, hdr, blen, 10); - - free(hdr); - - return 0; -} - - -/* get TKIP station sequence counter, prism54 is only 6 bytes */ -static int prism54_get_seqnum(const char *ifname, void *priv, const u8 *addr, - int idx, u8 *seq) -{ - struct prism54_driver_data *drv = priv; - struct obj_stasc *stasc; - pimdev_hdr *hdr; - size_t blen; - int ret = 0; - - blen = sizeof(*stasc) + sizeof(*hdr); - hdr = malloc(blen); - if (hdr == NULL) - return -1; - - stasc = (struct obj_stasc *) &hdr[1]; - - if (addr == NULL) - memset(&stasc->address[0], 0xff, ETH_ALEN); - else - memcpy(&stasc->address[0], addr, ETH_ALEN); - - hdr->oid = htonl(DOT11_OID_STASC); - hdr->op = htonl(PIMOP_GET); - stasc->keyid = idx; - if (send(drv->pim_sock,hdr,blen,0) <= 0) { - free(hdr); - return -1; - } - if (prism54_waitpim(priv, DOT11_OID_STASC, hdr, blen, 10) <= 0) { - ret = -1; - } else { - if (hdr->op == (int) htonl(PIMOP_RESPONSE)) { - memcpy(seq + 2, &stasc->sc_high, ETH_ALEN); - memset(seq, 0, 2); - } else { - ret = -1; - } - } - free(hdr); - - return ret; -} - - -/* include unencrypted, set mlme autolevel to extended */ -static int prism54_init_1x(void *priv) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - unsigned long *ul; - int blen = sizeof(*hdr) + sizeof(*ul); - - hdr = malloc(blen); - if (hdr == NULL) - return -1; - - ul = (unsigned long *) &hdr[1]; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_EXUNENCRYPTED); - *ul = htonl(DOT11_BOOL_TRUE); /* not accept */ - send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_EXUNENCRYPTED, hdr, blen, 10); - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_MLMEAUTOLEVEL); - *ul = htonl(DOT11_MLME_EXTENDED); - send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_MLMEAUTOLEVEL, hdr, blen, 10); - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_DOT1XENABLE); - *ul = htonl(DOT11_BOOL_TRUE); - send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_DOT1XENABLE, hdr, blen, 10); - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_AUTHENABLE); - *ul = htonl(DOT11_AUTH_OS); /* OS */ - send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_AUTHENABLE, hdr, blen, 10); - free(hdr); - return 0; -} - - -static int prism54_set_privacy_invoked(const char *ifname, void *priv, - int flag) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - unsigned long *ul; - int ret; - int blen = sizeof(*hdr) + sizeof(*ul); - hdr = malloc(blen); - if (hdr == NULL) - return -1; - ul = (unsigned long *) &hdr[1]; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_PRIVACYINVOKED); - if (flag) { - *ul = htonl(DOT11_BOOL_TRUE); /* has privacy */ - } else { - *ul = 0; - } - ret = send(drv->pim_sock, hdr, blen, 0); - if (ret >= 0) { - ret = prism54_waitpim(priv, DOT11_OID_PRIVACYINVOKED, hdr, - blen, 10); - } - free(hdr); - return ret; -} - - -static int prism54_ioctl_setiwessid(const char *ifname, void *priv, - const u8 *buf, int len) -{ -#if 0 - struct prism54_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len + 1; - - if (ioctl(drv->pim_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } -#endif - return 0; -} - - -/* kick all stations */ -/* does not work during init, but at least it won't crash firmware */ -static int prism54_flush(void *priv) -{ - struct prism54_driver_data *drv = priv; - struct obj_mlmeex *mlme; - pimdev_hdr *hdr; - int ret; - unsigned int i; - long *nsta; - int blen = sizeof(*hdr) + sizeof(*mlme); - char *mac_id; - - hdr = os_zalloc(blen); - if (hdr == NULL) - return -1; - - mlme = (struct obj_mlmeex *) &hdr[1]; - nsta = (long *) &hdr[1]; - hdr->op = htonl(PIMOP_GET); - hdr->oid = htonl(DOT11_OID_CLIENTS); - ret = send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(long), 0); - ret = prism54_waitpim(priv, DOT11_OID_CLIENTS, hdr, blen, 10); - if ((ret < 0) || (hdr->op != (int) htonl(PIMOP_RESPONSE)) || - (le_to_host32(*nsta) > 2007)) { - free(hdr); - return 0; - } - for (i = 0; i < le_to_host32(*nsta); i++) { - mlme->id = -1; - mac_id = mac_id_get(drv, i); - if (mac_id) - memcpy(&mlme->address[0], mac_id, ETH_ALEN); - mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED); - mlme->state = htons(DOT11_STATE_NONE); - mlme->size = 0; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX); - ret = send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, - 100); - } - for (i = 0; i < le_to_host32(*nsta); i++) { - mlme->id = -1; - mac_id = mac_id_get(drv, i); - if (mac_id) - memcpy(&mlme->address[0], mac_id, ETH_ALEN); - mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED); - mlme->state = htons(DOT11_STATE_NONE); - mlme->size = 0; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX); - ret = send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, - 100); - } - free(hdr); - return 0; -} - - -static int prism54_sta_deauth(void *priv, const u8 *addr, int reason) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - struct obj_mlmeex *mlme; - int ret; - int blen = sizeof(*hdr) + sizeof(*mlme); - hdr = malloc(blen); - if (hdr == NULL) - return -1; - mlme = (struct obj_mlmeex *) &hdr[1]; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX); - memcpy(&mlme->address[0], addr, ETH_ALEN); - mlme->id = -1; - mlme->state = htons(DOT11_STATE_NONE); - mlme->code = host_to_le16(reason); - mlme->size = 0; - ret = send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 10); - free(hdr); - return ret; -} - - -static int prism54_sta_disassoc(void *priv, const u8 *addr, int reason) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - struct obj_mlmeex *mlme; - int ret; - int blen = sizeof(*hdr) + sizeof(*mlme); - hdr = malloc(blen); - if (hdr == NULL) - return -1; - mlme = (struct obj_mlmeex *) &hdr[1]; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX); - memcpy(&mlme->address[0], addr, ETH_ALEN); - mlme->id = -1; - mlme->state = htons(DOT11_STATE_NONE); - mlme->code = host_to_le16(reason); - mlme->size = 0; - ret = send(drv->pim_sock, hdr, blen, 0); - prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 10); - free(hdr); - return ret; -} - - -static int prism54_get_inact_sec(void *priv, const u8 *addr) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - struct obj_sta *sta; - int blen = sizeof(*hdr) + sizeof(*sta); - int ret; - - hdr = malloc(blen); - if (hdr == NULL) - return -1; - hdr->op = htonl(PIMOP_GET); - hdr->oid = htonl(DOT11_OID_CLIENTFIND); - sta = (struct obj_sta *) &hdr[1]; - memcpy(&sta->address[0], addr, ETH_ALEN); - ret = send(drv->pim_sock, hdr, blen, 0); - ret = prism54_waitpim(priv, DOT11_OID_CLIENTFIND, hdr, blen, 10); - if (ret != blen) { - printf("get_inact_sec: bad return %d\n", ret); - free(hdr); - return -1; - } - if (hdr->op != (int) htonl(PIMOP_RESPONSE)) { - printf("get_inact_sec: bad resp\n"); - free(hdr); - return -1; - } - free(hdr); - return le_to_host16(sta->age); -} - - -/* set attachments */ -static int prism54_set_generic_elem(const char *ifname, void *priv, - const u8 *elem, size_t elem_len) -{ - struct prism54_driver_data *drv = priv; - pimdev_hdr *hdr; - char *pos; - struct obj_attachment_hdr *attach; - size_t blen = sizeof(*hdr) + sizeof(*attach) + elem_len; - hdr = os_zalloc(blen); - if (hdr == NULL) { - printf("%s: memory low\n", __func__); - return -1; - } - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_ATTACHMENT); - attach = (struct obj_attachment_hdr *)&hdr[1]; - attach->type = DOT11_PKT_BEACON; - attach->id = -1; - attach->size = host_to_le16((short)elem_len); - pos = ((char*) attach) + sizeof(*attach); - if (elem) - memcpy(pos, elem, elem_len); - send(drv->pim_sock, hdr, blen, 0); - attach->type = DOT11_PKT_PROBE_RESP; - send(drv->pim_sock, hdr, blen, 0); - free(hdr); - return 0; -} - - -/* tell the card to auth the sta */ -static void prism54_handle_probe(struct prism54_driver_data *drv, - void *buf, size_t len) -{ - struct obj_mlmeex *mlme; - pimdev_hdr *hdr; - struct sta_info *sta; - hdr = (pimdev_hdr *)buf; - mlme = (struct obj_mlmeex *) &hdr[1]; - sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]); - if (sta != NULL) { - if (sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC)) - return; - } - if (len < sizeof(*mlme)) { - printf("bad probe packet\n"); - return; - } - mlme->state = htons(DOT11_STATE_AUTHING); - mlme->code = 0; - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX); - mlme->size = 0; - send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0); -} - - -static void prism54_handle_deauth(struct prism54_driver_data *drv, - void *buf, size_t len) -{ - struct obj_mlme *mlme; - pimdev_hdr *hdr; - struct sta_info *sta; - char *mac_id; - - hdr = (pimdev_hdr *) buf; - mlme = (struct obj_mlme *) &hdr[1]; - sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]); - mac_id = mac_id_get(drv, mlme->id); - if (sta == NULL || mac_id == NULL) - return; - memcpy(&mlme->address[0], mac_id, ETH_ALEN); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(drv->hapd, sta); -} - - -static void prism54_handle_disassoc(struct prism54_driver_data *drv, - void *buf, size_t len) -{ - struct obj_mlme *mlme; - pimdev_hdr *hdr; - struct sta_info *sta; - char *mac_id; - - hdr = (pimdev_hdr *) buf; - mlme = (struct obj_mlme *) &hdr[1]; - mac_id = mac_id_get(drv, mlme->id); - if (mac_id == NULL) - return; - memcpy(&mlme->address[0], mac_id, ETH_ALEN); - sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]); - if (sta == NULL) { - return; - } - sta->flags &= ~WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - accounting_sta_stop(drv->hapd, sta); - ieee802_1x_free_station(sta); -} - - -/* to auth it, just allow it now, later for os/sk */ -static void prism54_handle_auth(struct prism54_driver_data *drv, - void *buf, size_t len) -{ - struct obj_mlmeex *mlme; - pimdev_hdr *hdr; - struct sta_info *sta; - int resp; - - hdr = (pimdev_hdr *) buf; - mlme = (struct obj_mlmeex *) &hdr[1]; - if (len < sizeof(*mlme)) { - printf("bad auth packet\n"); - return; - } - - if (mlme->state == htons(DOT11_STATE_AUTHING)) { - sta = ap_sta_add(drv->hapd, (u8 *) &mlme->address[0]); - if (drv->hapd->tkip_countermeasures) { - resp = WLAN_REASON_MICHAEL_MIC_FAILURE; - goto fail; - } - mac_id_refresh(drv, mlme->id, &mlme->address[0]); - if (!sta) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - sta->flags &= ~WLAN_STA_PREAUTH; - - ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); - sta->flags |= WLAN_STA_AUTH; - wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); - mlme->code = 0; - mlme->state=htons(DOT11_STATE_AUTH); - hdr->op = htonl(PIMOP_SET); - hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX); - mlme->size = 0; - sta->timeout_next = STA_NULLFUNC; - send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0); - } - return; - -fail: - printf("auth fail: %x\n", resp); - mlme->code = host_to_le16(resp); - mlme->size = 0; - if (sta) - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX); - hdr->op = htonl(PIMOP_SET); - send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0); -} - - -/* do the wpa thing */ -static void prism54_handle_assoc(struct prism54_driver_data *drv, - void *buf, size_t len) -{ - pimdev_hdr *hdr; - struct obj_mlmeex *mlme; - struct ieee802_11_elems elems; - struct sta_info *sta; - u8 *wpa_ie; - u8 *cb; - int ieofs = 0; - size_t wpa_ie_len; - int resp, new_assoc; - char *mac_id; - - resp = 0; - hdr = (pimdev_hdr *) buf; - mlme = (struct obj_mlmeex *) &hdr[1]; - switch (ntohl(hdr->oid)) { - case DOT11_OID_ASSOCIATE: - case DOT11_OID_REASSOCIATE: - mlme->size = 0; - default: - break; - } - if ((mlme->state == (int) htonl(DOT11_STATE_ASSOCING)) || - (mlme->state == (int) htonl(DOT11_STATE_REASSOCING))) { - if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) { - printf("bad assoc packet\n"); - return; - } - mac_id = mac_id_get(drv, mlme->id); - if (mac_id == NULL) - return; - memcpy(&mlme->address[0], mac_id, ETH_ALEN); - sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]); - if (sta == NULL) { - printf("cannot get sta\n"); - return; - } - cb = (u8 *) &mlme->data[0]; - if (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) { - ieofs = 4; - } else if (hdr->oid == htonl(DOT11_OID_REASSOCIATEEX)) { - ieofs = 10; - } - if (le_to_host16(mlme->size) <= ieofs) { - printf("attach too small\n"); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - if (ieee802_11_parse_elems(cb + ieofs, - le_to_host16(mlme->size) - ieofs, - &elems, 1) == ParseFailed) { - printf("STA " MACSTR " sent invalid association " - "request\n", MAC2STR(sta->addr)); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto fail; - } - if ((drv->hapd->conf->wpa & WPA_PROTO_RSN) && - elems.rsn_ie) { - wpa_ie = elems.rsn_ie; - wpa_ie_len = elems.rsn_ie_len; - } else if ((drv->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; - } - if (drv->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 (drv->hapd->conf->wpa) { - int res; - wpa_ie -= 2; - wpa_ie_len += 2; - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init( - drv->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(drv->hapd->wpa_auth, - sta->wpa_sm, - wpa_ie, wpa_ie_len, - NULL, 0); - 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; - else if (res != WPA_IE_OK) - resp = WLAN_STATUS_INVALID_IE; - if (resp != WLAN_STATUS_SUCCESS) - goto fail; - } - hdr->oid = (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) ? - htonl(DOT11_OID_ASSOCIATEEX) : - htonl(DOT11_OID_REASSOCIATEEX); - hdr->op = htonl(PIMOP_SET); - mlme->code = 0; - mlme->state = htons(DOT11_STATE_ASSOC); - mlme->size = 0; - send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0); - return; - } else if (mlme->state==htons(DOT11_STATE_ASSOC)) { - if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) { - printf("bad assoc packet\n"); - return; - } - mac_id = mac_id_get(drv, mlme->id); - if (mac_id == NULL) - return; - memcpy(&mlme->address[0], mac_id, ETH_ALEN); - sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]); - if (sta == NULL) { - printf("cannot get sta\n"); - return; - } - new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - hostapd_new_assoc_sta(drv->hapd, sta, !new_assoc); - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - sta->timeout_next = STA_NULLFUNC; - return; - } - return; - -fail: - printf("Prism54: assoc fail: %x\n", resp); - mlme->code = host_to_le16(resp); - mlme->size = 0; - mlme->state = htons(DOT11_STATE_ASSOCING); - hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX); - hdr->op = htonl(PIMOP_SET); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0); -} - - -static void handle_pim(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct prism54_driver_data *drv = eloop_ctx; - int len; - pimdev_hdr *hdr; - - hdr = malloc(PIM_BUF_SIZE); - if (hdr == NULL) - return; - len = recv(sock, hdr, PIM_BUF_SIZE, 0); - if (len < 0) { - perror("recv"); - free(hdr); - return; - } - if (len < 8) { - printf("handle_pim: too short (%d)\n", len); - free(hdr); - return; - } - - if (hdr->op != (int) htonl(PIMOP_TRAP)) { - free(hdr); - return; - } - switch (ntohl(hdr->oid)) { - case DOT11_OID_PROBE: - prism54_handle_probe(drv, hdr, len); - break; - case DOT11_OID_DEAUTHENTICATEEX: - case DOT11_OID_DEAUTHENTICATE: - prism54_handle_deauth(drv, hdr, len); - break; - case DOT11_OID_DISASSOCIATEEX: - case DOT11_OID_DISASSOCIATE: - prism54_handle_disassoc(drv, hdr, len); - break; - case DOT11_OID_AUTHENTICATEEX: - case DOT11_OID_AUTHENTICATE: - prism54_handle_auth(drv, hdr, len); - break; - case DOT11_OID_ASSOCIATEEX: - case DOT11_OID_REASSOCIATEEX: - case DOT11_OID_ASSOCIATE: - case DOT11_OID_REASSOCIATE: - prism54_handle_assoc(drv, hdr, len); - default: - break; - } - - free(hdr); -} - - -static void handle_802_3(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; - int len; - ieee802_3_hdr *hdr; - - hdr = malloc(PIM_BUF_SIZE); - if (hdr == NULL) - return; - len = recv(sock, hdr, PIM_BUF_SIZE, 0); - if (len < 0) { - perror("recv"); - free(hdr); - return; - } - if (len < 14) { - wpa_printf(MSG_MSGDUMP, "handle_802_3: too short (%d)", len); - free(hdr); - return; - } - if (hdr->type == htons(ETH_P_PAE)) { - ieee802_1x_receive(hapd, (u8 *) &hdr->sa[0], (u8 *) &hdr[1], - len - sizeof(*hdr)); - } - free(hdr); -} - - -static int prism54_init_sockets(struct prism54_driver_data *drv) -{ - struct hostapd_data *hapd = drv->hapd; - struct ifreq ifr; - struct sockaddr_ll addr; - - drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); - if (drv->sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - return -1; - } - - if (eloop_register_read_sock(drv->sock, handle_802_3, drv->hapd, NULL)) - { - printf("Could not register read socket\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - if (hapd->conf->bridge[0] != '\0') { - printf("opening bridge: %s\n", hapd->conf->bridge); - os_strlcpy(ifr.ifr_name, hapd->conf->bridge, - sizeof(ifr.ifr_name)); - } else { - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - } - if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - addr.sll_protocol = htons(ETH_P_PAE); - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - return -1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - return -1; - } - memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - drv->pim_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->pim_sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - return -1; - } - - if (eloop_register_read_sock(drv->pim_sock, handle_pim, drv, NULL)) { - printf("Could not register read socket\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); - if (ioctl(drv->pim_sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - addr.sll_protocol = htons(ETH_P_ALL); - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - if (bind(drv->pim_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind"); - return -1; - } - - return 0; -} - - -static void * prism54_driver_init(struct hostapd_data *hapd) -{ - struct prism54_driver_data *drv; - - drv = os_zalloc(sizeof(struct prism54_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for hostapd Prism54 driver " - "data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->pim_sock = drv->sock = -1; - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); - - if (prism54_init_sockets(drv)) { - free(drv); - return NULL; - } - prism54_init_1x(drv); - /* must clean previous elems */ - prism54_set_generic_elem(drv->iface, drv, NULL, 0); - - return drv; -} - - -static void prism54_driver_deinit(void *priv) -{ - struct prism54_driver_data *drv = priv; - - if (drv->pim_sock >= 0) - close(drv->pim_sock); - - if (drv->sock >= 0) - close(drv->sock); - - free(drv); -} - - -const struct wpa_driver_ops wpa_driver_prism54_ops = { - .name = "prism54", - .init = prism54_driver_init, - .deinit = prism54_driver_deinit, - /* .set_ieee8021x = prism54_init_1x, */ - .set_privacy = prism54_set_privacy_invoked, - .set_encryption = prism54_set_encryption, - .get_seqnum = prism54_get_seqnum, - .flush = prism54_flush, - .set_generic_elem = prism54_set_generic_elem, - .send_eapol = prism54_send_eapol, - .sta_set_flags = prism54_sta_set_flags, - .sta_deauth = prism54_sta_deauth, - .sta_disassoc = prism54_sta_disassoc, - .set_ssid = prism54_ioctl_setiwessid, - .get_inact_sec = prism54_get_inact_sec, -}; diff --git a/hostapd/driver_test.c b/hostapd/driver_test.c deleted file mode 100644 index 9930a8284755..000000000000 --- a/hostapd/driver_test.c +++ /dev/null @@ -1,1300 +0,0 @@ -/* - * hostapd / Driver interface for development testing - * Copyright (c) 2004-2008, Jouni Malinen - * - * 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 -#include - -#include "hostapd.h" -#include "driver.h" -#include "sha1.h" -#include "eloop.h" -#include "ieee802_1x.h" -#include "sta_info.h" -#include "wpa.h" -#include "accounting.h" -#include "radius/radius.h" -#include "l2_packet/l2_packet.h" -#include "ieee802_11.h" -#include "hw_features.h" -#include "wps_hostapd.h" - - -struct test_client_socket { - struct test_client_socket *next; - u8 addr[ETH_ALEN]; - struct sockaddr_un un; - socklen_t unlen; - struct test_driver_bss *bss; -}; - -struct test_driver_bss { - struct test_driver_bss *next; - char ifname[IFNAMSIZ + 1]; - u8 bssid[ETH_ALEN]; - u8 *ie; - size_t ielen; - u8 *wps_beacon_ie; - size_t wps_beacon_ie_len; - u8 *wps_probe_resp_ie; - size_t wps_probe_resp_ie_len; - u8 ssid[32]; - size_t ssid_len; - int privacy; -}; - -struct test_driver_data { - struct hostapd_data *hapd; - struct test_client_socket *cli; - int test_socket; - struct test_driver_bss *bss; - char *socket_dir; - char *own_socket_path; - int udp_port; -}; - - -static void test_driver_free_bss(struct test_driver_bss *bss) -{ - free(bss->ie); - free(bss->wps_beacon_ie); - free(bss->wps_probe_resp_ie); - free(bss); -} - - -static void test_driver_free_priv(struct test_driver_data *drv) -{ - struct test_driver_bss *bss, *prev; - - if (drv == NULL) - return; - - bss = drv->bss; - while (bss) { - prev = bss; - bss = bss->next; - test_driver_free_bss(prev); - } - free(drv->own_socket_path); - free(drv->socket_dir); - free(drv); -} - - -static struct test_client_socket * -test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from, - socklen_t fromlen) -{ - struct test_client_socket *cli = drv->cli; - - while (cli) { - if (cli->unlen == fromlen && - strncmp(cli->un.sun_path, from->sun_path, - fromlen - sizeof(cli->un.sun_family)) == 0) - return cli; - cli = cli->next; - } - - return NULL; -} - - -static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, - const u8 *own_addr) -{ - struct test_driver_data *drv = priv; - struct test_client_socket *cli; - struct msghdr msg; - struct iovec io[3]; - struct l2_ethhdr eth; - - if (drv->test_socket < 0) - return -1; - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - - if (!cli) { - wpa_printf(MSG_DEBUG, "%s: no destination client entry", - __func__); - return -1; - } - - memcpy(eth.h_dest, addr, ETH_ALEN); - memcpy(eth.h_source, own_addr, ETH_ALEN); - eth.h_proto = host_to_be16(ETH_P_EAPOL); - - io[0].iov_base = "EAPOL "; - io[0].iov_len = 6; - io[1].iov_base = ð - io[1].iov_len = sizeof(eth); - io[2].iov_base = (u8 *) data; - io[2].iov_len = data_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 3; - msg.msg_name = &cli->un; - msg.msg_namelen = cli->unlen; - return sendmsg(drv->test_socket, &msg, 0); -} - - -static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src, - u16 proto, const u8 *data, size_t data_len) -{ - struct test_driver_data *drv = priv; - struct msghdr msg; - struct iovec io[3]; - struct l2_ethhdr eth; - char desttxt[30]; - struct sockaddr_un addr; - struct dirent *dent; - DIR *dir; - int ret = 0, broadcast = 0, count = 0; - - if (drv->test_socket < 0 || drv->socket_dir == NULL) { - wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d " - "socket_dir=%p)", - __func__, drv->test_socket, drv->socket_dir); - return -1; - } - - broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; - snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst)); - - memcpy(eth.h_dest, dst, ETH_ALEN); - memcpy(eth.h_source, src, ETH_ALEN); - eth.h_proto = host_to_be16(proto); - - io[0].iov_base = "ETHER "; - io[0].iov_len = 6; - io[1].iov_base = ð - io[1].iov_len = sizeof(eth); - io[2].iov_base = (u8 *) data; - io[2].iov_len = data_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 3; - - dir = opendir(drv->socket_dir); - if (dir == NULL) { - perror("test_driver: opendir"); - return -1; - } - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. Also accept - * DT_UNKNOWN (0) in case the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", - drv->socket_dir, dent->d_name); - - if (strcmp(addr.sun_path, drv->own_socket_path) == 0) - continue; - if (!broadcast && strstr(dent->d_name, desttxt) == NULL) - continue; - - wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s", - __func__, dent->d_name); - - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - ret = sendmsg(drv->test_socket, &msg, 0); - if (ret < 0) - perror("driver_test: sendmsg"); - count++; - } - closedir(dir); - - if (!broadcast && count == 0) { - wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found", - __func__, MAC2STR(dst)); - return -1; - } - - return ret; -} - - -static int test_driver_send_mgmt_frame(void *priv, const void *buf, - size_t len, int flags) -{ - struct test_driver_data *drv = priv; - struct msghdr msg; - struct iovec io[2]; - const u8 *dest; - int ret = 0, broadcast = 0; - char desttxt[30]; - struct sockaddr_un addr; - struct dirent *dent; - DIR *dir; - struct ieee80211_hdr *hdr; - u16 fc; - - if (drv->test_socket < 0 || len < 10 || drv->socket_dir == NULL) { - wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu" - " socket_dir=%p)", - __func__, drv->test_socket, (unsigned long) len, - drv->socket_dir); - return -1; - } - - dest = buf; - dest += 4; - broadcast = memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; - snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest)); - - io[0].iov_base = "MLME "; - io[0].iov_len = 5; - io[1].iov_base = (void *) buf; - io[1].iov_len = len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 2; - - dir = opendir(drv->socket_dir); - if (dir == NULL) { - perror("test_driver: opendir"); - return -1; - } - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. Also accept - * DT_UNKNOWN (0) in case the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", - drv->socket_dir, dent->d_name); - - if (strcmp(addr.sun_path, drv->own_socket_path) == 0) - continue; - if (!broadcast && strstr(dent->d_name, desttxt) == NULL) - continue; - - wpa_printf(MSG_DEBUG, "%s: Send management frame to %s", - __func__, dent->d_name); - - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - ret = sendmsg(drv->test_socket, &msg, 0); - if (ret < 0) - perror("driver_test: sendmsg"); - } - closedir(dir); - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - ieee802_11_mgmt_cb(drv->hapd, (u8 *) buf, len, WLAN_FC_GET_STYPE(fc), - ret >= 0); - - return ret; -} - - -static void test_driver_scan(struct test_driver_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - char *data) -{ - char buf[512], *pos, *end; - int ret; - struct test_driver_bss *bss; - u8 sa[ETH_ALEN]; - u8 ie[512]; - size_t ielen; - - /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */ - - wpa_printf(MSG_DEBUG, "test_driver: SCAN"); - - if (*data) { - if (*data != ' ' || - hwaddr_aton(data + 1, sa)) { - wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN " - "command format"); - return; - } - - data += 18; - while (*data == ' ') - data++; - ielen = os_strlen(data) / 2; - if (ielen > sizeof(ie)) - ielen = sizeof(ie); - if (hexstr2bin(data, ie, ielen) < 0) - ielen = 0; - - wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR, - MAC2STR(sa)); - wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen); - - hostapd_wps_probe_req_rx(drv->hapd, sa, ie, ielen); - } - - for (bss = drv->bss; bss; bss = bss->next) { - pos = buf; - end = buf + sizeof(buf); - - /* reply: SCANRESP BSSID SSID IEs */ - ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", - MAC2STR(bss->bssid)); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, - bss->ssid, bss->ssid_len); - ret = snprintf(pos, end - pos, " "); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen); - pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie, - bss->wps_probe_resp_ie_len); - - if (bss->privacy) { - ret = snprintf(pos, end - pos, " PRIVACY"); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - } - - sendto(drv->test_socket, buf, pos - buf, 0, - (struct sockaddr *) from, fromlen); - } -} - - -static struct hostapd_data * test_driver_get_hapd(struct test_driver_data *drv, - struct test_driver_bss *bss) -{ - struct hostapd_iface *iface = drv->hapd->iface; - struct hostapd_data *hapd = NULL; - size_t i; - - if (bss == NULL) { - wpa_printf(MSG_DEBUG, "%s: bss == NULL", __func__); - return NULL; - } - - for (i = 0; i < iface->num_bss; i++) { - hapd = iface->bss[i]; - if (memcmp(hapd->own_addr, bss->bssid, ETH_ALEN) == 0) - break; - } - if (i == iface->num_bss) { - wpa_printf(MSG_DEBUG, "%s: no matching interface entry found " - "for BSSID " MACSTR, __func__, MAC2STR(bss->bssid)); - return NULL; - } - - return hapd; -} - - -static int test_driver_new_sta(struct test_driver_data *drv, - struct test_driver_bss *bss, const u8 *addr, - const u8 *ie, size_t ielen) -{ - struct hostapd_data *hapd; - struct sta_info *sta; - int new_assoc, res; - - hapd = test_driver_get_hapd(drv, bss); - if (hapd == NULL) - return -1; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "associated"); - - sta = ap_get_sta(hapd, addr); - if (sta) { - accounting_sta_stop(hapd, sta); - } else { - sta = ap_sta_add(hapd, addr); - if (sta == NULL) - return -1; - } - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); - - if (hapd->conf->wpa) { - if (ie == NULL || ielen == 0) { - if (hapd->conf->wps_state) { - sta->flags |= WLAN_STA_WPS; - goto skip_wpa_check; - } - - printf("test_driver: no IE from STA\n"); - return -1; - } - if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && - os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { - sta->flags |= WLAN_STA_WPS; - goto skip_wpa_check; - } - - if (sta->wpa_sm == NULL) - sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, - sta->addr); - if (sta->wpa_sm == NULL) { - printf("test_driver: Failed to initialize WPA state " - "machine\n"); - return -1; - } - res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, - ie, ielen, NULL, 0); - if (res != WPA_IE_OK) { - printf("WPA/RSN information element rejected? " - "(res %u)\n", res); - wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); - return -1; - } - } -skip_wpa_check: - - new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - - hostapd_new_assoc_sta(hapd, sta, !new_assoc); - - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - - return 0; -} - - -static void test_driver_assoc(struct test_driver_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - char *data) -{ - struct test_client_socket *cli; - u8 ie[256], ssid[32]; - size_t ielen, ssid_len = 0; - char *pos, *pos2, cmd[50]; - struct test_driver_bss *bss; - - /* data: STA-addr SSID(hex) IEs(hex) */ - - cli = os_zalloc(sizeof(*cli)); - if (cli == NULL) - return; - - if (hwaddr_aton(data, cli->addr)) { - printf("test_socket: Invalid MAC address '%s' in ASSOC\n", - data); - free(cli); - return; - } - pos = data + 17; - while (*pos == ' ') - pos++; - pos2 = strchr(pos, ' '); - ielen = 0; - if (pos2) { - ssid_len = (pos2 - pos) / 2; - if (hexstr2bin(pos, ssid, ssid_len) < 0) { - wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__); - free(cli); - return; - } - wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID", - ssid, ssid_len); - - pos = pos2 + 1; - ielen = strlen(pos) / 2; - if (ielen > sizeof(ie)) - ielen = sizeof(ie); - if (hexstr2bin(pos, ie, ielen) < 0) - ielen = 0; - } - - for (bss = drv->bss; bss; bss = bss->next) { - if (bss->ssid_len == ssid_len && - memcmp(bss->ssid, ssid, ssid_len) == 0) - break; - } - if (bss == NULL) { - wpa_printf(MSG_DEBUG, "%s: No matching SSID found from " - "configured BSSes", __func__); - free(cli); - return; - } - - cli->bss = bss; - memcpy(&cli->un, from, sizeof(cli->un)); - cli->unlen = fromlen; - cli->next = drv->cli; - drv->cli = cli; - wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path", - (const u8 *) cli->un.sun_path, - cli->unlen - sizeof(cli->un.sun_family)); - - snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0", - MAC2STR(bss->bssid)); - sendto(drv->test_socket, cmd, strlen(cmd), 0, - (struct sockaddr *) from, fromlen); - - if (test_driver_new_sta(drv, bss, cli->addr, ie, ielen) < 0) { - wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA"); - } -} - - -static void test_driver_disassoc(struct test_driver_data *drv, - struct sockaddr_un *from, socklen_t fromlen) -{ - struct test_client_socket *cli; - struct sta_info *sta; - - cli = test_driver_get_cli(drv, from, fromlen); - if (!cli) - return; - - hostapd_logger(drv->hapd, cli->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated"); - - sta = ap_get_sta(drv->hapd, cli->addr); - if (sta != NULL) { - sta->flags &= ~WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(drv->hapd, sta); - } -} - - -static void test_driver_eapol(struct test_driver_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - u8 *data, size_t datalen) -{ - struct test_client_socket *cli; - if (datalen > 14) { - /* Skip Ethernet header */ - wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src=" - MACSTR " proto=%04x", - MAC2STR(data), MAC2STR(data + ETH_ALEN), - WPA_GET_BE16(data + 2 * ETH_ALEN)); - data += 14; - datalen -= 14; - } - cli = test_driver_get_cli(drv, from, fromlen); - if (cli) { - struct hostapd_data *hapd; - hapd = test_driver_get_hapd(drv, cli->bss); - if (hapd == NULL) - return; - ieee802_1x_receive(hapd, cli->addr, data, datalen); - } else { - wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown " - "client"); - } -} - - -static void test_driver_ether(struct test_driver_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - u8 *data, size_t datalen) -{ - struct l2_ethhdr *eth; - - if (datalen < sizeof(*eth)) - return; - - eth = (struct l2_ethhdr *) data; - wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src=" - MACSTR " proto=%04x", - MAC2STR(eth->h_dest), MAC2STR(eth->h_source), - be_to_host16(eth->h_proto)); - -#ifdef CONFIG_IEEE80211R - if (be_to_host16(eth->h_proto) == ETH_P_RRB) { - wpa_ft_rrb_rx(drv->hapd->wpa_auth, eth->h_source, - data + sizeof(*eth), datalen - sizeof(*eth)); - } -#endif /* CONFIG_IEEE80211R */ -} - - -static void test_driver_mlme(struct test_driver_data *drv, - struct sockaddr_un *from, socklen_t fromlen, - u8 *data, size_t datalen) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *) data; - - if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) { - struct test_client_socket *cli; - cli = os_zalloc(sizeof(*cli)); - if (cli == NULL) - return; - wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR, - MAC2STR(hdr->addr2)); - memcpy(cli->addr, hdr->addr2, ETH_ALEN); - memcpy(&cli->un, from, sizeof(cli->un)); - cli->unlen = fromlen; - cli->next = drv->cli; - drv->cli = cli; - } - - wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame", - data, datalen); - fc = le_to_host16(hdr->frame_control); - if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) { - wpa_printf(MSG_ERROR, "%s: received non-mgmt frame", - __func__); - return; - } - ieee802_11_mgmt(drv->hapd, data, datalen, WLAN_FC_GET_STYPE(fc), NULL); -} - - -static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct test_driver_data *drv = eloop_ctx; - char buf[2000]; - int res; - struct sockaddr_un from; - socklen_t fromlen = sizeof(from); - - res = recvfrom(sock, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &from, &fromlen); - if (res < 0) { - perror("recvfrom(test_socket)"); - return; - } - buf[res] = '\0'; - - wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); - - if (strncmp(buf, "SCAN", 4) == 0) { - test_driver_scan(drv, &from, fromlen, buf + 4); - } else if (strncmp(buf, "ASSOC ", 6) == 0) { - test_driver_assoc(drv, &from, fromlen, buf + 6); - } else if (strcmp(buf, "DISASSOC") == 0) { - test_driver_disassoc(drv, &from, fromlen); - } else if (strncmp(buf, "EAPOL ", 6) == 0) { - test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6, - res - 6); - } else if (strncmp(buf, "ETHER ", 6) == 0) { - test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6, - res - 6); - } else if (strncmp(buf, "MLME ", 5) == 0) { - test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5); - } else { - wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", - (u8 *) buf, res); - } -} - - -static struct test_driver_bss * -test_driver_get_bss(struct test_driver_data *drv, const char *ifname) -{ - struct test_driver_bss *bss; - - for (bss = drv->bss; bss; bss = bss->next) { - if (strcmp(bss->ifname, ifname) == 0) - return bss; - } - return NULL; -} - - -static int test_driver_set_generic_elem(const char *ifname, void *priv, - const u8 *elem, size_t elem_len) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss; - - bss = test_driver_get_bss(drv, ifname); - if (bss == NULL) - return -1; - - free(bss->ie); - - if (elem == NULL) { - bss->ie = NULL; - bss->ielen = 0; - return 0; - } - - bss->ie = malloc(elem_len); - if (bss->ie == NULL) { - bss->ielen = 0; - return -1; - } - - memcpy(bss->ie, elem, elem_len); - bss->ielen = elem_len; - return 0; -} - - -static int test_driver_set_wps_beacon_ie(const char *ifname, void *priv, - const u8 *ie, size_t len) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss; - - wpa_hexdump(MSG_DEBUG, "test_driver: Beacon WPS IE", ie, len); - bss = test_driver_get_bss(drv, ifname); - if (bss == NULL) - return -1; - - free(bss->wps_beacon_ie); - - if (ie == NULL) { - bss->wps_beacon_ie = NULL; - bss->wps_beacon_ie_len = 0; - return 0; - } - - bss->wps_beacon_ie = malloc(len); - if (bss->wps_beacon_ie == NULL) { - bss->wps_beacon_ie_len = 0; - return -1; - } - - memcpy(bss->wps_beacon_ie, ie, len); - bss->wps_beacon_ie_len = len; - return 0; -} - - -static int test_driver_set_wps_probe_resp_ie(const char *ifname, void *priv, - const u8 *ie, size_t len) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss; - - wpa_hexdump(MSG_DEBUG, "test_driver: ProbeResp WPS IE", ie, len); - bss = test_driver_get_bss(drv, ifname); - if (bss == NULL) - return -1; - - free(bss->wps_probe_resp_ie); - - if (ie == NULL) { - bss->wps_probe_resp_ie = NULL; - bss->wps_probe_resp_ie_len = 0; - return 0; - } - - bss->wps_probe_resp_ie = malloc(len); - if (bss->wps_probe_resp_ie == NULL) { - bss->wps_probe_resp_ie_len = 0; - return -1; - } - - memcpy(bss->wps_probe_resp_ie, ie, len); - bss->wps_probe_resp_ie_len = len; - return 0; -} - - -static int test_driver_sta_deauth(void *priv, const u8 *addr, int reason) -{ - struct test_driver_data *drv = priv; - struct test_client_socket *cli; - - if (drv->test_socket < 0) - return -1; - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - - if (!cli) - return -1; - - return sendto(drv->test_socket, "DEAUTH", 6, 0, - (struct sockaddr *) &cli->un, cli->unlen); -} - - -static int test_driver_sta_disassoc(void *priv, const u8 *addr, int reason) -{ - struct test_driver_data *drv = priv; - struct test_client_socket *cli; - - if (drv->test_socket < 0) - return -1; - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - - if (!cli) - return -1; - - return sendto(drv->test_socket, "DISASSOC", 8, 0, - (struct sockaddr *) &cli->un, cli->unlen); -} - - -static struct hostapd_hw_modes * -test_driver_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) -{ - struct hostapd_hw_modes *modes; - - *num_modes = 3; - *flags = 0; - modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); - if (modes == NULL) - return NULL; - modes[0].mode = HOSTAPD_MODE_IEEE80211G; - modes[0].num_channels = 1; - modes[0].num_rates = 1; - modes[0].channels = os_zalloc(sizeof(struct hostapd_channel_data)); - modes[0].rates = os_zalloc(sizeof(struct hostapd_rate_data)); - if (modes[0].channels == NULL || modes[0].rates == NULL) { - hostapd_free_hw_features(modes, *num_modes); - return NULL; - } - modes[0].channels[0].chan = 1; - modes[0].channels[0].freq = 2412; - modes[0].channels[0].flag = 0; - modes[0].rates[0].rate = 10; - modes[0].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED | - HOSTAPD_RATE_CCK | HOSTAPD_RATE_MANDATORY; - - modes[1].mode = HOSTAPD_MODE_IEEE80211B; - modes[1].num_channels = 1; - modes[1].num_rates = 1; - modes[1].channels = os_zalloc(sizeof(struct hostapd_channel_data)); - modes[1].rates = os_zalloc(sizeof(struct hostapd_rate_data)); - if (modes[1].channels == NULL || modes[1].rates == NULL) { - hostapd_free_hw_features(modes, *num_modes); - return NULL; - } - modes[1].channels[0].chan = 1; - modes[1].channels[0].freq = 2412; - modes[1].channels[0].flag = 0; - modes[1].rates[0].rate = 10; - modes[1].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED | - HOSTAPD_RATE_CCK | HOSTAPD_RATE_MANDATORY; - - modes[2].mode = HOSTAPD_MODE_IEEE80211A; - modes[2].num_channels = 1; - modes[2].num_rates = 1; - modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data)); - modes[2].rates = os_zalloc(sizeof(struct hostapd_rate_data)); - if (modes[2].channels == NULL || modes[2].rates == NULL) { - hostapd_free_hw_features(modes, *num_modes); - return NULL; - } - modes[2].channels[0].chan = 60; - modes[2].channels[0].freq = 5300; - modes[2].channels[0].flag = 0; - modes[2].rates[0].rate = 60; - modes[2].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED | - HOSTAPD_RATE_MANDATORY; - - return modes; -} - - -static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")", - __func__, ifname, MAC2STR(bssid)); - - bss = os_zalloc(sizeof(*bss)); - if (bss == NULL) - return -1; - - os_strlcpy(bss->ifname, ifname, IFNAMSIZ); - memcpy(bss->bssid, bssid, ETH_ALEN); - - bss->next = drv->bss; - drv->bss = bss; - - return 0; -} - - -static int test_driver_bss_remove(void *priv, const char *ifname) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss, *prev; - struct test_client_socket *cli, *prev_c; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname); - - for (prev = NULL, bss = drv->bss; bss; prev = bss, bss = bss->next) { - if (strcmp(bss->ifname, ifname) != 0) - continue; - - if (prev) - prev->next = bss->next; - else - drv->bss = bss->next; - - for (prev_c = NULL, cli = drv->cli; cli; - prev_c = cli, cli = cli->next) { - if (cli->bss != bss) - continue; - if (prev_c) - prev_c->next = cli->next; - else - drv->cli = cli->next; - free(cli); - break; - } - - test_driver_free_bss(bss); - return 0; - } - - return -1; -} - - -static int test_driver_if_add(const char *iface, void *priv, - enum hostapd_driver_if_type type, char *ifname, - const u8 *addr) -{ - wpa_printf(MSG_DEBUG, "%s(iface=%s type=%d ifname=%s)", - __func__, iface, type, ifname); - return 0; -} - - -static int test_driver_if_update(void *priv, enum hostapd_driver_if_type type, - char *ifname, const u8 *addr) -{ - wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname); - return 0; -} - - -static int test_driver_if_remove(void *priv, enum hostapd_driver_if_type type, - const char *ifname, const u8 *addr) -{ - wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname); - return 0; -} - - -static int test_driver_valid_bss_mask(void *priv, const u8 *addr, - const u8 *mask) -{ - return 0; -} - - -static int test_driver_set_ssid(const char *ifname, void *priv, const u8 *buf, - int len) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname); - wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len); - - for (bss = drv->bss; bss; bss = bss->next) { - if (strcmp(bss->ifname, ifname) != 0) - continue; - - if (len < 0 || (size_t) len > sizeof(bss->ssid)) - return -1; - - memcpy(bss->ssid, buf, len); - bss->ssid_len = len; - - return 0; - } - - return -1; -} - - -static int test_driver_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct test_driver_data *drv = priv; - struct test_driver_bss *bss; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s enabled=%d)", - __func__, ifname, enabled); - - for (bss = drv->bss; bss; bss = bss->next) { - if (strcmp(bss->ifname, ifname) != 0) - continue; - - bss->privacy = enabled; - - return 0; - } - - return -1; -} - - -static int test_driver_set_encryption(const char *iface, void *priv, - const char *alg, const u8 *addr, int idx, - const u8 *key, size_t key_len, int txkey) -{ - wpa_printf(MSG_DEBUG, "%s(iface=%s alg=%s idx=%d txkey=%d)", - __func__, iface, alg, idx, txkey); - if (addr) - wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); - if (key) - wpa_hexdump_key(MSG_DEBUG, " key", key, key_len); - return 0; -} - - -static int test_driver_set_sta_vlan(void *priv, const u8 *addr, - const char *ifname, int vlan_id) -{ - wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)", - __func__, MAC2STR(addr), ifname, vlan_id); - return 0; -} - - -static int test_driver_sta_add(const char *ifname, void *priv, const u8 *addr, - u16 aid, u16 capability, u8 *supp_rates, - size_t supp_rates_len, int flags, - u16 listen_interval) -{ - struct test_driver_data *drv = priv; - struct test_client_socket *cli; - struct test_driver_bss *bss; - - wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d " - "capability=0x%x flags=0x%x listen_interval=%d)", - __func__, ifname, MAC2STR(addr), aid, capability, flags, - listen_interval); - wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates", - supp_rates, supp_rates_len); - - cli = drv->cli; - while (cli) { - if (memcmp(cli->addr, addr, ETH_ALEN) == 0) - break; - cli = cli->next; - } - if (!cli) { - wpa_printf(MSG_DEBUG, "%s: no matching client entry", - __func__); - return -1; - } - - for (bss = drv->bss; bss; bss = bss->next) { - if (strcmp(ifname, bss->ifname) == 0) - break; - } - if (bss == NULL) { - wpa_printf(MSG_DEBUG, "%s: No matching interface found from " - "configured BSSes", __func__); - return -1; - } - - cli->bss = bss; - - return 0; -} - - -static void * test_driver_init(struct hostapd_data *hapd) -{ - struct test_driver_data *drv; - struct sockaddr_un addr_un; - struct sockaddr_in addr_in; - struct sockaddr *addr; - socklen_t alen; - - drv = os_zalloc(sizeof(struct test_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for test driver data\n"); - return NULL; - } - drv->bss = os_zalloc(sizeof(*drv->bss)); - if (drv->bss == NULL) { - printf("Could not allocate memory for test driver BSS data\n"); - free(drv); - return NULL; - } - - drv->hapd = hapd; - - /* Generate a MAC address to help testing with multiple APs */ - hapd->own_addr[0] = 0x02; /* locally administered */ - sha1_prf((const u8 *) hapd->conf->iface, strlen(hapd->conf->iface), - "hostapd test bssid generation", - (const u8 *) hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len, - hapd->own_addr + 1, ETH_ALEN - 1); - - os_strlcpy(drv->bss->ifname, hapd->conf->iface, IFNAMSIZ); - memcpy(drv->bss->bssid, hapd->own_addr, ETH_ALEN); - - if (hapd->conf->test_socket) { - if (strlen(hapd->conf->test_socket) >= - sizeof(addr_un.sun_path)) { - printf("Too long test_socket path\n"); - test_driver_free_priv(drv); - return NULL; - } - if (strncmp(hapd->conf->test_socket, "DIR:", 4) == 0) { - size_t len = strlen(hapd->conf->test_socket) + 30; - drv->socket_dir = strdup(hapd->conf->test_socket + 4); - drv->own_socket_path = malloc(len); - if (drv->own_socket_path) { - snprintf(drv->own_socket_path, len, - "%s/AP-" MACSTR, - hapd->conf->test_socket + 4, - MAC2STR(hapd->own_addr)); - } - } else if (strncmp(hapd->conf->test_socket, "UDP:", 4) == 0) { - drv->udp_port = atoi(hapd->conf->test_socket + 4); - } else { - drv->own_socket_path = strdup(hapd->conf->test_socket); - } - if (drv->own_socket_path == NULL && drv->udp_port == 0) { - test_driver_free_priv(drv); - return NULL; - } - - drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX, - SOCK_DGRAM, 0); - if (drv->test_socket < 0) { - perror("socket"); - test_driver_free_priv(drv); - return NULL; - } - - if (drv->udp_port) { - os_memset(&addr_in, 0, sizeof(addr_in)); - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(drv->udp_port); - addr = (struct sockaddr *) &addr_in; - alen = sizeof(addr_in); - } else { - os_memset(&addr_un, 0, sizeof(addr_un)); - addr_un.sun_family = AF_UNIX; - os_strlcpy(addr_un.sun_path, drv->own_socket_path, - sizeof(addr_un.sun_path)); - addr = (struct sockaddr *) &addr_un; - alen = sizeof(addr_un); - } - if (bind(drv->test_socket, addr, alen) < 0) { - perror("bind(PF_UNIX)"); - close(drv->test_socket); - if (drv->own_socket_path) - unlink(drv->own_socket_path); - test_driver_free_priv(drv); - return NULL; - } - eloop_register_read_sock(drv->test_socket, - test_driver_receive_unix, drv, NULL); - } else - drv->test_socket = -1; - - return drv; -} - - -static void test_driver_deinit(void *priv) -{ - struct test_driver_data *drv = priv; - struct test_client_socket *cli, *prev; - - cli = drv->cli; - while (cli) { - prev = cli; - cli = cli->next; - free(prev); - } - - if (drv->test_socket >= 0) { - eloop_unregister_read_sock(drv->test_socket); - close(drv->test_socket); - if (drv->own_socket_path) - unlink(drv->own_socket_path); - } - - /* There should be only one BSS remaining at this point. */ - if (drv->bss == NULL) - wpa_printf(MSG_ERROR, "%s: drv->bss == NULL", __func__); - else if (drv->bss->next) - wpa_printf(MSG_ERROR, "%s: drv->bss->next != NULL", __func__); - - test_driver_free_priv(drv); -} - - -const struct wpa_driver_ops wpa_driver_test_ops = { - .name = "test", - .init = test_driver_init, - .deinit = test_driver_deinit, - .send_eapol = test_driver_send_eapol, - .send_mgmt_frame = test_driver_send_mgmt_frame, - .set_generic_elem = test_driver_set_generic_elem, - .sta_deauth = test_driver_sta_deauth, - .sta_disassoc = test_driver_sta_disassoc, - .get_hw_feature_data = test_driver_get_hw_feature_data, - .bss_add = test_driver_bss_add, - .bss_remove = test_driver_bss_remove, - .if_add = test_driver_if_add, - .if_update = test_driver_if_update, - .if_remove = test_driver_if_remove, - .valid_bss_mask = test_driver_valid_bss_mask, - .set_ssid = test_driver_set_ssid, - .set_privacy = test_driver_set_privacy, - .set_encryption = test_driver_set_encryption, - .set_sta_vlan = test_driver_set_sta_vlan, - .sta_add = test_driver_sta_add, - .send_ether = test_driver_send_ether, - .set_wps_beacon_ie = test_driver_set_wps_beacon_ie, - .set_wps_probe_resp_ie = test_driver_set_wps_probe_resp_ie, -}; diff --git a/hostapd/driver_wired.c b/hostapd/driver_wired.c deleted file mode 100644 index 61cb667cca7f..000000000000 --- a/hostapd/driver_wired.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * hostapd / Kernel driver communication for wired (Ethernet) drivers - * Copyright (c) 2002-2007, Jouni Malinen - * Copyright (c) 2004, Gunter Burchardt - * - * 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 - -#ifdef USE_KERNEL_HEADERS -#include -#include -#include /* The L2 protocols */ -#include -#include -#else /* USE_KERNEL_HEADERS */ -#include -#include -#include -#endif /* USE_KERNEL_HEADERS */ - -#include "hostapd.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "sta_info.h" -#include "driver.h" -#include "accounting.h" - - -struct wired_driver_data { - struct hostapd_data *hapd; - - int sock; /* raw packet socket for driver access */ - int dhcp_sock; /* socket for dhcp packets */ - int use_pae_group_addr; -}; - - -#define WIRED_EAPOL_MULTICAST_GROUP {0x01,0x80,0xc2,0x00,0x00,0x03} - - -/* TODO: detecting new devices should eventually be changed from using DHCP - * snooping to trigger on any packet from a new layer 2 MAC address, e.g., - * based on ebtables, etc. */ - -struct dhcp_message { - u_int8_t op; - u_int8_t htype; - u_int8_t hlen; - u_int8_t hops; - u_int32_t xid; - u_int16_t secs; - u_int16_t flags; - u_int32_t ciaddr; - u_int32_t yiaddr; - u_int32_t siaddr; - u_int32_t giaddr; - u_int8_t chaddr[16]; - u_int8_t sname[64]; - u_int8_t file[128]; - u_int32_t cookie; - u_int8_t options[308]; /* 312 - cookie */ -}; - - -static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr) -{ - struct sta_info *sta; - - sta = ap_get_sta(hapd, addr); - if (sta) - return; - - wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR - " - adding a new STA", MAC2STR(addr)); - sta = ap_sta_add(hapd, addr); - if (sta) { - hostapd_new_assoc_sta(hapd, sta, 0); - } else { - wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, - MAC2STR(addr)); - } -} - - -static void handle_data(struct hostapd_data *hapd, unsigned char *buf, - size_t len) -{ - struct ieee8023_hdr *hdr; - u8 *pos, *sa; - size_t left; - - /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, - * 2 byte ethertype */ - if (len < 14) { - wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", - (unsigned long) len); - return; - } - - hdr = (struct ieee8023_hdr *) buf; - - switch (ntohs(hdr->ethertype)) { - case ETH_P_PAE: - wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); - sa = hdr->src; - wired_possible_new_sta(hapd, sa); - - pos = (u8 *) (hdr + 1); - left = len - sizeof(*hdr); - - ieee802_1x_receive(hapd, sa, pos, left); - break; - - default: - wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", - ntohs(hdr->ethertype)); - break; - } -} - - -static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; - int len; - unsigned char buf[3000]; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - handle_data(hapd, buf, len); -} - - -static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx; - int len; - unsigned char buf[3000]; - struct dhcp_message *msg; - u8 *mac_address; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - /* must contain at least dhcp_message->chaddr */ - if (len < 44) { - wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); - return; - } - - msg = (struct dhcp_message *) buf; - mac_address = (u8 *) &(msg->chaddr); - - wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, - MAC2STR(mac_address)); - - wired_possible_new_sta(hapd, mac_address); -} - - -static int wired_init_sockets(struct wired_driver_data *drv) -{ - struct hostapd_data *hapd = drv->hapd; - struct ifreq ifr; - struct sockaddr_ll addr; - struct sockaddr_in addr2; - struct packet_mreq mreq; - u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP; - int n = 1; - - drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); - if (drv->sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - return -1; - } - - if (eloop_register_read_sock(drv->sock, handle_read, hapd, NULL)) { - printf("Could not register read socket\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { - perror("ioctl(SIOCGIFINDEX)"); - return -1; - } - - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind"); - return -1; - } - - /* filter multicast address */ - memset(&mreq, 0, sizeof(mreq)); - mreq.mr_ifindex = ifr.ifr_ifindex; - mreq.mr_type = PACKET_MR_MULTICAST; - mreq.mr_alen = 6; - memcpy(mreq.mr_address, multicastgroup_eapol, mreq.mr_alen); - - if (setsockopt(drv->sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)) < 0) { - perror("setsockopt[SOL_SOCKET,PACKET_ADD_MEMBERSHIP]"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - return -1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - return -1; - } - memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - /* setup dhcp listen socket for sta detection */ - if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - perror("socket call failed for dhcp"); - return -1; - } - - if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL)) - { - printf("Could not register read socket\n"); - return -1; - } - - memset(&addr2, 0, sizeof(addr2)); - addr2.sin_family = AF_INET; - addr2.sin_port = htons(67); - addr2.sin_addr.s_addr = INADDR_ANY; - - if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, - sizeof(n)) == -1) { - perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); - return -1; - } - if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, - sizeof(n)) == -1) { - perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ); - if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, - (char *) &ifr, sizeof(ifr)) < 0) { - perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); - return -1; - } - - if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, - sizeof(struct sockaddr)) == -1) { - perror("bind"); - return -1; - } - - return 0; -} - - -static int wired_send_eapol(void *priv, const u8 *addr, - const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr) -{ - struct wired_driver_data *drv = priv; - u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP; - struct ieee8023_hdr *hdr; - size_t len; - u8 *pos; - int res; - - len = sizeof(*hdr) + data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for wired_send_eapol(len=%lu)\n", - (unsigned long) len); - return -1; - } - - memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, - ETH_ALEN); - memcpy(hdr->src, own_addr, ETH_ALEN); - hdr->ethertype = htons(ETH_P_PAE); - - pos = (u8 *) (hdr + 1); - memcpy(pos, data, data_len); - - res = send(drv->sock, (u8 *) hdr, len, 0); - free(hdr); - - if (res < 0) { - perror("wired_send_eapol: send"); - printf("wired_send_eapol - packet len: %lu - failed\n", - (unsigned long) len); - } - - return res; -} - - -static void * wired_driver_init(struct hostapd_data *hapd) -{ - struct wired_driver_data *drv; - - drv = os_zalloc(sizeof(struct wired_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for wired driver data\n"); - return NULL; - } - - drv->hapd = hapd; - drv->use_pae_group_addr = hapd->conf->use_pae_group_addr; - - if (wired_init_sockets(drv)) { - free(drv); - return NULL; - } - - return drv; -} - - -static void wired_driver_deinit(void *priv) -{ - struct wired_driver_data *drv = priv; - - if (drv->sock >= 0) - close(drv->sock); - - if (drv->dhcp_sock >= 0) - close(drv->dhcp_sock); - - free(drv); -} - - -const struct wpa_driver_ops wpa_driver_wired_ops = { - .name = "wired", - .init = wired_driver_init, - .deinit = wired_driver_deinit, - .send_eapol = wired_send_eapol, -}; diff --git a/hostapd/drivers.c b/hostapd/drivers.c deleted file mode 100644 index bde6e609f3d4..000000000000 --- a/hostapd/drivers.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * hostapd / driver interface list - * Copyright (c) 2007, Jouni Malinen - * - * 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_ATHEROS -extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ -#endif /* CONFIG_DRIVER_ATHEROS */ -#ifdef CONFIG_DRIVER_BSD -extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ -#endif /* CONFIG_DRIVER_BSD */ -#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_ATHEROS - &wpa_driver_atheros_ops, -#endif /* CONFIG_DRIVER_ATHEROS */ -#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/hostapd/eap_testing.txt b/hostapd/eap_testing.txt deleted file mode 100644 index 04468c39f01e..000000000000 --- a/hostapd/eap_testing.txt +++ /dev/null @@ -1,77 +0,0 @@ -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/hostapd/hostap_common.h b/hostapd/hostap_common.h deleted file mode 100644 index 5a57dca46d3e..000000000000 --- a/hostapd/hostap_common.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * hostapd / Kernel driver communication with Linux Host AP driver - * Copyright (c) 2002-2006, Jouni Malinen - * - * 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/hostapd/hostapd.8 b/hostapd/hostapd.8 deleted file mode 100644 index a67a1bcca6c7..000000000000 --- a/hostapd/hostapd.8 +++ /dev/null @@ -1,59 +0,0 @@ -.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 ] -.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 -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 . -.PP -This manual page was written by Faidon Liambotis , -for the Debian project (but may be used by others). diff --git a/hostapd/hostapd.accept b/hostapd/hostapd.accept deleted file mode 100644 index 2d2a0a27efdc..000000000000 --- a/hostapd/hostapd.accept +++ /dev/null @@ -1,6 +0,0 @@ -# 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/hostapd/hostapd.c b/hostapd/hostapd.c deleted file mode 100644 index 3fbd3d0b03a0..000000000000 --- a/hostapd/hostapd.c +++ /dev/null @@ -1,2039 +0,0 @@ -/* - * hostapd / Initialization and configuration - * Copyright (c) 2002-2009, Jouni Malinen - * - * 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 -#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_wmm_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->wmm_enabled = conf->wmm_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; - size_t j; - - 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. - */ - for (j = 0; j < iface->num_bss; j++) - hostapd_flush_old_stations(iface->bss[j]); - - /* TODO: update dynamic data based on changed configuration - * items (e.g., open/close sockets, etc.) */ - 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); - - if (hapd->conf->ssid.ssid_set && - hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len)) { - wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); - /* try to continue */ - } - - if (hapd->conf->ieee802_1x || hapd->conf->wpa) - hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1); - - hostapd_config_free(oldconf); - - wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); - - 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_WMM ? "[WMM]" : ""), - (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; - } - } - - hostapd_flush_old_stations(hapd); - hostapd_set_privacy(hapd, 0); - - hostapd_broadcast_wep_clear(hapd); - if (hostapd_setup_encryption(hapd->conf->iface, hapd)) - return -1; - - /* - * Fetch the SSID from the system and use it or, - * if one was specified in the config file, verify they - * 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; - 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; - } - } - - 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_set_beacon_int(hapd, hapd->iconf->beacon_int); - - 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 0; -} - - -/** - * 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 " - "and contributors\n"); -} - - -static void usage(void) -{ - show_version(); - fprintf(stderr, - "\n" - "usage: hostapd [-hdBKtv] [-P ] " - "\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(¶ms, 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, ¶ms)) { - 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; - 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': - os_free(pid_file); - pid_file = os_rel2abs_path(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); - os_free(pid_file); - - return ret; -} diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf deleted file mode 100644 index 703b6469b0b8..000000000000 --- a/hostapd/hostapd.conf +++ /dev/null @@ -1,1025 +0,0 @@ -##### 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 ' 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 ' 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__ -# 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 (= UP) to AC mappings -# WMM specifies following mapping of data frames to different ACs. This mapping -# can be configured using Linux QoS/tc and sch_pktpri.o module. -# 802.1D Tag 802.1D Designation Access Category WMM Designation -# 1 BK AC_BK Background -# 2 - AC_BK Background -# 0 BE AC_BE Best Effort -# 3 EE AC_BE Best Effort -# 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 -# -wmm_enabled=1 -# -# Low priority / AC_BK = background -wmm_ac_bk_cwmin=4 -wmm_ac_bk_cwmax=10 -wmm_ac_bk_aifs=7 -wmm_ac_bk_txop_limit=0 -wmm_ac_bk_acm=0 -# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10 -# -# Normal priority / AC_BE = best effort -wmm_ac_be_aifs=3 -wmm_ac_be_cwmin=4 -wmm_ac_be_cwmax=10 -wmm_ac_be_txop_limit=0 -wmm_ac_be_acm=0 -# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7 -# -# High priority / AC_VI = video -wmm_ac_vi_aifs=2 -wmm_ac_vi_cwmin=3 -wmm_ac_vi_cwmax=4 -wmm_ac_vi_txop_limit=94 -wmm_ac_vi_acm=0 -# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188 -# -# Highest priority / AC_VO = voice -wmm_ac_vo_aifs=2 -wmm_ac_vo_cwmin=2 -wmm_ac_vo_cwmax=3 -wmm_ac_vo_txop_limit=47 -wmm_ac_vo_acm=0 -# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 - -# Static WEP key configuration -# -# 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 -# Note: You will also need to enable WMM for full HT functionality. -#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: <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: <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 = 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 ). -# -# 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/hostapd/hostapd.deny b/hostapd/hostapd.deny deleted file mode 100644 index 1616678f579e..000000000000 --- a/hostapd/hostapd.deny +++ /dev/null @@ -1,5 +0,0 @@ -# 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/hostapd/hostapd.eap_user b/hostapd/hostapd.eap_user deleted file mode 100644 index ac9a5d896a04..000000000000 --- a/hostapd/hostapd.eap_user +++ /dev/null @@ -1,91 +0,0 @@ -# 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/hostapd/hostapd.h b/hostapd/hostapd.h deleted file mode 100644 index 26f30d7016ff..000000000000 --- a/hostapd/hostapd.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * hostapd / Initialization and configuration - * Host AP kernel driver - * Copyright (c) 2002-2008, Jouni Malinen - * 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/hostapd/hostapd.radius_clients b/hostapd/hostapd.radius_clients deleted file mode 100644 index 3980427253b4..000000000000 --- a/hostapd/hostapd.radius_clients +++ /dev/null @@ -1,4 +0,0 @@ -# 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/hostapd/hostapd.sim_db b/hostapd/hostapd.sim_db deleted file mode 100644 index 01c593de8d2d..000000000000 --- a/hostapd/hostapd.sim_db +++ /dev/null @@ -1,9 +0,0 @@ -# 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/hostapd/hostapd.vlan b/hostapd/hostapd.vlan deleted file mode 100644 index 98254fa84f01..000000000000 --- a/hostapd/hostapd.vlan +++ /dev/null @@ -1,9 +0,0 @@ -# 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/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk deleted file mode 100644 index 0a9499acd736..000000000000 --- a/hostapd/hostapd.wpa_psk +++ /dev/null @@ -1,9 +0,0 @@ -# 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/hostapd/hostapd_cli.1 b/hostapd/hostapd_cli.1 deleted file mode 100644 index 2fe49071a2e3..000000000000 --- a/hostapd/hostapd_cli.1 +++ /dev/null @@ -1,83 +0,0 @@ -.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] [\-i] [\-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 to find control sockets. - -Default: /var/run/hostapd -.TP -.B \-i -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 -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 -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 . -.PP -This manual page was written by Faidon Liambotis , -for the Debian project (but may be used by others). diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c deleted file mode 100644 index c2ecd4e23cae..000000000000 --- a/hostapd/hostapd_cli.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2009, Jouni Malinen - * - * 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 - -#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 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 get MIB variables for one station\n" -" all_sta get MIB variables for all stations\n" -" new_sta add a new station\n" -#ifdef CONFIG_IEEE80211W -" sa_query send SA Query to a station\n" -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WPS -" wps_pin [timeout] add WPS Enrollee PIN (Device Password)\n" -" wps_pbc indicate button pushed to initiate PBC\n" -#endif /* CONFIG_WPS */ -" help show this usage help\n" -" interface [ifname] show interfaces/select interface\n" -" 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] [-i] [-hv] " - "[-G] \\\n" - " [command..]\n" - "\n" - "Options:\n" - " -h help (show this usage text)\n" - " -v shown version information\n" - " -p path to find control sockets (default: " - "/var/run/hostapd)\n" - " -i 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 - at least two arguments, " - "UUID and PIN, are required.\n"); - return -1; - } - if (argc > 2) - snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", - argv[0], argv[1], argv[2]); - else - snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); - return wpa_ctrl_command(ctrl, buf); -} - - -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/hostapd/logwatch/README b/hostapd/logwatch/README deleted file mode 100644 index 3cba51190963..000000000000 --- a/hostapd/logwatch/README +++ /dev/null @@ -1,9 +0,0 @@ -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/hostapd/logwatch/hostapd b/hostapd/logwatch/hostapd deleted file mode 100755 index 97b24ef6e1b8..000000000000 --- a/hostapd/logwatch/hostapd +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/perl -w -# -# Logwatch script for hostapd -# -# Copyright 2005 Henrik Brix Andersen -# 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 = )) { - 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/hostapd/logwatch/hostapd.conf b/hostapd/logwatch/hostapd.conf deleted file mode 100644 index 5bebe6ad2c1b..000000000000 --- a/hostapd/logwatch/hostapd.conf +++ /dev/null @@ -1,10 +0,0 @@ -# Logwatch configuration for hostapd -# -# Copyright 2005 Henrik Brix Andersen -# 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/hostapd/nt_password_hash.c b/hostapd/nt_password_hash.c deleted file mode 100644 index 9df307d54a84..000000000000 --- a/hostapd/nt_password_hash.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * hostapd - Plaintext password to NtPasswordHash - * Copyright (c) 2005, Jouni Malinen - * - * 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/hostapd/prism54.h b/hostapd/prism54.h deleted file mode 100644 index cb0a9a19ba8b..000000000000 --- a/hostapd/prism54.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef PRISM54_H -#define PRISM54_H - -struct ieee802_3_hdr_s { - unsigned char da[6]; - unsigned char sa[6]; - unsigned short type; -} __attribute__ ((packed)); - -typedef struct ieee802_3_hdr_s ieee802_3_hdr; - -#define PIMOP_GET 0 -#define PIMOP_SET 1 -#define PIMOP_RESPONSE 2 -#define PIMOP_ERROR 3 -#define PIMOP_TRAP 4 - -struct pimdev_hdr_s { - int op; - unsigned long oid; -} __attribute__ ((packed)); - -typedef struct pimdev_hdr_s pimdev_hdr; - -#define DOT11_OID_ATTACHMENT 0x19000003 - -/* really need to check */ -#define DOT11_PKT_BEACON 0x80 -#define DOT11_PKT_ASSOC_RESP 0x10 -#define DOT11_PKT_REASSOC_RESP 0x30 -#define DOT11_PKT_PROBE_RESP 0x50 - -struct obj_attachment_hdr { - char type; - char reserved; - short id; - short size; -} __attribute__ ((packed)); - -struct obj_attachment { - char type; - char reserved; - short id; - short size; - char data[1]; -} __attribute__ ((packed)); - -#define DOT11_OID_MLMEAUTOLEVEL 0x19000001 -#define DOT11_MLME_AUTO 0 -#define DOT11_MLME_INTERMEDIATE 0x01000000 -#define DOT11_MLME_EXTENDED 0x02000000 - -#define DOT11_OID_DEAUTHENTICATE 0x18000000 -#define DOT11_OID_AUTHENTICATE 0x18000001 -#define DOT11_OID_DISASSOCIATE 0x18000002 -#define DOT11_OID_ASSOCIATE 0x18000003 -#define DOT11_OID_BEACON 0x18000005 -#define DOT11_OID_PROBE 0x18000006 -#define DOT11_OID_REASSOCIATE 0x1800000b - -struct obj_mlme { - char address[6]; - short id; - short state; - short code; -} __attribute__ ((packed)); - -#define DOT11_OID_DEAUTHENTICATEEX 0x18000007 -#define DOT11_OID_AUTHENTICATEEX 0x18000008 -#define DOT11_OID_DISASSOCIATEEX 0x18000009 -#define DOT11_OID_ASSOCIATEEX 0x1800000a -#define DOT11_OID_REASSOCIATEEX 0x1800000c - -struct obj_mlmeex { - char address[6]; - short id; - short state; - short code; - short size; - char data[1]; -} __attribute__ ((packed)); - -#define DOT11_OID_STAKEY 0x12000008 - -#define DOT11_PRIV_WEP 0 -#define DOT11_PRIV_TKIP 1 - -/* endian reversed to bigger endian */ -#define DOT11_STAKEY_OPTION_DEFAULTKEY 0x100 - -struct obj_stakey { - char address[6]; - char keyid; - char reserved; - short options; - char type; - char length; - char key[32]; -} __attribute__ ((packed)); - -#define DOT11_OID_DEFKEYID 0x12000003 -#define DOT11_OID_DEFKEY1 0x12000004 -#define DOT11_OID_DEFKEY2 0x12000005 -#define DOT11_OID_DEFKEY3 0x12000006 -#define DOT11_OID_DEFKEY4 0x12000007 - -struct obj_key { - char type; - char length; - char key[32]; -} __attribute__ ((packed)); - -#define DOT11_OID_STASC 0x1200000a - -struct obj_stasc { - char address[6]; - char keyid; - char tx_sc; - unsigned long sc_high; - unsigned short sc_low; -} __attribute__ ((packed)); - -#define DOT11_OID_CLIENTS 0x15000001 -#define DOT11_OID_CLIENTSASSOCIATED 0x15000002 -#define DOT11_OID_CLIENTST 0x15000003 -#define DOT11_OID_CLIENTEND 0x150007d9 -#define DOT11_OID_CLIENTFIND 0x150007db - -#define DOT11_NODE_UNKNOWN -#define DOT11_NODE_CLIENT -#define DOT11_NODE_AP - -/* endian reversed to bigger endian */ -#define DOT11_STATE_NONE 0 -#define DOT11_STATE_AUTHING 0x100 -#define DOT11_STATE_AUTH 0x200 -#define DOT11_STATE_ASSOCING 0x300 -#define DOT11_STATE_REASSOCING 0x400 -#define DOT11_STATE_ASSOC 0x500 -#define DOT11_STATE_WDS 0x600 - -struct obj_sta { - char address[6]; - char pad[2]; - char state; - char node; - short age; - char reserved1; - char rssi; - char rate; - char reserved2; -} __attribute__ ((packed)); - -#define DOT11_OID_SSID 0x10000002 -#define DOT11_OID_SSIDOVERRIDE 0x10000006 - -struct obj_ssid { - char length; - char octets[33]; -} __attribute__ ((packed)); - -#define DOT11_OID_EAPAUTHSTA 0x150007de -#define DOT11_OID_EAPUNAUTHSTA 0x150007df -/* not in 38801 datasheet??? */ -#define DOT11_OID_DOT1XENABLE 0x150007e0 -#define DOT11_OID_MICFAILURE 0x150007e1 -#define DOT11_OID_AUTHENABLE 0x12000000 -#define DOT11_OID_PRIVACYINVOKED 0x12000001 -#define DOT11_OID_EXUNENCRYPTED 0x12000002 - -#define DOT11_AUTH_OS 0x01000000 -#define DOT11_AUTH_SK 0x02000000 -#define DOT11_AUTH_BOTH 0x03000000 - -#define DOT11_BOOL_TRUE 0x01000000 - -#endif /* PRISM54_H */ diff --git a/hostapd/priv_netlink.h b/hostapd/priv_netlink.h deleted file mode 100644 index d1f6f663ebf7..000000000000 --- a/hostapd/priv_netlink.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef PRIV_NETLINK_H -#define PRIV_NETLINK_H - -/* Private copy of needed Linux netlink/rtnetlink definitions. - * - * This should be replaced with user space header once one is available with C - * library, etc.. - */ - -#ifndef IFLA_IFNAME -#define IFLA_IFNAME 3 -#endif -#ifndef IFLA_WIRELESS -#define IFLA_WIRELESS 11 -#endif - -#define NETLINK_ROUTE 0 -#define RTMGRP_LINK 1 -#define RTM_BASE 0x10 -#define RTM_NEWLINK (RTM_BASE + 0) -#define RTM_DELLINK (RTM_BASE + 1) - -#define NLMSG_ALIGNTO 4 -#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)) -#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr))) -#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0))) - -#define RTA_ALIGNTO 4 -#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)) -#define RTA_OK(rta,len) \ -((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \ -(rta)->rta_len <= (len)) -#define RTA_NEXT(rta,attrlen) \ -((attrlen) -= RTA_ALIGN((rta)->rta_len), \ -(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len))) - - -struct sockaddr_nl -{ - sa_family_t nl_family; - unsigned short nl_pad; - u32 nl_pid; - u32 nl_groups; -}; - -struct nlmsghdr -{ - u32 nlmsg_len; - u16 nlmsg_type; - u16 nlmsg_flags; - u32 nlmsg_seq; - u32 nlmsg_pid; -}; - -struct ifinfomsg -{ - unsigned char ifi_family; - unsigned char __ifi_pad; - unsigned short ifi_type; - int ifi_index; - unsigned ifi_flags; - unsigned ifi_change; -}; - -struct rtattr -{ - unsigned short rta_len; - unsigned short rta_type; -}; - -#endif /* PRIV_NETLINK_H */ diff --git a/hostapd/radiotap.h b/hostapd/radiotap.h deleted file mode 100644 index 508264c4cf33..000000000000 --- a/hostapd/radiotap.h +++ /dev/null @@ -1,242 +0,0 @@ -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ - -/*- - * Copyright (c) 2003, 2004 David Young. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of David Young may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID - * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* - * Modifications to fit into the linux IEEE 802.11 stack, - * Mike Kershaw (dragorn@kismetwireless.net) - */ - -#ifndef IEEE80211RADIOTAP_H -#define IEEE80211RADIOTAP_H - -#include - -/* Base version of the radiotap packet header data */ -#define PKTHDR_RADIOTAP_VERSION 0 - -/* A generic radio capture format is desirable. There is one for - * Linux, but it is neither rigidly defined (there were not even - * units given for some fields) nor easily extensible. - * - * I suggest the following extensible radio capture format. It is - * based on a bitmap indicating which fields are present. - * - * I am trying to describe precisely what the application programmer - * should expect in the following, and for that reason I tell the - * units and origin of each measurement (where it applies), or else I - * use sufficiently weaselly language ("is a monotonically nondecreasing - * function of...") that I cannot set false expectations for lawyerly - * readers. - */ - -/* The radio capture header precedes the 802.11 header. - * All data in the header is little endian on all platforms. - */ -struct ieee80211_radiotap_header { - uint8_t it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - uint8_t it_pad; - uint16_t it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - uint32_t it_present; /* A bitmap telling which - * fields are present. Set bit 31 - * (0x80000000) to extend the - * bitmap by another 32 bits. - * Additional extensions are made - * by setting bit 31. - */ -}; - -/* Name Data type Units - * ---- --------- ----- - * - * IEEE80211_RADIOTAP_TSFT __le64 microseconds - * - * Value in microseconds of the MAC's 64-bit 802.11 Time - * Synchronization Function timer when the first bit of the - * MPDU arrived at the MAC. For received frames, only. - * - * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap - * - * Tx/Rx frequency in MHz, followed by flags (see below). - * - * IEEE80211_RADIOTAP_FHSS uint16_t see below - * - * For frequency-hopping radios, the hop set (first byte) - * and pattern (second byte). - * - * IEEE80211_RADIOTAP_RATE u8 500kb/s - * - * Tx/Rx data rate - * - * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from - * one milliwatt (dBm) - * - * RF signal power at the antenna, decibel difference from - * one milliwatt. - * - * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from - * one milliwatt (dBm) - * - * RF noise power at the antenna, decibel difference from one - * milliwatt. - * - * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) - * - * RF signal power at the antenna, decibel difference from an - * arbitrary, fixed reference. - * - * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) - * - * RF noise power at the antenna, decibel difference from an - * arbitrary, fixed reference point. - * - * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless - * - * Quality of Barker code lock. Unitless. Monotonically - * nondecreasing with "better" lock strength. Called "Signal - * Quality" in datasheets. (Is there a standard way to measure - * this?) - * - * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless - * - * Transmit power expressed as unitless distance from max - * power set at factory calibration. 0 is max power. - * Monotonically nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) - * - * Transmit power expressed as decibel distance from max power - * set at factory calibration. 0 is max power. Monotonically - * nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from - * one milliwatt (dBm) - * - * Transmit power expressed as dBm (decibels from a 1 milliwatt - * reference). This is the absolute power level measured at - * the antenna port. - * - * IEEE80211_RADIOTAP_FLAGS u8 bitmap - * - * Properties of transmitted and received frames. See flags - * defined below. - * - * IEEE80211_RADIOTAP_ANTENNA u8 antenna index - * - * Unitless indication of the Rx/Tx antenna for this packet. - * The first antenna is antenna 0. - * - * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap - * - * Properties of received frames. See flags defined below. - * - * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap - * - * Properties of transmitted frames. See flags defined below. - * - * IEEE80211_RADIOTAP_RTS_RETRIES u8 data - * - * Number of rts retries a transmitted frame used. - * - * IEEE80211_RADIOTAP_DATA_RETRIES u8 data - * - * Number of unicast retries a transmitted frame used. - * - */ -enum ieee80211_radiotap_type { - IEEE80211_RADIOTAP_TSFT = 0, - IEEE80211_RADIOTAP_FLAGS = 1, - IEEE80211_RADIOTAP_RATE = 2, - IEEE80211_RADIOTAP_CHANNEL = 3, - IEEE80211_RADIOTAP_FHSS = 4, - IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, - IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, - IEEE80211_RADIOTAP_LOCK_QUALITY = 7, - IEEE80211_RADIOTAP_TX_ATTENUATION = 8, - IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, - IEEE80211_RADIOTAP_DBM_TX_POWER = 10, - IEEE80211_RADIOTAP_ANTENNA = 11, - IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, - IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - IEEE80211_RADIOTAP_RX_FLAGS = 14, - IEEE80211_RADIOTAP_TX_FLAGS = 15, - IEEE80211_RADIOTAP_RTS_RETRIES = 16, - IEEE80211_RADIOTAP_DATA_RETRIES = 17, - IEEE80211_RADIOTAP_EXT = 31 -}; - -/* Channel flags. */ -#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ -#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ -#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ -#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ -#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ -#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ -#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ -#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ - -/* For IEEE80211_RADIOTAP_FLAGS */ -#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received - * during CFP - */ -#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received - * with short - * preamble - */ -#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received - * with WEP encryption - */ -#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received - * with fragmentation - */ -#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ -#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between - * 802.11 header and payload - * (to 32-bit boundary) - */ -/* For IEEE80211_RADIOTAP_RX_FLAGS */ -#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ - -/* For IEEE80211_RADIOTAP_TX_FLAGS */ -#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive - * retries */ -#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ -#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ - -#endif /* IEEE80211_RADIOTAP_H */ diff --git a/hostapd/sta_info.h b/hostapd/sta_info.h deleted file mode 100644 index e83597092381..000000000000 --- a/hostapd/sta_info.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * hostapd / Station table - * Copyright (c) 2002-2008, Jouni Malinen - * - * 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/hostapd/wired.conf b/hostapd/wired.conf deleted file mode 100644 index 956f8c53c540..000000000000 --- a/hostapd/wired.conf +++ /dev/null @@ -1,40 +0,0 @@ -##### 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/hostapd/wme.h b/hostapd/wme.h deleted file mode 100644 index e06b5bcab312..000000000000 --- a/hostapd/wme.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 - -/* - * WMM Information Element (used in (Re)Association Request frames; may also be - * used in Beacon frames) - */ -struct wmm_information_element { - /* Element ID: 221 (0xdd); Length: 7 */ - /* required fields for WMM version 1 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 0 */ - u8 version; /* 1 for WMM version 1.0 */ - u8 qos_info; /* AP/STA specific QoS info */ - -} __attribute__ ((packed)); - -#define WMM_AC_AIFSN_MASK 0x0f -#define WMM_AC_AIFNS_SHIFT 0 -#define WMM_AC_ACM 0x10 -#define WMM_AC_ACI_MASK 0x60 -#define WMM_AC_ACI_SHIFT 5 - -#define WMM_AC_ECWMIN_MASK 0x0f -#define WMM_AC_ECWMIN_SHIFT 0 -#define WMM_AC_ECWMAX_MASK 0xf0 -#define WMM_AC_ECWMAX_SHIFT 4 - -struct wmm_ac_parameter { - u8 aci_aifsn; /* AIFSN, ACM, ACI */ - u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ - le16 txop_limit; -} __attribute__ ((packed)); - -/* - * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association - * Response frmaes) - */ -struct wmm_parameter_element { - /* Element ID: 221 (0xdd); Length: 24 */ - /* required fields for WMM version 1 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 1 */ - u8 version; /* 1 for WMM version 1.0 */ - u8 qos_info; /* AP/STA specif QoS info */ - u8 reserved; /* 0 */ - struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ - -} __attribute__ ((packed)); - -/* WMM TSPEC Element */ -struct wmm_tspec_element { - u8 eid; /* 221 = 0xdd */ - u8 length; /* 6 + 55 = 61 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 2 */ - u8 version; /* 1 */ - /* WMM TSPEC body (55 octets): */ - u8 ts_info[3]; - le16 nominal_msdu_size; - le16 maximum_msdu_size; - le32 minimum_service_interval; - le32 maximum_service_interval; - le32 inactivity_interval; - le32 suspension_interval; - le32 service_start_time; - le32 minimum_data_rate; - le32 mean_data_rate; - le32 peak_data_rate; - le32 maximum_burst_size; - le32 delay_bound; - le32 minimum_phy_rate; - le16 surplus_bandwidth_allowance; - le16 medium_time; -} __attribute__ ((packed)); - - -/* Access Categories / ACI to AC coding */ -enum { - WMM_AC_BE = 0 /* Best Effort */, - WMM_AC_BK = 1 /* Background */, - WMM_AC_VI = 2 /* Video */, - WMM_AC_VO = 3 /* Voice */ -}; - -struct ieee80211_mgmt; - -u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid); -int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len); -int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta); -void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, - size_t len); - -#endif /* WME_H */ diff --git a/patches/openssl-0.9.8-tls-extensions.patch b/patches/openssl-0.9.8-tls-extensions.patch new file mode 100644 index 000000000000..44490cca226e --- /dev/null +++ b/patches/openssl-0.9.8-tls-extensions.patch @@ -0,0 +1,429 @@ +This patch is adding support for TLS hello extensions and externally +generated pre-shared key material to OpenSSL 0.9.8. This is +based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + + + +diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h +--- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700 ++++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700 +@@ -340,6 +340,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -968,6 +971,15 @@ struct ssl_st + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ ++ ++ /* TLS externsions */ ++ TLS_EXTENSION *tls_extension; ++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); ++ void *tls_extension_cb_arg; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; + }; + + #ifdef __cplusplus +@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h +--- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700 ++++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700 +@@ -282,6 +282,14 @@ extern "C" { + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile +--- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700 ++++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.000000000 -0700 +@@ -24,7 +24,7 @@ LIBSRC= \ + s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \ + s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \ + s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \ +- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ ++ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \ + d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ + d1_both.c d1_enc.c \ + ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ +@@ -35,7 +35,7 @@ LIBOBJ= \ + s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ + s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ + s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \ +- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \ ++ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \ + d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \ + d1_both.o d1_enc.o \ + ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ +@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h .. + t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h + t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h + t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c ++t1_ext.o: t1_ext.c ssl_locl.h +diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c +--- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700 ++++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700 +@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s) + } + *(p++)=0; /* Add the NULL method */ + ++ /* send client hello extensions if any */ ++ if (s->version >= TLS1_VERSION && s->tls_extension) ++ { ++ // set the total extensions length ++ s2n(s->tls_extension->length + 4, p); ++ ++ // put the extensions with type and length ++ s2n(s->tls_extension->type, p); ++ s2n(s->tls_extension->length, p); ++ ++ memcpy(p, s->tls_extension->data, s->tls_extension->length); ++ p+=s->tls_extension->length; ++ } ++ + l=(p-d); + d=buf; + *(d++)=SSL3_MT_CLIENT_HELLO; +@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s) + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *c; + unsigned char *p,*d; +- int i,al,ok; ++ int i,al,ok,pre_shared; + unsigned int j; + long n; + SSL_COMP *comp; +@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s) + goto f_err; + } + +- if (j != 0 && j == s->session->session_id_length ++ /* check if we want to resume the session based on external pre-shared secret */ ++ pre_shared = 0; ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); ++ s->session->session_id_length = j; ++ memcpy(s->session->session_id, p, j); ++ pre_shared = 1; ++ } ++ } ++ ++ if ((pre_shared || j != 0) && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { + if(s->sid_ctx_length != s->session->sid_ctx_length +diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c +--- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700 ++++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700 +@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s) + } + #endif + ++ /* Check for TLS client hello extension here */ ++ if (p < (d+n) && s->version >= TLS1_VERSION) ++ { ++ if (s->tls_extension_cb) ++ { ++ TLS_EXTENSION tls_ext; ++ unsigned short ext_total_len; ++ ++ n2s(p, ext_total_len); ++ n2s(p, tls_ext.type); ++ n2s(p, tls_ext.length); ++ ++ // sanity check in TLS extension len ++ if (tls_ext.length > (d+n) - p) ++ { ++ // just cut the lenth to packet border ++ tls_ext.length = (d+n) - p; ++ } ++ ++ tls_ext.data = p; ++ ++ // returns an alert code or 0 ++ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg); ++ if (al != 0) ++ { ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); ++ goto f_err; ++ } ++ } ++ } ++ ++ /* Check if we want to use external pre-shared secret for this handshake */ ++ /* for not reused session only */ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } ++ + /* Given s->session->ciphers and SSL_get_ciphers, we must + * pick a cipher */ + +diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c +--- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700 ++++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.000000000 -0700 +@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, + {0,NULL} + }; + +diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h +--- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700 ++++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700 +@@ -340,6 +340,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -968,6 +971,15 @@ struct ssl_st + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ ++ ++ /* TLS externsions */ ++ TLS_EXTENSION *tls_extension; ++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); ++ void *tls_extension_cb_arg; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; + }; + + #ifdef __cplusplus +@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c +--- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700 ++++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.000000000 -0700 +@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX * + return(s->session_timeout); + } + ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++{ ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++} ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c +--- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800 ++++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.000000000 -0700 +@@ -0,0 +1,48 @@ ++ ++#include ++#include "ssl_locl.h" ++ ++ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ s->tls_extension = NULL; ++ } ++ ++ if(ext_data) ++ { ++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); ++ if(!s->tls_extension) ++ { ++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ s->tls_extension->type = ext_type; ++ s->tls_extension->length = ext_len; ++ s->tls_extension->data = s->tls_extension + 1; ++ memcpy(s->tls_extension->data, ext_data, ext_len); ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ s->tls_extension_cb = cb; ++ s->tls_extension_cb_arg = arg; ++ ++ return 1; ++ } ++ ++ return 0; ++} +diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c +--- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700 ++++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700 +@@ -131,6 +131,10 @@ int tls1_new(SSL *s) + + void tls1_free(SSL *s) + { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ } + ssl3_free(s); + } + +diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h +--- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700 ++++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700 +@@ -282,6 +282,14 @@ extern "C" { + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num +--- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700 ++++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700 +@@ -226,3 +226,6 @@ DTLSv1_server_method + SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP + SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP + SSL_SESSION_get_id 277 EXIST::FUNCTION: ++SSL_set_hello_extension 278 EXIST::FUNCTION: ++SSL_set_hello_extension_cb 279 EXIST::FUNCTION: ++SSL_set_session_secret_cb 280 EXIST::FUNCTION: diff --git a/patches/openssl-0.9.8d-tls-extensions.patch b/patches/openssl-0.9.8d-tls-extensions.patch new file mode 100644 index 000000000000..eec6db8a1341 --- /dev/null +++ b/patches/openssl-0.9.8d-tls-extensions.patch @@ -0,0 +1,429 @@ +This patch is adding support for TLS hello extensions and externally +generated pre-shared key material to OpenSSL 0.9.8d. This is +based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + + + +diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h +--- openssl-0.9.8d.orig/include/openssl/ssl.h 2006-06-14 06:52:49.000000000 -0700 ++++ openssl-0.9.8d/include/openssl/ssl.h 2006-12-10 08:20:02.000000000 -0800 +@@ -345,6 +345,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -973,6 +976,15 @@ struct ssl_st + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ ++ ++ /* TLS externsions */ ++ TLS_EXTENSION *tls_extension; ++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); ++ void *tls_extension_cb_arg; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; + }; + + #ifdef __cplusplus +@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h +--- openssl-0.9.8d.orig/include/openssl/tls1.h 2006-06-14 10:52:01.000000000 -0700 ++++ openssl-0.9.8d/include/openssl/tls1.h 2006-12-10 08:20:02.000000000 -0800 +@@ -296,6 +296,14 @@ extern "C" { + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile +--- openssl-0.9.8d.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800 ++++ openssl-0.9.8d/ssl/Makefile 2006-12-10 08:20:02.000000000 -0800 +@@ -24,7 +24,7 @@ LIBSRC= \ + s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \ + s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \ + s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \ +- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ ++ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \ + d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ + d1_both.c d1_enc.c \ + ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ +@@ -35,7 +35,7 @@ LIBOBJ= \ + s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ + s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ + s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \ +- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \ ++ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \ + d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \ + d1_both.o d1_enc.o \ + ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ +@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h .. + t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h + t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h + t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c ++t1_ext.o: t1_ext.c ssl_locl.h +diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c +--- openssl-0.9.8d.orig/ssl/s3_clnt.c 2005-12-12 23:41:46.000000000 -0800 ++++ openssl-0.9.8d/ssl/s3_clnt.c 2006-12-10 08:20:02.000000000 -0800 +@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s) + #endif + *(p++)=0; /* Add the NULL method */ + ++ /* send client hello extensions if any */ ++ if (s->version >= TLS1_VERSION && s->tls_extension) ++ { ++ // set the total extensions length ++ s2n(s->tls_extension->length + 4, p); ++ ++ // put the extensions with type and length ++ s2n(s->tls_extension->type, p); ++ s2n(s->tls_extension->length, p); ++ ++ memcpy(p, s->tls_extension->data, s->tls_extension->length); ++ p+=s->tls_extension->length; ++ } ++ + l=(p-d); + d=buf; + *(d++)=SSL3_MT_CLIENT_HELLO; +@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s) + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *c; + unsigned char *p,*d; +- int i,al,ok; ++ int i,al,ok,pre_shared; + unsigned int j; + long n; + #ifndef OPENSSL_NO_COMP +@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s) + goto f_err; + } + +- if (j != 0 && j == s->session->session_id_length ++ /* check if we want to resume the session based on external pre-shared secret */ ++ pre_shared = 0; ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); ++ s->session->session_id_length = j; ++ memcpy(s->session->session_id, p, j); ++ pre_shared = 1; ++ } ++ } ++ ++ if ((pre_shared || j != 0) && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { + if(s->sid_ctx_length != s->session->sid_ctx_length +diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c +--- openssl-0.9.8d.orig/ssl/s3_srvr.c 2006-09-28 04:29:03.000000000 -0700 ++++ openssl-0.9.8d/ssl/s3_srvr.c 2006-12-10 08:20:02.000000000 -0800 +@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s) + } + #endif + ++ /* Check for TLS client hello extension here */ ++ if (p < (d+n) && s->version >= TLS1_VERSION) ++ { ++ if (s->tls_extension_cb) ++ { ++ TLS_EXTENSION tls_ext; ++ unsigned short ext_total_len; ++ ++ n2s(p, ext_total_len); ++ n2s(p, tls_ext.type); ++ n2s(p, tls_ext.length); ++ ++ // sanity check in TLS extension len ++ if (tls_ext.length > (d+n) - p) ++ { ++ // just cut the lenth to packet border ++ tls_ext.length = (d+n) - p; ++ } ++ ++ tls_ext.data = p; ++ ++ // returns an alert code or 0 ++ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg); ++ if (al != 0) ++ { ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); ++ goto f_err; ++ } ++ } ++ } ++ ++ /* Check if we want to use external pre-shared secret for this handshake */ ++ /* for not reused session only */ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } ++ + /* Given s->session->ciphers and SSL_get_ciphers, we must + * pick a cipher */ + +diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h +--- openssl-0.9.8d.orig/ssl/ssl.h 2006-06-14 06:52:49.000000000 -0700 ++++ openssl-0.9.8d/ssl/ssl.h 2006-12-10 08:20:02.000000000 -0800 +@@ -345,6 +345,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -973,6 +976,15 @@ struct ssl_st + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ ++ ++ /* TLS externsions */ ++ TLS_EXTENSION *tls_extension; ++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); ++ void *tls_extension_cb_arg; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; + }; + + #ifdef __cplusplus +@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c +--- openssl-0.9.8d.orig/ssl/ssl_err.c 2006-01-08 13:52:46.000000000 -0800 ++++ openssl-0.9.8d/ssl/ssl_err.c 2006-12-10 08:20:02.000000000 -0800 +@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, + {0,NULL} + }; + +diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c +--- openssl-0.9.8d.orig/ssl/ssl_sess.c 2005-12-30 15:51:57.000000000 -0800 ++++ openssl-0.9.8d/ssl/ssl_sess.c 2006-12-10 08:20:02.000000000 -0800 +@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX * + return(s->session_timeout); + } + ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++{ ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++} ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c +--- openssl-0.9.8d.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800 ++++ openssl-0.9.8d/ssl/t1_ext.c 2006-12-10 08:20:02.000000000 -0800 +@@ -0,0 +1,48 @@ ++ ++#include ++#include "ssl_locl.h" ++ ++ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ s->tls_extension = NULL; ++ } ++ ++ if(ext_data) ++ { ++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); ++ if(!s->tls_extension) ++ { ++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ s->tls_extension->type = ext_type; ++ s->tls_extension->length = ext_len; ++ s->tls_extension->data = s->tls_extension + 1; ++ memcpy(s->tls_extension->data, ext_data, ext_len); ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ s->tls_extension_cb = cb; ++ s->tls_extension_cb_arg = arg; ++ ++ return 1; ++ } ++ ++ return 0; ++} +diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c +--- openssl-0.9.8d.orig/ssl/t1_lib.c 2005-08-05 16:52:07.000000000 -0700 ++++ openssl-0.9.8d/ssl/t1_lib.c 2006-12-10 08:20:02.000000000 -0800 +@@ -97,6 +97,10 @@ int tls1_new(SSL *s) + + void tls1_free(SSL *s) + { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ } + ssl3_free(s); + } + +diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h +--- openssl-0.9.8d.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700 ++++ openssl-0.9.8d/ssl/tls1.h 2006-12-10 08:20:02.000000000 -0800 +@@ -296,6 +296,14 @@ extern "C" { + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num +--- openssl-0.9.8d.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700 ++++ openssl-0.9.8d/util/ssleay.num 2006-12-10 08:20:02.000000000 -0800 +@@ -226,3 +226,6 @@ DTLSv1_server_method + SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP + SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP + SSL_SESSION_get_id 277 EXIST::FUNCTION: ++SSL_set_hello_extension 278 EXIST::FUNCTION: ++SSL_set_hello_extension_cb 279 EXIST::FUNCTION: ++SSL_set_session_secret_cb 280 EXIST::FUNCTION: diff --git a/patches/openssl-0.9.8e-tls-extensions.patch b/patches/openssl-0.9.8e-tls-extensions.patch new file mode 100644 index 000000000000..ede053f779b6 --- /dev/null +++ b/patches/openssl-0.9.8e-tls-extensions.patch @@ -0,0 +1,353 @@ +This patch is adding support for TLS hello extensions and externally +generated pre-shared key material to OpenSSL 0.9.8e. This is +based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + + + +diff -uprN openssl-0.9.8e.orig/ssl/Makefile openssl-0.9.8e/ssl/Makefile +--- openssl-0.9.8e.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800 ++++ openssl-0.9.8e/ssl/Makefile 2007-03-22 20:23:19.000000000 -0700 +@@ -24,7 +24,7 @@ LIBSRC= \ + s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \ + s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \ + s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \ +- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ ++ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \ + d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ + d1_both.c d1_enc.c \ + ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ +@@ -35,7 +35,7 @@ LIBOBJ= \ + s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ + s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ + s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \ +- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \ ++ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \ + d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \ + d1_both.o d1_enc.o \ + ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ +@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h .. + t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h + t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h + t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c ++t1_ext.o: t1_ext.c ssl_locl.h +diff -uprN openssl-0.9.8e.orig/ssl/s3_clnt.c openssl-0.9.8e/ssl/s3_clnt.c +--- openssl-0.9.8e.orig/ssl/s3_clnt.c 2006-09-28 05:23:15.000000000 -0700 ++++ openssl-0.9.8e/ssl/s3_clnt.c 2007-03-22 20:23:19.000000000 -0700 +@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s) + #endif + *(p++)=0; /* Add the NULL method */ + ++ /* send client hello extensions if any */ ++ if (s->version >= TLS1_VERSION && s->tls_extension) ++ { ++ // set the total extensions length ++ s2n(s->tls_extension->length + 4, p); ++ ++ // put the extensions with type and length ++ s2n(s->tls_extension->type, p); ++ s2n(s->tls_extension->length, p); ++ ++ memcpy(p, s->tls_extension->data, s->tls_extension->length); ++ p+=s->tls_extension->length; ++ } ++ + l=(p-d); + d=buf; + *(d++)=SSL3_MT_CLIENT_HELLO; +@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s) + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *c; + unsigned char *p,*d; +- int i,al,ok; ++ int i,al,ok,pre_shared; + unsigned int j; + long n; + #ifndef OPENSSL_NO_COMP +@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s) + goto f_err; + } + +- if (j != 0 && j == s->session->session_id_length ++ /* check if we want to resume the session based on external pre-shared secret */ ++ pre_shared = 0; ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); ++ s->session->session_id_length = j; ++ memcpy(s->session->session_id, p, j); ++ pre_shared = 1; ++ } ++ } ++ ++ if ((pre_shared || j != 0) && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { + if(s->sid_ctx_length != s->session->sid_ctx_length +diff -uprN openssl-0.9.8e.orig/ssl/s3_srvr.c openssl-0.9.8e/ssl/s3_srvr.c +--- openssl-0.9.8e.orig/ssl/s3_srvr.c 2007-02-07 12:36:40.000000000 -0800 ++++ openssl-0.9.8e/ssl/s3_srvr.c 2007-03-22 20:23:19.000000000 -0700 +@@ -945,6 +945,75 @@ int ssl3_get_client_hello(SSL *s) + } + #endif + ++ /* Check for TLS client hello extension here */ ++ if (p < (d+n) && s->version >= TLS1_VERSION) ++ { ++ if (s->tls_extension_cb) ++ { ++ TLS_EXTENSION tls_ext; ++ unsigned short ext_total_len; ++ ++ n2s(p, ext_total_len); ++ n2s(p, tls_ext.type); ++ n2s(p, tls_ext.length); ++ ++ // sanity check in TLS extension len ++ if (tls_ext.length > (d+n) - p) ++ { ++ // just cut the lenth to packet border ++ tls_ext.length = (d+n) - p; ++ } ++ ++ tls_ext.data = p; ++ ++ // returns an alert code or 0 ++ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg); ++ if (al != 0) ++ { ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR); ++ goto f_err; ++ } ++ } ++ } ++ ++ /* Check if we want to use external pre-shared secret for this handshake */ ++ /* for not reused session only */ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } ++ + /* Given s->session->ciphers and SSL_get_ciphers, we must + * pick a cipher */ + +diff -uprN openssl-0.9.8e.orig/ssl/ssl.h openssl-0.9.8e/ssl/ssl.h +--- openssl-0.9.8e.orig/ssl/ssl.h 2007-02-19 09:55:07.000000000 -0800 ++++ openssl-0.9.8e/ssl/ssl.h 2007-03-22 20:23:19.000000000 -0700 +@@ -345,6 +345,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -973,6 +976,15 @@ struct ssl_st + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ ++ ++ /* TLS externsions */ ++ TLS_EXTENSION *tls_extension; ++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg); ++ void *tls_extension_cb_arg; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; + }; + + #ifdef __cplusplus +@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -uprN openssl-0.9.8e.orig/ssl/ssl_err.c openssl-0.9.8e/ssl/ssl_err.c +--- openssl-0.9.8e.orig/ssl/ssl_err.c 2006-11-21 12:14:46.000000000 -0800 ++++ openssl-0.9.8e/ssl/ssl_err.c 2007-03-22 20:23:19.000000000 -0700 +@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, + {0,NULL} + }; + +diff -uprN openssl-0.9.8e.orig/ssl/ssl_sess.c openssl-0.9.8e/ssl/ssl_sess.c +--- openssl-0.9.8e.orig/ssl/ssl_sess.c 2007-02-10 02:40:24.000000000 -0800 ++++ openssl-0.9.8e/ssl/ssl_sess.c 2007-03-22 20:23:19.000000000 -0700 +@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX * + return(s->session_timeout); + } + ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++{ ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++} ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +diff -uprN openssl-0.9.8e.orig/ssl/t1_ext.c openssl-0.9.8e/ssl/t1_ext.c +--- openssl-0.9.8e.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800 ++++ openssl-0.9.8e/ssl/t1_ext.c 2007-03-22 20:23:19.000000000 -0700 +@@ -0,0 +1,48 @@ ++ ++#include ++#include "ssl_locl.h" ++ ++ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ s->tls_extension = NULL; ++ } ++ ++ if(ext_data) ++ { ++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); ++ if(!s->tls_extension) ++ { ++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ s->tls_extension->type = ext_type; ++ s->tls_extension->length = ext_len; ++ s->tls_extension->data = s->tls_extension + 1; ++ memcpy(s->tls_extension->data, ext_data, ext_len); ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ s->tls_extension_cb = cb; ++ s->tls_extension_cb_arg = arg; ++ ++ return 1; ++ } ++ ++ return 0; ++} +diff -uprN openssl-0.9.8e.orig/ssl/t1_lib.c openssl-0.9.8e/ssl/t1_lib.c +--- openssl-0.9.8e.orig/ssl/t1_lib.c 2007-01-21 08:07:25.000000000 -0800 ++++ openssl-0.9.8e/ssl/t1_lib.c 2007-03-22 20:23:19.000000000 -0700 +@@ -97,6 +97,10 @@ int tls1_new(SSL *s) + + void tls1_free(SSL *s) + { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ } + ssl3_free(s); + } + +diff -uprN openssl-0.9.8e.orig/ssl/tls1.h openssl-0.9.8e/ssl/tls1.h +--- openssl-0.9.8e.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700 ++++ openssl-0.9.8e/ssl/tls1.h 2007-03-22 20:23:19.000000000 -0700 +@@ -296,6 +296,14 @@ extern "C" { + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -uprN openssl-0.9.8e.orig/util/ssleay.num openssl-0.9.8e/util/ssleay.num +--- openssl-0.9.8e.orig/util/ssleay.num 2006-11-30 05:04:43.000000000 -0800 ++++ openssl-0.9.8e/util/ssleay.num 2007-03-22 20:24:07.000000000 -0700 +@@ -238,3 +238,6 @@ SSL_CTX_set_info_callback + SSL_CTX_sess_get_new_cb 287 EXIST::FUNCTION: + SSL_CTX_get_client_cert_cb 288 EXIST::FUNCTION: + SSL_CTX_sess_get_remove_cb 289 EXIST::FUNCTION: ++SSL_set_hello_extension 290 EXIST::FUNCTION: ++SSL_set_hello_extension_cb 291 EXIST::FUNCTION: ++SSL_set_session_secret_cb 292 EXIST::FUNCTION: diff --git a/patches/openssl-0.9.8g-tls-extensions.patch b/patches/openssl-0.9.8g-tls-extensions.patch new file mode 100644 index 000000000000..8ccbfaa29ddf --- /dev/null +++ b/patches/openssl-0.9.8g-tls-extensions.patch @@ -0,0 +1,330 @@ +This patch adds support for TLS SessionTicket extension (RFC 5077) for +the parts used by EAP-FAST (RFC 4851). + +This is based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + +OpenSSL 0.9.8g does not enable TLS extension support by default, so it +will need to be enabled by adding enable-tlsext to config script +command line. + + +diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c +--- openssl-0.9.8g.orig/ssl/s3_clnt.c 2007-08-31 03:28:51.000000000 +0300 ++++ openssl-0.9.8g/ssl/s3_clnt.c 2008-04-15 17:11:46.000000000 +0300 +@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s) + goto f_err; + } + ++#ifndef OPENSSL_NO_TLSEXT ++ /* check if we want to resume the session based on external pre-shared secret */ ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); ++ } ++ } ++#endif /* OPENSSL_NO_TLSEXT */ ++ + if (j != 0 && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { +diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c +--- openssl-0.9.8g.orig/ssl/s3_srvr.c 2007-09-30 21:55:59.000000000 +0300 ++++ openssl-0.9.8g/ssl/s3_srvr.c 2008-04-15 17:10:37.000000000 +0300 +@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s) + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } ++ ++ /* Check if we want to use external pre-shared secret for this ++ * handshake for not reused session only. We need to generate ++ * server_random before calling tls_session_secret_cb in order to allow ++ * SessionTicket processing to use it in key derivation. */ ++ { ++ unsigned long Time; ++ unsigned char *pos; ++ Time=(unsigned long)time(NULL); /* Time */ ++ pos=s->s3->server_random; ++ l2n(Time,pos); ++ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) ++ { ++ al=SSL_AD_INTERNAL_ERROR; ++ goto f_err; ++ } ++ } ++ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } + #endif + /* Worst case, we will use the NULL compression, but if we have other + * options, we will now look for them. We have i-1 compression +@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s) + unsigned char *buf; + unsigned char *p,*d; + int i,sl; +- unsigned long l,Time; ++ unsigned long l; ++#ifdef OPENSSL_NO_TLSEXT ++ unsigned long Time; ++#endif + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + buf=(unsigned char *)s->init_buf->data; ++#ifdef OPENSSL_NO_TLSEXT + p=s->s3->server_random; ++ /* Generate server_random if it was not needed previously */ + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + return -1; ++#endif + /* Do the message type and length last */ + d=p= &(buf[4]); + +diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h +--- openssl-0.9.8g.orig/ssl/ssl.h 2007-10-19 10:42:38.000000000 +0300 ++++ openssl-0.9.8g/ssl/ssl.h 2008-04-15 17:10:37.000000000 +0300 +@@ -342,6 +342,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -1004,6 +1007,14 @@ struct ssl_st + */ + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; ++ ++ /* TLS extensions */ ++ TLS_EXTENSION *tls_extension; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; ++ + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ + #define session_ctx initial_ctx + #else +@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c +--- openssl-0.9.8g.orig/ssl/ssl_err.c 2007-10-11 17:36:59.000000000 +0300 ++++ openssl-0.9.8g/ssl/ssl_err.c 2008-04-15 17:10:37.000000000 +0300 +@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, + {0,NULL} + }; + +diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c +--- openssl-0.9.8g.orig/ssl/ssl_sess.c 2007-10-19 10:36:34.000000000 +0300 ++++ openssl-0.9.8g/ssl/ssl_sess.c 2008-04-15 17:10:37.000000000 +0300 +@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX * + return(s->session_timeout); + } + ++#ifndef OPENSSL_NO_TLSEXT ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++{ ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++} ++ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ s->tls_extension = NULL; ++ } ++ ++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); ++ if(!s->tls_extension) ++ { ++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ s->tls_extension->type = ext_type; ++ ++ if(ext_data) ++ { ++ s->tls_extension->length = ext_len; ++ s->tls_extension->data = s->tls_extension + 1; ++ memcpy(s->tls_extension->data, ext_data, ext_len); ++ } else { ++ s->tls_extension->length = 0; ++ s->tls_extension->data = NULL; ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++#endif /* OPENSSL_NO_TLSEXT */ ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c +--- openssl-0.9.8g.orig/ssl/t1_lib.c 2007-10-19 10:44:10.000000000 +0300 ++++ openssl-0.9.8g/ssl/t1_lib.c 2008-04-15 17:10:37.000000000 +0300 +@@ -105,6 +105,12 @@ int tls1_new(SSL *s) + + void tls1_free(SSL *s) + { ++#ifndef OPENSSL_NO_TLSEXT ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ } ++#endif + ssl3_free(s); + } + +@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex + int ticklen; + if (s->session && s->session->tlsext_tick) + ticklen = s->session->tlsext_ticklen; ++ else if (s->session && s->tls_extension && ++ s->tls_extension->type == TLSEXT_TYPE_session_ticket && ++ s->tls_extension->data) ++ { ++ ticklen = s->tls_extension->length; ++ s->session->tlsext_tick = OPENSSL_malloc(ticklen); ++ if (!s->session->tlsext_tick) ++ return NULL; ++ memcpy(s->session->tlsext_tick, s->tls_extension->data, ++ ticklen); ++ s->session->tlsext_ticklen = ticklen; ++ } + else + ticklen = 0; ++ if (ticklen == 0 && s->tls_extension && ++ s->tls_extension->type == TLSEXT_TYPE_session_ticket && ++ s->tls_extension->data == NULL) ++ goto skip_ext; + /* Check for enough room 2 for extension type, 2 for len + * rest for ticket + */ +@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex + ret += ticklen; + } + } ++ skip_ext: + + if ((extdatalen = ret-p-2)== 0) + return p; +@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned + s->tlsext_ticket_expected = 1; + return 0; /* Cache miss */ + } ++ if (s->tls_session_secret_cb) ++ return 0; + return tls_decrypt_ticket(s, p, size, session_id, len, + ret); + } +diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h +--- openssl-0.9.8g.orig/ssl/tls1.h 2007-08-28 04:12:44.000000000 +0300 ++++ openssl-0.9.8g/ssl/tls1.h 2008-04-15 17:10:37.000000000 +0300 +@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num +--- openssl-0.9.8g.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300 ++++ openssl-0.9.8g/util/ssleay.num 2008-04-15 17:10:37.000000000 +0300 +@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb + SSL_set_SSL_CTX 290 EXIST::FUNCTION: + SSL_get_servername 291 EXIST::FUNCTION:TLSEXT + SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT ++SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT ++SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT diff --git a/patches/openssl-0.9.8h-tls-extensions.patch b/patches/openssl-0.9.8h-tls-extensions.patch new file mode 100644 index 000000000000..c68f2279b762 --- /dev/null +++ b/patches/openssl-0.9.8h-tls-extensions.patch @@ -0,0 +1,344 @@ +This patch adds support for TLS SessionTicket extension (RFC 5077) for +the parts used by EAP-FAST (RFC 4851). + +This is based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + +OpenSSL 0.9.8h does not enable TLS extension support by default, so it +will need to be enabled by adding enable-tlsext to config script +command line. + + +diff -upr openssl-0.9.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c +--- openssl-0.9.8h.orig/ssl/s3_clnt.c 2008-05-28 10:29:27.000000000 +0300 ++++ openssl-0.9.8h/ssl/s3_clnt.c 2008-05-29 10:44:25.000000000 +0300 +@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s) + goto f_err; + } + ++#ifndef OPENSSL_NO_TLSEXT ++ /* check if we want to resume the session based on external pre-shared secret */ ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j); ++ } ++ } ++#endif /* OPENSSL_NO_TLSEXT */ ++ + if (j != 0 && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { +@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s) + { + int ok; + long n; +- /* If we have no ticket or session ID is non-zero length (a match of +- * a non-zero session length would never reach here) it cannot be a +- * resumed session. +- */ +- if (!s->session->tlsext_tick || s->session->session_id_length) ++ /* If we have no ticket it cannot be a resumed session. */ ++ if (!s->session->tlsext_tick) + return 1; + /* this function is called when we really expect a Certificate + * message, so permit appropriate message length */ +diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c +--- openssl-0.9.8h.orig/ssl/s3_srvr.c 2008-04-30 19:11:32.000000000 +0300 ++++ openssl-0.9.8h/ssl/s3_srvr.c 2008-05-28 18:49:34.000000000 +0300 +@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s) + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } ++ ++ /* Check if we want to use external pre-shared secret for this ++ * handshake for not reused session only. We need to generate ++ * server_random before calling tls_session_secret_cb in order to allow ++ * SessionTicket processing to use it in key derivation. */ ++ { ++ unsigned long Time; ++ unsigned char *pos; ++ Time=(unsigned long)time(NULL); /* Time */ ++ pos=s->s3->server_random; ++ l2n(Time,pos); ++ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) ++ { ++ al=SSL_AD_INTERNAL_ERROR; ++ goto f_err; ++ } ++ } ++ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } + #endif + /* Worst case, we will use the NULL compression, but if we have other + * options, we will now look for them. We have i-1 compression +@@ -1097,16 +1150,22 @@ int ssl3_send_server_hello(SSL *s) + unsigned char *buf; + unsigned char *p,*d; + int i,sl; +- unsigned long l,Time; ++ unsigned long l; ++#ifdef OPENSSL_NO_TLSEXT ++ unsigned long Time; ++#endif + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + buf=(unsigned char *)s->init_buf->data; ++#ifdef OPENSSL_NO_TLSEXT + p=s->s3->server_random; ++ /* Generate server_random if it was not needed previously */ + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + return -1; ++#endif + /* Do the message type and length last */ + d=p= &(buf[4]); + +diff -upr openssl-0.9.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h +--- openssl-0.9.8h.orig/ssl/ssl.h 2008-04-30 19:11:32.000000000 +0300 ++++ openssl-0.9.8h/ssl/ssl.h 2008-05-28 18:49:34.000000000 +0300 +@@ -343,6 +343,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_extension_st TLS_EXTENSION; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -364,6 +365,8 @@ DECLARE_STACK_OF(SSL_CIPHER) + typedef struct ssl_st SSL; + typedef struct ssl_ctx_st SSL_CTX; + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -1027,6 +1030,14 @@ struct ssl_st + + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; ++ ++ /* TLS extensions */ ++ TLS_EXTENSION *tls_extension; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; ++ + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ + #define session_ctx initial_ctx + #else +@@ -1625,6 +1636,12 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1815,6 +1832,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_HELLO_EXTENSION 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +diff -upr openssl-0.9.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c +--- openssl-0.9.8h.orig/ssl/ssl_err.c 2007-10-12 03:00:30.000000000 +0300 ++++ openssl-0.9.8h/ssl/ssl_err.c 2008-05-28 18:49:34.000000000 +0300 +@@ -251,6 +251,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"}, + {0,NULL} + }; + +diff -upr openssl-0.9.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c +--- openssl-0.9.8h.orig/ssl/ssl_sess.c 2007-10-17 20:30:15.000000000 +0300 ++++ openssl-0.9.8h/ssl/ssl_sess.c 2008-05-28 18:49:34.000000000 +0300 +@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX * + return(s->session_timeout); + } + ++#ifndef OPENSSL_NO_TLSEXT ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++{ ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++} ++ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) ++{ ++ if(s->version >= TLS1_VERSION) ++ { ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ s->tls_extension = NULL; ++ } ++ ++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len); ++ if(!s->tls_extension) ++ { ++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ s->tls_extension->type = ext_type; ++ ++ if(ext_data) ++ { ++ s->tls_extension->length = ext_len; ++ s->tls_extension->data = s->tls_extension + 1; ++ memcpy(s->tls_extension->data, ext_data, ext_len); ++ } else { ++ s->tls_extension->length = 0; ++ s->tls_extension->data = NULL; ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++} ++#endif /* OPENSSL_NO_TLSEXT */ ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +diff -upr openssl-0.9.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c +--- openssl-0.9.8h.orig/ssl/t1_lib.c 2008-05-28 10:26:33.000000000 +0300 ++++ openssl-0.9.8h/ssl/t1_lib.c 2008-05-28 18:49:34.000000000 +0300 +@@ -106,6 +106,12 @@ int tls1_new(SSL *s) + + void tls1_free(SSL *s) + { ++#ifndef OPENSSL_NO_TLSEXT ++ if(s->tls_extension) ++ { ++ OPENSSL_free(s->tls_extension); ++ } ++#endif + ssl3_free(s); + } + +@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex + int ticklen; + if (s->session && s->session->tlsext_tick) + ticklen = s->session->tlsext_ticklen; ++ else if (s->session && s->tls_extension && ++ s->tls_extension->type == TLSEXT_TYPE_session_ticket && ++ s->tls_extension->data) ++ { ++ ticklen = s->tls_extension->length; ++ s->session->tlsext_tick = OPENSSL_malloc(ticklen); ++ if (!s->session->tlsext_tick) ++ return NULL; ++ memcpy(s->session->tlsext_tick, s->tls_extension->data, ++ ticklen); ++ s->session->tlsext_ticklen = ticklen; ++ } + else + ticklen = 0; ++ if (ticklen == 0 && s->tls_extension && ++ s->tls_extension->type == TLSEXT_TYPE_session_ticket && ++ s->tls_extension->data == NULL) ++ goto skip_ext; + /* Check for enough room 2 for extension type, 2 for len + * rest for ticket + */ +@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex + ret += ticklen; + } + } ++ skip_ext: + + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { +@@ -774,6 +797,8 @@ int tls1_process_ticket(SSL *s, unsigned + s->tlsext_ticket_expected = 1; + return 0; /* Cache miss */ + } ++ if (s->tls_session_secret_cb) ++ return 0; + return tls_decrypt_ticket(s, p, size, session_id, len, + ret); + } +diff -upr openssl-0.9.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h +--- openssl-0.9.8h.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300 ++++ openssl-0.9.8h/ssl/tls1.h 2008-05-28 18:49:34.000000000 +0300 +@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_extension_st ++{ ++ unsigned short type; ++ unsigned short length; ++ void *data; ++}; ++ + #ifdef __cplusplus + } + #endif +diff -upr openssl-0.9.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num +--- openssl-0.9.8h.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300 ++++ openssl-0.9.8h/util/ssleay.num 2008-05-28 18:49:34.000000000 +0300 +@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb + SSL_set_SSL_CTX 290 EXIST::FUNCTION: + SSL_get_servername 291 EXIST::FUNCTION:TLSEXT + SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT ++SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT ++SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT diff --git a/patches/openssl-0.9.8i-tls-extensions.patch b/patches/openssl-0.9.8i-tls-extensions.patch new file mode 100644 index 000000000000..90bff544eb59 --- /dev/null +++ b/patches/openssl-0.9.8i-tls-extensions.patch @@ -0,0 +1,404 @@ +This patch adds support for TLS SessionTicket extension (RFC 5077) for +the parts used by EAP-FAST (RFC 4851). + +This is based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + +OpenSSL 0.9.8i does not enable TLS extension support by default, so it +will need to be enabled by adding enable-tlsext to config script +command line. + + +Index: openssl-0.9.8i/ssl/s3_clnt.c +=================================================================== +--- openssl-0.9.8i.orig/ssl/s3_clnt.c 2008-06-16 19:56:41.000000000 +0300 ++++ openssl-0.9.8i/ssl/s3_clnt.c 2008-11-23 20:39:40.000000000 +0200 +@@ -759,6 +759,21 @@ + goto f_err; + } + ++#ifndef OPENSSL_NO_TLSEXT ++ /* check if we want to resume the session based on external pre-shared secret */ ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ NULL, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->session->cipher=pref_cipher ? ++ pref_cipher : ssl_get_cipher_by_char(s,p+j); ++ } ++ } ++#endif /* OPENSSL_NO_TLSEXT */ ++ + if (j != 0 && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { +@@ -2701,11 +2716,8 @@ + { + int ok; + long n; +- /* If we have no ticket or session ID is non-zero length (a match of +- * a non-zero session length would never reach here) it cannot be a +- * resumed session. +- */ +- if (!s->session->tlsext_tick || s->session->session_id_length) ++ /* If we have no ticket it cannot be a resumed session. */ ++ if (!s->session->tlsext_tick) + return 1; + /* this function is called when we really expect a Certificate + * message, so permit appropriate message length */ +Index: openssl-0.9.8i/ssl/s3_srvr.c +=================================================================== +--- openssl-0.9.8i.orig/ssl/s3_srvr.c 2008-09-14 21:16:09.000000000 +0300 ++++ openssl-0.9.8i/ssl/s3_srvr.c 2008-11-23 20:37:40.000000000 +0200 +@@ -959,6 +959,59 @@ + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } ++ ++ /* Check if we want to use external pre-shared secret for this ++ * handshake for not reused session only. We need to generate ++ * server_random before calling tls_session_secret_cb in order to allow ++ * SessionTicket processing to use it in key derivation. */ ++ { ++ unsigned long Time; ++ unsigned char *pos; ++ Time=(unsigned long)time(NULL); /* Time */ ++ pos=s->s3->server_random; ++ l2n(Time,pos); ++ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) ++ { ++ al=SSL_AD_INTERNAL_ERROR; ++ goto f_err; ++ } ++ } ++ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } + #endif + /* Worst case, we will use the NULL compression, but if we have other + * options, we will now look for them. We have i-1 compression +@@ -1097,16 +1150,22 @@ + unsigned char *buf; + unsigned char *p,*d; + int i,sl; +- unsigned long l,Time; ++ unsigned long l; ++#ifdef OPENSSL_NO_TLSEXT ++ unsigned long Time; ++#endif + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + buf=(unsigned char *)s->init_buf->data; ++#ifdef OPENSSL_NO_TLSEXT + p=s->s3->server_random; ++ /* Generate server_random if it was not needed previously */ + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + return -1; ++#endif + /* Do the message type and length last */ + d=p= &(buf[4]); + +Index: openssl-0.9.8i/ssl/ssl_err.c +=================================================================== +--- openssl-0.9.8i.orig/ssl/ssl_err.c 2008-08-13 22:44:44.000000000 +0300 ++++ openssl-0.9.8i/ssl/ssl_err.c 2008-11-23 20:33:43.000000000 +0200 +@@ -253,6 +253,7 @@ + {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"}, + {0,NULL} + }; + +Index: openssl-0.9.8i/ssl/ssl.h +=================================================================== +--- openssl-0.9.8i.orig/ssl/ssl.h 2008-08-13 22:44:44.000000000 +0300 ++++ openssl-0.9.8i/ssl/ssl.h 2008-11-23 20:35:41.000000000 +0200 +@@ -344,6 +344,7 @@ + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -362,6 +363,9 @@ + + DECLARE_STACK_OF(SSL_CIPHER) + ++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg); ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -1034,6 +1038,18 @@ + + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; ++ ++ /* TLS Session Ticket extension override */ ++ TLS_SESSION_TICKET_EXT *tlsext_session_ticket; ++ ++ /* TLS Session Ticket extension callback */ ++ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb; ++ void *tls_session_ticket_ext_cb_arg; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; ++ + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ + #define session_ctx initial_ctx + #else +@@ -1632,6 +1648,15 @@ + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* TLS extensions functions */ ++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); ++ ++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, ++ void *arg); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1824,6 +1849,7 @@ + #define SSL_F_TLS1_ENC 210 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +Index: openssl-0.9.8i/ssl/ssl_sess.c +=================================================================== +--- openssl-0.9.8i.orig/ssl/ssl_sess.c 2008-06-04 21:35:27.000000000 +0300 ++++ openssl-0.9.8i/ssl/ssl_sess.c 2008-11-23 20:32:24.000000000 +0200 +@@ -707,6 +707,61 @@ + return(s->session_timeout); + } + ++#ifndef OPENSSL_NO_TLSEXT ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++ { ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++ } ++ ++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, ++ void *arg) ++ { ++ if (s == NULL) return(0); ++ s->tls_session_ticket_ext_cb = cb; ++ s->tls_session_ticket_ext_cb_arg = arg; ++ return(1); ++ } ++ ++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len) ++ { ++ if (s->version >= TLS1_VERSION) ++ { ++ if (s->tlsext_session_ticket) ++ { ++ OPENSSL_free(s->tlsext_session_ticket); ++ s->tlsext_session_ticket = NULL; ++ } ++ ++ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len); ++ if (!s->tlsext_session_ticket) ++ { ++ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ if (ext_data) ++ { ++ s->tlsext_session_ticket->length = ext_len; ++ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1; ++ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len); ++ } ++ else ++ { ++ s->tlsext_session_ticket->length = 0; ++ s->tlsext_session_ticket->data = NULL; ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++ } ++#endif /* OPENSSL_NO_TLSEXT */ ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +Index: openssl-0.9.8i/ssl/t1_lib.c +=================================================================== +--- openssl-0.9.8i.orig/ssl/t1_lib.c 2008-09-04 01:13:04.000000000 +0300 ++++ openssl-0.9.8i/ssl/t1_lib.c 2008-11-23 20:31:20.000000000 +0200 +@@ -106,6 +106,12 @@ + + void tls1_free(SSL *s) + { ++#ifndef OPENSSL_NO_TLSEXT ++ if (s->tlsext_session_ticket) ++ { ++ OPENSSL_free(s->tlsext_session_ticket); ++ } ++#endif + ssl3_free(s); + } + +@@ -175,8 +181,23 @@ + int ticklen; + if (s->session && s->session->tlsext_tick) + ticklen = s->session->tlsext_ticklen; ++ else if (s->session && s->tlsext_session_ticket && ++ s->tlsext_session_ticket->data) ++ { ++ ticklen = s->tlsext_session_ticket->length; ++ s->session->tlsext_tick = OPENSSL_malloc(ticklen); ++ if (!s->session->tlsext_tick) ++ return NULL; ++ memcpy(s->session->tlsext_tick, ++ s->tlsext_session_ticket->data, ++ ticklen); ++ s->session->tlsext_ticklen = ticklen; ++ } + else + ticklen = 0; ++ if (ticklen == 0 && s->tlsext_session_ticket && ++ s->tlsext_session_ticket->data == NULL) ++ goto skip_ext; + /* Check for enough room 2 for extension type, 2 for len + * rest for ticket + */ +@@ -190,6 +211,7 @@ + ret += ticklen; + } + } ++ skip_ext: + + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { +@@ -407,6 +429,15 @@ + } + + } ++ else if (type == TLSEXT_TYPE_session_ticket) ++ { ++ if (s->tls_session_ticket_ext_cb && ++ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) ++ { ++ *al = TLS1_AD_INTERNAL_ERROR; ++ return 0; ++ } ++ } + else if (type == TLSEXT_TYPE_status_request + && s->ctx->tlsext_status_cb) + { +@@ -553,6 +584,12 @@ + } + else if (type == TLSEXT_TYPE_session_ticket) + { ++ if (s->tls_session_ticket_ext_cb && ++ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) ++ { ++ *al = TLS1_AD_INTERNAL_ERROR; ++ return 0; ++ } + if ((SSL_get_options(s) & SSL_OP_NO_TICKET) + || (size > 0)) + { +@@ -776,6 +813,15 @@ + s->tlsext_ticket_expected = 1; + return 0; /* Cache miss */ + } ++ if (s->tls_session_secret_cb) ++ { ++ /* Indicate cache miss here and instead of ++ * generating the session from ticket now, ++ * trigger abbreviated handshake based on ++ * external mechanism to calculate the master ++ * secret later. */ ++ return 0; ++ } + return tls_decrypt_ticket(s, p, size, session_id, len, + ret); + } +Index: openssl-0.9.8i/ssl/tls1.h +=================================================================== +--- openssl-0.9.8i.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300 ++++ openssl-0.9.8i/ssl/tls1.h 2008-11-23 20:22:38.000000000 +0200 +@@ -398,6 +398,13 @@ + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS extension struct */ ++struct tls_session_ticket_ext_st ++ { ++ unsigned short length; ++ void *data; ++ }; ++ + #ifdef __cplusplus + } + #endif +Index: openssl-0.9.8i/util/ssleay.num +=================================================================== +--- openssl-0.9.8i.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300 ++++ openssl-0.9.8i/util/ssleay.num 2008-11-23 20:22:05.000000000 +0200 +@@ -242,3 +242,5 @@ + SSL_get_servername 291 EXIST::FUNCTION:TLSEXT + SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT + SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE ++SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT ++SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT diff --git a/patches/openssl-0.9.9-session-ticket.patch b/patches/openssl-0.9.9-session-ticket.patch new file mode 100644 index 000000000000..3afa639ad898 --- /dev/null +++ b/patches/openssl-0.9.9-session-ticket.patch @@ -0,0 +1,374 @@ +This patch adds support for TLS SessionTicket extension (RFC 5077) for +the parts used by EAP-FAST (RFC 4851). + +This is based on the patch from Alexey Kobozev +(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300). + +NOTE: This patch (without SSL_set_hello_extension() wrapper) was +merged into the upstream OpenSSL 0.9.9 tree and as such, an external +patch for EAP-FAST support is not needed anymore. + + + +Index: openssl-SNAP-20081111/ssl/s3_clnt.c +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/s3_clnt.c ++++ openssl-SNAP-20081111/ssl/s3_clnt.c +@@ -788,6 +788,23 @@ int ssl3_get_server_hello(SSL *s) + goto f_err; + } + ++#ifndef OPENSSL_NO_TLSEXT ++ /* check if we want to resume the session based on external pre-shared secret */ ++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if (s->tls_session_secret_cb(s, s->session->master_key, ++ &s->session->master_key_length, ++ NULL, &pref_cipher, ++ s->tls_session_secret_cb_arg)) ++ { ++ s->session->cipher = pref_cipher ? ++ pref_cipher : ssl_get_cipher_by_char(s, p+j); ++ } ++ } ++#endif /* OPENSSL_NO_TLSEXT */ ++ + if (j != 0 && j == s->session->session_id_length + && memcmp(p,s->session->session_id,j) == 0) + { +@@ -2927,11 +2944,8 @@ static int ssl3_check_finished(SSL *s) + { + int ok; + long n; +- /* If we have no ticket or session ID is non-zero length (a match of +- * a non-zero session length would never reach here) it cannot be a +- * resumed session. +- */ +- if (!s->session->tlsext_tick || s->session->session_id_length) ++ /* If we have no ticket it cannot be a resumed session. */ ++ if (!s->session->tlsext_tick) + return 1; + /* this function is called when we really expect a Certificate + * message, so permit appropriate message length */ +Index: openssl-SNAP-20081111/ssl/s3_srvr.c +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/s3_srvr.c ++++ openssl-SNAP-20081111/ssl/s3_srvr.c +@@ -1010,6 +1010,59 @@ int ssl3_get_client_hello(SSL *s) + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } ++ ++ /* Check if we want to use external pre-shared secret for this ++ * handshake for not reused session only. We need to generate ++ * server_random before calling tls_session_secret_cb in order to allow ++ * SessionTicket processing to use it in key derivation. */ ++ { ++ unsigned long Time; ++ unsigned char *pos; ++ Time=(unsigned long)time(NULL); /* Time */ ++ pos=s->s3->server_random; ++ l2n(Time,pos); ++ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) ++ { ++ al=SSL_AD_INTERNAL_ERROR; ++ goto f_err; ++ } ++ } ++ ++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) ++ { ++ SSL_CIPHER *pref_cipher=NULL; ++ ++ s->session->master_key_length=sizeof(s->session->master_key); ++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, ++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg)) ++ { ++ s->hit=1; ++ s->session->ciphers=ciphers; ++ s->session->verify_result=X509_V_OK; ++ ++ ciphers=NULL; ++ ++ /* check if some cipher was preferred by call back */ ++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); ++ if (pref_cipher == NULL) ++ { ++ al=SSL_AD_HANDSHAKE_FAILURE; ++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); ++ goto f_err; ++ } ++ ++ s->session->cipher=pref_cipher; ++ ++ if (s->cipher_list) ++ sk_SSL_CIPHER_free(s->cipher_list); ++ ++ if (s->cipher_list_by_id) ++ sk_SSL_CIPHER_free(s->cipher_list_by_id); ++ ++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); ++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); ++ } ++ } + #endif + + /* Worst case, we will use the NULL compression, but if we have other +@@ -1134,16 +1187,22 @@ int ssl3_send_server_hello(SSL *s) + unsigned char *buf; + unsigned char *p,*d; + int i,sl; +- unsigned long l,Time; ++ unsigned long l; ++#ifdef OPENSSL_NO_TLSEXT ++ unsigned long Time; ++#endif + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + buf=(unsigned char *)s->init_buf->data; ++#ifdef OPENSSL_NO_TLSEXT + p=s->s3->server_random; ++ /* Generate server_random if it was not needed previously */ + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + return -1; ++#endif + /* Do the message type and length last */ + d=p= &(buf[4]); + +Index: openssl-SNAP-20081111/ssl/ssl_err.c +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/ssl_err.c ++++ openssl-SNAP-20081111/ssl/ssl_err.c +@@ -263,6 +263,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, ++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"}, + {0,NULL} + }; + +Index: openssl-SNAP-20081111/ssl/ssl.h +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/ssl.h ++++ openssl-SNAP-20081111/ssl/ssl.h +@@ -355,6 +355,7 @@ extern "C" { + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ + typedef struct ssl_st *ssl_crock_st; ++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; + + /* used to hold info on the particular ciphers used */ + typedef struct ssl_cipher_st +@@ -378,6 +379,8 @@ typedef struct ssl_cipher_st + + DECLARE_STACK_OF(SSL_CIPHER) + ++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); ++ + /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ + typedef struct ssl_method_st + { +@@ -1145,6 +1148,13 @@ struct ssl_st + void *tlsext_opaque_prf_input; + size_t tlsext_opaque_prf_input_len; + ++ /* TLS Session Ticket extension override */ ++ TLS_SESSION_TICKET_EXT *tlsext_session_ticket; ++ ++ /* TLS pre-shared secret session resumption */ ++ tls_session_secret_cb_fn tls_session_secret_cb; ++ void *tls_session_secret_cb_arg; ++ + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ + #define session_ctx initial_ctx + #else +@@ -1746,6 +1756,16 @@ void *SSL_COMP_get_compression_methods(v + int SSL_COMP_add_compression_method(int id,void *cm); + #endif + ++/* NOTE: This function will be removed; it is only here for backwards ++ * compatibility for the API during testing. */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len); ++ ++/* TLS extensions functions */ ++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); ++ ++/* Pre-shared secret session resumption functions */ ++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); ++ + /* BEGIN ERROR CODES */ + /* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. +@@ -1948,6 +1968,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_TLS1_PRF 284 + #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 + #define SSL_F_WRITE_PENDING 212 ++#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213 + + /* Reason codes. */ + #define SSL_R_APP_DATA_IN_HANDSHAKE 100 +Index: openssl-SNAP-20081111/ssl/ssl_sess.c +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/ssl_sess.c ++++ openssl-SNAP-20081111/ssl/ssl_sess.c +@@ -834,6 +834,62 @@ long SSL_CTX_get_timeout(const SSL_CTX * + return(s->session_timeout); + } + ++#ifndef OPENSSL_NO_TLSEXT ++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg) ++ { ++ if (s == NULL) return(0); ++ s->tls_session_secret_cb = tls_session_secret_cb; ++ s->tls_session_secret_cb_arg = arg; ++ return(1); ++ } ++ ++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len) ++ { ++ if (s->version >= TLS1_VERSION) ++ { ++ if (s->tlsext_session_ticket) ++ { ++ OPENSSL_free(s->tlsext_session_ticket); ++ s->tlsext_session_ticket = NULL; ++ } ++ ++ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len); ++ if (!s->tlsext_session_ticket) ++ { ++ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE); ++ return 0; ++ } ++ ++ if (ext_data) ++ { ++ s->tlsext_session_ticket->length = ext_len; ++ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1; ++ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len); ++ } ++ else ++ { ++ s->tlsext_session_ticket->length = 0; ++ s->tlsext_session_ticket->data = NULL; ++ } ++ ++ return 1; ++ } ++ ++ return 0; ++ } ++ ++/* NOTE: This function will be removed; it is only here for backwards ++ * compatibility for the API during testing. */ ++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len) ++ { ++ if (ext_type != TLSEXT_TYPE_session_ticket) ++ return 0; ++ ++ return SSL_set_session_ticket_ext(s, ext_data, ext_len); ++ } ++#endif /* OPENSSL_NO_TLSEXT */ ++ + typedef struct timeout_param_st + { + SSL_CTX *ctx; +Index: openssl-SNAP-20081111/ssl/t1_lib.c +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/t1_lib.c ++++ openssl-SNAP-20081111/ssl/t1_lib.c +@@ -154,6 +154,12 @@ int tls1_new(SSL *s) + + void tls1_free(SSL *s) + { ++#ifndef OPENSSL_NO_TLSEXT ++ if (s->tlsext_session_ticket) ++ { ++ OPENSSL_free(s->tlsext_session_ticket); ++ } ++#endif /* OPENSSL_NO_TLSEXT */ + ssl3_free(s); + } + +@@ -357,8 +363,23 @@ unsigned char *ssl_add_clienthello_tlsex + int ticklen; + if (s->session && s->session->tlsext_tick) + ticklen = s->session->tlsext_ticklen; ++ else if (s->session && s->tlsext_session_ticket && ++ s->tlsext_session_ticket->data) ++ { ++ ticklen = s->tlsext_session_ticket->length; ++ s->session->tlsext_tick = OPENSSL_malloc(ticklen); ++ if (!s->session->tlsext_tick) ++ return NULL; ++ memcpy(s->session->tlsext_tick, ++ s->tlsext_session_ticket->data, ++ ticklen); ++ s->session->tlsext_ticklen = ticklen; ++ } + else + ticklen = 0; ++ if (ticklen == 0 && s->tlsext_session_ticket && ++ s->tlsext_session_ticket->data == NULL) ++ goto skip_ext; + /* Check for enough room 2 for extension type, 2 for len + * rest for ticket + */ +@@ -371,6 +392,7 @@ unsigned char *ssl_add_clienthello_tlsex + ret += ticklen; + } + } ++ skip_ext: + + #ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) +@@ -1435,6 +1457,15 @@ int tls1_process_ticket(SSL *s, unsigned + s->tlsext_ticket_expected = 1; + return 0; /* Cache miss */ + } ++ if (s->tls_session_secret_cb) ++ { ++ /* Indicate cache miss here and instead of ++ * generating the session from ticket now, ++ * trigger abbreviated handshake based on ++ * external mechanism to calculate the master ++ * secret later. */ ++ return 0; ++ } + return tls_decrypt_ticket(s, p, size, session_id, len, + ret); + } +Index: openssl-SNAP-20081111/ssl/tls1.h +=================================================================== +--- openssl-SNAP-20081111.orig/ssl/tls1.h ++++ openssl-SNAP-20081111/ssl/tls1.h +@@ -512,6 +512,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T + #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ + #endif + ++/* TLS Session Ticket extension struct */ ++struct tls_session_ticket_ext_st ++ { ++ unsigned short length; ++ void *data; ++ }; ++ + #ifdef __cplusplus + } + #endif +Index: openssl-SNAP-20081111/util/ssleay.num +=================================================================== +--- openssl-SNAP-20081111.orig/util/ssleay.num ++++ openssl-SNAP-20081111/util/ssleay.num +@@ -254,3 +254,5 @@ PEM_read_bio_SSL_SESSION + SSL_CTX_set_psk_server_callback 303 EXIST::FUNCTION:PSK + SSL_get_psk_identity 304 EXIST::FUNCTION:PSK + PEM_write_SSL_SESSION 305 EXIST:!WIN16:FUNCTION: ++SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT ++SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT diff --git a/src/Makefile b/src/Makefile index bd1c160cd514..f47da7b5ac73 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ -SUBDIRS=common crypto drivers hlr_auc_gw eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils wps +SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils wps all: - @echo Nothing to be made. + for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done clean: for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done diff --git a/src/hlr_auc_gw/Makefile b/src/ap/Makefile similarity index 65% rename from src/hlr_auc_gw/Makefile rename to src/ap/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/hlr_auc_gw/Makefile +++ b/src/ap/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/hostapd/accounting.c b/src/ap/accounting.c similarity index 96% rename from hostapd/accounting.c rename to src/ap/accounting.c index ce71678af4e9..7939c680f580 100644 --- a/hostapd/accounting.c +++ b/src/ap/accounting.c @@ -1,6 +1,6 @@ /* * hostapd / RADIUS Accounting - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -12,15 +12,18 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "hostapd.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "drivers/driver.h" #include "radius/radius.h" #include "radius/radius_client.h" -#include "eloop.h" -#include "accounting.h" +#include "hostapd.h" #include "ieee802_1x.h" -#include "driver.h" +#include "ap_config.h" +#include "sta_info.h" +#include "accounting.h" /* Default interval in seconds for polling TX/RX octets from the driver if @@ -175,7 +178,6 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd, fail: radius_msg_free(msg); - os_free(msg); return NULL; } @@ -184,7 +186,7 @@ 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)) + if (hapd->drv.read_sta_data(hapd, data, sta->addr)) return -1; if (sta->last_rx_bytes > data->rx_bytes) @@ -247,7 +249,7 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) 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); + hapd->drv.sta_clear_stats(hapd, sta->addr); if (!hapd->conf->radius->acct_server) return; @@ -364,7 +366,6 @@ static void accounting_sta_report(struct hostapd_data *hapd, fail: radius_msg_free(msg); - os_free(msg); } @@ -425,7 +426,7 @@ 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) { + if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { printf("Unknown RADIUS message code\n"); return RADIUS_RX_UNKNOWN; } @@ -460,7 +461,6 @@ static void accounting_report_state(struct hostapd_data *hapd, int on) { printf("Could not add Acct-Terminate-Cause\n"); radius_msg_free(msg); - os_free(msg); return; } @@ -497,14 +497,3 @@ 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/hostapd/accounting.h b/src/ap/accounting.h similarity index 64% rename from hostapd/accounting.h rename to src/ap/accounting.h index 51e6b4d49870..f3d60f0155a6 100644 --- a/hostapd/accounting.h +++ b/src/ap/accounting.h @@ -15,12 +15,31 @@ #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); +#ifdef CONFIG_NO_ACCOUNTING +static inline void accounting_sta_start(struct hostapd_data *hapd, + struct sta_info *sta) +{ +} + +static inline void accounting_sta_stop(struct hostapd_data *hapd, + struct sta_info *sta) +{ +} + +static inline int accounting_init(struct hostapd_data *hapd) +{ + return 0; +} + +static inline void accounting_deinit(struct hostapd_data *hapd) +{ +} +#else /* CONFIG_NO_ACCOUNTING */ +void accounting_sta_start(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 /* CONFIG_NO_ACCOUNTING */ #endif /* ACCOUNTING_H */ diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c new file mode 100644 index 000000000000..59969933e2f9 --- /dev/null +++ b/src/ap/ap_config.c @@ -0,0 +1,605 @@ +/* + * hostapd / Configuration helper functions + * Copyright (c) 2003-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "crypto/sha1.h" +#include "radius/radius_client.h" +#include "common/ieee802_11_defs.h" +#include "common/eapol_common.h" +#include "eap_common/eap_wsc_common.h" +#include "eap_server/eap.h" +#include "wpa_auth.h" +#include "sta_info.h" +#include "ap_config.h" + + +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; +} + + +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_SERVER_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_SERVER_FAST */ +} + + +struct hostapd_config * hostapd_config_defaults(void) +{ + struct hostapd_config *conf; + struct hostapd_bss_config *bss; + int i; + const int aCWmin = 4, aCWmax = 10; + const struct hostapd_wmm_ac_params ac_bk = + { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ + const struct hostapd_wmm_ac_params ac_be = + { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ + const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ + { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 }; + const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ + { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 }; + + conf = os_zalloc(sizeof(*conf)); + bss = os_zalloc(sizeof(*bss)); + if (conf == NULL || bss == NULL) { + wpa_printf(MSG_ERROR, "Failed to allocate memory for " + "configuration data."); + 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; + + for (i = 0; i < NUM_TX_QUEUES; i++) + conf->tx_queue[i].aifs = -1; /* use hw default */ + + conf->wmm_ac_params[0] = ac_be; + conf->wmm_ac_params[1] = ac_bk; + conf->wmm_ac_params[2] = ac_vi; + conf->wmm_ac_params[3] = ac_vo; + + conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED; + + 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_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; +} + + +static int hostapd_derive_psk(struct hostapd_ssid *ssid) +{ + 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_key(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_key(MSG_DEBUG, "PSK (from passphrase)", + ssid->wpa_psk->psk, PMK_LEN); + return 0; +} + + +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_DEBUG, "Using pre-configured WPA PSK " + "instead of passphrase"); + } else { + wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on " + "passphrase"); + if (hostapd_derive_psk(ssid) < 0) + return -1; + } + 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; +} + + +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); + hostapd_config_free_wep(&conf->ssid.wep); +#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->supported_rates); + os_free(conf->basic_rates); + + 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 && 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 = conf->ap_pin ? + os_strlen(conf->ap_pin) : 0; + 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/hostapd/config.h b/src/ap/ap_config.h similarity index 90% rename from hostapd/config.h rename to src/ap/ap_config.h index ea530d45d169..f509b5bbb197 100644 --- a/hostapd/config.h +++ b/src/ap/ap_config.h @@ -1,7 +1,6 @@ /* - * hostapd / Configuration file - * Copyright (c) 2003-2007, Jouni Malinen - * Copyright (c) 2007-2008, Intel Corporation + * hostapd / Configuration definitions and helpers functions + * Copyright (c) 2003-2009, Jouni Malinen * * 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 @@ -13,16 +12,15 @@ * See README and COPYING for more details. */ -#ifndef CONFIG_H -#define CONFIG_H +#ifndef HOSTAPD_CONFIG_H +#define HOSTAPD_CONFIG_H -#include "defs.h" +#include "common/defs.h" #include "ip_addr.h" -#include "wpa_common.h" +#include "common/wpa_common.h" -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif +#define MAX_STA_COUNT 2007 +#define MAX_VLAN_ID 4094 typedef u8 macaddr[ETH_ALEN]; @@ -171,6 +169,7 @@ struct hostapd_bss_config { struct hostapd_ip_addr own_ip_addr; char *nas_identifier; struct hostapd_radius_servers *radius; + int acct_interim_interval; struct hostapd_ssid ssid; @@ -198,6 +197,7 @@ struct hostapd_bss_config { int num_accept_mac; struct mac_acl_entry *deny_mac; int num_deny_mac; + int wds_sta; int auth_algs; /* bitfield of allowed IEEE 802.11 authentication * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ @@ -205,11 +205,7 @@ struct hostapd_bss_config { 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; + enum mfp_options ieee80211w; /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ unsigned int assoc_sa_query_max_timeout; /* dot11AssociationSAQueryRetryTimeout (in TUs) */ @@ -238,7 +234,9 @@ struct hostapd_bss_config { #endif /* CONFIG_IEEE80211R */ char *ctrl_interface; /* directory for UNIX domain sockets */ +#ifndef CONFIG_NATIVE_WINDOWS gid_t ctrl_interface_gid; +#endif /* CONFIG_NATIVE_WINDOWS */ int ctrl_interface_gid_set; char *ca_cert; @@ -272,6 +270,7 @@ struct hostapd_bss_config { int ignore_broadcast_ssid; int wmm_enabled; + int wmm_uapsd; struct hostapd_vlan *vlan, *vlan_tail; @@ -316,14 +315,6 @@ struct hostapd_bss_config { }; -typedef enum { - HOSTAPD_MODE_IEEE80211B, - HOSTAPD_MODE_IEEE80211G, - HOSTAPD_MODE_IEEE80211A, - NUM_HOSTAPD_MODES -} hostapd_hw_mode; - - /** * struct hostapd_config - Per-radio interface configuration */ @@ -336,7 +327,7 @@ struct hostapd_config { int fragm_threshold; u8 send_probe_response; u8 channel; - hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ + enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ enum { LONG_PREAMBLE = 0, SHORT_PREAMBLE = 1 @@ -353,9 +344,6 @@ struct hostapd_config { 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; @@ -379,16 +367,8 @@ struct hostapd_config { */ struct hostapd_wmm_ac_params wmm_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; }; @@ -396,7 +376,8 @@ struct hostapd_config { 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); +struct hostapd_config * hostapd_config_defaults(void); +void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); 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); @@ -412,4 +393,4 @@ 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 */ +#endif /* HOSTAPD_CONFIG_H */ diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c new file mode 100644 index 000000000000..f264a3e407ff --- /dev/null +++ b/src/ap/ap_drv_ops.c @@ -0,0 +1,621 @@ +/* + * hostapd - Driver operations + * Copyright (c) 2009-2010, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "drivers/driver.h" +#include "common/ieee802_11_defs.h" +#include "hostapd.h" +#include "ieee802_11.h" +#include "sta_info.h" +#include "ap_config.h" +#include "ap_drv_ops.h" + + +static int hostapd_sta_flags_to_drv(int flags) +{ + int res = 0; + if (flags & WLAN_STA_AUTHORIZED) + res |= WPA_STA_AUTHORIZED; + if (flags & WLAN_STA_WMM) + res |= WPA_STA_WMM; + if (flags & WLAN_STA_SHORT_PREAMBLE) + res |= WPA_STA_SHORT_PREAMBLE; + if (flags & WLAN_STA_MFP) + res |= WPA_STA_MFP; + return res; +} + + +static int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) +{ + struct wpabuf *beacon, *proberesp; + int ret; + + if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) + return 0; + + beacon = hapd->wps_beacon_ie; + proberesp = hapd->wps_probe_resp_ie; + + ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp); + + return ret; +} + + +static int hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, + size_t len) +{ + if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) + return 0; + return hapd->driver->send_mlme(hapd->drv_priv, msg, len); +} + + +static 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->hapd_send_eapol == NULL) + return 0; + return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data, + data_len, encrypt, + hapd->own_addr); +} + + +static int hostapd_set_authorized(struct hostapd_data *hapd, + struct sta_info *sta, int authorized) +{ + if (authorized) { + return hostapd_sta_set_flags(hapd, sta->addr, + hostapd_sta_flags_to_drv( + sta->flags), + WPA_STA_AUTHORIZED, ~0); + } + + return hostapd_sta_set_flags(hapd, sta->addr, + hostapd_sta_flags_to_drv(sta->flags), + 0, ~WPA_STA_AUTHORIZED); +} + + +static int hostapd_set_key(const char *ifname, struct hostapd_data *hapd, + enum wpa_alg alg, const u8 *addr, int key_idx, + int set_tx, const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + if (hapd->driver == NULL || hapd->driver->set_key == NULL) + return 0; + return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr, + key_idx, set_tx, seq, seq_len, key, + key_len); +} + + +static 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 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 int hostapd_set_sta_flags(struct hostapd_data *hapd, + struct sta_info *sta) +{ + int set_flags, total_flags, flags_and, flags_or; + total_flags = hostapd_sta_flags_to_drv(sta->flags); + set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP; + if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || + sta->auth_alg == WLAN_AUTH_FT) && + sta->flags & WLAN_STA_AUTHORIZED) + set_flags |= WPA_STA_AUTHORIZED; + flags_or = total_flags & set_flags; + flags_and = total_flags | ~set_flags; + return hostapd_sta_set_flags(hapd, sta->addr, total_flags, + flags_or, flags_and); +} + + +static int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, + const char *ifname, int enabled) +{ + struct wpa_bss_params params; + os_memset(¶ms, 0, sizeof(params)); + params.ifname = ifname; + params.enabled = enabled; + if (enabled) { + params.wpa = hapd->conf->wpa; + params.ieee802_1x = hapd->conf->ieee802_1x; + params.wpa_group = hapd->conf->wpa_group; + params.wpa_pairwise = hapd->conf->wpa_pairwise; + params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt; + params.rsn_preauth = hapd->conf->rsn_preauth; + } + return hostapd_set_ieee8021x(hapd, ¶ms); +} + + +static 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 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); +} + + +static int hostapd_set_bss_params(struct hostapd_data *hapd, + int use_protection) +{ + int ret = 0; + int preamble; +#ifdef CONFIG_IEEE80211N + u8 buf[60], *ht_capab, *ht_oper, *pos; + + pos = buf; + ht_capab = pos; + pos = hostapd_eid_ht_capabilities(hapd, pos); + ht_oper = pos; + pos = hostapd_eid_ht_operation(hapd, pos); + if (pos > ht_oper && ht_oper > ht_capab && + hostapd_set_ht_params(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"); + ret = -1; + } + +#endif /* CONFIG_IEEE80211N */ + + if (hostapd_set_cts_protect(hapd, use_protection)) { + wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel " + "driver"); + ret = -1; + } + + 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"); + ret = -1; + } + + 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"); + ret = -1; + } + + return ret; +} + + +static int hostapd_set_beacon(struct hostapd_data *hapd, + const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, int dtim_period, + int beacon_int) +{ + if (hapd->driver == NULL || hapd->driver->set_beacon == NULL) + return 0; + return hapd->driver->set_beacon(hapd->drv_priv, + head, head_len, tail, tail_len, + dtim_period, beacon_int); +} + + +static int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname) +{ + char force_ifname[IFNAMSIZ]; + u8 if_addr[ETH_ALEN]; + return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, NULL, NULL, NULL, + force_ifname, if_addr); +} + +static int hostapd_vlan_if_remove(struct hostapd_data *hapd, + const char *ifname) +{ + return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname); +} + + +static int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, + int aid, int val) +{ + if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL) + return 0; + return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val); +} + + +static 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 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 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, hapd->own_addr, addr, + reason); +} + + +static 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, hapd->own_addr, addr, + reason); +} + + +static int hostapd_sta_add(struct hostapd_data *hapd, + const u8 *addr, u16 aid, u16 capability, + const u8 *supp_rates, size_t supp_rates_len, + u16 listen_interval, + const struct ieee80211_ht_capabilities *ht_capab) +{ + struct hostapd_sta_add_params params; + + if (hapd->driver == NULL) + return 0; + if (hapd->driver->sta_add == NULL) + return 0; + + os_memset(¶ms, 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.listen_interval = listen_interval; + params.ht_capabilities = ht_capab; + return hapd->driver->sta_add(hapd->drv_priv, ¶ms); +} + + +static 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 int hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled) +{ + if (hapd->driver == NULL || + hapd->driver->hapd_set_countermeasures == NULL) + return 0; + return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled); +} + + +void hostapd_set_driver_ops(struct hostapd_driver_ops *ops) +{ + ops->set_ap_wps_ie = hostapd_set_ap_wps_ie; + ops->send_mgmt_frame = hostapd_send_mgmt_frame; + ops->send_eapol = hostapd_send_eapol; + ops->set_authorized = hostapd_set_authorized; + ops->set_key = hostapd_set_key; + ops->read_sta_data = hostapd_read_sta_data; + ops->sta_clear_stats = hostapd_sta_clear_stats; + ops->set_sta_flags = hostapd_set_sta_flags; + ops->set_drv_ieee8021x = hostapd_set_drv_ieee8021x; + ops->set_radius_acl_auth = hostapd_set_radius_acl_auth; + ops->set_radius_acl_expire = hostapd_set_radius_acl_expire; + ops->set_bss_params = hostapd_set_bss_params; + ops->set_beacon = hostapd_set_beacon; + ops->vlan_if_add = hostapd_vlan_if_add; + ops->vlan_if_remove = hostapd_vlan_if_remove; + ops->set_wds_sta = hostapd_set_wds_sta; + ops->set_sta_vlan = hostapd_set_sta_vlan; + ops->get_inact_sec = hostapd_get_inact_sec; + ops->sta_deauth = hostapd_sta_deauth; + ops->sta_disassoc = hostapd_sta_disassoc; + ops->sta_add = hostapd_sta_add; + ops->sta_remove = hostapd_sta_remove; + ops->set_countermeasures = hostapd_set_countermeasures; +} + + +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->drv_priv, enabled); +} + + +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->drv_priv, elem, elem_len); +} + + +int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len) +{ + if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL) + return 0; + return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len); +} + + +int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len) +{ + if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL) + return 0; + return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len); +} + + +int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, + const char *ifname, const u8 *addr, void *bss_ctx, + void **drv_priv, char *force_ifname, u8 *if_addr) +{ + if (hapd->driver == NULL || hapd->driver->if_add == NULL) + return -1; + return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr, + bss_ctx, drv_priv, force_ifname, if_addr); +} + + +int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, + const char *ifname) +{ + if (hapd->driver == NULL || hapd->driver->if_remove == NULL) + return -1; + return hapd->driver->if_remove(hapd->drv_priv, type, ifname); +} + + +int hostapd_set_ieee8021x(struct hostapd_data *hapd, + struct wpa_bss_params *params) +{ + if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL) + return 0; + return hapd->driver->set_ieee8021x(hapd->drv_priv, params); +} + + +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); +} + + +int hostapd_flush(struct hostapd_data *hapd) +{ + if (hapd->driver == NULL || hapd->driver->flush == NULL) + return 0; + return hapd->driver->flush(hapd->drv_priv); +} + + +int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, + int channel, int ht_enabled, int sec_channel_offset) +{ + struct hostapd_freq_params data; + if (hapd->driver == NULL) + return 0; + if (hapd->driver->set_freq == NULL) + return 0; + os_memset(&data, 0, sizeof(data)); + data.mode = mode; + data.freq = freq; + data.channel = channel; + data.ht_enabled = ht_enabled; + data.sec_channel_offset = sec_channel_offset; + return hapd->driver->set_freq(hapd->drv_priv, &data); +} + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +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); +} + + +int hostapd_set_ht_params(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(hapd->drv_priv, + ht_capab, ht_capab_len, + ht_oper, ht_oper_len); +} + + +int hostapd_drv_none(struct hostapd_data *hapd) +{ + return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0; +} + + +int hostapd_driver_scan(struct hostapd_data *hapd, + struct wpa_driver_scan_params *params) +{ + if (hapd->driver && hapd->driver->scan2) + return hapd->driver->scan2(hapd->drv_priv, params); + return -1; +} + + +struct wpa_scan_results * hostapd_driver_get_scan_results( + struct hostapd_data *hapd) +{ + if (hapd->driver && hapd->driver->get_scan_results2) + return hapd->driver->get_scan_results2(hapd->drv_priv); + return NULL; +} diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h new file mode 100644 index 000000000000..9b75d096a009 --- /dev/null +++ b/src/ap/ap_drv_ops.h @@ -0,0 +1,67 @@ +/* + * hostapd - Driver operations + * Copyright (c) 2009, Jouni Malinen + * + * 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_DRV_OPS +#define AP_DRV_OPS + +enum wpa_driver_if_type; +struct wpa_bss_params; +struct wpa_driver_scan_params; + +void hostapd_set_driver_ops(struct hostapd_driver_ops *ops); +int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); +int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, + size_t elem_len); +int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len); +int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len); +int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, + const char *ifname, const u8 *addr, void *bss_ctx, + void **drv_priv, char *force_ifname, u8 *if_addr); +int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, + const char *ifname); +int hostapd_set_ieee8021x(struct hostapd_data *hapd, + struct wpa_bss_params *params); +int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, + const u8 *addr, int idx, u8 *seq); +int hostapd_flush(struct hostapd_data *hapd); +int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, + int channel, int ht_enabled, int sec_channel_offset); +int hostapd_set_rts(struct hostapd_data *hapd, int rts); +int hostapd_set_frag(struct hostapd_data *hapd, int frag); +int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, + int total_flags, int flags_or, int flags_and); +int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, + int *basic_rates, int mode); +int hostapd_set_country(struct hostapd_data *hapd, const char *country); +int hostapd_set_cts_protect(struct hostapd_data *hapd, int value); +int hostapd_set_preamble(struct hostapd_data *hapd, int value); +int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value); +int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, + int cw_min, int cw_max, int burst_time); +int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, + const u8 *mask); +struct hostapd_hw_modes * +hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, + u16 *flags); +int hostapd_driver_commit(struct hostapd_data *hapd); +int hostapd_set_ht_params(struct hostapd_data *hapd, + const u8 *ht_capab, size_t ht_capab_len, + const u8 *ht_oper, size_t ht_oper_len); +int hostapd_drv_none(struct hostapd_data *hapd); +int hostapd_driver_scan(struct hostapd_data *hapd, + struct wpa_driver_scan_params *params); +struct wpa_scan_results * hostapd_driver_get_scan_results( + struct hostapd_data *hapd); + +#endif /* AP_DRV_OPS */ diff --git a/hostapd/ap_list.c b/src/ap/ap_list.c similarity index 71% rename from hostapd/ap_list.c rename to src/ap/ap_list.c index 4f217dc54121..5297dbf3bf5f 100644 --- a/hostapd/ap_list.c +++ b/src/ap/ap_list.c @@ -1,9 +1,8 @@ /* * hostapd / AP table - * Copyright (c) 2002-2003, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * 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 @@ -15,52 +14,19 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "drivers/driver.h" #include "hostapd.h" +#include "ap_config.h" #include "ieee802_11.h" -#include "eloop.h" -#include "ap_list.h" -#include "hw_features.h" +#include "sta_info.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, -}; +#include "ap_list.h" /* AP list is a double linked list with head->prev pointing to the end of the @@ -69,29 +35,11 @@ enum ieee80211_phytype { * 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; @@ -108,16 +56,7 @@ static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap) } -#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 * ap_get_ap(struct hostapd_iface *iface, const u8 *ap) { struct ap_info *s; @@ -257,7 +196,7 @@ int ap_ap_for_each(struct hostapd_iface *iface, } -static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr) +static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr) { struct ap_info *ap; @@ -275,8 +214,6 @@ static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr) 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); } @@ -285,7 +222,7 @@ static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr) void ap_list_process_beacon(struct hostapd_iface *iface, - struct ieee80211_mgmt *mgmt, + const struct ieee80211_mgmt *mgmt, struct ieee802_11_elems *elems, struct hostapd_frame_info *fi) { @@ -357,15 +294,11 @@ void ap_list_process_beacon(struct hostapd_iface *iface, 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) { + if (!new_ap && 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); @@ -381,7 +314,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface, } #ifdef CONFIG_IEEE80211N - if (!iface->olbc_ht && ap_list_beacon_olbc_ht(iface, ap)) { + if (!iface->olbc_ht && !ap->ht_support) { iface->olbc_ht = 1; hostapd_ht_operation_update(iface); wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR @@ -409,18 +342,12 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) 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); } @@ -432,10 +359,8 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) 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)) + if (!ap->ht_support) olbc_ht = 1; -#endif /* CONFIG_IEEE80211N */ ap = ap->next; } if (!olbc && iface->olbc) { @@ -470,32 +395,3 @@ 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/hostapd/ap_list.h b/src/ap/ap_list.h similarity index 86% rename from hostapd/ap_list.h rename to src/ap/ap_list.h index 93704f8bb612..f49f58b54e43 100644 --- a/hostapd/ap_list.h +++ b/src/ap/ap_list.h @@ -3,7 +3,6 @@ * Copyright (c) 2002-2003, Jouni Malinen * 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 @@ -39,7 +38,6 @@ struct ap_info { 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; @@ -56,16 +54,25 @@ struct ap_info { struct ieee802_11_elems; struct hostapd_frame_info; -struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta); +struct ap_info * ap_get_ap(struct hostapd_iface *iface, const 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, + const struct ieee80211_mgmt *mgmt, struct ieee802_11_elems *elems, struct hostapd_frame_info *fi); +#ifdef NEED_AP_MLME 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); +#else /* NEED_AP_MLME */ +static inline int ap_list_init(struct hostapd_iface *iface) +{ + return 0; +} + +static inline void ap_list_deinit(struct hostapd_iface *iface) +{ +} +#endif /* NEED_AP_MLME */ #endif /* AP_LIST_H */ diff --git a/hostapd/mlme.c b/src/ap/ap_mlme.c similarity index 95% rename from hostapd/mlme.c rename to src/ap/ap_mlme.c index d883931cf414..2b09b11e79c1 100644 --- a/hostapd/mlme.c +++ b/src/ap/ap_mlme.c @@ -14,14 +14,17 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "hostapd.h" +#include "utils/common.h" +#include "common/ieee802_11_defs.h" #include "ieee802_11.h" -#include "wpa.h" -#include "mlme.h" +#include "wpa_auth.h" +#include "sta_info.h" +#include "ap_mlme.h" +#ifndef CONFIG_NO_HOSTAPD_LOGGER static const char * mlme_auth_alg_str(int alg) { switch (alg) { @@ -35,6 +38,7 @@ static const char * mlme_auth_alg_str(int alg) return "unknown"; } +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ /** diff --git a/hostapd/mlme.h b/src/ap/ap_mlme.h similarity index 100% rename from hostapd/mlme.h rename to src/ap/ap_mlme.h diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c new file mode 100644 index 000000000000..0ab0668acc56 --- /dev/null +++ b/src/ap/authsrv.c @@ -0,0 +1,216 @@ +/* + * Authentication server setup + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "crypto/tls.h" +#include "eap_server/eap.h" +#include "eap_server/eap_sim_db.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "radius/radius_server.h" +#include "hostapd.h" +#include "ap_config.h" +#include "sta_info.h" +#include "authsrv.h" + + +#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA) +#define EAP_SIM_DB +#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */ + + +#ifdef EAP_SIM_DB +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) { +#ifdef RADIUS_SERVER + radius_server_eap_pending_cb(hapd->radius_srv, session_ctx); +#endif /* RADIUS_SERVER */ + } +} +#endif /* EAP_SIM_DB */ + + +#ifdef RADIUS_SERVER + +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 hostapd_setup_radius_srv(struct hostapd_data *hapd) +{ + struct radius_server_conf srv; + struct hostapd_bss_config *conf = hapd->conf; + 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.msg_ctx = hapd->msg_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; +} + +#endif /* RADIUS_SERVER */ + + +int authsrv_init(struct hostapd_data *hapd) +{ +#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"); + authsrv_deinit(hapd); + return -1; + } + + os_memset(¶ms, 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, ¶ms)) { + wpa_printf(MSG_ERROR, "Failed to set TLS parameters"); + authsrv_deinit(hapd); + return -1; + } + + if (tls_global_set_verify(hapd->ssl_ctx, + hapd->conf->check_crl)) { + wpa_printf(MSG_ERROR, "Failed to enable check_crl"); + authsrv_deinit(hapd); + return -1; + } + } +#endif /* EAP_TLS_FUNCS */ + +#ifdef EAP_SIM_DB + 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"); + authsrv_deinit(hapd); + return -1; + } + } +#endif /* EAP_SIM_DB */ + +#ifdef RADIUS_SERVER + if (hapd->conf->radius_server_clients && + hostapd_setup_radius_srv(hapd)) + return -1; +#endif /* RADIUS_SERVER */ + + return 0; +} + + +void authsrv_deinit(struct hostapd_data *hapd) +{ +#ifdef RADIUS_SERVER + radius_server_deinit(hapd->radius_srv); + hapd->radius_srv = NULL; +#endif /* RADIUS_SERVER */ + +#ifdef EAP_TLS_FUNCS + if (hapd->ssl_ctx) { + tls_deinit(hapd->ssl_ctx); + hapd->ssl_ctx = NULL; + } +#endif /* EAP_TLS_FUNCS */ + +#ifdef EAP_SIM_DB + if (hapd->eap_sim_db_priv) { + eap_sim_db_deinit(hapd->eap_sim_db_priv); + hapd->eap_sim_db_priv = NULL; + } +#endif /* EAP_SIM_DB */ +} diff --git a/src/crypto/rc4.h b/src/ap/authsrv.h similarity index 58% rename from src/crypto/rc4.h rename to src/ap/authsrv.h index 35c7e41fba06..be3051ebfa2e 100644 --- a/src/crypto/rc4.h +++ b/src/ap/authsrv.h @@ -1,6 +1,6 @@ /* - * RC4 stream cipher - * Copyright (c) 2002-2005, Jouni Malinen + * Authentication server setup + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -12,10 +12,10 @@ * See README and COPYING for more details. */ -#ifndef RC4_H -#define RC4_H +#ifndef AUTHSRV_H +#define AUTHSRV_H -void rc4_skip(const u8 *key, size_t keylen, size_t skip, - u8 *data, size_t data_len); +int authsrv_init(struct hostapd_data *hapd); +void authsrv_deinit(struct hostapd_data *hapd); -#endif /* RC4_H */ +#endif /* AUTHSRV_H */ diff --git a/hostapd/beacon.c b/src/ap/beacon.c similarity index 80% rename from hostapd/beacon.c rename to src/ap/beacon.c index 1f82d9cb7238..004cc8a5f336 100644 --- a/hostapd/beacon.c +++ b/src/ap/beacon.c @@ -2,8 +2,7 @@ * 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 - * Copyright (c) 2007-2008, Intel Corporation + * Copyright (c) 2008-2009, Jouni Malinen * * 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 @@ -15,19 +14,21 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" #ifndef CONFIG_NATIVE_WINDOWS +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "drivers/driver.h" #include "hostapd.h" #include "ieee802_11.h" -#include "wpa.h" -#include "wme.h" -#include "beacon.h" -#include "hw_features.h" -#include "driver.h" +#include "wpa_auth.h" +#include "wmm.h" +#include "ap_config.h" #include "sta_info.h" -#include "wps_hostapd.h" +#include "beacon.h" static u8 ieee802_11_erp_info(struct hostapd_data *hapd) @@ -56,7 +57,8 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd) } break; } - if (hapd->iface->num_sta_no_short_preamble > 0) + if (hapd->iface->num_sta_no_short_preamble > 0 || + hapd->iconf->preamble == LONG_PREAMBLE) erp |= ERP_INFO_BARKER_PREAMBLE_MODE; return erp; @@ -191,20 +193,26 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, } -void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, - size_t len) +void handle_probe_req(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_mgmt *resp; struct ieee802_11_elems elems; char *ssid; - u8 *pos, *epos, *ie; + u8 *pos, *epos; + const u8 *ie; size_t ssid_len, ie_len; struct sta_info *sta = NULL; + size_t buflen; + size_t i; 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); + for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) + if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, + mgmt->sa, ie, ie_len) > 0) + return; if (!hapd->iconf->send_probe_response) return; @@ -258,7 +266,12 @@ void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, /* 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); + buflen = MAX_PROBERESP_LEN; +#ifdef CONFIG_WPS + if (hapd->wps_probe_resp_ie) + buflen += wpabuf_len(hapd->wps_probe_resp_ie); +#endif /* CONFIG_WPS */ + resp = os_zalloc(buflen); if (resp == NULL) return; epos = ((u8 *) resp) + MAX_PROBERESP_LEN; @@ -296,23 +309,26 @@ void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, /* Extended supported rates */ pos = hostapd_eid_ext_supp_rates(hapd, pos); + /* RSN, MDIE, WPA */ pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); +#ifdef CONFIG_IEEE80211N + pos = hostapd_eid_ht_capabilities(hapd, pos); + pos = hostapd_eid_ht_operation(hapd, pos); +#endif /* CONFIG_IEEE80211N */ + /* Wi-Fi Alliance WMM */ pos = hostapd_eid_wmm(hapd, pos); - pos = hostapd_eid_ht_capabilities_info(hapd, pos); - pos = hostapd_eid_ht_operation(hapd, pos); - #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; + os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), + wpabuf_len(hapd->wps_probe_resp_ie)); + pos += wpabuf_len(hapd->wps_probe_resp_ie); } #endif /* CONFIG_WPS */ - if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0) + if (hapd->drv.send_mgmt_frame(hapd, resp, pos - (u8 *) resp) < 0) perror("handle_probe_req: send"); os_free(resp); @@ -327,16 +343,18 @@ 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); + tail_len = BEACON_TAIL_BUF_SIZE; +#ifdef CONFIG_WPS + if (hapd->conf->wps_state && hapd->wps_beacon_ie) + tail_len += wpabuf_len(hapd->wps_beacon_ie); +#endif /* CONFIG_WPS */ + tailpos = tail = os_malloc(tail_len); if (head == NULL || tail == NULL) { wpa_printf(MSG_ERROR, "Failed to set beacon data"); os_free(head); @@ -392,68 +410,39 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) /* Extended supported rates */ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); + /* RSN, MDIE, WPA */ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - tailpos, NULL); +#ifdef CONFIG_IEEE80211N + tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); + tailpos = hostapd_eid_ht_operation(hapd, tailpos); +#endif /* CONFIG_IEEE80211N */ + /* Wi-Fi Alliance WMM */ tailpos = hostapd_eid_wmm(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; + os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), + wpabuf_len(hapd->wps_beacon_ie)); + tailpos += wpabuf_len(hapd->wps_beacon_ie); } #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"); + if (hapd->drv.set_beacon(hapd, (u8 *) head, head_len, + tail, tail_len, hapd->conf->dtim_period, + hapd->iconf->beacon_int)) + wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM " + "period"); 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"); + hapd->drv.set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) & + ERP_INFO_USE_PROTECTION)); } diff --git a/hostapd/beacon.h b/src/ap/beacon.h similarity index 66% rename from hostapd/beacon.h rename to src/ap/beacon.h index 18e0da2e89f6..c1510e194254 100644 --- a/hostapd/beacon.h +++ b/src/ap/beacon.h @@ -16,9 +16,21 @@ #ifndef BEACON_H #define BEACON_H -void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, - size_t len); +struct ieee80211_mgmt; + +void handle_probe_req(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len); +#ifdef NEED_AP_MLME void ieee802_11_set_beacon(struct hostapd_data *hapd); void ieee802_11_set_beacons(struct hostapd_iface *iface); +#else /* NEED_AP_MLME */ +static inline void ieee802_11_set_beacon(struct hostapd_data *hapd) +{ +} + +static inline void ieee802_11_set_beacons(struct hostapd_iface *iface) +{ +} +#endif /* NEED_AP_MLME */ #endif /* BEACON_H */ diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c new file mode 100644 index 000000000000..e50b0a70ca95 --- /dev/null +++ b/src/ap/ctrl_iface_ap.c @@ -0,0 +1,104 @@ +/* + * Control interface for shared AP commands + * Copyright (c) 2004-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "hostapd.h" +#include "ieee802_1x.h" +#include "wpa_auth.h" +#include "ieee802_11.h" +#include "sta_info.h" +#include "wps_hostapd.h" +#include "ctrl_iface_ap.h" + + +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; + res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, + buflen - len); + if (res >= 0) + len += res; + + return len; +} + + +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); +} + + +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); +} + + +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); +} diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h new file mode 100644 index 000000000000..8690beaad455 --- /dev/null +++ b/src/ap/ctrl_iface_ap.h @@ -0,0 +1,25 @@ +/* + * Control interface for shared AP commands + * Copyright (c) 2004-2009, Jouni Malinen + * + * 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_AP_H +#define CTRL_IFACE_AP_H + +int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, + char *buf, size_t buflen); +int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, + char *buf, size_t buflen); +int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, + char *buf, size_t buflen); + +#endif /* CTRL_IFACE_AP_H */ diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c new file mode 100644 index 000000000000..26ef5845abfd --- /dev/null +++ b/src/ap/drv_callbacks.c @@ -0,0 +1,457 @@ +/* + * hostapd / Callback functions for driver wrappers + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "radius/radius.h" +#include "drivers/driver.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" +#include "hostapd.h" +#include "ieee802_11.h" +#include "sta_info.h" +#include "accounting.h" +#include "tkip_countermeasures.h" +#include "iapp.h" +#include "ieee802_1x.h" +#include "wpa_auth.h" +#include "wmm.h" +#include "wps_hostapd.h" +#include "ap_config.h" + + +int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, + const u8 *ie, size_t ielen) +{ + struct sta_info *sta; + int new_assoc, res; + struct ieee802_11_elems elems; + + if (addr == NULL) { + /* + * This could potentially happen with unexpected event from the + * driver wrapper. This was seen at least in one case where the + * driver ended up being set to station mode while hostapd was + * running, so better make sure we stop processing such an + * event here. + */ + wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " + "no address"); + return -1; + } + + hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "associated"); + + ieee802_11_parse_elems(ie, ielen, &elems, 0); + if (elems.wps_ie) { + ie = elems.wps_ie - 2; + ielen = elems.wps_ie_len + 2; + wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); + } else if (elems.rsn_ie) { + ie = elems.rsn_ie - 2; + ielen = elems.rsn_ie_len + 2; + wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); + } else if (elems.wpa_ie) { + ie = elems.wpa_ie - 2; + ielen = elems.wpa_ie_len + 2; + wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); + } else { + ie = NULL; + ielen = 0; + wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " + "(Re)AssocReq"); + } + + sta = ap_get_sta(hapd, addr); + if (sta) { + accounting_sta_stop(hapd, sta); + } else { + sta = ap_sta_add(hapd, addr); + if (sta == NULL) + return -1; + } + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + + if (hapd->conf->wpa) { + if (ie == NULL || ielen == 0) { + if (hapd->conf->wps_state) { + wpa_printf(MSG_DEBUG, "STA did not include " + "WPA/RSN IE in (Re)Association " + "Request - possible WPS use"); + sta->flags |= WLAN_STA_MAYBE_WPS; + goto skip_wpa_check; + } + + wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); + return -1; + } + if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && + os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + sta->flags |= WLAN_STA_WPS; + goto skip_wpa_check; + } + + 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_ERROR, "Failed to initialize WPA state " + "machine"); + return -1; + } + res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, + ie, ielen, NULL, 0); + if (res != WPA_IE_OK) { + int resp; + wpa_printf(MSG_DEBUG, "WPA/RSN information element " + "rejected? (res %u)", res); + wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); + if (res == WPA_INVALID_GROUP) + resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; + else if (res == WPA_INVALID_PAIRWISE) + resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; + else if (res == WPA_INVALID_AKMP) + resp = WLAN_REASON_AKMP_NOT_VALID; +#ifdef CONFIG_IEEE80211W + else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) + resp = WLAN_REASON_INVALID_IE; + else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) + resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; +#endif /* CONFIG_IEEE80211W */ + else + resp = WLAN_REASON_INVALID_IE; + hapd->drv.sta_disassoc(hapd, sta->addr, resp); + ap_free_sta(hapd, sta); + return -1; + } + } else if (hapd->conf->wps_state) { + if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && + os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + sta->flags |= WLAN_STA_WPS; + } else + sta->flags |= WLAN_STA_MAYBE_WPS; + } +skip_wpa_check: + + new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; + wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); + + hostapd_new_assoc_sta(hapd, sta, !new_assoc); + + ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); + + return 0; +} + + +void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) +{ + struct sta_info *sta; + + hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "disassociated"); + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Disassociation notification for " + "unknown STA " MACSTR, MAC2STR(addr)); + return; + } + + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); + wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); + sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); + ap_free_sta(hapd, sta); +} + + +#ifdef HOSTAPD + +#ifdef NEED_AP_MLME + +static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) +{ + u16 fc, type, stype; + + /* + * PS-Poll frames are 16 bytes. All other frames are + * 24 bytes or longer. + */ + if (len < 16) + return NULL; + + fc = le_to_host16(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + switch (type) { + case WLAN_FC_TYPE_DATA: + if (len < 24) + return NULL; + switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { + case WLAN_FC_FROMDS | WLAN_FC_TODS: + case WLAN_FC_TODS: + return hdr->addr1; + case WLAN_FC_FROMDS: + return hdr->addr2; + default: + return NULL; + } + case WLAN_FC_TYPE_CTRL: + if (stype != WLAN_FC_STYPE_PSPOLL) + return NULL; + return hdr->addr1; + case WLAN_FC_TYPE_MGMT: + return hdr->addr3; + default: + return NULL; + } +} + + +#define HAPD_BROADCAST ((struct hostapd_data *) -1) + +static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, + const u8 *bssid) +{ + size_t i; + + if (bssid == NULL) + return NULL; + if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && + bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) + return HAPD_BROADCAST; + + for (i = 0; i < iface->num_bss; i++) { + if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) + return iface->bss[i]; + } + + return NULL; +} + + +static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, + const u8 *frame, size_t len) +{ + const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame; + u16 fc = le_to_host16(hdr->frame_control); + hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); + if (hapd == NULL || hapd == HAPD_BROADCAST) + return; + + ieee802_11_rx_from_unknown(hapd, hdr->addr2, + (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == + (WLAN_FC_TODS | WLAN_FC_FROMDS)); +} + + +static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) +{ + struct hostapd_iface *iface = hapd->iface; + const struct ieee80211_hdr *hdr; + const u8 *bssid; + struct hostapd_frame_info fi; + + hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; + bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); + if (bssid == NULL) + return; + + hapd = get_hapd_bssid(iface, bssid); + if (hapd == NULL) { + u16 fc; + fc = le_to_host16(hdr->frame_control); + + /* + * Drop frames to unknown BSSIDs except for Beacon frames which + * could be used to update neighbor information. + */ + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) + hapd = iface->bss[0]; + else + return; + } + + os_memset(&fi, 0, sizeof(fi)); + fi.datarate = rx_mgmt->datarate; + fi.ssi_signal = rx_mgmt->ssi_signal; + + if (hapd == HAPD_BROADCAST) { + size_t i; + for (i = 0; i < iface->num_bss; i++) + ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, + rx_mgmt->frame_len, &fi); + } else + ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi); +} + + +static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, + size_t len, u16 stype, int ok) +{ + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *) buf; + hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); + if (hapd == NULL || hapd == HAPD_BROADCAST) + return; + ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); +} + +#endif /* NEED_AP_MLME */ + + +static int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, + const u8 *ie, size_t ie_len) +{ + size_t i; + int ret = 0; + + for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { + if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, + sa, ie, ie_len) > 0) { + ret = 1; + break; + } + } + return ret; +} + + +static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) +{ + struct sta_info *sta = ap_get_sta(hapd, addr); + if (sta) + return 0; + + wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR + " - adding a new STA", MAC2STR(addr)); + sta = ap_sta_add(hapd, addr); + if (sta) { + hostapd_new_assoc_sta(hapd, sta, 0); + } else { + wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, + MAC2STR(addr)); + return -1; + } + + return 0; +} + + +static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, + const u8 *data, size_t data_len) +{ + struct hostapd_iface *iface = hapd->iface; + size_t j; + + for (j = 0; j < iface->num_bss; j++) { + if (ap_get_sta(iface->bss[j], src)) { + hapd = iface->bss[j]; + break; + } + } + + ieee802_1x_receive(hapd, src, data, data_len); +} + + +void wpa_supplicant_event(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) +{ + struct hostapd_data *hapd = ctx; + + switch (event) { + case EVENT_MICHAEL_MIC_FAILURE: + michael_mic_failure(hapd, data->michael_mic_failure.src, 1); + break; + case EVENT_SCAN_RESULTS: + if (hapd->iface->scan_cb) + hapd->iface->scan_cb(hapd->iface); + break; +#ifdef CONFIG_IEEE80211R + case EVENT_FT_RRB_RX: + wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src, + data->ft_rrb_rx.data, data->ft_rrb_rx.data_len); + break; +#endif /* CONFIG_IEEE80211R */ + case EVENT_WPS_BUTTON_PUSHED: + hostapd_wps_button_pushed(hapd); + break; +#ifdef NEED_AP_MLME + case EVENT_TX_STATUS: + switch (data->tx_status.type) { + case WLAN_FC_TYPE_MGMT: + hostapd_mgmt_tx_cb(hapd, data->tx_status.data, + data->tx_status.data_len, + data->tx_status.stype, + data->tx_status.ack); + break; + case WLAN_FC_TYPE_DATA: + hostapd_tx_status(hapd, data->tx_status.dst, + data->tx_status.data, + data->tx_status.data_len, + data->tx_status.ack); + break; + } + break; + case EVENT_RX_FROM_UNKNOWN: + hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame, + data->rx_from_unknown.len); + break; + case EVENT_RX_MGMT: + hostapd_mgmt_rx(hapd, &data->rx_mgmt); + break; +#endif /* NEED_AP_MLME */ + case EVENT_RX_PROBE_REQ: + hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, + data->rx_probe_req.ie, + data->rx_probe_req.ie_len); + break; + case EVENT_NEW_STA: + hostapd_event_new_sta(hapd, data->new_sta.addr); + break; + case EVENT_EAPOL_RX: + hostapd_event_eapol_rx(hapd, data->eapol_rx.src, + data->eapol_rx.data, + data->eapol_rx.data_len); + break; + case EVENT_ASSOC: + hostapd_notif_assoc(hapd, data->assoc_info.addr, + data->assoc_info.req_ies, + data->assoc_info.req_ies_len); + break; + case EVENT_DISASSOC: + if (data) + hostapd_notif_disassoc(hapd, data->disassoc_info.addr); + break; + case EVENT_DEAUTH: + if (data) + hostapd_notif_disassoc(hapd, data->deauth_info.addr); + break; + default: + wpa_printf(MSG_DEBUG, "Unknown event %d", event); + break; + } +} + +#endif /* HOSTAPD */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c new file mode 100644 index 000000000000..841f9c59c46b --- /dev/null +++ b/src/ap/hostapd.c @@ -0,0 +1,887 @@ +/* + * hostapd / Initialization and configuration + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" +#include "radius/radius_client.h" +#include "drivers/driver.h" +#include "hostapd.h" +#include "authsrv.h" +#include "sta_info.h" +#include "accounting.h" +#include "ap_list.h" +#include "beacon.h" +#include "iapp.h" +#include "ieee802_1x.h" +#include "ieee802_11_auth.h" +#include "vlan_init.h" +#include "wpa_auth.h" +#include "wps_hostapd.h" +#include "hw_features.h" +#include "wpa_auth_glue.h" +#include "ap_drv_ops.h" +#include "ap_config.h" + + +static int hostapd_flush_old_stations(struct hostapd_data *hapd); +static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); + +extern int wpa_debug_level; + + +int hostapd_reload_config(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + struct hostapd_config *newconf, *oldconf; + size_t j; + + if (iface->config_read_cb == NULL) + return -1; + newconf = iface->config_read_cb(iface->config_fname); + if (newconf == NULL) + return -1; + + /* + * Deauthenticate all stations since the new configuration may not + * allow them to use the BSS anymore. + */ + for (j = 0; j < iface->num_bss; j++) + hostapd_flush_old_stations(iface->bss[j]); + +#ifndef CONFIG_NO_RADIUS + /* TODO: update dynamic data based on changed configuration + * items (e.g., open/close sockets, etc.) */ + radius_client_flush(hapd->radius, 0); +#endif /* CONFIG_NO_RADIUS */ + + 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->ieee802_1x || hapd->conf->wpa) + hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1); + else + hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0); + + if (hapd->conf->wpa && hapd->wpa_auth == NULL) + hostapd_setup_wpa(hapd); + else if (hapd->conf->wpa) { + const u8 *wpa_ie; + size_t wpa_ie_len; + hostapd_reconfig_wpa(hapd); + 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."); + } 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); + hostapd_set_generic_elem(hapd, (u8 *) "", 0); + } + + ieee802_11_set_beacon(hapd); + hostapd_update_wps(hapd); + + if (hapd->conf->ssid.ssid_set && + hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len)) { + wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); + /* try to continue */ + } + + hostapd_config_free(oldconf); + + wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); + + return 0; +} + + +static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, + char *ifname) +{ + int i; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, + i == 0 ? 1 : 0, NULL, 0, NULL, 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 (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, + i, i == 0 ? 1 : 0, NULL, 0, + NULL, 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 && + hapd->drv.set_key(hapd->conf->iface, + hapd, WPA_ALG_WEP, NULL, idx, + idx == ssid->wep.idx, + NULL, 0, ssid->wep.key[idx], + ssid->wep.len[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 (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, + idx, idx == key->idx, NULL, 0, + key->key[idx], key->len[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) +{ + if (hapd->iface->ctrl_iface_deinit) + hapd->iface->ctrl_iface_deinit(hapd); + + iapp_deinit(hapd->iapp); + hapd->iapp = NULL; + accounting_deinit(hapd); + hostapd_deinit_wpa(hapd); + vlan_deinit(hapd); + hostapd_acl_deinit(hapd); +#ifndef CONFIG_NO_RADIUS + radius_client_deinit(hapd->radius); + hapd->radius = NULL; +#endif /* CONFIG_NO_RADIUS */ + + hostapd_deinit_wps(hapd); + + authsrv_deinit(hapd); + + if (hapd->interface_added && + hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { + wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s", + hapd->conf->iface); + } + + os_free(hapd->probereq_cb); + hapd->probereq_cb = NULL; +} + + +/** + * 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) { + hostapd_set_privacy(hapd, 1); + return 0; + } + + for (i = 0; i < 4; i++) { + if (hapd->conf->ssid.wep.key[i] && + hapd->drv.set_key(iface, hapd, WPA_ALG_WEP, NULL, i, + i == hapd->conf->ssid.wep.idx, NULL, 0, + hapd->conf->ssid.wep.key[i], + hapd->conf->ssid.wep.len[i])) { + 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) || hapd->drv_priv == NULL) + 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"); + + /* 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) { + u8 addr[ETH_ALEN]; + os_memset(addr, 0xff, ETH_ALEN); + hapd->drv.sta_deauth(hapd, addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + } + + return ret; +} + + +/** + * 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; + int auto_addr = 0; + + 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) { + if (j) + auto_addr++; + continue; + } + + for (i = 0; i < ETH_ALEN; i++) { + mask[i] |= + iface->conf->bss[j].bssid[i] ^ + hapd->own_addr[i]; + } + } + + if (!auto_addr) + goto skip_mask_ext; + + 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) { + wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", + bits); + 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; + +skip_mask_ext: + 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; + } + + if (!auto_addr) + return 0; + + 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; +} + + + + +/** + * 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; + char force_ifname[IFNAMSIZ]; + u8 if_addr[ETH_ALEN]; + + 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_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, + hapd->conf->iface, hapd->own_addr, hapd, + &hapd->drv_priv, force_ifname, if_addr)) { + wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" + MACSTR ")", MAC2STR(hapd->own_addr)); + return -1; + } + } + + hostapd_flush_old_stations(hapd); + hostapd_set_privacy(hapd, 0); + + hostapd_broadcast_wep_clear(hapd); + if (hostapd_setup_encryption(hapd->conf->iface, hapd)) + return -1; + + /* + * Fetch the SSID from the system and use it or, + * if one was specified in the config file, verify they + * 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 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; +#ifndef CONFIG_NO_RADIUS + hapd->radius = radius_client_init(hapd, conf->radius); + if (hapd->radius == NULL) { + wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); + return -1; + } +#endif /* CONFIG_NO_RADIUS */ + + if (hostapd_acl_init(hapd)) { + wpa_printf(MSG_ERROR, "ACL initialization failed."); + return -1; + } + if (hostapd_init_wps(hapd, conf)) + return -1; + + if (authsrv_init(hapd) < 0) + 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 (hapd->iface->ctrl_iface_init && + hapd->iface->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; + } + + ieee802_11_set_beacon(hapd); + + 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 setup_interface(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + size_t i; + char country[4]; + + /* + * Make sure that all BSSes get configured with a pointer to the same + * driver interface. + */ + for (i = 1; 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; + + 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 (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; + } + ret = hostapd_check_ht_capab(iface); + if (ret < 0) + return -1; + if (ret == 1) { + wpa_printf(MSG_DEBUG, "Interface initialization will " + "be completed in a callback"); + return 0; + } + } + return hostapd_setup_interface_complete(iface, 0); +} + + +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) +{ + struct hostapd_data *hapd = iface->bss[0]; + size_t j; + u8 *prev_addr; + + if (err) { + wpa_printf(MSG_ERROR, "Interface initialization failed"); + eloop_terminate(); + return -1; + } + + wpa_printf(MSG_DEBUG, "Completing interface initialization"); + if (hapd->iconf->channel) { + iface->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, iface->freq); + + if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, + hapd->iconf->channel, + hapd->iconf->ieee80211n, + hapd->iconf->secondary_channel)) { + wpa_printf(MSG_ERROR, "Could not set channel for " + "kernel driver"); + return -1; + } + } + + 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; + } + + wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", + iface->bss[0]->conf->iface); + + return 0; +} + + +/** + * 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. + */ +int hostapd_setup_interface(struct hostapd_iface *iface) +{ + int ret; + + ret = setup_interface(iface); + if (ret) { + wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", + iface->bss[0]->conf->iface); + return -1; + } + + return 0; +} + + +/** + * 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. + */ +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; + + hostapd_set_driver_ops(&hapd->drv); + hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; + hapd->iconf = conf; + hapd->conf = bss; + hapd->iface = hapd_iface; + hapd->driver = hapd->iconf->driver; + + return hapd; +} + + +void hostapd_interface_deinit(struct hostapd_iface *iface) +{ + size_t j; + + if (iface == NULL) + return; + + hostapd_cleanup_iface_pre(iface); + for (j = 0; j < iface->num_bss; j++) { + struct hostapd_data *hapd = iface->bss[j]; + hostapd_free_stas(hapd); + hostapd_flush_old_stations(hapd); + hostapd_cleanup(hapd); + } +} + + +void hostapd_interface_free(struct hostapd_iface *iface) +{ + size_t j; + for (j = 0; j < iface->num_bss; j++) + os_free(iface->bss[j]); + hostapd_cleanup_iface(iface); +} + + +/** + * 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 from ieee802_11.c for drivers that export MLME to hostapd and + * from drv_callbacks.c based on driver events 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) { + hapd->drv.sta_deauth(hapd, sta->addr, + WLAN_REASON_MICHAEL_MIC_FAILURE); + return; + } + + hostapd_prune_associations(hapd, sta->addr); + + /* 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); + + /* 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); +} diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h new file mode 100644 index 000000000000..d0d67c8228a4 --- /dev/null +++ b/src/ap/hostapd.h @@ -0,0 +1,276 @@ +/* + * hostapd / Initialization and configuration + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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/defs.h" + +struct wpa_driver_ops; +struct wpa_ctrl_dst; +struct radius_server_data; +struct upnp_wps_device_sm; +struct hapd_interfaces; +struct hostapd_data; +struct sta_info; +struct hostap_sta_driver_data; +struct ieee80211_ht_capabilities; +struct full_dynamic_vlan; + +struct hostapd_probereq_cb { + int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len); + void *ctx; +}; + +#define HOSTAPD_RATE_BASIC 0x00000001 + +struct hostapd_rate_data { + int rate; /* rate in 100 kbps */ + int flags; /* HOSTAPD_RATE_ flags */ +}; + +struct hostapd_frame_info { + u32 channel; + u32 datarate; + u32 ssi_signal; +}; + + +struct hostapd_driver_ops { + int (*set_ap_wps_ie)(struct hostapd_data *hapd); + int (*send_mgmt_frame)(struct hostapd_data *hapd, const void *msg, + size_t len); + int (*send_eapol)(struct hostapd_data *hapd, const u8 *addr, + const u8 *data, size_t data_len, int encrypt); + int (*set_authorized)(struct hostapd_data *hapd, struct sta_info *sta, + int authorized); + int (*set_key)(const char *ifname, struct hostapd_data *hapd, + enum wpa_alg alg, const u8 *addr, int key_idx, + int set_tx, const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len); + int (*read_sta_data)(struct hostapd_data *hapd, + struct hostap_sta_driver_data *data, + const u8 *addr); + int (*sta_clear_stats)(struct hostapd_data *hapd, const u8 *addr); + int (*set_sta_flags)(struct hostapd_data *hapd, struct sta_info *sta); + int (*set_drv_ieee8021x)(struct hostapd_data *hapd, const char *ifname, + int enabled); + int (*set_radius_acl_auth)(struct hostapd_data *hapd, + const u8 *mac, int accepted, + u32 session_timeout); + int (*set_radius_acl_expire)(struct hostapd_data *hapd, + const u8 *mac); + int (*set_bss_params)(struct hostapd_data *hapd, int use_protection); + int (*set_beacon)(struct hostapd_data *hapd, + const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, int dtim_period, + int beacon_int); + int (*vlan_if_add)(struct hostapd_data *hapd, const char *ifname); + int (*vlan_if_remove)(struct hostapd_data *hapd, const char *ifname); + int (*set_wds_sta)(struct hostapd_data *hapd, const u8 *addr, int aid, + int val); + int (*set_sta_vlan)(const char *ifname, struct hostapd_data *hapd, + const u8 *addr, int vlan_id); + int (*get_inact_sec)(struct hostapd_data *hapd, const u8 *addr); + int (*sta_deauth)(struct hostapd_data *hapd, const u8 *addr, + int reason); + int (*sta_disassoc)(struct hostapd_data *hapd, const u8 *addr, + int reason); + int (*sta_add)(struct hostapd_data *hapd, + const u8 *addr, u16 aid, u16 capability, + const u8 *supp_rates, size_t supp_rates_len, + u16 listen_interval, + const struct ieee80211_ht_capabilities *ht_capab); + int (*sta_remove)(struct hostapd_data *hapd, const u8 *addr); + int (*set_countermeasures)(struct hostapd_data *hapd, int enabled); +}; + +/** + * 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 */ +#define STA_HASH_SIZE 256 +#define STA_HASH(sta) (sta[5]) + struct sta_info *sta_hash[STA_HASH_SIZE]; + + /* + * Bitfield for indicating which AIDs are allocated. Only AID values + * 1-2007 are used and as such, the bit at index 0 corresponds to AID + * 1. + */ +#define AID_WORDS ((2008 + 31) / 32) + u32 sta_aid[AID_WORDS]; + + const struct wpa_driver_ops *driver; + void *drv_priv; + struct hostapd_driver_ops drv; + + void (*new_assoc_sta_cb)(struct hostapd_data *hapd, + struct sta_info *sta, int reassoc); + + void *msg_ctx; /* ctx for wpa_msg() calls */ + + struct radius_client_data *radius; + 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; + + struct wpabuf *wps_beacon_ie; + struct wpabuf *wps_probe_resp_ie; +#ifdef CONFIG_WPS + unsigned int ap_pin_failures; + struct upnp_wps_device_sm *wps_upnp; + unsigned int ap_pin_lockout_time; +#endif /* CONFIG_WPS */ + + struct hostapd_probereq_cb *probereq_cb; + size_t num_probereq_cb; + + void (*public_action_cb)(void *ctx, const u8 *buf, size_t len, + int freq); + void *public_action_cb_ctx; + + void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr, + const u8 *uuid_e); + void *wps_reg_success_cb_ctx; +}; + + +/** + * struct hostapd_iface - hostapd per-interface data structure + */ +struct hostapd_iface { + struct hapd_interfaces *interfaces; + void *owner; + int (*reload_config)(struct hostapd_iface *iface); + struct hostapd_config * (*config_read_cb)(const char *config_fname); + 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; + int freq; + + 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; + + u16 ht_op_mode; + void (*scan_cb)(struct hostapd_iface *iface); + + int (*ctrl_iface_init)(struct hostapd_data *hapd); + void (*ctrl_iface_deinit)(struct hostapd_data *hapd); + + int (*for_each_interface)(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); +}; + +/* hostapd.c */ +int hostapd_reload_config(struct hostapd_iface *iface); +struct hostapd_data * +hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, + struct hostapd_config *conf, + struct hostapd_bss_config *bss); +int hostapd_setup_interface(struct hostapd_iface *iface); +int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); +void hostapd_interface_deinit(struct hostapd_iface *iface); +void hostapd_interface_free(struct hostapd_iface *iface); +void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, + int reassoc); + +/* utils.c */ +int hostapd_register_probereq_cb(struct hostapd_data *hapd, + int (*cb)(void *ctx, const u8 *sa, + const u8 *ie, size_t ie_len), + void *ctx); +void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); + +/* drv_callbacks.c (TODO: move to somewhere else?) */ +int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, + const u8 *ie, size_t ielen); +void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); + +#endif /* HOSTAPD_H */ diff --git a/hostapd/hw_features.c b/src/ap/hw_features.c similarity index 63% rename from hostapd/hw_features.c rename to src/ap/hw_features.c index 1d6299e625ed..0159c725180e 100644 --- a/hostapd/hw_features.c +++ b/src/ap/hw_features.c @@ -2,7 +2,7 @@ * hostapd / Hardware feature query and different modes * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2008, Jouni Malinen + * Copyright (c) 2008-2009, Jouni Malinen * * 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 @@ -14,12 +14,17 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "drivers/driver.h" #include "hostapd.h" +#include "ap_config.h" +#include "ap_drv_ops.h" #include "hw_features.h" -#include "driver.h" -#include "config.h" void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, @@ -131,7 +136,7 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd, hapd->iface->num_rates = 0; hapd->iface->current_rates = - os_malloc(mode->num_rates * sizeof(struct hostapd_rate_data)); + os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data)); if (!hapd->iface->current_rates) { wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " "table."); @@ -143,17 +148,15 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd, if (hapd->iconf->supported_rates && !hostapd_rate_found(hapd->iconf->supported_rates, - mode->rates[i].rate)) + mode->rates[i])) continue; rate = &hapd->iface->current_rates[hapd->iface->num_rates]; - os_memcpy(rate, &mode->rates[i], - sizeof(struct hostapd_rate_data)); + rate->rate = mode->rates[i]; 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++; @@ -236,6 +239,245 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) } +static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) +{ + if (iface->conf->secondary_channel > 0) { + iface->conf->channel += 4; + iface->conf->secondary_channel = -1; + } else { + iface->conf->channel -= 4; + iface->conf->secondary_channel = 1; + } +} + + +static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, + int *pri_chan, int *sec_chan) +{ + struct ieee80211_ht_operation *oper; + struct ieee802_11_elems elems; + + *pri_chan = *sec_chan = 0; + + ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); + if (elems.ht_operation && + elems.ht_operation_len >= sizeof(*oper)) { + oper = (struct ieee80211_ht_operation *) elems.ht_operation; + *pri_chan = oper->control_chan; + if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { + if (oper->ht_param & + HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) + *sec_chan = *pri_chan + 4; + else if (oper->ht_param & + HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) + *sec_chan = *pri_chan - 4; + } + } +} + + +static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, + struct wpa_scan_results *scan_res) +{ + int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; + int bss_pri_chan, bss_sec_chan; + size_t i; + int match; + + pri_chan = iface->conf->channel; + sec_chan = iface->conf->secondary_channel * 4; + pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); + if (iface->conf->secondary_channel > 0) + sec_freq = pri_freq + 20; + else + sec_freq = pri_freq - 20; + + /* + * Switch PRI/SEC channels if Beacons were detected on selected SEC + * channel, but not on selected PRI channel. + */ + pri_bss = sec_bss = 0; + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + if (bss->freq == pri_freq) + pri_bss++; + else if (bss->freq == sec_freq) + sec_bss++; + } + if (sec_bss && !pri_bss) { + wpa_printf(MSG_INFO, "Switch own primary and secondary " + "channel to get secondary channel with no Beacons " + "from other BSSes"); + ieee80211n_switch_pri_sec(iface); + } + + /* + * Match PRI/SEC channel with any existing HT40 BSS on the same + * channels that we are about to use (if already mixed order in + * existing BSSes, use own preference). + */ + match = 0; + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); + if (pri_chan == bss_pri_chan && + sec_chan == bss_sec_chan) { + match = 1; + break; + } + } + if (!match) { + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, + &bss_sec_chan); + if (pri_chan == bss_sec_chan && + sec_chan == bss_pri_chan) { + wpa_printf(MSG_INFO, "Switch own primary and " + "secondary channel due to BSS " + "overlap with " MACSTR, + MAC2STR(bss->bssid)); + ieee80211n_switch_pri_sec(iface); + break; + } + } + } + + return 1; +} + + +static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, + struct wpa_scan_results *scan_res) +{ + int pri_freq, sec_freq; + int affected_start, affected_end; + size_t i; + + pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); + if (iface->conf->secondary_channel > 0) + sec_freq = pri_freq + 20; + else + sec_freq = pri_freq - 20; + affected_start = (pri_freq + sec_freq) / 2 - 25; + affected_end = (pri_freq + sec_freq) / 2 + 25; + wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", + affected_start, affected_end); + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + int pri = bss->freq; + int sec = pri; + int sec_chan, pri_chan; + + ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); + + if (sec_chan) { + if (sec_chan < pri_chan) + sec = pri - 20; + else + sec = pri + 20; + } + + if ((pri < affected_start || pri > affected_end) && + (sec < affected_start || sec > affected_end)) + continue; /* not within affected channel range */ + + wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR + " freq=%d pri=%d sec=%d", + MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); + + if (sec_chan) { + if (pri_freq != pri || sec_freq != sec) { + wpa_printf(MSG_DEBUG, "40 MHz pri/sec " + "mismatch with BSS " MACSTR + " <%d,%d> (chan=%d%c) vs. <%d,%d>", + MAC2STR(bss->bssid), + pri, sec, pri_chan, + sec > pri ? '+' : '-', + pri_freq, sec_freq); + return 0; + } + } + + /* TODO: 40 MHz intolerant */ + } + + return 1; +} + + +static void wpa_scan_results_free(struct wpa_scan_results *res) +{ + size_t i; + + if (res == NULL) + return; + + for (i = 0; i < res->num; i++) + os_free(res->res[i]); + os_free(res->res); + os_free(res); +} + + +static void ieee80211n_check_scan(struct hostapd_iface *iface) +{ + struct wpa_scan_results *scan_res; + int oper40; + + /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is + * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */ + + iface->scan_cb = NULL; + + scan_res = hostapd_driver_get_scan_results(iface->bss[0]); + if (scan_res == NULL) { + hostapd_setup_interface_complete(iface, 1); + return; + } + + if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) + oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); + else + oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); + wpa_scan_results_free(scan_res); + + if (!oper40) { + wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " + "channel pri=%d sec=%d based on overlapping BSSes", + iface->conf->channel, + iface->conf->channel + + iface->conf->secondary_channel * 4); + iface->conf->secondary_channel = 0; + iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; + } + + hostapd_setup_interface_complete(iface, 0); +} + + +static int ieee80211n_check_40mhz(struct hostapd_iface *iface) +{ + struct wpa_driver_scan_params params; + + if (!iface->conf->secondary_channel) + return 0; /* HT40 not used */ + + wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " + "40 MHz channel"); + os_memset(¶ms, 0, sizeof(params)); + /* TODO: scan only the needed frequency */ + if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { + wpa_printf(MSG_ERROR, "Failed to request a scan of " + "neighboring BSSes"); + return -1; + } + + iface->scan_cb = ieee80211n_check_scan; + return 1; +} + + static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) { u16 hw = iface->current_mode->ht_capab; @@ -335,9 +577,27 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) return 1; } + #endif /* CONFIG_IEEE80211N */ +int hostapd_check_ht_capab(struct hostapd_iface *iface) +{ +#ifdef CONFIG_IEEE80211N + int ret; + ret = ieee80211n_check_40mhz(iface); + if (ret) + return ret; + if (!ieee80211n_allowed_ht40_channel_pair(iface)) + return -1; + if (!ieee80211n_supported_ht_capab(iface)) + return -1; +#endif /* CONFIG_IEEE80211N */ + + return 0; +} + + /** * hostapd_select_hw_mode - Select the hardware mode * @iface: Pointer to interface data. @@ -348,7 +608,7 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) */ int hostapd_select_hw_mode(struct hostapd_iface *iface) { - int i, j, ok, ret; + int i, j, ok; if (iface->num_hw_features < 1) return -1; @@ -356,7 +616,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) 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) { + if (mode->mode == iface->conf->hw_mode) { iface->current_mode = mode; break; } @@ -408,13 +668,6 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) 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, @@ -423,23 +676,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) 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; + return 0; } diff --git a/hostapd/hw_features.h b/src/ap/hw_features.h similarity index 50% rename from hostapd/hw_features.h rename to src/ap/hw_features.h index 7d43c89b6696..0295549fe1d3 100644 --- a/hostapd/hw_features.h +++ b/src/ap/hw_features.h @@ -16,41 +16,7 @@ #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; -}; - - +#ifdef NEED_AP_MLME 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); @@ -58,5 +24,39 @@ 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); +int hostapd_check_ht_capab(struct hostapd_iface *iface); +#else /* NEED_AP_MLME */ +static inline void +hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, + size_t num_hw_features) +{ +} + +static inline int hostapd_get_hw_features(struct hostapd_iface *iface) +{ + return -1; +} + +static inline int hostapd_select_hw_mode(struct hostapd_iface *iface) +{ + return -1; +} + +static inline const char * hostapd_hw_mode_txt(int mode) +{ + return NULL; +} + +static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) +{ + return -1; +} + +static inline int hostapd_check_ht_capab(struct hostapd_iface *iface) +{ + return 0; +} + +#endif /* NEED_AP_MLME */ #endif /* HW_FEATURES_H */ diff --git a/hostapd/iapp.c b/src/ap/iapp.c similarity index 95% rename from hostapd/iapp.c rename to src/ap/iapp.c index 6d6dba8f7b9a..115d91e8ce30 100644 --- a/hostapd/iapp.c +++ b/src/ap/iapp.c @@ -37,7 +37,7 @@ * - IEEE 802.11 context transfer */ -#include "includes.h" +#include "utils/includes.h" #include #include #ifdef USE_KERNEL_HEADERS @@ -46,11 +46,14 @@ #include #endif /* USE_KERNEL_HEADERS */ +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" #include "hostapd.h" +#include "ap_config.h" #include "ieee802_11.h" -#include "iapp.h" -#include "eloop.h" #include "sta_info.h" +#include "iapp.h" #define IAPP_MULTICAST "224.0.1.178" @@ -304,10 +307,7 @@ static void iapp_process_add_notify(struct iapp_data *iapp, 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; + ap_sta_disconnect(iapp->hapd, sta, NULL, 0); } @@ -533,21 +533,3 @@ void iapp_deinit(struct iapp_data *iapp) } 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/hostapd/iapp.h b/src/ap/iapp.h similarity index 79% rename from hostapd/iapp.h rename to src/ap/iapp.h index 86de59256043..5fc01cb70355 100644 --- a/hostapd/iapp.h +++ b/src/ap/iapp.h @@ -22,8 +22,6 @@ struct iapp_data; 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 */ @@ -42,13 +40,6 @@ 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/hostapd/ieee802_11.c b/src/ap/ieee802_11.c similarity index 68% rename from hostapd/ieee802_11.c rename to src/ap/ieee802_11.c index 70491b4fa22e..3375aa2a3cf8 100644 --- a/hostapd/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1,7 +1,6 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2008, Jouni Malinen - * Copyright (c) 2007-2008, Intel Corporation + * Copyright (c) 2002-2010, Jouni Malinen * * 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 @@ -13,29 +12,32 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" #ifndef CONFIG_NATIVE_WINDOWS -#include - -#include "eloop.h" -#include "hostapd.h" -#include "ieee802_11.h" -#include "beacon.h" -#include "hw_features.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "crypto/crypto.h" +#include "drivers/driver.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" +#include "wps/wps.h" +#include "hostapd.h" +#include "beacon.h" #include "ieee802_11_auth.h" #include "sta_info.h" -#include "rc4.h" #include "ieee802_1x.h" -#include "wpa.h" -#include "wme.h" +#include "wpa_auth.h" +#include "wmm.h" #include "ap_list.h" #include "accounting.h" -#include "driver.h" -#include "mlme.h" +#include "ap_config.h" +#include "ap_mlme.h" +#include "ieee802_11.h" u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) @@ -100,153 +102,6 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) } -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) { @@ -336,34 +191,9 @@ void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) } -/** - * 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) + u16 auth_transaction, const u8 *challenge, + int iswep) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -452,7 +282,7 @@ static void send_auth_reply(struct hostapd_data *hapd, " 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) + if (hapd->drv.send_mgmt_frame(hapd, reply, rlen) < 0) perror("send_auth_reply: send"); os_free(buf); @@ -485,15 +315,15 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, #endif /* CONFIG_IEEE80211R */ -static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, - size_t len) +static void handle_auth(struct hostapd_data *hapd, + const 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; + const u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; int vlan_id = 0; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; @@ -601,8 +431,7 @@ static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, 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) + if (hapd->conf->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); @@ -665,18 +494,388 @@ static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, } +static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) +{ + int i, j = 32, aid; + + /* get a unique AID */ + if (sta->aid > 0) { + wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); + return 0; + } + + for (i = 0; i < AID_WORDS; i++) { + if (hapd->sta_aid[i] == (u32) -1) + continue; + for (j = 0; j < 32; j++) { + if (!(hapd->sta_aid[i] & BIT(j))) + break; + } + if (j < 32) + break; + } + if (j == 32) + return -1; + aid = i * 32 + j + 1; + if (aid > 2007) + return -1; + + sta->aid = aid; + hapd->sta_aid[i] |= BIT(j); + wpa_printf(MSG_DEBUG, " new AID %d", sta->aid); + return 0; +} + + +static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ssid_ie, size_t ssid_ie_len) +{ + if (ssid_ie == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + if (ssid_ie_len != hapd->conf->ssid.ssid_len || + os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) { + char ssid_txt[33]; + ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len); + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Station tried to associate with unknown SSID " + "'%s'", ssid_txt); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} + + +static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *wmm_ie, size_t wmm_ie_len) +{ + sta->flags &= ~WLAN_STA_WMM; + if (wmm_ie && hapd->conf->wmm_enabled) { + if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_WPA, + HOSTAPD_LEVEL_DEBUG, + "invalid WMM element in association " + "request"); + else + sta->flags |= WLAN_STA_WMM; + } + return WLAN_STATUS_SUCCESS; +} + + +static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, + struct ieee802_11_elems *elems) +{ + if (!elems->supp_rates) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "No supported rates element in AssocReq"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (elems->supp_rates_len > sizeof(sta->supported_rates)) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "Invalid supported rates element length %d", + elems->supp_rates_len); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + 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, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "Invalid supported rates element length" + " %d+%d", elems->supp_rates_len, + elems->ext_supp_rates_len); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + 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; + } + + return WLAN_STATUS_SUCCESS; +} + + +static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ies, size_t ies_len, int reassoc) +{ + struct ieee802_11_elems elems; + u16 resp; + const u8 *wpa_ie; + size_t wpa_ie_len; + + if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Station sent an invalid " + "association request"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + resp = copy_supp_rates(hapd, sta, &elems); + if (resp != WLAN_STATUS_SUCCESS) + return resp; +#ifdef CONFIG_IEEE80211N + resp = copy_sta_ht_capab(sta, elems.ht_capabilities, + elems.ht_capabilities_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; +#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 && 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 = ieee802_11_vendor_ie_concat(ies, ies_len, + WPS_IE_VENDOR_TYPE); + wpa_ie = NULL; + wpa_ie_len = 0; + } else if (hapd->conf->wps_state && wpa_ie == NULL) { + 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) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "No WPA/RSN IE in association request"); + return WLAN_STATUS_INVALID_IE; + } + + 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) { + wpa_printf(MSG_WARNING, "Failed to initialize WPA " + "state machine"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + 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) + return resp; +#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); + + return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; + } + + 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)); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies, + ies_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + } +#endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211N + if ((sta->flags & WLAN_STA_HT) && + wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Station tried to use TKIP with HT " + "association"); + return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; + } +#endif /* CONFIG_IEEE80211N */ + } else + wpa_auth_sta_no_wpa(sta->wpa_sm); + + return WLAN_STATUS_SUCCESS; +} + + +static void send_deauth(struct hostapd_data *hapd, const u8 *addr, + u16 reason_code) +{ + int send_len; + struct ieee80211_mgmt reply; + + os_memset(&reply, 0, sizeof(reply)); + reply.frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); + os_memcpy(reply.da, addr, ETH_ALEN); + os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN); + os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN); + + send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); + reply.u.deauth.reason_code = host_to_le16(reason_code); + + if (hapd->drv.send_mgmt_frame(hapd, &reply, send_len) < 0) + wpa_printf(MSG_INFO, "Failed to send deauth: %s", + strerror(errno)); +} + + +static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, + u16 status_code, int reassoc, const u8 *ies, + size_t ies_len) +{ + int send_len; + u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; + struct ieee80211_mgmt *reply; + u8 *p; + + os_memset(buf, 0, sizeof(buf)); + reply = (struct ieee80211_mgmt *) buf; + reply->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, + (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : + WLAN_FC_STYPE_ASSOC_RESP)); + os_memcpy(reply->da, sta->addr, ETH_ALEN); + os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); + + send_len = IEEE80211_HDRLEN; + 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(status_code); + 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); + +#ifdef CONFIG_IEEE80211R + if (status_code == WLAN_STATUS_SUCCESS) { + /* IEEE 802.11r: Mobility Domain Information, Fast BSS + * Transition Information, RSN, [RIC Response] */ + p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, + buf + sizeof(buf) - p, + sta->auth_alg, ies, ies_len); + } +#endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211W + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) + p = hostapd_eid_assoc_comeback_time(hapd, sta, p); +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_IEEE80211N + p = hostapd_eid_ht_capabilities(hapd, p); + p = hostapd_eid_ht_operation(hapd, p); +#endif /* CONFIG_IEEE80211N */ + + if (sta->flags & WLAN_STA_WMM) + p = hostapd_eid_wmm(hapd, p); + +#ifdef CONFIG_WPS + if (sta->flags & WLAN_STA_WPS) { + struct wpabuf *wps = wps_build_assoc_resp_ie(); + if (wps) { + os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); + p += wpabuf_len(wps); + wpabuf_free(wps); + } + } +#endif /* CONFIG_WPS */ + + send_len += p - reply->u.assoc_resp.variable; + + if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0) + wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", + strerror(errno)); +} + + static void handle_assoc(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, size_t len, int reassoc) + const 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; + const u8 *pos; + int 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))) { @@ -717,15 +916,15 @@ static void handle_assoc(struct hostapd_data *hapd, } 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; + hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Station tried to " + "associate before authentication " + "(aid=%d flags=0x%x)", + sta ? sta->aid : -1, + sta ? sta->flags : 0); + send_deauth(hapd, mgmt->sa, + WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); + return; } if (hapd->tkip_countermeasures) { @@ -742,225 +941,21 @@ static void handle_assoc(struct hostapd_data *hapd, 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; + resp = check_assoc_ies(hapd, sta, pos, left, reassoc); + if (resp != WLAN_STATUS_SUCCESS) 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_WMM; - if (elems.wmm && hapd->conf->wmm_enabled) { - if (hostapd_eid_wmm_valid(hapd, elems.wmm, elems.wmm_len)) - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_WPA, - HOSTAPD_LEVEL_DEBUG, - "invalid WMM element in association " - "request"); - else - sta->flags |= WLAN_STA_WMM; - } - - if (!elems.supp_rates) { + if (hostapd_get_aid(hapd, sta) < 0) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "No supported rates element in AssocReq"); - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + HOSTAPD_LEVEL_INFO, "No room for more AIDs"); + resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 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); + sta->capability = capab_info; + sta->listen_interval = listen_interval; if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) sta->flags |= WLAN_STA_NONERP; @@ -1002,66 +997,9 @@ static void handle_assoc(struct hostapd_data *hapd, } #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); + update_ht_state(hapd, sta); #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); @@ -1097,64 +1035,12 @@ static void handle_assoc(struct hostapd_data *hapd, 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_WMM) - p = hostapd_eid_wmm(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"); + send_assoc_resp(hapd, sta, resp, reassoc, pos, left); } static void handle_disassoc(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, size_t len) + const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; @@ -1176,6 +1062,8 @@ static void handle_disassoc(struct hostapd_data *hapd, } sta->flags &= ~WLAN_STA_ASSOC; + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); @@ -1185,7 +1073,7 @@ static void handle_disassoc(struct hostapd_data *hapd, * authenticated. */ accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); - hostapd_sta_remove(hapd, sta->addr); + hapd->drv.sta_remove(hapd, sta->addr); if (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC) { @@ -1201,7 +1089,7 @@ static void handle_disassoc(struct hostapd_data *hapd, static void handle_deauth(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, size_t len) + const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; @@ -1224,6 +1112,8 @@ static void handle_deauth(struct hostapd_data *hapd, } sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticated"); @@ -1236,7 +1126,7 @@ static void handle_deauth(struct hostapd_data *hapd, static void handle_beacon(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, size_t len, + const struct ieee80211_mgmt *mgmt, size_t len, struct hostapd_frame_info *fi) { struct ieee802_11_elems elems; @@ -1281,16 +1171,57 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, 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) + if (hapd->drv.send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt) < 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) +static void hostapd_sa_query_request(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt) { struct sta_info *sta; + struct ieee80211_mgmt resp; u8 *end; + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " + MACSTR, MAC2STR(mgmt->sa)); + wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", + mgmt->u.action.u.sa_query_resp.trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + + sta = ap_get_sta(hapd, mgmt->sa); + if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " + "from unassociated STA " MACSTR, MAC2STR(mgmt->sa)); + return; + } + + wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " + MACSTR, MAC2STR(mgmt->sa)); + + os_memset(&resp, 0, sizeof(resp)); + resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + 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.action.category = WLAN_ACTION_SA_QUERY; + resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; + os_memcpy(resp.u.action.u.sa_query_req.trans_id, + mgmt->u.action.u.sa_query_req.trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; + if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0) + perror("hostapd_sa_query_request: send"); +} + + +static void hostapd_sa_query_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct sta_info *sta; + const u8 *end; int i; end = mgmt->u.action.u.sa_query_resp.trans_id + @@ -1301,6 +1232,11 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, return; } + if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) { + hostapd_sa_query_request(hapd, mgmt); + 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); @@ -1352,7 +1288,7 @@ static int robust_action_frame(u8 category) static void handle_action(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, size_t len) + const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; @@ -1403,6 +1339,14 @@ static void handle_action(struct hostapd_data *hapd, hostapd_sa_query_action(hapd, mgmt, len); return; #endif /* CONFIG_IEEE80211W */ + case WLAN_ACTION_PUBLIC: + if (hapd->public_action_cb) { + hapd->public_action_cb(hapd->public_action_cb_ctx, + (u8 *) mgmt, len, + hapd->iface->freq); + return; + } + break; } hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1412,6 +1356,8 @@ static void handle_action(struct hostapd_data *hapd, mgmt->u.action.category); if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) && !(mgmt->sa[0] & 0x01)) { + struct ieee80211_mgmt *resp; + /* * IEEE 802.11-REVma/D9.0 - 7.3.1.11 * Return the Action frame to the source without change @@ -1419,12 +1365,17 @@ static void handle_action(struct hostapd_data *hapd, */ 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; + resp = os_malloc(len); + if (resp == NULL) + return; + os_memcpy(resp, mgmt, len); + os_memcpy(resp->da, resp->sa, ETH_ALEN); + os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); + resp->u.action.category |= 0x80; - hostapd_send_mgmt_frame(hapd, mgmt, len, 0); + hapd->drv.send_mgmt_frame(hapd, resp, len); + os_free(resp); } } @@ -1435,7 +1386,6 @@ static void handle_action(struct hostapd_data *hapd, * 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 @@ -1443,20 +1393,22 @@ static void handle_action(struct hostapd_data *hapd, * 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, +void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, struct hostapd_frame_info *fi) { - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf; + struct ieee80211_mgmt *mgmt; int broadcast; + u16 fc, stype; + + mgmt = (struct ieee80211_mgmt *) buf; + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); 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; @@ -1517,7 +1469,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype, static void handle_auth_cb(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, + const struct ieee80211_mgmt *mgmt, size_t len, int ok) { u16 auth_alg, auth_transaction, status_code; @@ -1557,38 +1509,14 @@ static void handle_auth_cb(struct hostapd_data *hapd, } -#ifdef CONFIG_IEEE80211N -static void -hostapd_get_ht_capab(struct hostapd_data *hapd, - struct ht_cap_ie *ht_cap_ie, - struct ht_cap_ie *neg_ht_cap_ie) -{ - u16 cap; - - os_memcpy(neg_ht_cap_ie, ht_cap_ie, sizeof(struct ht_cap_ie)); - cap = le_to_host16(neg_ht_cap_ie->data.capabilities_info); - cap &= hapd->iconf->ht_capab; - cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED); - - /* FIXME: Rx STBC needs to be handled specially */ - cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK); - neg_ht_cap_ie->data.capabilities_info = host_to_le16(cap); -} -#endif /* CONFIG_IEEE80211N */ - - static void handle_assoc_cb(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, + const struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int ok) { u16 status; struct sta_info *sta; int new_assoc = 1; -#ifdef CONFIG_IEEE80211N - struct ht_cap_ie ht_cap; -#endif /* CONFIG_IEEE80211N */ - struct ht_cap_ie *ht_cap_ptr = NULL; - int set_flags, flags_and, flags_or; + struct ieee80211_ht_capabilities ht_cap; if (!ok) { hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, @@ -1631,19 +1559,22 @@ static void handle_assoc_cb(struct hostapd_data *hapd, if (sta->flags & WLAN_STA_ASSOC) new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; + if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || + sta->auth_alg == WLAN_AUTH_FT) { + /* + * Open, static WEP, or FT protocol; no separate authorization + * step. + */ + sta->flags |= WLAN_STA_AUTHORIZED; + wpa_msg(hapd->msg_ctx, MSG_INFO, + AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); + } if (reassoc) mlme_reassociate_indication(hapd, sta); else mlme_associate_indication(hapd, sta); -#ifdef CONFIG_IEEE80211N - if (sta->flags & WLAN_STA_HT) { - ht_cap_ptr = &ht_cap; - hostapd_get_ht_capab(hapd, &sta->ht_capabilities, ht_cap_ptr); - } -#endif /* CONFIG_IEEE80211N */ - #ifdef CONFIG_IEEE80211W sta->sa_query_timed_out = 0; #endif /* CONFIG_IEEE80211W */ @@ -1653,13 +1584,17 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * cleared and configuration gets updated in case of reassociation back * to the same AP. */ - hostapd_sta_remove(hapd, sta->addr); + hapd->drv.sta_remove(hapd, sta->addr); - if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid, - sta->capability, sta->supported_rates, - sta->supported_rates_len, 0, sta->listen_interval, - ht_cap_ptr)) - { +#ifdef CONFIG_IEEE80211N + if (sta->flags & WLAN_STA_HT) + hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); +#endif /* CONFIG_IEEE80211N */ + + if (hapd->drv.sta_add(hapd, sta->addr, sta->aid, sta->capability, + sta->supported_rates, sta->supported_rates_len, + sta->listen_interval, + sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "Could not add STA to kernel driver"); @@ -1671,26 +1606,21 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * 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); + if (ap_sta_bind_vlan(hapd, sta, 0) < 0) + goto fail; } 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 (ap_sta_bind_vlan(hapd, sta, 0) < 0) + goto fail; } - set_flags = WLAN_STA_SHORT_PREAMBLE | WLAN_STA_WMM | WLAN_STA_MFP; - if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && - sta->flags & WLAN_STA_AUTHORIZED) - set_flags |= WLAN_STA_AUTHORIZED; - flags_or = sta->flags & set_flags; - flags_and = sta->flags | ~set_flags; - hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - flags_or, flags_and); + hapd->drv.set_sta_flags(hapd, sta); 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); + hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); @@ -1712,10 +1642,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * @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, +void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, u16 stype, int ok) { - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf; + const struct ieee80211_mgmt *mgmt; + mgmt = (const struct ieee80211_mgmt *) buf; switch (stype) { case WLAN_FC_STYPE_AUTH: @@ -1746,76 +1677,6 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len, } -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 */ @@ -1830,4 +1691,65 @@ int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, return 0; } + +void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, + const u8 *buf, size_t len, int ack) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, addr); + if (sta) + break; + } + } + if (sta == NULL) + return; + if (sta->flags & WLAN_STA_PENDING_POLL) { + wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " + "activity poll", MAC2STR(sta->addr), + ack ? "ACKed" : "did not ACK"); + if (ack) + sta->flags &= ~WLAN_STA_PENDING_POLL; + } + + ieee802_1x_tx_status(hapd, sta, buf, len, ack); +} + + +void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, + int wds) +{ + struct sta_info *sta; + + sta = ap_get_sta(hapd, src); + if (sta && (sta->flags & WLAN_STA_ASSOC)) { + if (wds && !(sta->flags & WLAN_STA_WDS)) { + wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " + "STA " MACSTR " (aid %u)", + MAC2STR(sta->addr), sta->aid); + sta->flags |= WLAN_STA_WDS; + hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 1); + } + return; + } + + wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " + MACSTR, MAC2STR(src)); + if (sta && (sta->flags & WLAN_STA_AUTH)) + hapd->drv.sta_disassoc( + hapd, src, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + else + hapd->drv.sta_deauth( + hapd, src, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); +} + + #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/hostapd/ieee802_11.h b/src/ap/ieee802_11.h similarity index 50% rename from hostapd/ieee802_11.h rename to src/ap/ieee802_11.h index ca8ef93c090e..cfc069c8094f 100644 --- a/hostapd/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -1,7 +1,6 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2006, Jouni Malinen - * Copyright (c) 2007-2008, Intel Corporation + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -16,41 +15,53 @@ #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; +struct hostapd_frame_info; +struct ieee80211_ht_capabilities; -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, +void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, + struct hostapd_frame_info *fi); +void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const 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); +#ifdef NEED_AP_MLME 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); +#else /* NEED_AP_MLME */ +static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, + size_t buflen) +{ + return 0; +} + +static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd, + struct sta_info *sta, + char *buf, size_t buflen) +{ + return 0; +} +#endif /* NEED_AP_MLME */ 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_capabilities(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); +void hostapd_get_ht_capab(struct hostapd_data *hapd, + struct ieee80211_ht_capabilities *ht_cap, + struct ieee80211_ht_capabilities *neg_ht_cap); +u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab, + size_t ht_capab_len); +void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); +void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, + const u8 *buf, size_t len, int ack); +void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, + int wds); #endif /* IEEE802_11_H */ diff --git a/hostapd/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c similarity index 92% rename from hostapd/ieee802_11_auth.c rename to src/ap/ieee802_11_auth.c index 9aba1fe854bd..dec56d1e1a1e 100644 --- a/hostapd/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2007, Jouni Malinen + * Copyright (c) 2003-2009, Jouni Malinen * * 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 @@ -17,17 +17,16 @@ * authentication frame processing. */ -#include "includes.h" +#include "utils/includes.h" -#ifndef CONFIG_NATIVE_WINDOWS - -#include "hostapd.h" -#include "ieee802_11.h" -#include "ieee802_11_auth.h" +#include "utils/common.h" +#include "utils/eloop.h" #include "radius/radius.h" #include "radius/radius_client.h" -#include "eloop.h" -#include "driver.h" +#include "hostapd.h" +#include "ap_config.h" +#include "ieee802_11.h" +#include "ieee802_11_auth.h" #define RADIUS_ACL_TIMEOUT 30 @@ -53,6 +52,7 @@ struct hostapd_acl_query_data { }; +#ifndef CONFIG_NO_RADIUS static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) { struct hostapd_cached_radius_acl *prev; @@ -96,6 +96,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, return -1; } +#endif /* CONFIG_NO_RADIUS */ static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) @@ -107,6 +108,7 @@ static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) } +#ifndef CONFIG_NO_RADIUS static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, struct hostapd_acl_query_data *query) { @@ -193,9 +195,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, fail: radius_msg_free(msg); - os_free(msg); return -1; } +#endif /* CONFIG_NO_RADIUS */ /** @@ -234,6 +236,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, return HOSTAPD_ACL_REJECT; if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) { +#ifdef CONFIG_NO_RADIUS + return HOSTAPD_ACL_REJECT; +#else /* CONFIG_NO_RADIUS */ struct hostapd_acl_query_data *query; /* Check whether ACL cache has an entry for this station */ @@ -289,12 +294,14 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, /* Queued data will be processed in hostapd_acl_recv_radius() * when RADIUS server replies to the sent Access-Request. */ return HOSTAPD_ACL_PENDING; +#endif /* CONFIG_NO_RADIUS */ } return HOSTAPD_ACL_REJECT; } +#ifndef CONFIG_NO_RADIUS static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now) { struct hostapd_cached_radius_acl *prev, *entry, *tmp; @@ -311,7 +318,7 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now) else hapd->acl_cache = entry->next; #ifdef CONFIG_DRIVER_RADIUS_ACL - hostapd_set_radius_acl_expire(hapd, entry->addr); + hapd->drv.set_radius_acl_expire(hapd, entry->addr); #endif /* CONFIG_DRIVER_RADIUS_ACL */ tmp = entry; entry = entry->next; @@ -389,11 +396,12 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, struct hostapd_data *hapd = data; struct hostapd_acl_query_data *query, *prev; struct hostapd_cached_radius_acl *cache; + struct radius_hdr *hdr = radius_msg_get_hdr(msg); query = hapd->acl_queries; prev = NULL; while (query) { - if (query->radius_id == msg->hdr->identifier) + if (query->radius_id == hdr->identifier) break; prev = query; query = query->next; @@ -410,10 +418,10 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, return RADIUS_RX_INVALID_AUTHENTICATOR; } - if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT && - msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) { + if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && + hdr->code != RADIUS_CODE_ACCESS_REJECT) { wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " - "query", msg->hdr->code); + "query", hdr->code); return RADIUS_RX_UNKNOWN; } @@ -425,7 +433,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, } time(&cache->timestamp); os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); - if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { + if (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; @@ -450,14 +458,15 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, hapd->acl_cache = cache; #ifdef CONFIG_DRIVER_RADIUS_ACL - hostapd_set_radius_acl_auth(hapd, query->addr, cache->accepted, - cache->session_timeout); + hapd->drv.set_radius_acl_auth(hapd, query->addr, cache->accepted, + cache->session_timeout); #else /* CONFIG_DRIVER_RADIUS_ACL */ +#ifdef NEED_AP_MLME /* 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); + ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); +#endif /* NEED_AP_MLME */ #endif /* CONFIG_DRIVER_RADIUS_ACL */ done: @@ -470,6 +479,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, return RADIUS_RX_PROCESSED; } +#endif /* CONFIG_NO_RADIUS */ /** @@ -479,11 +489,13 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, */ int hostapd_acl_init(struct hostapd_data *hapd) { +#ifndef CONFIG_NO_RADIUS 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); +#endif /* CONFIG_NO_RADIUS */ return 0; } @@ -497,9 +509,11 @@ void hostapd_acl_deinit(struct hostapd_data *hapd) { struct hostapd_acl_query_data *query, *prev; +#ifndef CONFIG_NO_RADIUS eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL); hostapd_acl_cache_free(hapd->acl_cache); +#endif /* CONFIG_NO_RADIUS */ query = hapd->acl_queries; while (query) { @@ -508,16 +522,3 @@ void hostapd_acl_deinit(struct hostapd_data *hapd) 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/hostapd/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h similarity index 91% rename from hostapd/ieee802_11_auth.h rename to src/ap/ieee802_11_auth.h index 0eed825e29a4..b2971e5092b5 100644 --- a/hostapd/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -27,7 +27,5 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, 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/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c new file mode 100644 index 000000000000..7541b83816d0 --- /dev/null +++ b/src/ap/ieee802_11_ht.c @@ -0,0 +1,270 @@ +/* + * hostapd / IEEE 802.11n HT + * Copyright (c) 2002-2009, Jouni Malinen + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "drivers/driver.h" +#include "hostapd.h" +#include "ap_config.h" +#include "sta_info.h" +#include "beacon.h" +#include "ieee802_11.h" + + +u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) +{ + struct ieee80211_ht_capabilities *cap; + u8 *pos = eid; + + if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode) + return eid; + + *pos++ = WLAN_EID_HT_CAP; + *pos++ = sizeof(*cap); + + cap = (struct ieee80211_ht_capabilities *) pos; + os_memset(cap, 0, sizeof(*cap)); + cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab); + cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params; + os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set, + 16); + + /* TODO: ht_extended_capabilities (now fully disabled) */ + /* TODO: tx_bf_capability_info (now fully disabled) */ + /* TODO: asel_capabilities (now fully disabled) */ + + pos += sizeof(*cap); + + return pos; +} + + +u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) +{ + 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; +} + + +/* +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; +} + + +u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab, + size_t ht_capab_len) +{ + if (!ht_capab || + ht_capab_len < sizeof(struct ieee80211_ht_capabilities)) { + sta->flags &= ~WLAN_STA_HT; + os_free(sta->ht_capabilities); + sta->ht_capabilities = NULL; + return WLAN_STATUS_SUCCESS; + } + + if (sta->ht_capabilities == NULL) { + sta->ht_capabilities = + os_zalloc(sizeof(struct ieee80211_ht_capabilities)); + if (sta->ht_capabilities == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_HT; + os_memcpy(sta->ht_capabilities, ht_capab, + sizeof(struct ieee80211_ht_capabilities)); + + return WLAN_STATUS_SUCCESS; +} + + +static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta) +{ + u16 ht_capab; + + ht_capab = le_to_host16(sta->ht_capabilities->ht_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); + } +} + + +static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta) +{ + 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); + } +} + + +void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) +{ + if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) + update_sta_ht(hapd, sta); + else + update_sta_no_ht(hapd, sta); + + if (hostapd_ht_operation_update(hapd->iface) > 0) + ieee802_11_set_beacons(hapd->iface); +} + + +void hostapd_get_ht_capab(struct hostapd_data *hapd, + struct ieee80211_ht_capabilities *ht_cap, + struct ieee80211_ht_capabilities *neg_ht_cap) +{ + u16 cap; + + if (ht_cap == NULL) + return; + os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap)); + cap = le_to_host16(neg_ht_cap->ht_capabilities_info); + cap &= hapd->iconf->ht_capab; + cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED); + + /* + * STBC needs to be handled specially + * if we don't support RX STBC, mask out TX STBC in the STA's HT caps + * if we don't support TX STBC, mask out RX STBC in the STA's HT caps + */ + if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK)) + cap &= ~HT_CAP_INFO_TX_STBC; + if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC)) + cap &= ~HT_CAP_INFO_RX_STBC_MASK; + + neg_ht_cap->ht_capabilities_info = host_to_le16(cap); +} diff --git a/hostapd/ieee802_1x.c b/src/ap/ieee802_1x.c similarity index 88% rename from hostapd/ieee802_1x.c rename to src/ap/ieee802_1x.c index 7fd80280577c..eb160f8e015c 100644 --- a/hostapd/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.1X-2004 Authenticator - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -12,25 +12,28 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "hostapd.h" -#include "ieee802_1x.h" -#include "accounting.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" +#include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.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" +#include "eap_common/eap_wsc_common.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "eapol_auth/eapol_auth_sm_i.h" +#include "hostapd.h" +#include "accounting.h" +#include "sta_info.h" +#include "wpa_auth.h" +#include "preauth_auth.h" +#include "pmksa_cache_auth.h" +#include "ap_config.h" +#include "ieee802_1x.h" static void ieee802_1x_finished(struct hostapd_data *hapd, @@ -67,7 +70,7 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, if (sta->flags & WLAN_STA_PREAUTH) { rsn_preauth_send(hapd, sta, buf, len); } else { - hostapd_send_eapol(hapd, sta->addr, buf, len, encrypt); + hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt); } os_free(buf); @@ -83,15 +86,21 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, return; if (authorized) { + if (!(sta->flags & WLAN_STA_AUTHORIZED)) + wpa_msg(hapd->msg_ctx, MSG_INFO, + AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); sta->flags |= WLAN_STA_AUTHORIZED; - res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - WLAN_STA_AUTHORIZED, ~0); + res = hapd->drv.set_authorized(hapd, sta, 1); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "authorizing port"); } else { + if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) == + (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) + wpa_msg(hapd->msg_ctx, MSG_INFO, + AP_STA_DISCONNECTED MACSTR, + MAC2STR(sta->addr)); sta->flags &= ~WLAN_STA_AUTHORIZED; - res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - 0, ~WLAN_STA_AUTHORIZED); + res = hapd->drv.set_authorized(hapd, sta, 0); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); } @@ -185,6 +194,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, } +#ifndef CONFIG_NO_VLAN static struct hostapd_wep_keys * ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) { @@ -219,11 +229,11 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) 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)) + if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1, + NULL, 0, key->key[key->idx], key->len[key->idx])) printf("Could not set dynamic VLAN WEP encryption key.\n"); - hostapd_set_ieee8021x(ifname, hapd, 1); + hapd->drv.set_drv_ieee8021x(hapd, ifname, 1); return key; } @@ -279,13 +289,17 @@ ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid, return ssid->dyn_vlan_keys[vlan_id]; } +#endif /* CONFIG_NO_VLAN */ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) { - struct hostapd_wep_keys *key = NULL; + struct eapol_authenticator *eapol = hapd->eapol_auth; struct eapol_state_machine *sm = sta->eapol_sm; +#ifndef CONFIG_NO_VLAN + struct hostapd_wep_keys *key = NULL; int vlan_id; +#endif /* CONFIG_NO_VLAN */ if (sm == NULL || !sm->eap_if->eapKeyData) return; @@ -293,6 +307,7 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, MAC2STR(sta->addr)); +#ifndef CONFIG_NO_VLAN vlan_id = sta->vlan_id; if (vlan_id < 0 || vlan_id > MAX_VLAN_ID) vlan_id = 0; @@ -303,9 +318,11 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 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, + } else +#endif /* CONFIG_NO_VLAN */ + if (eapol->default_wep_key) { + ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, + eapol->default_wep_key, hapd->conf->default_wep_key_len); } @@ -328,10 +345,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) /* 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)) { + if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, + sta->addr, 0, 1, NULL, 0, ikey, + hapd->conf->individual_wep_key_len)) { wpa_printf(MSG_ERROR, "Could not set individual WEP " "encryption."); } @@ -343,10 +359,7 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) const char *radius_mode_txt(struct hostapd_data *hapd) { - if (hapd->iface->current_mode == NULL) - return "802.11"; - - switch (hapd->iface->current_mode->mode) { + switch (hapd->iface->conf->hw_mode) { case HOSTAPD_MODE_IEEE80211A: return "802.11a"; case HOSTAPD_MODE_IEEE80211G: @@ -371,6 +384,7 @@ int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) } +#ifndef CONFIG_NO_RADIUS static void ieee802_1x_learn_identity(struct hostapd_data *hapd, struct eapol_state_machine *sm, const u8 *eap, size_t len) @@ -520,7 +534,8 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, /* 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 == + if (sm->last_recv_radius && + radius_msg_get_hdr(sm->last_recv_radius)->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, sm->last_recv_radius, RADIUS_ATTR_STATE); @@ -539,30 +554,8 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 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"; - } } +#endif /* CONFIG_NO_RADIUS */ static void handle_eap_response(struct hostapd_data *hapd, @@ -587,7 +580,7 @@ static void handle_eap_response(struct hostapd_data *hapd, 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); + eap_server_get_name(0, type), type); sm->dot1xAuthEapolRespFramesRx++; @@ -647,6 +640,22 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, } +static struct eapol_state_machine * +ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) +{ + int flags = 0; + if (sta->flags & WLAN_STA_PREAUTH) + flags |= EAPOL_SM_PREAUTH; + if (sta->wpa_sm) { + flags |= EAPOL_SM_USES_WPA; + if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) + flags |= EAPOL_SM_FROM_PMKSA_CACHE; + } + return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, + sta->wps_ie, sta); +} + + /** * ieee802_1x_receive - Process the EAPOL frames from the Supplicant * @hapd: hostapd BSS data @@ -672,8 +681,9 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 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"); + if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " + "associated STA"); return; } @@ -720,9 +730,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; if (!sta->eapol_sm) { - sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr, - sta->flags & WLAN_STA_PREAUTH, - sta); + sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); if (!sta->eapol_sm) return; @@ -839,9 +847,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 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); + sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); if (sta->eapol_sm == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, @@ -900,47 +906,6 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) } -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; @@ -950,17 +915,17 @@ void ieee802_1x_free_station(struct sta_info *sta) sta->eapol_sm = NULL; - if (sm->last_recv_radius) { - radius_msg_free(sm->last_recv_radius); - os_free(sm->last_recv_radius); - } +#ifndef CONFIG_NO_RADIUS + radius_msg_free(sm->last_recv_radius); + radius_free_class(&sm->radius_class); +#endif /* CONFIG_NO_RADIUS */ os_free(sm->identity); - ieee802_1x_free_radius_class(&sm->radius_class); eapol_auth_free(sm); } +#ifndef CONFIG_NO_RADIUS static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, struct sta_info *sta) { @@ -1010,12 +975,14 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 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 >= 0 ? eap_server_get_name(0, 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 >= 0 ? eap_server_get_name(0, eap_type) : + "??", eap_type); break; case EAP_CODE_SUCCESS: @@ -1097,7 +1064,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, sm == NULL) return; - ieee802_1x_free_radius_class(&sm->radius_class); + radius_free_class(&sm->radius_class); count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); if (count <= 0) return; @@ -1225,8 +1192,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, int session_timeout_set, old_vlanid = 0; struct eapol_state_machine *sm; int override_eapReq = 0; + struct radius_hdr *hdr = radius_msg_get_hdr(msg); - sm = ieee802_1x_search_radius_identifier(hapd, msg->hdr->identifier); + sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); if (sm == NULL) { wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " "station for this RADIUS message"); @@ -1236,7 +1204,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, /* 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 && + if (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) { @@ -1250,9 +1218,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 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) { + if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && + hdr->code != RADIUS_CODE_ACCESS_REJECT && + hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { printf("Unknown RADIUS message code\n"); return RADIUS_RX_UNKNOWN; } @@ -1261,11 +1229,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 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); - } - + radius_msg_free(sm->last_recv_radius); sm->last_recv_radius = msg; session_timeout_set = @@ -1275,8 +1239,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, &termination_action)) termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; - if (hapd->conf->radius->acct_interim_interval == 0 && - msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT && + if (hapd->conf->acct_interim_interval == 0 && + 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) { @@ -1291,10 +1255,11 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, } - switch (msg->hdr->code) { + switch (hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) sta->vlan_id = 0; +#ifndef CONFIG_NO_VLAN else { old_vlanid = sta->vlan_id; sta->vlan_id = radius_msg_get_vlanid(msg); @@ -1315,8 +1280,10 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, "ID in Access-Accept"); break; } +#endif /* CONFIG_NO_VLAN */ - ap_sta_bind_vlan(hapd, sta, old_vlanid); + if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) + break; /* RFC 3580, Ch. 3.17 */ if (session_timeout_set && termination_action == @@ -1373,6 +1340,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, return RADIUS_RX_QUEUED; } +#endif /* CONFIG_NO_RADIUS */ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) @@ -1384,11 +1352,10 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 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; - } +#ifndef CONFIG_NO_RADIUS + radius_msg_free(sm->last_recv_radius); + sm->last_recv_radius = NULL; +#endif /* CONFIG_NO_RADIUS */ if (sm->eap_if->eapTimeout) { /* @@ -1397,74 +1364,32 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) * 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; + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); } } -#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) { + struct eapol_authenticator *eapol = hapd->eapol_auth; + 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, + os_free(eapol->default_wep_key); + eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); + if (eapol->default_wep_key == NULL || + os_get_random(eapol->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; + os_free(eapol->default_wep_key); + eapol->default_wep_key = NULL; return -1; } wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", - hapd->default_wep_key, + eapol->default_wep_key, hapd->conf->default_wep_key_len); return 0; @@ -1485,36 +1410,37 @@ static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) { struct hostapd_data *hapd = eloop_ctx; + struct eapol_authenticator *eapol = hapd->eapol_auth; - if (hapd->default_wep_key_idx >= 3) - hapd->default_wep_key_idx = + if (eapol->default_wep_key_idx >= 3) + eapol->default_wep_key_idx = hapd->conf->individual_wep_key_len > 0 ? 1 : 0; else - hapd->default_wep_key_idx++; + eapol->default_wep_key_idx++; wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", - hapd->default_wep_key_idx); + eapol->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; + os_free(eapol->default_wep_key); + eapol->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)) { + if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL, + eapol->default_wep_key_idx, 1, NULL, 0, + eapol->default_wep_key, + hapd->conf->default_wep_key_len)) { 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; + os_free(eapol->default_wep_key); + eapol->default_wep_key = NULL; return; } @@ -1530,6 +1456,30 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, const u8 *data, size_t datalen) { +#ifdef CONFIG_WPS + struct sta_info *sta = sta_ctx; + + if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == + WLAN_STA_MAYBE_WPS) { + const u8 *identity; + size_t identity_len; + struct eapol_state_machine *sm = sta->eapol_sm; + + identity = eap_get_identity(sm->eap, &identity_len); + if (identity && + ((identity_len == WSC_ID_ENROLLEE_LEN && + os_memcmp(identity, WSC_ID_ENROLLEE, + WSC_ID_ENROLLEE_LEN) == 0) || + (identity_len == WSC_ID_REGISTRAR_LEN && + os_memcmp(identity, WSC_ID_REGISTRAR, + WSC_ID_REGISTRAR_LEN) == 0))) { + wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " + "WLAN_STA_WPS"); + sta->flags |= WLAN_STA_WPS; + } + } +#endif /* CONFIG_WPS */ + ieee802_1x_send(ctx, sta_ctx, type, data, datalen); } @@ -1537,10 +1487,12 @@ static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, const u8 *data, size_t datalen) { +#ifndef CONFIG_NO_RADIUS struct hostapd_data *hapd = ctx; struct sta_info *sta = sta_ctx; ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); +#endif /* CONFIG_NO_RADIUS */ } @@ -1608,6 +1560,7 @@ static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) static void ieee802_1x_logger(void *ctx, const u8 *addr, eapol_logger_level level, const char *txt) { +#ifndef CONFIG_NO_HOSTAPD_LOGGER struct hostapd_data *hapd = ctx; int hlevel; @@ -1626,6 +1579,7 @@ static void ieee802_1x_logger(void *ctx, const u8 *addr, hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", txt); +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ } @@ -1654,6 +1608,22 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) } +static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, + enum eapol_event type) +{ + /* struct hostapd_data *hapd = ctx; */ + struct sta_info *sta = sta_ctx; + switch (type) { + case EAPOL_AUTH_SM_CHANGE: + wpa_auth_sm_notify(sta->wpa_sm); + break; + case EAPOL_AUTH_REAUTHENTICATE: + wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); + break; + } +} + + int ieee802_1x_init(struct hostapd_data *hapd) { int i; @@ -1661,12 +1631,13 @@ int ieee802_1x_init(struct hostapd_data *hapd) struct eapol_auth_cb cb; os_memset(&conf, 0, sizeof(conf)); - conf.hapd = hapd; + conf.ctx = 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.msg_ctx = hapd->msg_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; @@ -1691,29 +1662,31 @@ int ieee802_1x_init(struct hostapd_data *hapd) cb.set_port_authorized = ieee802_1x_set_port_authorized; cb.abort_auth = _ieee802_1x_abort_auth; cb.tx_key = _ieee802_1x_tx_key; + cb.eapol_event = ieee802_1x_eapol_event; 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)) + hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) return -1; +#ifndef CONFIG_NO_RADIUS if (radius_client_register(hapd->radius, RADIUS_AUTH, ieee802_1x_receive_auth, hapd)) return -1; +#endif /* CONFIG_NO_RADIUS */ 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); + hapd->drv.set_key(hapd->conf->iface, hapd, + WPA_ALG_NONE, NULL, i, 0, NULL, 0, + NULL, 0); ieee802_1x_rekey(hapd, NULL); - if (hapd->default_wep_key == NULL) + if (hapd->eapol_auth->default_wep_key == NULL) return -1; } @@ -1727,24 +1700,15 @@ void ieee802_1x_deinit(struct hostapd_data *hapd) if (hapd->driver != NULL && (hapd->conf->ieee802_1x || hapd->conf->wpa)) - hostapd_set_ieee8021x(hapd->conf->iface, hapd, 0); + hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 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) + const u8 *buf, size_t len, int ack) { struct ieee80211_hdr *hdr; struct ieee802_1x_hdr *xhdr; @@ -2039,4 +2003,23 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "Added PMKSA cache entry (IEEE 802.1X)"); } + +#ifdef CONFIG_WPS + if (!success && (sta->flags & WLAN_STA_WPS)) { + /* + * Many devices require deauthentication after WPS provisioning + * and some may not be be able to do that themselves, so + * disconnect the client here. + */ + wpa_printf(MSG_DEBUG, "WPS: Force disconnection after " + "EAP-Failure"); + /* Add a small sleep to increase likelihood of previously + * requested EAP-Failure TX getting out before this should the + * driver reorder operations. + */ + os_sleep(0, 10000); + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + } +#endif /* CONFIG_WPS */ } diff --git a/hostapd/ieee802_1x.h b/src/ap/ieee802_1x.h similarity index 89% rename from hostapd/ieee802_1x.h rename to src/ap/ieee802_1x.h index 94cff9356372..1a4d2eb0f2c1 100644 --- a/hostapd/ieee802_1x.h +++ b/src/ap/ieee802_1x.h @@ -21,6 +21,10 @@ struct eapol_state_machine; struct hostapd_config; struct hostapd_bss_config; +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + /* RFC 3580, 4. RC4 EAPOL-Key Frame */ struct ieee802_1x_eapol_key { @@ -43,7 +47,11 @@ struct ieee802_1x_eapol_key { * 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)); +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, @@ -58,11 +66,8 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 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); + const 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); @@ -78,12 +83,6 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 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); diff --git a/hostapd/peerkey.c b/src/ap/peerkey_auth.c similarity index 98% rename from hostapd/peerkey.c rename to src/ap/peerkey_auth.c index 83f3ce513de3..f68c47909ae6 100644 --- a/hostapd/peerkey.c +++ b/src/ap/peerkey_auth.c @@ -1,6 +1,6 @@ /* * hostapd - PeerKey for Direct Link Setup (DLS) - * Copyright (c) 2006-2008, Jouni Malinen + * Copyright (c) 2006-2009, Jouni Malinen * * 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 @@ -12,14 +12,13 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "common.h" -#include "eloop.h" -#include "sha1.h" -#include "sha256.h" -#include "wpa.h" -#include "defs.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "wpa_auth.h" #include "wpa_auth_i.h" #include "wpa_auth_ie.h" diff --git a/hostapd/pmksa_cache.c b/src/ap/pmksa_cache_auth.c similarity index 79% rename from hostapd/pmksa_cache.c rename to src/ap/pmksa_cache_auth.c index 5f54a34c11d4..22f44b78464a 100644 --- a/hostapd/pmksa_cache.c +++ b/src/ap/pmksa_cache_auth.c @@ -12,18 +12,15 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/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" +#include "utils/common.h" +#include "utils/eloop.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "eapol_auth/eapol_auth_sm_i.h" +#include "sta_info.h" +#include "ap_config.h" +#include "pmksa_cache_auth.h" static const int pmksa_cache_max_entries = 1024; @@ -41,40 +38,6 @@ struct rsn_pmksa_cache { }; -/** - * 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); @@ -83,7 +46,9 @@ 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); +#ifndef CONFIG_NO_RADIUS + radius_free_class(&entry->radius_class); +#endif /* CONFIG_NO_RADIUS */ os_free(entry); } @@ -177,11 +142,12 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry, } } - ieee802_1x_copy_radius_class(&entry->radius_class, - &eapol->radius_class); +#ifndef CONFIG_NO_RADIUS + radius_copy_class(&entry->radius_class, &eapol->radius_class); +#endif /* CONFIG_NO_RADIUS */ entry->eap_type_authsrv = eapol->eap_type_authsrv; - entry->vlan_id = eapol->sta->vlan_id; + entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id; } @@ -203,16 +169,17 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, eapol->identity, eapol->identity_len); } - ieee802_1x_free_radius_class(&eapol->radius_class); - ieee802_1x_copy_radius_class(&eapol->radius_class, - &entry->radius_class); +#ifndef CONFIG_NO_RADIUS + radius_free_class(&eapol->radius_class); + radius_copy_class(&eapol->radius_class, &entry->radius_class); +#endif /* CONFIG_NO_RADIUS */ 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; + ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id; } @@ -248,8 +215,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, /** - * pmksa_cache_add - Add a PMKSA cache entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * pmksa_cache_auth_add - Add a PMKSA cache entry + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() * @pmk: The new pairwise master key * @pmk_len: PMK length in bytes, usually PMK_LEN (32) * @aa: Authenticator address @@ -265,7 +232,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, * based on the PMK. */ struct rsn_pmksa_cache_entry * -pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, +pmksa_cache_auth_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) { @@ -294,7 +262,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, /* Replace an old entry for the same STA (if found) with the new entry */ - pos = pmksa_cache_get(pmksa, spa, NULL); + pos = pmksa_cache_auth_get(pmksa, spa, NULL); if (pos) pmksa_cache_free_entry(pmksa, pos); @@ -337,8 +305,9 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, old_entry->identity_len); } } - ieee802_1x_copy_radius_class(&entry->radius_class, - &old_entry->radius_class); +#ifndef CONFIG_NO_RADIUS + radius_copy_class(&entry->radius_class, &old_entry->radius_class); +#endif /* CONFIG_NO_RADIUS */ entry->eap_type_authsrv = old_entry->eap_type_authsrv; entry->vlan_id = old_entry->vlan_id; entry->opportunistic = 1; @@ -350,10 +319,10 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, /** - * pmksa_cache_deinit - Free all entries in PMKSA cache - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * pmksa_cache_auth_deinit - Free all entries in PMKSA cache + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() */ -void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) +void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa) { struct rsn_pmksa_cache_entry *entry, *prev; int i; @@ -375,14 +344,15 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) /** - * pmksa_cache_get - Fetch a PMKSA cache entry - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * pmksa_cache_auth_get - Fetch a PMKSA cache entry + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_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 * +pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, + const u8 *spa, const u8 *pmkid) { struct rsn_pmksa_cache_entry *entry; @@ -404,7 +374,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, /** * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() * @aa: Authenticator address * @spa: Supplicant address * @pmkid: PMKID @@ -434,14 +404,14 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( /** - * pmksa_cache_init - Initialize PMKSA cache + * pmksa_cache_auth_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) +pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx), void *ctx) { struct rsn_pmksa_cache *pmksa; diff --git a/hostapd/pmksa_cache.h b/src/ap/pmksa_cache_auth.h similarity index 71% rename from hostapd/pmksa_cache.h rename to src/ap/pmksa_cache_auth.h index 6ba2da6073eb..9628b13da029 100644 --- a/hostapd/pmksa_cache.h +++ b/src/ap/pmksa_cache_auth.h @@ -15,6 +15,8 @@ #ifndef PMKSA_CACHE_H #define PMKSA_CACHE_H +#include "radius/radius.h" + /** * struct rsn_pmksa_cache_entry - PMKSA cache entry */ @@ -38,25 +40,25 @@ struct rsn_pmksa_cache_entry { 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); +pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx), void *ctx); +void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa); +struct rsn_pmksa_cache_entry * +pmksa_cache_auth_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); +pmksa_cache_auth_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/hostapd/preauth.c b/src/ap/preauth_auth.c similarity index 95% rename from hostapd/preauth.c rename to src/ap/preauth_auth.c index 9ab41eda0bee..8e133158a976 100644 --- a/hostapd/preauth.c +++ b/src/ap/preauth_auth.c @@ -12,19 +12,22 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" #ifdef CONFIG_RSN_PREAUTH -#include "hostapd.h" +#include "utils/common.h" +#include "utils/eloop.h" #include "l2_packet/l2_packet.h" +#include "common/wpa_common.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "eapol_auth/eapol_auth_sm_i.h" +#include "hostapd.h" +#include "ap_config.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" +#include "wpa_auth.h" +#include "preauth_auth.h" #ifndef ETH_P_PREAUTH #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ @@ -256,7 +259,7 @@ void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, 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); + ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH); os_memcpy(ethhdr + 1, buf, len); if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr, diff --git a/hostapd/preauth.h b/src/ap/preauth_auth.h similarity index 100% rename from hostapd/preauth.h rename to src/ap/preauth_auth.h diff --git a/hostapd/sta_info.c b/src/ap/sta_info.c similarity index 88% rename from hostapd/sta_info.c rename to src/ap/sta_info.c index a139ba9bdf94..335c9a5bd724 100644 --- a/hostapd/sta_info.c +++ b/src/ap/sta_info.c @@ -1,7 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2008, Jouni Malinen - * Copyright (c) 2007-2008, Intel Corporation + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -13,26 +12,28 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" +#include "radius/radius.h" +#include "radius/radius_client.h" +#include "drivers/driver.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 "wpa_auth.h" +#include "preauth_auth.h" +#include "ap_config.h" #include "beacon.h" -#include "hw_features.h" -#include "mlme.h" +#include "ap_mlme.h" #include "vlan_init.h" +#include "sta_info.h" -static int ap_sta_in_other_bss(struct hostapd_data *hapd, - struct sta_info *sta, u32 flags); +static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, + struct sta_info *sta); 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); @@ -120,15 +121,18 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) 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); + if (sta->flags & WLAN_STA_WDS) + hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0); + + if (!(sta->flags & WLAN_STA_PREAUTH)) + hapd->drv.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->sta_aid[(sta->aid - 1) / 32] &= + ~BIT((sta->aid - 1) % 32); hapd->num_sta--; if (sta->nonerp_set) { @@ -154,7 +158,6 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) set_beacon++; } -#ifdef CONFIG_IEEE80211N if (sta->no_ht_gf_set) { sta->no_ht_gf_set = 0; hapd->iface->num_sta_ht_no_gf--; @@ -170,9 +173,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) hapd->iface->num_sta_ht_20mhz--; } +#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) if (hostapd_ht_operation_update(hapd->iface) > 0) set_beacon++; -#endif /* CONFIG_IEEE80211N */ +#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ if (set_beacon) ieee802_11_set_beacons(hapd->iface); @@ -183,7 +187,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) ieee802_1x_free_station(sta); wpa_auth_sta_deinit(sta->wpa_sm); rsn_preauth_free_station(hapd, sta); +#ifndef CONFIG_NO_RADIUS radius_client_flush_auth(hapd->radius, sta->addr); +#endif /* CONFIG_NO_RADIUS */ os_free(sta->last_assoc_req); os_free(sta->challenge); @@ -195,6 +201,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) wpabuf_free(sta->wps_ie); + os_free(sta->ht_capabilities); + os_free(sta); } @@ -247,7 +255,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) int inactive_sec; wpa_printf(MSG_DEBUG, "Checking STA " MACSTR " inactivity:", MAC2STR(sta->addr)); - inactive_sec = hostapd_get_inact_sec(hapd, sta->addr); + inactive_sec = hapd->drv.get_inact_sec(hapd, sta->addr); if (inactive_sec == -1) { wpa_printf(MSG_DEBUG, "Could not get station info " "from kernel driver for " MACSTR ".", @@ -280,6 +288,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) if (sta->timeout_next == STA_NULLFUNC && (sta->flags & WLAN_STA_ASSOC)) { +#ifndef CONFIG_NATIVE_WINDOWS /* send data frame to poll STA and check whether this frame * is ACKed */ struct ieee80211_hdr hdr; @@ -287,7 +296,6 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) 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) { @@ -311,7 +319,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) ETH_ALEN); os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN); - if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0) + if (hapd->drv.send_mgmt_frame(hapd, &hdr, sizeof(hdr)) < 0) perror("ap_handle_timer: send"); #endif /* CONFIG_NATIVE_WINDOWS */ } else if (sta->timeout_next != STA_REMOVE) { @@ -322,10 +330,10 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) MAC2STR(sta->addr)); if (deauth) { - hostapd_sta_deauth(hapd, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); + hapd->drv.sta_deauth(hapd, sta->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); } else { - hostapd_sta_disassoc( + hapd->drv.sta_disassoc( hapd, sta->addr, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); } @@ -389,7 +397,7 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) 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); + hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); } @@ -432,7 +440,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) wpa_printf(MSG_ERROR, "malloc failed"); return NULL; } - sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval; + sta->acct_interim_interval = hapd->conf->acct_interim_interval; /* initialize STA info data */ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, @@ -443,6 +451,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) hapd->num_sta++; ap_sta_hash_add(hapd, sta); sta->ssid = &hapd->conf->ssid; + ap_sta_remove_in_other_bss(hapd, sta); return sta; } @@ -454,7 +463,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver", MAC2STR(sta->addr)); - if (hostapd_sta_remove(hapd, sta->addr) && + if (hapd->drv.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)); @@ -464,8 +473,8 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) } -static int ap_sta_in_other_bss(struct hostapd_data *hapd, - struct sta_info *sta, u32 flags) +static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, + struct sta_info *sta) { struct hostapd_iface *iface = hapd->iface; size_t i; @@ -480,11 +489,12 @@ static int ap_sta_in_other_bss(struct hostapd_data *hapd, if (bss == hapd || bss == NULL) continue; sta2 = ap_get_sta(bss, sta->addr); - if (sta2 && ((sta2->flags & flags) == flags)) - return 1; - } + if (!sta2) + continue; - return 0; + ap_sta_disconnect(bss, sta2, sta2->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + } } @@ -494,8 +504,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, 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); + 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, @@ -513,8 +522,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, 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); + 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, @@ -529,8 +537,10 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, int old_vlanid) { +#ifndef CONFIG_NO_VLAN const char *iface; struct hostapd_vlan *vlan = NULL; + int ret; /* * Do not proceed furthur if the vlan id remains same. We do not want @@ -626,7 +636,16 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, 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); + ret = hapd->drv.set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); + if (ret < 0) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "could not bind the STA " + "entry to vlan_id=%d", sta->vlan_id); + } + return ret; +#else /* CONFIG_NO_VLAN */ + return 0; +#endif /* CONFIG_NO_VLAN */ } @@ -690,7 +709,9 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) HOSTAPD_LEVEL_DEBUG, "association SA Query attempt %d", sta->sa_query_count); +#ifdef NEED_AP_MLME ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); +#endif /* NEED_AP_MLME */ } @@ -709,3 +730,22 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) } #endif /* CONFIG_IEEE80211W */ + + +void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *addr, u16 reason) +{ + + if (sta == NULL && addr) + sta = ap_get_sta(hapd, addr); + + if (addr) + hapd->drv.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; +} diff --git a/hostapd/ap.h b/src/ap/sta_info.h similarity index 68% rename from hostapd/ap.h rename to src/ap/sta_info.h index 2c6d7e9799cd..55faa5a28c5e 100644 --- a/hostapd/ap.h +++ b/src/ap/sta_info.h @@ -1,7 +1,6 @@ /* - * hostapd / Station table data structures - * Copyright (c) 2002-2008, Jouni Malinen - * Copyright (c) 2007-2008, Intel Corporation + * hostapd / Station table + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -13,12 +12,8 @@ * See README and COPYING for more details. */ -#ifndef AP_H -#define AP_H - -#ifdef CONFIG_IEEE80211N -#include "ieee802_11_defs.h" -#endif /* CONFIG_IEEE80211N */ +#ifndef STA_INFO_H +#define STA_INFO_H /* STA flags */ #define WLAN_STA_AUTH BIT(0) @@ -35,6 +30,7 @@ #define WLAN_STA_HT BIT(11) #define WLAN_STA_WPS BIT(12) #define WLAN_STA_MAYBE_WPS BIT(13) +#define WLAN_STA_WDS BIT(14) #define WLAN_STA_NONERP BIT(31) /* Maximum number of supported rates (from both Supported Rates and Extended @@ -47,7 +43,7 @@ struct sta_info { 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; + u32 flags; /* Bitfield of WLAN_STA_* */ u16 capability; u16 listen_interval; /* or beacon_int for APs */ u8 supported_rates[WLAN_SUPP_RATES_MAX]; @@ -95,9 +91,7 @@ struct sta_info { int vlan_id; -#ifdef CONFIG_IEEE80211N - struct ht_cap_ie ht_capabilities; /* IEEE 802.11n capabilities */ -#endif /* CONFIG_IEEE80211N */ + struct ieee80211_ht_capabilities *ht_capabilities; #ifdef CONFIG_IEEE80211W int sa_query_count; /* number of pending SA Query requests; @@ -113,14 +107,6 @@ struct sta_info { }; -/* 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 @@ -136,4 +122,34 @@ struct sta_info { /* Number of seconds to keep STA entry after it has been deauthenticated. */ #define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5) -#endif /* AP_H */ + +struct hostapd_data; + +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); +void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *addr, u16 reason); + +#endif /* STA_INFO_H */ diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c new file mode 100644 index 000000000000..9690348e9ccf --- /dev/null +++ b/src/ap/tkip_countermeasures.c @@ -0,0 +1,93 @@ +/* + * hostapd / TKIP countermeasures + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "common/ieee802_11_defs.h" +#include "hostapd.h" +#include "sta_info.h" +#include "ap_mlme.h" +#include "wpa_auth.h" +#include "tkip_countermeasures.h" + + +static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx, + void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + hapd->tkip_countermeasures = 0; + hapd->drv.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; + hapd->drv.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) { + hapd->drv.sta_deauth(hapd, sta->addr, + WLAN_REASON_MICHAEL_MIC_FAILURE); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_AUTHORIZED); + hapd->drv.sta_remove(hapd, sta->addr); + } +} + + +void 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; +} diff --git a/hostapd/ctrl_iface.h b/src/ap/tkip_countermeasures.h similarity index 53% rename from hostapd/ctrl_iface.h rename to src/ap/tkip_countermeasures.h index d86de8c94066..5a1afceb0314 100644 --- a/hostapd/ctrl_iface.h +++ b/src/ap/tkip_countermeasures.h @@ -1,6 +1,6 @@ /* - * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004, Jouni Malinen + * hostapd / TKIP countermeasures + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -12,10 +12,9 @@ * See README and COPYING for more details. */ -#ifndef CTRL_IFACE_H -#define CTRL_IFACE_H +#ifndef TKIP_COUNTERMEASURES_H +#define TKIP_COUNTERMEASURES_H -int hostapd_ctrl_iface_init(struct hostapd_data *hapd); -void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); +void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local); -#endif /* CTRL_IFACE_H */ +#endif /* TKIP_COUNTERMEASURES_H */ diff --git a/src/ap/utils.c b/src/ap/utils.c new file mode 100644 index 000000000000..0ff48aeb37de --- /dev/null +++ b/src/ap/utils.c @@ -0,0 +1,88 @@ +/* + * AP mode helper functions + * Copyright (c) 2009, Jouni Malinen + * + * 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 "common/ieee802_11_defs.h" +#include "sta_info.h" +#include "hostapd.h" + + +int hostapd_register_probereq_cb(struct hostapd_data *hapd, + int (*cb)(void *ctx, const u8 *sa, + const u8 *ie, size_t ie_len), + void *ctx) +{ + struct hostapd_probereq_cb *n; + + n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) * + sizeof(struct hostapd_probereq_cb)); + if (n == NULL) + return -1; + + hapd->probereq_cb = n; + n = &hapd->probereq_cb[hapd->num_probereq_cb]; + hapd->num_probereq_cb++; + + n->cb = cb; + n->ctx = ctx; + + return 0; +} + + +struct prune_data { + struct hostapd_data *hapd; + const u8 *addr; +}; + +static int prune_associations(struct hostapd_iface *iface, void *ctx) +{ + struct prune_data *data = ctx; + struct sta_info *osta; + struct hostapd_data *ohapd; + size_t j; + + for (j = 0; j < iface->num_bss; j++) { + ohapd = iface->bss[j]; + if (ohapd == data->hapd) + continue; + osta = ap_get_sta(ohapd, data->addr); + if (!osta) + continue; + + ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED); + } + + return 0; +} + +/** + * hostapd_prune_associations - Remove extraneous associations + * @hapd: Pointer to BSS data for the most recent association + * @addr: Associated STA address + * + * This function looks through all radios and BSS's for previous + * (stale) associations of STA. If any are found they are removed. + */ +void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr) +{ + struct prune_data data; + data.hapd = hapd; + data.addr = addr; + if (hapd->iface->for_each_interface) + hapd->iface->for_each_interface(hapd->iface->interfaces, + prune_associations, &data); +} diff --git a/hostapd/vlan_init.c b/src/ap/vlan_init.c similarity index 68% rename from hostapd/vlan_init.c rename to src/ap/vlan_init.c index 87c61e2c0115..c9d166a8f346 100644 --- a/hostapd/vlan_init.c +++ b/src/ap/vlan_init.c @@ -2,6 +2,7 @@ * hostapd / VLAN initialization * Copyright 2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2009, Jouni Malinen * * 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 @@ -13,10 +14,11 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" +#include "utils/common.h" #include "hostapd.h" -#include "driver.h" +#include "ap_config.h" #include "vlan_init.h" @@ -28,8 +30,8 @@ #include #include -#include "priv_netlink.h" -#include "eloop.h" +#include "drivers/priv_netlink.h" +#include "utils/eloop.h" struct full_dynamic_vlan { @@ -43,7 +45,8 @@ static int ifconfig_helper(const char *if_name, int up) struct ifreq ifr; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -51,7 +54,9 @@ static int ifconfig_helper(const char *if_name, int up) os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ); if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); + wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed " + "for interface %s: %s", + __func__, if_name, strerror(errno)); close(fd); return -1; } @@ -62,7 +67,9 @@ static int ifconfig_helper(const char *if_name, int up) ifr.ifr_flags &= ~IFF_UP; if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); + wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed " + "for interface %s (up=%d): %s", + __func__, if_name, up, strerror(errno)); close(fd); return -1; } @@ -74,12 +81,14 @@ static int ifconfig_helper(const char *if_name, int up) static int ifconfig_up(const char *if_name) { + wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name); return ifconfig_helper(if_name, 1); } static int ifconfig_down(const char *if_name) { + wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name); return ifconfig_helper(if_name, 0); } @@ -104,16 +113,19 @@ static int br_delif(const char *br_name, const char *if_name) unsigned long args[2]; int if_index; + wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } if_index = if_nametoindex(if_name); if (if_index == 0) { - printf("Failure determining interface index for '%s'\n", - if_name); + wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " + "interface index for '%s'", + __func__, if_name); close(fd); return -1; } @@ -126,7 +138,9 @@ static int br_delif(const char *br_name, const char *if_name) if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) { /* No error if interface already removed. */ - perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]"); + wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," + "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: " + "%s", __func__, br_name, if_name, strerror(errno)); close(fd); return -1; } @@ -150,16 +164,19 @@ static int br_addif(const char *br_name, const char *if_name) unsigned long args[2]; int if_index; + wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } if_index = if_nametoindex(if_name); if (if_index == 0) { - printf("Failure determining interface index for '%s'\n", - if_name); + wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " + "interface index for '%s'", + __func__, if_name); close(fd); return -1; } @@ -177,7 +194,9 @@ static int br_addif(const char *br_name, const char *if_name) return 1; } - perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]"); + wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," + "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: " + "%s", __func__, br_name, if_name, strerror(errno)); close(fd); return -1; } @@ -192,8 +211,10 @@ static int br_delbr(const char *br_name) int fd; unsigned long arg[2]; + wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -202,7 +223,8 @@ static int br_delbr(const char *br_name) if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) { /* No error if bridge already removed. */ - perror("ioctl[BRCTL_DEL_BRIDGE]"); + wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for " + "%s: %s", __func__, br_name, strerror(errno)); close(fd); return -1; } @@ -222,10 +244,13 @@ static int br_delbr(const char *br_name) static int br_addbr(const char *br_name) { int fd; - unsigned long arg[2]; + unsigned long arg[4]; + struct ifreq ifr; + wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -238,12 +263,29 @@ static int br_addbr(const char *br_name) close(fd); return 1; } else { - perror("ioctl[BRCTL_ADD_BRIDGE]"); + wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE " + "failed for %s: %s", + __func__, br_name, strerror(errno)); close(fd); return -1; } } + /* Decrease forwarding delay to avoid EAPOL timeouts. */ + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ); + arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY; + arg[1] = 1; + arg[2] = 0; + arg[3] = 0; + ifr.ifr_data = (char *) &arg; + if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { + wpa_printf(MSG_ERROR, "VLAN: %s: " + "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for " + "%s: %s", __func__, br_name, strerror(errno)); + /* Continue anyway */ + } + close(fd); return 0; } @@ -259,7 +301,8 @@ static int br_getnumports(const char *br_name) struct ifreq ifr; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -273,7 +316,9 @@ static int br_getnumports(const char *br_name) ifr.ifr_data = (__caddr_t) arg; if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { - perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]"); + wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST " + "failed for %s: %s", + __func__, br_name, strerror(errno)); close(fd); return -1; } @@ -294,13 +339,16 @@ static int vlan_rem(const char *if_name) int fd; struct vlan_ioctl_args if_request; + wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name); if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { - fprintf(stderr, "Interface name to long.\n"); + wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", + if_name); return -1; } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -310,7 +358,8 @@ static int vlan_rem(const char *if_name) if_request.cmd = DEL_VLAN_CMD; if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]"); + wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: " + "%s", __func__, if_name, strerror(errno)); close(fd); return -1; } @@ -333,15 +382,19 @@ static int vlan_add(const char *if_name, int vid) int fd; struct vlan_ioctl_args if_request; + wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)", + if_name, vid); ifconfig_up(if_name); if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { - fprintf(stderr, "Interface name to long.\n"); + wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", + if_name); return -1; } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -363,6 +416,9 @@ static int vlan_add(const char *if_name, int vid) os_strncmp(if_request.u.device2, if_name, sizeof(if_request.u.device2)) == 0) { close(fd); + wpa_printf(MSG_DEBUG, "VLAN: vlan_add: " + "if_name %s exists already", + if_request.device1); return 1; } } @@ -376,7 +432,9 @@ static int vlan_add(const char *if_name, int vid) if_request.cmd = ADD_VLAN_CMD; if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]"); + wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: " + "%s", + __func__, if_request.device1, strerror(errno)); close(fd); return -1; } @@ -391,8 +449,11 @@ static int vlan_set_name_type(unsigned int name_type) int fd; struct vlan_ioctl_args if_request; + wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)", + name_type); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket[AF_INET,SOCK_STREAM]"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " + "failed: %s", __func__, strerror(errno)); return -1; } @@ -401,7 +462,9 @@ static int vlan_set_name_type(unsigned int name_type) 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]"); + wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD " + "name_type=%u failed: %s", + __func__, name_type, strerror(errno)); close(fd); return -1; } @@ -418,6 +481,8 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd) struct hostapd_vlan *vlan = hapd->conf->vlan; char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; + wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); + while (vlan) { if (os_strcmp(ifname, vlan->ifname) == 0) { @@ -461,7 +526,8 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd) char br_name[IFNAMSIZ]; struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan; char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; - int numports; + + wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname); first = prev = vlan; @@ -470,19 +536,24 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd) os_snprintf(br_name, sizeof(br_name), "brvlan%d", vlan->vlan_id); + if (vlan->clean & DVLAN_CLEAN_WLAN_PORT) + br_delif(br_name, vlan->ifname); + if (tagged_interface) { os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vlan->vlan_id); - - numports = br_getnumports(br_name); - if (numports == 1) { + if (vlan->clean & DVLAN_CLEAN_VLAN_PORT) br_delif(br_name, vlan_ifname); + ifconfig_down(vlan_ifname); + if (vlan->clean & DVLAN_CLEAN_VLAN) vlan_rem(vlan_ifname); + } - ifconfig_down(br_name); - br_delbr(br_name); - } + if ((vlan->clean & DVLAN_CLEAN_BR) && + br_getnumports(br_name) == 0) { + ifconfig_down(br_name); + br_delbr(br_name); } if (vlan == first) { @@ -561,7 +632,8 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) (struct sockaddr *) &from, &fromlen); if (left < 0) { if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); + wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s", + __func__, strerror(errno)); return; } @@ -572,8 +644,9 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) 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); + wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink " + "message: len=%d left=%d plen=%d", + len, left, plen); break; } @@ -592,8 +665,8 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) } if (left > 0) { - printf("%d extra bytes in the end of netlink message", - left); + wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of " + "netlink message", __func__, left); } } @@ -612,7 +685,9 @@ full_dynamic_vlan_init(struct hostapd_data *hapd) priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (priv->s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); + wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW," + "NETLINK_ROUTE) failed: %s", + __func__, strerror(errno)); os_free(priv); return NULL; } @@ -621,7 +696,8 @@ full_dynamic_vlan_init(struct hostapd_data *hapd) local.nl_family = AF_NETLINK; local.nl_groups = RTMGRP_LINK; if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); + wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s", + __func__, strerror(errno)); close(priv->s); os_free(priv); return NULL; @@ -661,12 +737,11 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd, * 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"); + hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i, + i == mssid->wep.idx, NULL, 0, + mssid->wep.key[i], mssid->wep.len[i])) { + wpa_printf(MSG_ERROR, "VLAN: Could not set WEP " + "encryption for dynamic VLAN"); return -1; } } @@ -679,14 +754,19 @@ 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; + if (vlan->vlan_id != VLAN_ID_WILDCARD) { + if (hapd->drv.vlan_if_add(hapd, vlan->ifname)) { + if (errno != EEXIST) { + wpa_printf(MSG_ERROR, "VLAN: Could " + "not add VLAN %s: %s", + vlan->ifname, + strerror(errno)); + return -1; + } } +#ifdef CONFIG_FULL_DYNAMIC_VLAN + ifconfig_up(vlan->ifname); +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ } vlan = vlan->next; @@ -705,10 +785,10 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd, 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)); + hapd->drv.vlan_if_remove(hapd, vlan->ifname)) { + wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " + "iface: %s: %s", + vlan->ifname, strerror(errno)); } #ifdef CONFIG_FULL_DYNAMIC_VLAN if (vlan->clean) @@ -722,13 +802,13 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd, 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 */ + if (vlan_dynamic_add(hapd, hapd->conf->vlan)) + return -1; + return 0; } @@ -743,17 +823,6 @@ void vlan_deinit(struct hostapd_data *hapd) } -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) @@ -765,6 +834,8 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, vlan->vlan_id != VLAN_ID_WILDCARD) return NULL; + wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", + __func__, vlan_id, vlan->ifname); ifname = os_strdup(vlan->ifname); if (ifname == NULL) return NULL; @@ -788,7 +859,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, pos); os_free(ifname); - if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) { + if (hapd->drv.vlan_if_add(hapd, n->ifname)) { os_free(n); return NULL; } @@ -796,6 +867,10 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, n->next = hapd->conf->vlan; hapd->conf->vlan = n; +#ifdef CONFIG_FULL_DYNAMIC_VLAN + ifconfig_up(n->ifname); +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + return n; } @@ -807,6 +882,8 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) return 1; + wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id); + vlan = hapd->conf->vlan; while (vlan) { if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { @@ -820,7 +897,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) return 1; if (vlan->dynamic_vlan == 0) - hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL); + hapd->drv.vlan_if_remove(hapd, vlan->ifname); return 0; } diff --git a/hostapd/vlan_init.h b/src/ap/vlan_init.h similarity index 59% rename from hostapd/vlan_init.h rename to src/ap/vlan_init.h index cf55ac246220..382d5dee4f80 100644 --- a/hostapd/vlan_init.h +++ b/src/ap/vlan_init.h @@ -16,10 +16,9 @@ #ifndef VLAN_INIT_H #define VLAN_INIT_H +#ifndef CONFIG_NO_VLAN 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); @@ -27,5 +26,34 @@ 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); +#else /* CONFIG_NO_VLAN */ +static inline int vlan_init(struct hostapd_data *hapd) +{ + return 0; +} + +static inline void vlan_deinit(struct hostapd_data *hapd) +{ +} + +static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, + struct hostapd_vlan *vlan, + int vlan_id) +{ + return NULL; +} + +static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) +{ + return -1; +} + +static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd, + struct hostapd_ssid *mssid, + const char *dyn_vlan) +{ + return -1; +} +#endif /* CONFIG_NO_VLAN */ #endif /* VLAN_INIT_H */ diff --git a/hostapd/wme.c b/src/ap/wmm.c similarity index 86% rename from hostapd/wme.c rename to src/ap/wmm.c index f2bbbd9cc2d0..36681309c3dc 100644 --- a/hostapd/wme.c +++ b/src/ap/wmm.c @@ -2,6 +2,7 @@ * hostapd / WMM (Wi-Fi Multimedia) * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2009, Jouni Malinen * * 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 @@ -13,13 +14,16 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "hostapd.h" #include "ieee802_11.h" -#include "wme.h" #include "sta_info.h" -#include "driver.h" +#include "ap_config.h" +#include "wmm.h" /* TODO: maintain separate sequence and fragment numbers for each AC @@ -67,6 +71,9 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) wmm->version = WMM_VERSION; wmm->qos_info = hapd->parameter_set_count & 0xf; + if (hapd->conf->wmm_uapsd) + wmm->qos_info |= 0x80; + /* fill in a parameter set record for each AC */ for (e = 0; e < 4; e++) { struct wmm_ac_parameter *ac = &wmm->ac[e]; @@ -90,7 +97,7 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) /* This function is called when a station sends an association request with * WMM info element. The function returns zero on success or non-zero on any * error in WMM element. eid does not include Element ID and Length octets. */ -int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len) +int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) { struct wmm_information_element *wmm; @@ -117,23 +124,6 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len) } -/* This function is called when a station sends an ACK frame for an AssocResp - * frame (status=success) and the matching AssocReq contained a WMM element. - */ -int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta) -{ - /* update kernel STA data for WMM related items (WLAN_STA_WPA flag) */ - if (sta->flags & WLAN_STA_WMM) - hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - WLAN_STA_WMM, ~0); - else - hostapd_sta_set_flags(hapd, sta->addr, sta->flags, - 0, ~WLAN_STA_WMM); - - return 0; -} - - static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, const struct wmm_tspec_element *tspec, u8 action_code, u8 dialogue_token, u8 status_code) @@ -160,30 +150,17 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); len = ((u8 *) (t + 1)) - buf; - if (hostapd_send_mgmt_frame(hapd, m, len, 0) < 0) + if (hapd->drv.send_mgmt_frame(hapd, m, len) < 0) perror("wmm_send_action: send"); } -static void wmm_addts_req(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, - struct wmm_tspec_element *tspec, size_t len) +int wmm_process_tspec(struct wmm_tspec_element *tspec) { - u8 *end = ((u8 *) mgmt) + len; int medium_time, pps, duration; int up, psb, dir, tid; u16 val, surplus; - if ((u8 *) (tspec + 1) > end) { - wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request"); - return; - } - - wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC " - "from " MACSTR, - mgmt->u.action.u.wmm_action.dialog_token, - MAC2STR(mgmt->sa)); - up = (tspec->ts_info[1] >> 3) & 0x07; psb = (tspec->ts_info[1] >> 2) & 0x01; dir = (tspec->ts_info[0] >> 5) & 0x03; @@ -204,7 +181,7 @@ static void wmm_addts_req(struct hostapd_data *hapd, val = le_to_host16(tspec->nominal_msdu_size); if (val == 0) { wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)"); - goto invalid; + return WMM_ADDTS_STATUS_INVALID_PARAMETERS; } /* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */ pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val; @@ -213,7 +190,7 @@ static void wmm_addts_req(struct hostapd_data *hapd, if (le_to_host32(tspec->minimum_phy_rate) < 1000000) { wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate"); - goto invalid; + return WMM_ADDTS_STATUS_INVALID_PARAMETERS; } duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 / @@ -226,7 +203,7 @@ static void wmm_addts_req(struct hostapd_data *hapd, if (surplus <= 0x2000) { wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not " "greater than unity"); - goto invalid; + return WMM_ADDTS_STATUS_INVALID_PARAMETERS; } medium_time = surplus * pps * duration / 0x2000; @@ -241,35 +218,47 @@ static void wmm_addts_req(struct hostapd_data *hapd, if (medium_time > 750000) { wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over " "75%% of available bandwidth"); - wmm_send_action(hapd, mgmt->sa, tspec, - WMM_ACTION_CODE_ADDTS_RESP, - mgmt->u.action.u.wmm_action.dialog_token, - WMM_ADDTS_STATUS_REFUSED); - return; + return WMM_ADDTS_STATUS_REFUSED; } /* Convert to 32 microseconds per second unit */ tspec->medium_time = host_to_le16(medium_time / 32); - wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP, - mgmt->u.action.u.wmm_action.dialog_token, - WMM_ADDTS_STATUS_ADMISSION_ACCEPTED); - return; - -invalid: - wmm_send_action(hapd, mgmt->sa, tspec, - WMM_ACTION_CODE_ADDTS_RESP, - mgmt->u.action.u.wmm_action.dialog_token, - WMM_ADDTS_STATUS_INVALID_PARAMETERS); + return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED; } -void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, - size_t len) +static void wmm_addts_req(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + struct wmm_tspec_element *tspec, size_t len) +{ + const u8 *end = ((const u8 *) mgmt) + len; + int res; + + if ((const u8 *) (tspec + 1) > end) { + wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request"); + return; + } + + wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC " + "from " MACSTR, + mgmt->u.action.u.wmm_action.dialog_token, + MAC2STR(mgmt->sa)); + + res = wmm_process_tspec(tspec); + wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res); + + wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP, + mgmt->u.action.u.wmm_action.dialog_token, res); +} + + +void hostapd_wmm_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len) { int action_code; int left = len - IEEE80211_HDRLEN - 4; - u8 *pos = ((u8 *) mgmt) + IEEE80211_HDRLEN + 4; + const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4; struct ieee802_11_elems elems; struct sta_info *sta = ap_get_sta(hapd, mgmt->sa); diff --git a/src/ap/wmm.h b/src/ap/wmm.h new file mode 100644 index 000000000000..96b04e890963 --- /dev/null +++ b/src/ap/wmm.h @@ -0,0 +1,29 @@ +/* + * 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 + +struct ieee80211_mgmt; +struct wmm_tspec_element; + +u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid); +int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, + size_t len); +void hostapd_wmm_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len); +int wmm_process_tspec(struct wmm_tspec_element *tspec); + +#endif /* WME_H */ diff --git a/hostapd/wpa.c b/src/ap/wpa_auth.c similarity index 89% rename from hostapd/wpa.c rename to src/ap/wpa_auth.c index 19b11d59d340..36cb0f4783c3 100644 --- a/hostapd/wpa.c +++ b/src/ap/wpa_auth.c @@ -12,23 +12,21 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/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 "utils/common.h" +#include "utils/eloop.h" +#include "utils/state_machine.h" +#include "common/ieee802_11_defs.h" +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "ap_config.h" #include "ieee802_11.h" -#include "pmksa_cache.h" -#include "state_machine.h" +#include "wpa_auth.h" +#include "pmksa_cache_auth.h" #include "wpa_auth_i.h" #include "wpa_auth_ie.h" @@ -38,7 +36,7 @@ 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_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, @@ -104,7 +102,7 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, - const char *alg, const u8 *addr, int idx, + enum wpa_alg alg, const u8 *addr, int idx, u8 *key, size_t key_len) { if (wpa_auth->cb.set_key == NULL) @@ -123,15 +121,6 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, } -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) @@ -382,7 +371,8 @@ struct wpa_authenticator * wpa_init(const u8 *addr, return NULL; } - wpa_auth->pmksa = pmksa_cache_init(wpa_auth_pmksa_free_cb, wpa_auth); + wpa_auth->pmksa = pmksa_cache_auth_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); @@ -395,7 +385,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, 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); + pmksa_cache_auth_deinit(wpa_auth->pmksa); os_free(wpa_auth); return NULL; } @@ -431,7 +421,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth) wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations); #endif /* CONFIG_PEERKEY */ - pmksa_cache_deinit(wpa_auth->pmksa); + pmksa_cache_auth_deinit(wpa_auth->pmksa); #ifdef CONFIG_IEEE80211R wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache); @@ -501,26 +491,25 @@ 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) +int 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; + return -1; #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; + return 0; } #endif /* CONFIG_IEEE80211R */ if (sm->started) { os_memset(&sm->key_replay, 0, sizeof(sm->key_replay)); sm->ReAuthenticationRequest = TRUE; - wpa_sm_step(sm); - return; + return wpa_sm_step(sm); } wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, @@ -528,10 +517,11 @@ void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, sm->started = 1; sm->Init = TRUE; - wpa_sm_step(sm); + if (wpa_sm_step(sm) == 1) + return 1; /* should not really happen */ sm->Init = FALSE; sm->AuthenticationRequest = TRUE; - wpa_sm_step(sm); + return wpa_sm_step(sm); } @@ -549,6 +539,9 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) static void wpa_free_sta_sm(struct wpa_state_machine *sm) { +#ifdef CONFIG_IEEE80211R + os_free(sm->assoc_resp_ftie); +#endif /* CONFIG_IEEE80211R */ os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); os_free(sm); @@ -608,6 +601,56 @@ static int wpa_replay_counter_valid(struct wpa_state_machine *sm, } +#ifdef CONFIG_IEEE80211R +static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + struct wpa_eapol_ie_parse *kde) +{ + struct wpa_ie_data ie; + struct rsn_mdie *mdie; + + if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 || + ie.num_pmkid != 1 || ie.pmkid == NULL) { + wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in " + "FT 4-way handshake message 2/4"); + return -1; + } + + os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant", + sm->sup_pmk_r1_name, PMKID_LEN); + + if (!kde->mdie || !kde->ftie) { + wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake " + "message 2/4", kde->mdie ? "FTIE" : "MDIE"); + return -1; + } + + mdie = (struct rsn_mdie *) (kde->mdie + 2); + if (kde->mdie[1] < sizeof(struct rsn_mdie) || + os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: MDIE mismatch"); + return -1; + } + + if (sm->assoc_resp_ftie && + (kde->ftie[1] != sm->assoc_resp_ftie[1] || + os_memcmp(kde->ftie, sm->assoc_resp_ftie, + 2 + sm->assoc_resp_ftie[1]) != 0)) { + wpa_printf(MSG_DEBUG, "FT: FTIE mismatch"); + wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4", + kde->ftie, kde->ftie_len); + wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp", + sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]); + return -1; + } + + return 0; +} +#endif /* CONFIG_IEEE80211R */ + + void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len) @@ -619,6 +662,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, SMK_M1, SMK_M3, SMK_ERROR } msg; char *msgtxt; struct wpa_eapol_ie_parse kde; + int ft; + const u8 *eapol_key_ie; + size_t eapol_key_ie_len; if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) return; @@ -749,9 +795,26 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, sm->wpa_ptk_state); return; } + if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length, + &kde) < 0) { + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + "received EAPOL-Key msg 2/4 with " + "invalid Key Data contents"); + return; + } + if (kde.rsn_ie) { + eapol_key_ie = kde.rsn_ie; + eapol_key_ie_len = kde.rsn_ie_len; + } else { + eapol_key_ie = kde.wpa_ie; + eapol_key_ie_len = kde.wpa_ie_len; + } + ft = sm->wpa == WPA_VERSION_WPA2 && + wpa_key_mgmt_ft(sm->wpa_key_mgmt); if (sm->wpa_ie == NULL || - sm->wpa_ie_len != key_data_length || - os_memcmp(sm->wpa_ie, key + 1, key_data_length) != 0) { + wpa_compare_rsn_ie(ft, + sm->wpa_ie, sm->wpa_ie_len, + eapol_key_ie, eapol_key_ie_len)) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "WPA IE from (Re)AssocReq did not " "match with msg 2/4"); @@ -760,11 +823,17 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, sm->wpa_ie, sm->wpa_ie_len); } wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4", - (u8 *) (key + 1), key_data_length); + eapol_key_ie, eapol_key_ie_len); /* MLME-DEAUTHENTICATE.request */ wpa_sta_disconnect(wpa_auth, sm->addr); return; } +#ifdef CONFIG_IEEE80211R + if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { + wpa_sta_disconnect(wpa_auth, sm->addr); + return; + } +#endif /* CONFIG_IEEE80211R */ break; case PAIRWISE_4: if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || @@ -1178,18 +1247,19 @@ 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); + wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_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 wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) { int remove_ptk = 1; if (sm == NULL) - return; + return -1; wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "event %d notification", event); @@ -1204,6 +1274,24 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) break; case WPA_REAUTH: case WPA_REAUTH_EAPOL: + if (!sm->started) { + /* + * When using WPS, we may end up here if the STA + * manages to re-associate without the previous STA + * entry getting removed. Consequently, we need to make + * sure that the WPA state machines gets initialized + * properly at this point. + */ + wpa_printf(MSG_DEBUG, "WPA state machine had not been " + "started - initialize now"); + sm->started = 1; + sm->Init = TRUE; + if (wpa_sm_step(sm) == 1) + return 1; /* should not really happen */ + sm->Init = FALSE; + sm->AuthenticationRequest = TRUE; + break; + } if (sm->GUpdateStationKeys) { /* * Reauthentication cancels the pending group key @@ -1217,9 +1305,13 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) break; case WPA_ASSOC_FT: #ifdef CONFIG_IEEE80211R + wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration " + "after association"); + wpa_ft_install_ptk(sm); + /* Using FT protocol, not WPA auth state machine */ sm->ft_completed = 1; - return; + return 0; #else /* CONFIG_IEEE80211R */ break; #endif /* CONFIG_IEEE80211R */ @@ -1242,22 +1334,22 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) wpa_remove_ptk(sm); } - wpa_sm_step(sm); + return wpa_sm_step(sm); } -static const char * wpa_alg_txt(int alg) +static enum wpa_alg wpa_alg_enum(int alg) { switch (alg) { case WPA_CIPHER_CCMP: - return "CCMP"; + return WPA_ALG_CCMP; case WPA_CIPHER_TKIP: - return "TKIP"; + return WPA_ALG_TKIP; case WPA_CIPHER_WEP104: case WPA_CIPHER_WEP40: - return "WEP"; + return WPA_ALG_WEP; default: - return ""; + return WPA_ALG_NONE; } } @@ -1492,6 +1584,27 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) return; } +#ifdef CONFIG_IEEE80211R + if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + /* + * Verify that PMKR1Name from EAPOL-Key message 2/4 matches + * with the value we derived. + */ + if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name, + WPA_PMK_NAME_LEN) != 0) { + wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + "PMKR1Name mismatch in FT 4-way " + "handshake"); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from " + "Supplicant", + sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); + return; + } + } +#endif /* CONFIG_IEEE80211R */ + eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { @@ -1537,8 +1650,8 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *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) + if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || + wpa_auth_get_seqnum(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, @@ -1581,10 +1694,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) return; } - /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, GTK[GN]) + /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], + GTK[GN], IGTK, [FTIE], [TIE * 2]) */ os_memset(rsc, 0, WPA_KEY_RSC_LEN); wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); + /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ wpa_ie = sm->wpa_auth->wpa_ie; wpa_ie_len = sm->wpa_auth->wpa_ie_len; if (sm->wpa == WPA_VERSION_WPA && @@ -1616,6 +1731,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) kde_len = wpa_ie_len + ieee80211w_kde_len(sm); if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */ + kde_len += 300; /* FTIE + 2 * TIE */ + } +#endif /* CONFIG_IEEE80211R */ kde = os_malloc(kde_len); if (kde == NULL) return; @@ -1623,6 +1744,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos = kde; os_memcpy(pos, wpa_ie, wpa_ie_len); pos += wpa_ie_len; +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); + if (res < 0) { + wpa_printf(MSG_ERROR, "FT: Failed to insert " + "PMKR1Name into RSN IE in EAPOL-Key data"); + os_free(kde); + return; + } + pos += res; + } +#endif /* CONFIG_IEEE80211R */ if (gtk) { u8 hdr[2]; hdr[0] = keyidx & 0x03; @@ -1632,6 +1765,40 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } pos = ieee80211w_kde_add(sm, pos); +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + int res; + struct wpa_auth_config *conf; + + conf = &sm->wpa_auth->conf; + res = wpa_write_ftie(conf, conf->r0_key_holder, + conf->r0_key_holder_len, + NULL, NULL, pos, kde + kde_len - pos, + NULL, 0); + if (res < 0) { + wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " + "into EAPOL-Key Key Data"); + os_free(kde); + return; + } + pos += res; + + /* TIE[ReassociationDeadline] (TU) */ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE; + WPA_PUT_LE32(pos, conf->reassociation_deadline); + pos += 4; + + /* TIE[KeyLifetime] (seconds) */ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_KEY_LIFETIME; + WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60); + pos += 4; + } +#endif /* CONFIG_IEEE80211R */ + 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 | @@ -1646,13 +1813,13 @@ SM_STATE(WPA_PTK, PTKINITDONE) SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk); sm->EAPOLKeyReceived = FALSE; if (sm->Pair) { - char *alg; + enum wpa_alg alg; int klen; if (sm->pairwise == WPA_CIPHER_TKIP) { - alg = "TKIP"; + alg = WPA_ALG_TKIP; klen = 32; } else { - alg = "CCMP"; + alg = WPA_ALG_CCMP; klen = 16; } if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, @@ -1934,7 +2101,7 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, group->GTK[group->GN - 1], group->GTK_len); #ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w != WPA_NO_IEEE80211W) { + if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { if (os_get_random(group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to get new random " @@ -2032,13 +2199,13 @@ static void wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, 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), + wpa_alg_enum(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", + if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { + wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK, NULL, group->GN_igtk, group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN); @@ -2067,17 +2234,17 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, } -static void wpa_sm_step(struct wpa_state_machine *sm) +static int wpa_sm_step(struct wpa_state_machine *sm) { if (sm == NULL) - return; + return 0; 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; + return 0; } sm->in_step_loop = 1; @@ -2102,7 +2269,9 @@ static void wpa_sm_step(struct wpa_state_machine *sm) wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state " "machine deinit for " MACSTR, MAC2STR(sm->addr)); wpa_free_sta_sm(sm); + return 1; } + return 0; } @@ -2404,9 +2573,9 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, 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)) + if (pmksa_cache_auth_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; @@ -2421,9 +2590,9 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, 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)) + if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr, + sta_addr, session_timeout, eapol, + WPA_KEY_MGMT_IEEE8021X)) return 0; return -1; @@ -2480,5 +2649,3 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) sm->group = group; return 0; } - -#endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/hostapd/wpa.h b/src/ap/wpa_auth.h similarity index 91% rename from hostapd/wpa.h rename to src/ap/wpa_auth.h index 7d9b3d310677..d0136c71b666 100644 --- a/hostapd/wpa.h +++ b/src/ap/wpa_auth.h @@ -15,8 +15,9 @@ #ifndef WPA_AUTH_H #define WPA_AUTH_H -#include "eapol_common.h" -#include "wpa_common.h" +#include "common/defs.h" +#include "common/eapol_common.h" +#include "common/wpa_common.h" #ifdef _MSC_VER #pragma pack(push, 1) @@ -44,13 +45,9 @@ struct ft_rrb_frame { #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 +#define FT_R0KH_R1KH_PUSH_DATA_LEN 88 struct ft_r0kh_r1kh_pull_frame { u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ @@ -77,14 +74,15 @@ struct ft_r0kh_r1kh_resp_frame { 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 */ + le16 pairwise; + u8 pad[2]; /* 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) */ + le16 data_length; /* little endian length of data (88) */ u8 ap_address[ETH_ALEN]; /* Encrypted with AES key-wrap */ @@ -95,6 +93,8 @@ struct ft_r0kh_r1kh_push_frame { u8 pmk_r0_name[WPA_PMK_NAME_LEN]; u8 pmk_r1[PMK_LEN]; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + le16 pairwise; + u8 pad[6]; /* 8-octet boundary for AES key wrap */ u8 key_wrap_extra[8]; } STRUCT_PACKED; @@ -142,13 +142,10 @@ struct wpa_auth_config { int eapol_version; int peerkey; int wmm_enabled; + int wmm_uapsd; int okc; #ifdef CONFIG_IEEE80211W - enum { - WPA_NO_IEEE80211W = 0, - WPA_IEEE80211W_OPTIONAL = 1, - WPA_IEEE80211W_REQUIRED = 2 - } ieee80211w; + enum mfp_options ieee80211w; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R #define SSID_LEN 32 @@ -187,10 +184,9 @@ struct wpa_auth_callbacks { 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 (*set_key)(void *ctx, int vlan_id, enum wpa_alg 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, @@ -227,8 +223,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, 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); +int 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, @@ -239,7 +235,7 @@ typedef enum { 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); +int 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); @@ -266,7 +262,8 @@ 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); + size_t max_len, int auth_alg, + const u8 *req_ies, size_t req_ies_len); 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, diff --git a/hostapd/wpa_ft.c b/src/ap/wpa_auth_ft.c similarity index 77% rename from hostapd/wpa_ft.c rename to src/ap/wpa_auth_ft.c index 31391051febd..c9871d9a61bf 100644 --- a/hostapd/wpa_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -1,6 +1,6 @@ /* * hostapd - IEEE 802.11r - Fast BSS Transition - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -12,25 +12,50 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "common.h" -#include "config.h" -#include "wpa.h" -#include "aes_wrap.h" +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "crypto/aes_wrap.h" +#include "ap_config.h" #include "ieee802_11.h" -#include "defs.h" +#include "wmm.h" +#include "wpa_auth.h" #include "wpa_auth_i.h" #include "wpa_auth_ie.h" #ifdef CONFIG_IEEE80211R +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; + const u8 *ric; + size_t ric_len; +}; + + +static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, + struct wpa_ft_ies *parse); + + 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; + wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst)); return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB, data, data_len); } @@ -73,11 +98,11 @@ int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len) } -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) +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; @@ -127,6 +152,7 @@ struct wpa_ft_pmk_r0_sa { u8 pmk_r0[PMK_LEN]; u8 pmk_r0_name[WPA_PMK_NAME_LEN]; u8 spa[ETH_ALEN]; + int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ int pmk_r1_pushed; }; @@ -136,6 +162,7 @@ struct wpa_ft_pmk_r1_sa { u8 pmk_r1[PMK_LEN]; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; u8 spa[ETH_ALEN]; + int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ }; @@ -181,7 +208,7 @@ void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *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) + const u8 *pmk_r0_name, int pairwise) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r0_sa *r0; @@ -195,6 +222,7 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, 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->pairwise = pairwise; r0->next = cache->pmk_r0; cache->pmk_r0 = r0; @@ -205,7 +233,7 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r0_name, - u8 *pmk_r0) + u8 *pmk_r0, int *pairwise) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r0_sa *r0; @@ -216,6 +244,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN) == 0) { os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN); + if (pairwise) + *pairwise = r0->pairwise; return 0; } @@ -228,7 +258,7 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r1, - const u8 *pmk_r1_name) + const u8 *pmk_r1_name, int pairwise) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r1_sa *r1; @@ -242,6 +272,7 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, 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->pairwise = pairwise; r1->next = cache->pmk_r1; cache->pmk_r1 = r1; @@ -252,7 +283,7 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r1_name, - u8 *pmk_r1) + u8 *pmk_r1, int *pairwise) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r1_sa *r1; @@ -263,6 +294,8 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN) == 0) { os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN); + if (pairwise) + *pairwise = r1->pairwise; return 0; } @@ -324,7 +357,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, struct wpa_ptk *ptk, size_t ptk_len) { u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN]; - u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_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; @@ -344,16 +377,19 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, 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_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name, + sm->pairwise); wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr, - pmk_r1, pmk_r1_name); + pmk_r1, sm->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_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, + WPA_PMK_NAME_LEN); + wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name, + sm->pairwise); wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, - sm->wpa_auth->addr, pmk_r1_name, + sm->wpa_auth->addr, sm->pmk_r1_name, (u8 *) ptk, ptk_len, ptk_name); wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); @@ -371,17 +407,6 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, } -#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; @@ -414,20 +439,21 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) key = gsm->GTK[gsm->GN - 1]; /* - * Sub-elem ID[1] | Length[1] | Key Info[1] | Key Length[1] | RSC[8] | + * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | * Key[5..32]. */ - subelem_len = 12 + key_len + 8; + subelem_len = 13 + 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)) { + subelem[1] = 11 + key_len + 8; + /* Key ID in B0-B1 of Key Info */ + WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03); + subelem[4] = gsm->GTK_len; + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5); + if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { os_free(subelem); return NULL; } @@ -456,7 +482,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) *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); + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos); pos += 6; *pos++ = WPA_IGTK_LEN; if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, @@ -471,14 +497,125 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) #endif /* CONFIG_IEEE80211W */ -u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, - size_t max_len, int auth_alg) +static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count, + const u8 *ies, size_t ies_len) { - u8 *end, *mdie, *ftie, *rsnie, *r0kh_id, *subelem = NULL; - size_t mdie_len, ftie_len, rsnie_len, r0kh_id_len, subelem_len = 0; + struct ieee802_11_elems parse; + struct rsn_rdie *rdie; + + wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d", + id, descr_count); + wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)", + ies, ies_len); + + if (end - pos < (int) sizeof(*rdie)) { + wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE"); + return pos; + } + + *pos++ = WLAN_EID_RIC_DATA; + *pos++ = sizeof(*rdie); + rdie = (struct rsn_rdie *) pos; + rdie->id = id; + rdie->descr_count = 0; + rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS); + pos += sizeof(*rdie); + + if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) == + ParseFailed) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs"); + rdie->status_code = + host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; + } + +#ifdef NEED_AP_MLME + if (parse.wmm_tspec) { + struct wmm_tspec_element *tspec; + int res; + + if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) { + wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE " + "(%d)", (int) parse.wmm_tspec_len); + rdie->status_code = + host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; + } + if (end - pos < (int) sizeof(*tspec)) { + wpa_printf(MSG_ERROR, "FT: Not enough room for " + "response TSPEC"); + rdie->status_code = + host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; + } + tspec = (struct wmm_tspec_element *) pos; + os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); + res = wmm_process_tspec(tspec); + wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res); + if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS) + rdie->status_code = + host_to_le16(WLAN_STATUS_INVALID_PARAMETERS); + else if (res == WMM_ADDTS_STATUS_REFUSED) + rdie->status_code = + host_to_le16(WLAN_STATUS_REQUEST_DECLINED); + else { + /* TSPEC accepted; include updated TSPEC in response */ + rdie->descr_count = 1; + pos += sizeof(*tspec); + } + return pos; + } +#endif /* NEED_AP_MLME */ + + wpa_printf(MSG_DEBUG, "FT: No supported resource requested"); + rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; +} + + +static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len) +{ + const u8 *rpos, *start; + const struct rsn_rdie *rdie; + + wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len); + + rpos = ric; + while (rpos + sizeof(*rdie) < ric + ric_len) { + if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) || + rpos + 2 + rpos[1] > ric + ric_len) + break; + rdie = (const struct rsn_rdie *) (rpos + 2); + rpos += 2 + rpos[1]; + start = rpos; + + while (rpos + 2 <= ric + ric_len && + rpos + 2 + rpos[1] <= ric + ric_len) { + if (rpos[0] == WLAN_EID_RIC_DATA) + break; + rpos += 2 + rpos[1]; + } + pos = wpa_ft_process_rdie(pos, end, rdie->id, + rdie->descr_count, + start, rpos - start); + } + + return pos; +} + + +u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, + size_t max_len, int auth_alg, + const u8 *req_ies, size_t req_ies_len) +{ + u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL; + size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0; int res; struct wpa_auth_config *conf; struct rsn_ftie *_ftie; + struct wpa_ft_ies parse; + u8 *ric_start; + u8 *anonce, *snonce; if (sm == NULL) return pos; @@ -491,13 +628,18 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *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; + if (auth_alg == WLAN_AUTH_FT) { + /* + * RSN (only present if this is a Reassociation Response and + * part of a fast BSS transition) + */ + 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); @@ -512,6 +654,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, subelem = wpa_ft_gtk_subelem(sm, &subelem_len); r0kh_id = sm->r0kh_id; r0kh_id_len = sm->r0kh_id_len; + anonce = sm->ANonce; + snonce = sm->SNonce; #ifdef CONFIG_IEEE80211W if (sm->mgmt_frame_prot) { u8 *igtk; @@ -537,8 +681,10 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, } else { r0kh_id = conf->r0_key_holder; r0kh_id_len = conf->r0_key_holder_len; + anonce = NULL; + snonce = NULL; } - res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, NULL, NULL, pos, + res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos, end - pos, subelem, subelem_len); os_free(subelem); if (res < 0) @@ -547,33 +693,38 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, ftie_len = res; pos += res; + os_free(sm->assoc_resp_ftie); + sm->assoc_resp_ftie = os_malloc(ftie_len); + if (sm->assoc_resp_ftie) + os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len); + _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, + if (auth_alg == WLAN_AUTH_FT) + _ftie->mic_control[1] = 3; /* Information element count */ + + ric_start = pos; + if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) { + pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len); + if (auth_alg == WLAN_AUTH_FT) + _ftie->mic_control[1] += + ieee802_11_ie_count(ric_start, + pos - ric_start); + } + if (ric_start == pos) + ric_start = NULL; + + if (auth_alg == WLAN_AUTH_FT && + 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) + rsnie, rsnie_len, + ric_start, ric_start ? pos - ric_start : 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) { @@ -623,6 +774,8 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, const u8 *end, *pos; struct wpa_ie_data data; int ret; + const struct rsn_ftie *ftie; + int prot_ie_count = 0; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) @@ -651,21 +804,67 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, parse->mdie_len = pos[1]; break; case WLAN_EID_FAST_BSS_TRANSITION: + if (pos[1] < sizeof(*ftie)) + return -1; + ftie = (const struct rsn_ftie *) (pos + 2); + prot_ie_count = ftie->mic_control[1]; if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) return -1; break; + case WLAN_EID_RIC_DATA: + if (parse->ric == NULL) + parse->ric = pos; } pos += 2 + pos[1]; } + if (prot_ie_count == 0) + return 0; /* no MIC */ + + /* + * Check that the protected IE count matches with IEs included in the + * frame. + */ + if (parse->rsn) + prot_ie_count--; + if (parse->mdie) + prot_ie_count--; + if (parse->ftie) + prot_ie_count--; + if (prot_ie_count < 0) { + wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " + "the protected IE count"); + return -1; + } + + if (prot_ie_count == 0 && parse->ric) { + wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " + "included in protected IE count"); + return -1; + } + + /* Determine the end of the RIC IE(s) */ + pos = parse->ric; + while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && + prot_ie_count) { + prot_ie_count--; + pos += 2 + pos[1]; + } + parse->ric_len = pos - parse->ric; + if (prot_ie_count) { + wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " + "frame", (int) prot_ie_count); + return -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, + enum wpa_alg alg, const u8 *addr, int idx, u8 *key, size_t key_len) { if (wpa_auth->cb.set_key == NULL) @@ -675,25 +874,29 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, } -static void wpa_ft_install_ptk(struct wpa_state_machine *sm) +void wpa_ft_install_ptk(struct wpa_state_machine *sm) { - char *alg; + enum wpa_alg alg; int klen; /* MLME-SETKEYS.request(PTK) */ if (sm->pairwise == WPA_CIPHER_TKIP) { - alg = "TKIP"; + alg = WPA_ALG_TKIP; klen = 32; } else if (sm->pairwise == WPA_CIPHER_CCMP) { - alg = "CCMP"; + alg = WPA_ALG_CCMP; klen = 16; - } else + } else { + wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip " + "PTK configuration", sm->pairwise); 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(?). + * after association has been completed. This function will be called + * again after association to get the PTK configured, but that could be + * optimized by adding the STA entry earlier. */ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, sm->PTK.tk1, klen)) @@ -717,6 +920,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, size_t buflen, ptk_len; int ret; u8 *pos, *end; + int pairwise; *resp_ies = NULL; *resp_ies_len = 0; @@ -772,8 +976,8 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, 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_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, + &pairwise) < 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 " @@ -804,7 +1008,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce", sm->ANonce, WPA_NONCE_LEN); - ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64; + ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48; wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, sm->wpa_auth->addr, pmk_r1_name, (u8 *) &sm->PTK, ptk_len, ptk_name); @@ -812,6 +1016,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, (u8 *) &sm->PTK, ptk_len); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); + sm->pairwise = pairwise; wpa_ft_install_ptk(sm); buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + @@ -895,6 +1100,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, struct rsn_mdie *mdie; struct rsn_ftie *ftie; u8 mic[16]; + unsigned int count; if (sm == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -938,20 +1144,79 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, 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 (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", + ftie->snonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", + sm->SNonce, WPA_NONCE_LEN); + return -1; + } + + if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", + ftie->anonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", + sm->ANonce, WPA_NONCE_LEN); + return -1; + } + + + if (parse.r0kh_id == NULL) { + wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); + return -1; + } + + if (parse.r0kh_id_len != sm->r0kh_id_len || + os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { + wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " + "the current R0KH-ID"); + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", + parse.r0kh_id, parse.r0kh_id_len); + wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", + sm->r0kh_id, sm->r0kh_id_len); + return -1; + } + + if (parse.r1kh_id == NULL) { + wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); + return -1; + } + + if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder, + FT_R1KH_ID_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " + "ReassocReq"); + wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE", + parse.r1kh_id, FT_R1KH_ID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID", + sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN); + return -1; + } + + if (parse.rsn_pmkid == NULL || + os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { + wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " + "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); + return -1; + } + + count = 3; + if (parse.ric) + count++; + if (ftie->mic_control[1] != count) { + wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " + "Control: received %u expected %u", + ftie->mic_control[1], count); + return -1; } 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, + parse.rsn - 2, parse.rsn_len + 2, + parse.ric, parse.ric_len, mic) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -1107,6 +1372,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, struct ft_remote_r1kh *r1kh; struct ft_r0kh_r1kh_resp_frame resp, r; u8 pmk_r0[PMK_LEN]; + int pairwise; wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull"); @@ -1154,8 +1420,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, 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) { + if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0, + &pairwise) < 0) { wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for " "PMK-R1 pull"); return -1; @@ -1166,6 +1432,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, 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); + r.pairwise = host_to_le16(pairwise); if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, r.nonce, resp.nonce) < 0) { @@ -1187,6 +1454,7 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, { struct ft_r0kh_r1kh_resp_frame *frame, f; struct ft_remote_r0kh *r0kh; + int pairwise; wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response"); @@ -1227,16 +1495,19 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, * and call this requests callback function to finish request * processing */ + pairwise = le_to_host16(f.pairwise); 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)); + MACSTR " pairwise=0x%x", + MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); 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); + wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, + pairwise); os_memset(f.pmk_r1, 0, PMK_LEN); return 0; @@ -1251,6 +1522,7 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, struct ft_remote_r0kh *r0kh; struct os_time now; os_time_t tsend; + int pairwise; wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push"); @@ -1299,14 +1571,17 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, return -1; } + pairwise = le_to_host16(f.pairwise); wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID=" - MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id)); + MACSTR " pairwise=0x%x", + MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); 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); + wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, + pairwise); os_memset(f.pmk_r1, 0, PMK_LEN); return 0; @@ -1436,7 +1711,7 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, 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) + const u8 *s1kh_id, int pairwise) { struct ft_r0kh_r1kh_push_frame frame, f; struct os_time now; @@ -1460,6 +1735,7 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, WPA_PMK_NAME_LEN); os_get_time(&now); WPA_PUT_LE32(f.timestamp, now.sec); + f.pairwise = host_to_le16(pairwise); if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, f.timestamp, frame.timestamp) < 0) return; @@ -1492,7 +1768,7 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) r1kh = wpa_auth->conf.r1kh_list; while (r1kh) { - wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr); + wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise); r1kh = r1kh->next; } } diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c new file mode 100644 index 000000000000..afa13a698bef --- /dev/null +++ b/src/ap/wpa_auth_glue.c @@ -0,0 +1,545 @@ +/* + * hostapd / WPA authenticator glue code + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "eapol_auth/eapol_auth_sm_i.h" +#include "eap_server/eap.h" +#include "l2_packet/l2_packet.h" +#include "drivers/driver.h" +#include "hostapd.h" +#include "ieee802_1x.h" +#include "preauth_auth.h" +#include "sta_info.h" +#include "tkip_countermeasures.h" +#include "ap_drv_ops.h" +#include "ap_config.h" +#include "wpa_auth.h" + + +#ifdef CONFIG_IEEE80211R +static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len); +#endif /* CONFIG_IEEE80211R */ + + +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->wmm_enabled = conf->wmm_enabled; + wconf->wmm_uapsd = conf->wmm_uapsd; + 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 */ +} + + +static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, + logger_level level, const char *txt) +{ +#ifndef CONFIG_NO_HOSTAPD_LOGGER + 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); +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ +} + + +static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, + u16 reason) +{ + struct hostapd_data *hapd = ctx; + wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " + "STA " MACSTR " reason %d", + __func__, MAC2STR(addr), reason); + ap_sta_disconnect(hapd, NULL, addr, reason); +} + + +static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) +{ + struct hostapd_data *hapd = ctx; + 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, enum wpa_alg 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 hapd->drv.set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, + key, key_len); +} + + +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_send_eapol(void *ctx, const u8 *addr, + const u8 *data, size_t data_len, + int encrypt) +{ + struct hostapd_data *hapd = ctx; + return hapd->drv.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; +} + + +struct wpa_auth_iface_iter_data { + int (*cb)(struct wpa_authenticator *sm, void *ctx); + void *cb_ctx; +}; + +static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) +{ + struct wpa_auth_iface_iter_data *data = ctx; + size_t i; + for (i = 0; i < iface->num_bss; i++) { + if (iface->bss[i]->wpa_auth && + data->cb(iface->bss[i]->wpa_auth, data->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 *hapd = ctx; + struct wpa_auth_iface_iter_data data; + if (hapd->iface->for_each_interface == NULL) + return -1; + data.cb = cb; + data.cb_ctx = cb_ctx; + return hapd->iface->for_each_interface(hapd->iface->interfaces, + wpa_auth_iface_iter, &data); +} + + +#ifdef CONFIG_IEEE80211R + +struct wpa_auth_ft_iface_iter_data { + struct hostapd_data *src_hapd; + const u8 *dst; + const u8 *data; + size_t data_len; +}; + + +static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) +{ + struct wpa_auth_ft_iface_iter_data *idata = ctx; + struct hostapd_data *hapd; + size_t j; + + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + if (hapd == idata->src_hapd) + continue; + if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) { + wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to " + "locally managed BSS " MACSTR "@%s -> " + MACSTR "@%s", + MAC2STR(idata->src_hapd->own_addr), + idata->src_hapd->conf->iface, + MAC2STR(hapd->own_addr), hapd->conf->iface); + hostapd_rrb_receive(hapd, idata->src_hapd->own_addr, + idata->data, idata->data_len); + return 1; + } + } + + return 0; +} + +#endif /* CONFIG_IEEE80211R */ + + +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; + +#ifdef CONFIG_IEEE80211R + if (proto == ETH_P_RRB && hapd->iface->for_each_interface) { + int res; + struct wpa_auth_ft_iface_iter_data idata; + idata.src_hapd = hapd; + idata.dst = dst; + idata.data = data; + idata.data_len = data_len; + res = hapd->iface->for_each_interface(hapd->iface->interfaces, + hostapd_wpa_auth_ft_iter, + &idata); + if (res == 1) + return data_len; + } +#endif /* CONFIG_IEEE80211R */ + + 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 = hapd->drv.send_mgmt_frame(hapd, (u8 *) m, mlen); + 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) { + sta->auth_alg = WLAN_AUTH_FT; + 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 */ + + +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.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; + } + +#ifdef CONFIG_IEEE80211R + if (!hostapd_drv_none(hapd)) { + hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ? + hapd->conf->bridge : + 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 */ + + return 0; + +} + + +void hostapd_reconfig_wpa(struct hostapd_data *hapd) +{ + struct wpa_auth_config wpa_auth_conf; + hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf); + wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); +} + + +void hostapd_deinit_wpa(struct hostapd_data *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); + +#ifdef CONFIG_IEEE80211R + l2_packet_deinit(hapd->l2); +#endif /* CONFIG_IEEE80211R */ +} diff --git a/src/ap/wpa_auth_glue.h b/src/ap/wpa_auth_glue.h new file mode 100644 index 000000000000..79d7e05c4055 --- /dev/null +++ b/src/ap/wpa_auth_glue.h @@ -0,0 +1,22 @@ +/* + * hostapd / WPA authenticator glue code + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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_GLUE_H +#define WPA_AUTH_GLUE_H + +int hostapd_setup_wpa(struct hostapd_data *hapd); +void hostapd_reconfig_wpa(struct hostapd_data *hapd); +void hostapd_deinit_wpa(struct hostapd_data *hapd); + +#endif /* WPA_AUTH_GLUE_H */ diff --git a/hostapd/wpa_auth_i.h b/src/ap/wpa_auth_i.h similarity index 94% rename from hostapd/wpa_auth_i.h rename to src/ap/wpa_auth_i.h index 925d3ee459ce..b69129ff44cf 100644 --- a/hostapd/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -116,6 +116,9 @@ struct wpa_state_machine { * Request */ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ size_t r0kh_id_len; + u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key + * message 2/4 */ + u8 *assoc_resp_ftie; #endif /* CONFIG_IEEE80211R */ }; @@ -212,10 +215,16 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211R int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); +int wpa_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); int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, struct wpa_ptk *ptk, size_t ptk_len); struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); +void wpa_ft_install_ptk(struct wpa_state_machine *sm); #endif /* CONFIG_IEEE80211R */ #endif /* WPA_AUTH_I_H */ diff --git a/hostapd/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c similarity index 97% rename from hostapd/wpa_auth_ie.c rename to src/ap/wpa_auth_ie.c index 7e0163528455..f8a1804c9f71 100644 --- a/hostapd/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -12,14 +12,15 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "common.h" -#include "config.h" +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "ap_config.h" #include "ieee802_11.h" -#include "eapol_sm.h" -#include "wpa.h" -#include "pmksa_cache.h" +#include "wpa_auth.h" +#include "pmksa_cache_auth.h" #include "wpa_auth_ie.h" #include "wpa_auth_i.h" @@ -220,9 +221,9 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != WPA_NO_IEEE80211W) { + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; - if (conf->ieee80211w == IEEE80211W_REQUIRED) + if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ @@ -240,7 +241,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } #ifdef CONFIG_IEEE80211W - if (conf->ieee80211w != WPA_NO_IEEE80211W) { + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { if (pos + 2 + 4 > buf + len) return -1; if (pmkid == NULL) { @@ -612,7 +613,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w == WPA_IEEE80211W_REQUIRED) { + if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { wpa_printf(MSG_DEBUG, "Management frame protection " "required, but client did not enable it"); @@ -632,7 +633,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } } - if (wpa_auth->conf.ieee80211w == WPA_NO_IEEE80211W || + if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || !(data.capabilities & WPA_CAPABILITY_MFPC)) sm->mgmt_frame_prot = 0; else @@ -670,8 +671,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, 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]); + sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, + &data.pmkid[i * PMKID_LEN]); if (sm->pmksa) { pmkid = sm->pmksa->pmkid; break; @@ -839,6 +840,9 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { ie->mdie = pos; ie->mdie_len = pos[1] + 2; + } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { + ie->ftie = pos; + ie->ftie_len = pos[1] + 2; #endif /* CONFIG_IEEE80211R */ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); diff --git a/hostapd/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h similarity index 97% rename from hostapd/wpa_auth_ie.h rename to src/ap/wpa_auth_ie.h index 9968d2d92a16..61d4cb4075fe 100644 --- a/hostapd/wpa_auth_ie.h +++ b/src/ap/wpa_auth_ie.h @@ -42,6 +42,8 @@ struct wpa_eapol_ie_parse { #ifdef CONFIG_IEEE80211R const u8 *mdie; size_t mdie_len; + const u8 *ftie; + size_t ftie_len; #endif /* CONFIG_IEEE80211R */ }; diff --git a/hostapd/wps_hostapd.c b/src/ap/wps_hostapd.c similarity index 69% rename from hostapd/wps_hostapd.c rename to src/ap/wps_hostapd.c index 818767ef46fa..a6ffd4d0db0b 100644 --- a/hostapd/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -1,6 +1,6 @@ /* * hostapd / WPS integration - * Copyright (c) 2008, Jouni Malinen + * Copyright (c) 2008-2010, Jouni Malinen * * 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 @@ -12,19 +12,24 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/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 "utils/common.h" +#include "utils/eloop.h" +#include "utils/uuid.h" +#include "crypto/dh_groups.h" +#include "common/wpa_ctrl.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "eapol_auth/eapol_auth_sm_i.h" #include "wps/wps.h" #include "wps/wps_defs.h" #include "wps/wps_dev_attr.h" +#include "hostapd.h" +#include "ap_config.h" +#include "beacon.h" +#include "sta_info.h" #include "wps_hostapd.h" @@ -35,6 +40,10 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd, static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd); #endif /* CONFIG_WPS_UPNP */ +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, + const u8 *ie, size_t ie_len); +static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); + static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, size_t psk_len) @@ -83,46 +92,16 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, } -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) +static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, + struct wpabuf *probe_resp_ie) { 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; + wpabuf_free(hapd->wps_beacon_ie); + hapd->wps_beacon_ie = beacon_ie; + wpabuf_free(hapd->wps_probe_resp_ie); + hapd->wps_probe_resp_ie = probe_resp_ie; + ieee802_11_set_beacon(hapd); + return hapd->drv.set_ap_wps_ie(hapd); } @@ -132,17 +111,19 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, struct hostapd_data *hapd = ctx; char uuid[40], txt[400]; int len; + char devtype[WPS_DEV_TYPE_BUFSIZE]; 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]", + "%s " MACSTR " [%s|%s|%s|%s|%s|%s]", 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); + wps_dev_type_bin2str(dev->pri_dev_type, devtype, + sizeof(devtype))); if (len > 0 && len < (int) sizeof(txt)) - wpa_msg(hapd, MSG_INFO, "%s", txt); + wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt); if (hapd->conf->wps_pin_requests) { FILE *f; @@ -152,11 +133,12 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, 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%s\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); + wps_dev_type_bin2str(dev->pri_dev_type, devtype, + sizeof(devtype))); fclose(f); } } @@ -169,8 +151,34 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, char uuid[40]; if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) return; - wpa_msg(hapd, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", MAC2STR(mac_addr), uuid); + if (hapd->wps_reg_success_cb) + hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, + mac_addr, uuid_e); +} + + +static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, + const u8 *uuid_e, + const u8 *pri_dev_type, + u16 config_methods, + u16 dev_password_id, u8 request_type, + const char *dev_name) +{ + struct hostapd_data *hapd = ctx; + char uuid[40]; + char devtype[WPS_DEV_TYPE_BUFSIZE]; + if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) + return; + if (dev_name == NULL) + dev_name = ""; + wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR + " %s %s 0x%x %u %u [%s]", + MAC2STR(addr), uuid, + wps_dev_type_bin2str(pri_dev_type, devtype, + sizeof(devtype)), + config_methods, dev_password_id, request_type, dev_name); } @@ -185,7 +193,7 @@ 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) { + if (iface->reload_config(iface) < 0) { wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated " "configuration"); } @@ -223,12 +231,12 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) if (_buf) { wpa_snprintf_hex(_buf, blen, cred->cred_attr, cred->cred_attr_len); - wpa_msg(hapd, MSG_INFO, "%s%s", + wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s", WPS_EVENT_NEW_AP_SETTINGS, _buf); os_free(_buf); } } else - wpa_msg(hapd, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); if (hapd->conf->wps_cred_processing == 1) return 0; @@ -414,44 +422,58 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) } +static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + if (hapd->conf->ap_setup_locked) + return; + + wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); + hapd->wps->ap_setup_locked = 0; + wps_registrar_update_ie(hapd->wps->registrar); +} + + static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, struct wps_event_pwd_auth_fail *data) { - FILE *f; - - if (!data->enrollee) + if (!data->enrollee || hapd->conf->ap_pin == NULL) return; /* * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup - * if this happens multiple times. + * for some time if this happens multiple times to slow down brute + * force attacks. */ hapd->ap_pin_failures++; - if (hapd->ap_pin_failures < 4) + wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u", + hapd->ap_pin_failures); + if (hapd->ap_pin_failures < 3) return; - wpa_msg(hapd, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); + wpa_msg(hapd->msg_ctx, 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; + if (!hapd->conf->ap_setup_locked) { + if (hapd->ap_pin_lockout_time == 0) + hapd->ap_pin_lockout_time = 60; + else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && + (hapd->ap_pin_failures % 3) == 0) + hapd->ap_pin_lockout_time *= 2; - f = fopen(hapd->iface->config_fname, "a"); - if (f == NULL) { - wpa_printf(MSG_WARNING, "WPS: Could not append to the current " - "configuration file"); - return; + wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", + hapd->ap_pin_lockout_time); + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + eloop_register_timeout(hapd->ap_pin_lockout_time, 0, + hostapd_wps_reenable_ap_pin, hapd, + NULL); } - 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"); + /* TODO: dualband AP may need to update other interfaces */ } @@ -467,15 +489,13 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event, static void hostapd_wps_clear_ies(struct hostapd_data *hapd) { - os_free(hapd->wps_beacon_ie); + wpabuf_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); + wpabuf_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); + + hapd->drv.set_ap_wps_ie(hapd); } @@ -521,43 +541,14 @@ int hostapd_init_wps(struct hostapd_data *hapd, 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]; - /* -- */ - 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->config_methods = + wps_config_methods_str2bin(hapd->conf->config_methods); + if (hapd->conf->device_type && + wps_dev_type_str2bin(hapd->conf->device_type, + wps->dev.pri_dev_type) < 0) { + wpa_printf(MSG_ERROR, "WPS: Invalid device_type"); + os_free(wps); + return -1; } wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? @@ -629,6 +620,11 @@ int hostapd_init_wps(struct hostapd_data *hapd, wps->network_key_len = conf->ssid.wep.len[0]; } + if (conf->ssid.wpa_psk) { + os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN); + wps->psk_set = 1; + } + if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) { /* Override parameters to enable security by default */ wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; @@ -642,6 +638,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, 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.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; cfg.cb_ctx = hapd; cfg.skip_cred_build = conf->skip_cred_build; cfg.extra_cred = conf->extra_cred; @@ -675,6 +672,8 @@ int hostapd_init_wps(struct hostapd_data *hapd, } #endif /* CONFIG_WPS_UPNP */ + hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd); + hapd->wps = wps; return 0; @@ -683,6 +682,8 @@ int hostapd_init_wps(struct hostapd_data *hapd, void hostapd_deinit_wps(struct hostapd_data *hapd) { + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); if (hapd->wps == NULL) return; #ifdef CONFIG_WPS_UPNP @@ -691,6 +692,10 @@ void hostapd_deinit_wps(struct hostapd_data *hapd) wps_registrar_deinit(hapd->wps->registrar); os_free(hapd->wps->network_key); wps_device_data_free(&hapd->wps->dev); + wpabuf_free(hapd->wps->dh_pubkey); + wpabuf_free(hapd->wps->dh_privkey); + wpabuf_free(hapd->wps->oob_conf.pubkey_hash); + wpabuf_free(hapd->wps->oob_conf.dev_password); wps_free_pending_msgs(hapd->wps->upnp_msgs); os_free(hapd->wps); hapd->wps = NULL; @@ -698,6 +703,17 @@ void hostapd_deinit_wps(struct hostapd_data *hapd) } +void hostapd_update_wps(struct hostapd_data *hapd) +{ + if (hapd->wps == NULL) + return; + if (hapd->conf->wps_state) + wps_registrar_update_ie(hapd->wps->registrar); + else + hostapd_deinit_wps(hapd); +} + + int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, const char *pin, int timeout) { @@ -724,47 +740,85 @@ 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) +#ifdef CONFIG_WPS_OOB +int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, + char *path, char *method, char *name) { + struct wps_context *wps = hapd->wps; + struct oob_device_data *oob_dev; + + oob_dev = wps_get_oob_device(device_type); + if (oob_dev == NULL) + return -1; + oob_dev->device_path = path; + oob_dev->device_name = name; + wps->oob_conf.oob_method = wps_get_oob_method(method); + + if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) { + /* + * Use pre-configured DH keys in order to be able to write the + * key hash into the OOB file. + */ + wpabuf_free(wps->dh_pubkey); + wpabuf_free(wps->dh_privkey); + wps->dh_privkey = NULL; + wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), + &wps->dh_privkey); + wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192); + if (wps->dh_pubkey == NULL) { + wpa_printf(MSG_ERROR, "WPS: Failed to initialize " + "Diffie-Hellman handshake"); + return -1; + } + } + + if (wps_process_oob(wps, oob_dev, 1) < 0) + goto error; + + if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E || + wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) && + hostapd_wps_add_pin(hapd, "any", + wpabuf_head(wps->oob_conf.dev_password), 0) < + 0) + goto error; + + return 0; + +error: + wpabuf_free(wps->dh_pubkey); + wps->dh_pubkey = NULL; + wpabuf_free(wps->dh_privkey); + wps->dh_privkey = NULL; + return -1; +} +#endif /* CONFIG_WPS_OOB */ + + +static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, + const u8 *ie, size_t ie_len) +{ + struct hostapd_data *hapd = ctx; struct wpabuf *wps_ie; - const u8 *end, *pos, *wps; + struct ieee802_11_elems elems; if (hapd->wps == NULL) - return; + return 0; - 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 (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { + wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " + MACSTR, MAC2STR(addr)); + return 0; } - if (wps == NULL) - return; /* No WPS IE in Probe Request */ + if (elems.ssid && elems.ssid_len > 0 && + (elems.ssid_len != hapd->conf->ssid.ssid_len || + os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != + 0)) + return 0; /* Not for us */ - wps_ie = wpabuf_alloc(ie_len); + wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); 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]; - } + return 0; if (wpabuf_len(wps_ie) > 0) { wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie); @@ -778,112 +832,13 @@ void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr, } wpabuf_free(wps_ie); + + return 0; } #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, @@ -941,42 +896,6 @@ static int hostapd_rx_req_put_wlan_response( } -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) { @@ -988,21 +907,9 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd, 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; + if (hapd->conf->ap_pin) + ctx->ap_pin = os_strdup(hapd->conf->ap_pin); hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd); if (hapd->wps_upnp == NULL) { @@ -1027,3 +934,87 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) } #endif /* CONFIG_WPS_UPNP */ + + +int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, + char *buf, size_t buflen) +{ + if (hapd->wps == NULL) + return 0; + return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); +} + + +static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); + hostapd_wps_ap_pin_disable(hapd); +} + + +static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) +{ + wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); + hapd->ap_pin_failures = 0; + hapd->conf->ap_setup_locked = 0; + if (hapd->wps->ap_setup_locked) { + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); + hapd->wps->ap_setup_locked = 0; + wps_registrar_update_ie(hapd->wps->registrar); + } + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + if (timeout > 0) + eloop_register_timeout(timeout, 0, + hostapd_wps_ap_pin_timeout, hapd, NULL); +} + + +void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = NULL; +#ifdef CONFIG_WPS_UPNP + upnp_wps_set_ap_pin(hapd->wps_upnp, NULL); +#endif /* CONFIG_WPS_UPNP */ + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); +} + + +const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) +{ + unsigned int pin; + char pin_txt[9]; + + pin = wps_generate_pin(); + os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin); + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = os_strdup(pin_txt); +#ifdef CONFIG_WPS_UPNP + upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt); +#endif /* CONFIG_WPS_UPNP */ + hostapd_wps_ap_pin_enable(hapd, timeout); + return hapd->conf->ap_pin; +} + + +const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) +{ + return hapd->conf->ap_pin; +} + + +int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, + int timeout) +{ + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = os_strdup(pin); + if (hapd->conf->ap_pin == NULL) + return -1; +#ifdef CONFIG_WPS_UPNP + upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin); +#endif /* CONFIG_WPS_UPNP */ + hostapd_wps_ap_pin_enable(hapd, timeout); + return 0; +} diff --git a/hostapd/wps_hostapd.h b/src/ap/wps_hostapd.h similarity index 52% rename from hostapd/wps_hostapd.h rename to src/ap/wps_hostapd.h index e949bee87ac6..e978a1cf668d 100644 --- a/hostapd/wps_hostapd.h +++ b/src/ap/wps_hostapd.h @@ -1,6 +1,6 @@ /* * hostapd / WPS integration - * Copyright (c) 2008, Jouni Malinen + * Copyright (c) 2008-2010, Jouni Malinen * * 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 @@ -20,11 +20,19 @@ int hostapd_init_wps(struct hostapd_data *hapd, struct hostapd_bss_config *conf); void hostapd_deinit_wps(struct hostapd_data *hapd); +void hostapd_update_wps(struct hostapd_data *hapd); int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, const char *pin, int timeout); int hostapd_wps_button_pushed(struct hostapd_data *hapd); -void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ie_len); +int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, + char *path, char *method, char *name); +int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, + char *buf, size_t buflen); +void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd); +const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout); +const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd); +int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, + int timeout); #else /* CONFIG_WPS */ @@ -38,11 +46,22 @@ 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) +static inline void hostapd_update_wps(struct hostapd_data *hapd) { } + +static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, + const u8 *addr, + char *buf, size_t buflen) +{ + return 0; +} + +static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd) +{ + return 0; +} + #endif /* CONFIG_WPS */ #endif /* WPS_HOSTAPD_H */ diff --git a/src/common/Makefile b/src/common/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/common/defs.h b/src/common/defs.h index 4930e73e75cc..173bbd1c9897 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -77,18 +77,44 @@ static inline int wpa_key_mgmt_sha256(int akm) #define WPA_AUTH_ALG_OPEN BIT(0) #define WPA_AUTH_ALG_SHARED BIT(1) #define WPA_AUTH_ALG_LEAP BIT(2) +#define WPA_AUTH_ALG_FT BIT(3) -typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP, - WPA_ALG_IGTK, WPA_ALG_PMK } wpa_alg; -typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, - CIPHER_WEP104 } wpa_cipher; -typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, - KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE, - KEY_MGMT_FT_802_1X, KEY_MGMT_FT_PSK, - KEY_MGMT_802_1X_SHA256, KEY_MGMT_PSK_SHA256, - KEY_MGMT_WPS -} wpa_key_mgmt; +enum wpa_alg { + WPA_ALG_NONE, + WPA_ALG_WEP, + WPA_ALG_TKIP, + WPA_ALG_CCMP, + WPA_ALG_IGTK, + WPA_ALG_PMK +}; + +/** + * enum wpa_cipher - Cipher suites + */ +enum wpa_cipher { + CIPHER_NONE, + CIPHER_WEP40, + CIPHER_TKIP, + CIPHER_CCMP, + CIPHER_WEP104 +}; + +/** + * enum wpa_key_mgmt - Key management suites + */ +enum wpa_key_mgmt { + KEY_MGMT_802_1X, + KEY_MGMT_PSK, + KEY_MGMT_NONE, + KEY_MGMT_802_1X_NO_WPA, + KEY_MGMT_WPA_NONE, + KEY_MGMT_FT_802_1X, + KEY_MGMT_FT_PSK, + KEY_MGMT_802_1X_SHA256, + KEY_MGMT_PSK_SHA256, + KEY_MGMT_WPS +}; /** * enum wpa_states - wpa_supplicant state @@ -100,7 +126,7 @@ typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used * to access the state variable. */ -typedef enum { +enum wpa_states { /** * WPA_DISCONNECTED - Disconnected state * @@ -128,6 +154,16 @@ typedef enum { */ WPA_SCANNING, + /** + * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID + * + * This state is entered when wpa_supplicant has found a suitable BSS + * to authenticate with and the driver is configured to try to + * authenticate with this BSS. This state is used only with drivers + * that use wpa_supplicant as the SME. + */ + WPA_AUTHENTICATING, + /** * WPA_ASSOCIATING - Trying to associate with a BSS/SSID * @@ -186,7 +222,7 @@ typedef enum { * fully configured. */ WPA_COMPLETED -} wpa_states; +}; #define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0 #define MLME_SETPROTECTION_PROTECT_TYPE_RX 1 @@ -196,4 +232,24 @@ typedef enum { #define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 #define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 + +/** + * enum mfp_options - Management frame protection (IEEE 802.11w) options + */ +enum mfp_options { + NO_MGMT_FRAME_PROTECTION = 0, + MGMT_FRAME_PROTECTION_OPTIONAL = 1, + MGMT_FRAME_PROTECTION_REQUIRED = 2 +}; + +/** + * enum hostapd_hw_mode - Hardware mode + */ +enum hostapd_hw_mode { + HOSTAPD_MODE_IEEE80211B, + HOSTAPD_MODE_IEEE80211G, + HOSTAPD_MODE_IEEE80211A, + NUM_HOSTAPD_MODES +}; + #endif /* DEFS_H */ diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 242f933b03fd..96ef5b65a176 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1,6 +1,6 @@ /* * IEEE 802.11 Common routines - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -19,7 +19,7 @@ #include "ieee802_11_common.h" -static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen, +static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, struct ieee802_11_elems *elems, int show_errors) { @@ -131,12 +131,12 @@ static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen, * @show_errors: Whether to show parsing errors in debug log * Returns: Parsing result */ -ParseRes ieee802_11_parse_elems(u8 *start, size_t len, +ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, struct ieee802_11_elems *elems, int show_errors) { size_t left = len; - u8 *pos = start; + const u8 *pos = start; int unknown = 0; os_memset(elems, 0, sizeof(*elems)); @@ -257,3 +257,70 @@ ParseRes ieee802_11_parse_elems(u8 *start, size_t len, return unknown ? ParseUnknown : ParseOK; } + + +int ieee802_11_ie_count(const u8 *ies, size_t ies_len) +{ + int count = 0; + const u8 *pos, *end; + + if (ies == NULL) + return 0; + + pos = ies; + end = ies + ies_len; + + while (pos + 2 <= end) { + if (pos + 2 + pos[1] > end) + break; + count++; + pos += 2 + pos[1]; + } + + return count; +} + + +struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, + u32 oui_type) +{ + struct wpabuf *buf; + const u8 *end, *pos, *ie; + + pos = ies; + end = ies + ies_len; + ie = NULL; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + return NULL; + if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && + WPA_GET_BE32(&pos[2]) == oui_type) { + ie = pos; + break; + } + pos += 2 + pos[1]; + } + + if (ie == NULL) + return NULL; /* No specified vendor IE found */ + + buf = wpabuf_alloc(ies_len); + if (buf == NULL) + return NULL; + + /* + * There may be multiple vendor IEs in the message, so need to + * concatenate their 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]) == oui_type) + wpabuf_put_data(buf, pos + 6, pos[1] - 4); + pos += 2 + pos[1]; + } + + return buf; +} diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index b7e497b6cc68..4a4f5a742cc5 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -1,6 +1,6 @@ /* * IEEE 802.11 Common routines - * Copyright (c) 2002-2008, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -17,58 +17,62 @@ /* Parsed Information Elements */ struct ieee802_11_elems { - u8 *ssid; + const u8 *ssid; + const u8 *supp_rates; + const u8 *fh_params; + const u8 *ds_params; + const u8 *cf_params; + const u8 *tim; + const u8 *ibss_params; + const u8 *challenge; + const u8 *erp_info; + const u8 *ext_supp_rates; + const u8 *wpa_ie; + const u8 *rsn_ie; + const u8 *wmm; /* WMM Information or Parameter Element */ + const u8 *wmm_tspec; + const u8 *wps_ie; + const u8 *power_cap; + const u8 *supp_channels; + const u8 *mdie; + const u8 *ftie; + const u8 *timeout_int; + const u8 *ht_capabilities; + const u8 *ht_operation; + const u8 *vendor_ht_cap; + u8 ssid_len; - u8 *supp_rates; u8 supp_rates_len; - u8 *fh_params; u8 fh_params_len; - u8 *ds_params; u8 ds_params_len; - u8 *cf_params; u8 cf_params_len; - u8 *tim; u8 tim_len; - u8 *ibss_params; u8 ibss_params_len; - u8 *challenge; u8 challenge_len; - u8 *erp_info; u8 erp_info_len; - u8 *ext_supp_rates; u8 ext_supp_rates_len; - u8 *wpa_ie; u8 wpa_ie_len; - u8 *rsn_ie; u8 rsn_ie_len; - u8 *wmm; /* WMM Information or Parameter Element */ u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ - u8 *wmm_tspec; u8 wmm_tspec_len; - u8 *wps_ie; u8 wps_ie_len; - u8 *power_cap; u8 power_cap_len; - u8 *supp_channels; u8 supp_channels_len; - u8 *mdie; u8 mdie_len; - u8 *ftie; u8 ftie_len; - u8 *timeout_int; u8 timeout_int_len; - u8 *ht_capabilities; u8 ht_capabilities_len; - u8 *ht_operation; u8 ht_operation_len; - u8 *vendor_ht_cap; u8 vendor_ht_cap_len; }; typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; -ParseRes ieee802_11_parse_elems(u8 *start, size_t len, +ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, struct ieee802_11_elems *elems, int show_errors); +int ieee802_11_ie_count(const u8 *ies, size_t ies_len); +struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, + u32 oui_type); #endif /* IEEE802_11_COMMON_H */ diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index d9e54a99ed50..4881e39a01a8 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1,6 +1,6 @@ /* * IEEE 802.11 Frame type definitions - * Copyright (c) 2002-2007, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * Copyright (c) 2007-2008 Intel Corporation * * This program is free software; you can redistribute it and/or modify @@ -116,9 +116,13 @@ #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 #define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 #define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 +#define WLAN_STATUS_R0KH_UNREACHABLE 28 /* IEEE 802.11w */ #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 +#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 +#define WLAN_STATUS_REQUEST_DECLINED 37 +#define WLAN_STATUS_INVALID_PARAMETERS 38 /* IEEE 802.11i */ #define WLAN_STATUS_INVALID_IE 40 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 @@ -233,6 +237,25 @@ #pragma pack(push, 1) #endif /* _MSC_VER */ +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; + +#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)) + struct ieee80211_mgmt { le16 frame_control; le16 duration; @@ -337,45 +360,14 @@ struct ieee80211_mgmt { } u; } STRUCT_PACKED; -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ -#define ERP_INFO_NON_ERP_PRESENT BIT(0) -#define ERP_INFO_USE_PROTECTION BIT(1) -#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) - - -/* HT Capability element */ - -enum { - MAX_RX_AMPDU_FACTOR_8KB = 0, - MAX_RX_AMPDU_FACTOR_16KB, - MAX_RX_AMPDU_FACTOR_32KB, - MAX_RX_AMPDU_FACTOR_64KB -}; - -enum { - CALIBRATION_NOT_SUPPORTED = 0, - CALIBRATION_CANNOT_INIT, - CALIBRATION_CAN_INIT, - CALIBRATION_FULL_SUPPORT -}; - -enum { - MCS_FEEDBACK_NOT_PROVIDED = 0, - MCS_FEEDBACK_UNSOLICITED, - MCS_FEEDBACK_MRQ_RESPONSE -}; - - -struct ieee80211_ht_capability { - le16 capabilities_info; - u8 mac_ht_params_info; +struct ieee80211_ht_capabilities { + le16 ht_capabilities_info; + u8 a_mpdu_params; u8 supported_mcs_set[16]; - le16 extended_ht_capability_info; - le32 tx_BF_capability_info; - u8 antenna_selection_info; + le16 ht_extended_capabilities; + le32 tx_bf_capability_info; + u8 asel_capabilities; } STRUCT_PACKED; @@ -387,47 +379,13 @@ struct ieee80211_ht_operation { u8 basic_set[16]; } STRUCT_PACKED; -/* auxiliary bit manipulation macros FIXME: move it to common later... */ -#define SET_2BIT_U8(_ptr_, _shift_, _val_) \ - ((*(_ptr_) &= ~(3 << (_shift_))), \ - (*(_ptr_) |= (*(_ptr_) & (((u8)3) << (_shift_))) | \ - (((u8)(_val_) & 3) << _shift_))) +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ -#define GET_2BIT_U8(_var_, _shift_) \ - (((_var_) & (((u8)3) << (_shift_))) >> (_shift_)) - -#define SET_2BIT_LE16(_u16ptr_, _shift_, _val_) \ - ((*(_u16ptr_) &= ~(3 << (_shift_))), \ - (*(_u16ptr_) |= \ - (((*(_u16ptr_)) & (((u16)3) << ((u16)_shift_))) | \ - (((u16)(_val_) & (u16)3) << (u16)(_shift_))))) - -#define GET_2BIT_LE16(_var_, _shift_) \ - (((_var_) & (((u16)3) << (_shift_))) >> (_shift_)) - -#define SET_2BIT_LE32(_u32ptr_, _shift_, _val_) \ - ((*(_u32ptr_) &= ~(3 << (_shift_))), \ - (*(_u32ptr_) |= (((*(_u32ptr_)) & (((u32)3) << (_shift_))) | \ - (((u32)(_val_) & 3) << _shift_)))) - -#define GET_2BIT_LE32(_var_, _shift_) \ - (((_var_) & (((u32)3) << (_shift_))) >> (_shift_)) - -#define SET_3BIT_LE16(_u16ptr_, _shift_, _val_) \ - ((*(_u16ptr_) &= ~(7 << (_shift_))), \ - (*(_u16ptr_) |= (((*(_u16ptr_)) & (((u16)7) << (_shift_))) | \ - (((u16)(_val_) & 7) << _shift_)))) - -#define GET_3BIT_LE16(_var_, _shift_) \ - (((_var_) & (((u16)7) << (_shift_))) >> (_shift_)) - -#define SET_3BIT_LE32(_u32ptr_, _shift_, _val_) \ - ((*(_u32ptr_) &= ~(7 << (_shift_))), \ - (*(_u32ptr_) |= (((*(_u32ptr_)) & (((u32)7) << (_shift_))) | \ - (((u32)(_val_) & 7) << _shift_)))) - -#define GET_3BIT_LE32(_var_, _shift_) \ - (((_var_) & (((u32)7) << (_shift_))) >> (_shift_)) +#define ERP_INFO_NON_ERP_PRESENT BIT(0) +#define ERP_INFO_USE_PROTECTION BIT(1) +#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) #define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) @@ -452,9 +410,6 @@ struct ieee80211_ht_operation { #define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) -#define MAC_HT_PARAM_INFO_MAX_RX_AMPDU_FACTOR_OFFSET 0 -#define MAC_HT_PARAM_INFO_MAX_MPDU_DENSITY_OFFSET 2 - #define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) #define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 #define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 @@ -490,22 +445,6 @@ struct ieee80211_ht_operation { #define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) #define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) - -struct ht_cap_ie { - u8 id; - u8 length; - struct ieee80211_ht_capability data; -} STRUCT_PACKED; - - -#define REC_TRANS_CHNL_WIDTH_20 0 -#define REC_TRANS_CHNL_WIDTH_ANY 1 - -#define OP_MODE_PURE 0 -#define OP_MODE_MAY_BE_LEGACY_STAS 1 -#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 -#define OP_MODE_MIXED 3 - #define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) #define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) @@ -514,6 +453,12 @@ struct ht_cap_ie { #define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) #define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) + +#define OP_MODE_PURE 0 +#define OP_MODE_MAY_BE_LEGACY_STAS 1 +#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 +#define OP_MODE_MIXED 3 + #define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ ((le16) (0x0001 | 0x0002)) #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 @@ -529,39 +474,10 @@ struct ht_cap_ie { #define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) -/* Secondary channel offset element */ -#define SECONDARY_CHANNEL_OFFSET_NONE 0 -#define SECONDARY_CHANNEL_OFFSET_ABOVE 1 -#define SECONDARY_CHANNEL_OFFSET_BELOW 3 -struct secondary_channel_offset_ie { - u8 id; - u8 length; - u8 secondary_offset_offset; -} STRUCT_PACKED; - - -/* body of Recommended Transmit Channel Width action frame */ -#define CHANNEL_WIDTH_20 0 -#define CHANNEL_WIDTH_ANY 1 -struct recommended_tx_channel_width_action { - u8 category; - u8 action; - u8 channel_width; -} STRUCT_PACKED; - -/* body of MIMO Power Save action frame */ -#define PWR_SAVE_MODE_STATIC 0 -#define PWR_SAVE_MODE_DYNAMIC 1 -struct mimo_pwr_save_action { - u8 category; - u8 action; - u8 enable; - u8 mode; -} STRUCT_PACKED; - - #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ +#define WPA_IE_VENDOR_TYPE 0x0050f201 +#define WPS_IE_VENDOR_TYPE 0x0050f204 #define WMM_OUI_TYPE 2 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 @@ -585,9 +501,107 @@ struct mimo_pwr_save_action { /* 2 - Reserved */ #define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 +/* + * WMM Information Element (used in (Re)Association Request frames; may also be + * used in Beacon frames) + */ +struct wmm_information_element { + /* Element ID: 221 (0xdd); Length: 7 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 0 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specific QoS info */ + +} STRUCT_PACKED; + +#define WMM_AC_AIFSN_MASK 0x0f +#define WMM_AC_AIFNS_SHIFT 0 +#define WMM_AC_ACM 0x10 +#define WMM_AC_ACI_MASK 0x60 +#define WMM_AC_ACI_SHIFT 5 + +#define WMM_AC_ECWMIN_MASK 0x0f +#define WMM_AC_ECWMIN_SHIFT 0 +#define WMM_AC_ECWMAX_MASK 0xf0 +#define WMM_AC_ECWMAX_SHIFT 4 + +struct wmm_ac_parameter { + u8 aci_aifsn; /* AIFSN, ACM, ACI */ + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ + le16 txop_limit; +} STRUCT_PACKED; + +/* + * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association + * Response frmaes) + */ +struct wmm_parameter_element { + /* Element ID: 221 (0xdd); Length: 24 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 1 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specif QoS info */ + u8 reserved; /* 0 */ + struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ + +} STRUCT_PACKED; + +/* WMM TSPEC Element */ +struct wmm_tspec_element { + u8 eid; /* 221 = 0xdd */ + u8 length; /* 6 + 55 = 61 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 2 */ + u8 version; /* 1 */ + /* WMM TSPEC body (55 octets): */ + u8 ts_info[3]; + le16 nominal_msdu_size; + le16 maximum_msdu_size; + le32 minimum_service_interval; + le32 maximum_service_interval; + le32 inactivity_interval; + le32 suspension_interval; + le32 service_start_time; + le32 minimum_data_rate; + le32 mean_data_rate; + le32 peak_data_rate; + le32 maximum_burst_size; + le32 delay_bound; + le32 minimum_phy_rate; + le16 surplus_bandwidth_allowance; + le16 medium_time; +} STRUCT_PACKED; + + +/* Access Categories / ACI to AC coding */ +enum { + WMM_AC_BE = 0 /* Best Effort */, + WMM_AC_BK = 1 /* Background */, + WMM_AC_VI = 2 /* Video */, + WMM_AC_VO = 3 /* Voice */ +}; + #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ #define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ +/* cipher suite selectors */ +#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 +#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 +#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 +/* reserved: 0x000FAC03 */ +#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 +#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 +#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 + +/* AKM suite selectors */ +#define WLAN_AKM_SUITE_8021X 0x000FAC01 +#define WLAN_AKM_SUITE_PSK 0x000FAC02 + #endif /* IEEE802_11_DEFS_H */ diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h index 81b7f5432ecc..cc900be9d20e 100644 --- a/src/common/privsep_commands.h +++ b/src/common/privsep_commands.h @@ -18,7 +18,6 @@ enum privsep_cmd { PRIVSEP_CMD_REGISTER, PRIVSEP_CMD_UNREGISTER, - PRIVSEP_CMD_SET_WPA, PRIVSEP_CMD_SCAN, PRIVSEP_CMD_GET_SCAN_RESULTS, PRIVSEP_CMD_ASSOCIATE, @@ -30,7 +29,6 @@ enum privsep_cmd { PRIVSEP_CMD_L2_UNREGISTER, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, PRIVSEP_CMD_L2_SEND, - PRIVSEP_CMD_SET_MODE, PRIVSEP_CMD_SET_COUNTRY, }; @@ -72,7 +70,6 @@ enum privsep_event { PRIVSEP_EVENT_STKSTART, PRIVSEP_EVENT_FT_RESPONSE, PRIVSEP_EVENT_RX_EAPOL, - PRIVSEP_EVENT_STA_RX, }; #endif /* PRIVSEP_COMMANDS_H */ diff --git a/src/common/version.h b/src/common/version.h index b79c4949c4da..02f34be3ab12 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -1,6 +1,6 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION_STR "0.6.10" +#define VERSION_STR "0.7.3" #endif /* VERSION_H */ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 074cb8064060..b295f315624a 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -15,11 +15,11 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "sha1.h" -#include "sha256.h" -#include "aes_wrap.h" -#include "crypto.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" #include "ieee802_11_defs.h" #include "defs.h" #include "wpa_common.h" @@ -50,10 +50,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, switch (ver) { case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: - hmac_md5(key, 16, buf, len, mic); - break; + return hmac_md5(key, 16, buf, len, mic); case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: - hmac_sha1(key, 16, buf, len, hash); + if (hmac_sha1(key, 16, buf, len, hash)) + return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) @@ -568,3 +568,220 @@ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, } #endif /* CONFIG_IEEE80211R */ + + +/** + * 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); +} + + +/** + * wpa_cipher_txt - Convert cipher suite to a text string + * @cipher: Cipher suite (WPA_CIPHER_* enum) + * Returns: Pointer to a text string of the cipher suite name + */ +const char * wpa_cipher_txt(int cipher) +{ + switch (cipher) { + case WPA_CIPHER_NONE: + return "NONE"; + case WPA_CIPHER_WEP40: + return "WEP-40"; + case WPA_CIPHER_WEP104: + return "WEP-104"; + case WPA_CIPHER_TKIP: + return "TKIP"; + case WPA_CIPHER_CCMP: + return "CCMP"; + case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: + return "CCMP+TKIP"; + default: + return "UNKNOWN"; + } +} + + +/** + * wpa_key_mgmt_txt - Convert key management suite to a text string + * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) + * @proto: WPA/WPA2 version (WPA_PROTO_*) + * Returns: Pointer to a text string of the key management suite name + */ +const char * wpa_key_mgmt_txt(int key_mgmt, int proto) +{ + switch (key_mgmt) { + case WPA_KEY_MGMT_IEEE8021X: + if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) + return "WPA2+WPA/IEEE 802.1X/EAP"; + return proto == WPA_PROTO_RSN ? + "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; + case WPA_KEY_MGMT_PSK: + if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) + return "WPA2-PSK+WPA-PSK"; + return proto == WPA_PROTO_RSN ? + "WPA2-PSK" : "WPA-PSK"; + case WPA_KEY_MGMT_NONE: + return "NONE"; + case WPA_KEY_MGMT_IEEE8021X_NO_WPA: + return "IEEE 802.1X (no WPA)"; +#ifdef CONFIG_IEEE80211R + case WPA_KEY_MGMT_FT_IEEE8021X: + return "FT-EAP"; + case WPA_KEY_MGMT_FT_PSK: + return "FT-PSK"; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + case WPA_KEY_MGMT_IEEE8021X_SHA256: + return "WPA2-EAP-SHA256"; + case WPA_KEY_MGMT_PSK_SHA256: + return "WPA2-PSK-SHA256"; +#endif /* CONFIG_IEEE80211W */ + default: + return "UNKNOWN"; + } +} + + +int wpa_compare_rsn_ie(int ft_initial_assoc, + const u8 *ie1, size_t ie1len, + const u8 *ie2, size_t ie2len) +{ + if (ie1 == NULL || ie2 == NULL) + return -1; + + if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) + return 0; /* identical IEs */ + +#ifdef CONFIG_IEEE80211R + if (ft_initial_assoc) { + struct wpa_ie_data ie1d, ie2d; + /* + * The PMKID-List in RSN IE is different between Beacon/Probe + * Response/(Re)Association Request frames and EAPOL-Key + * messages in FT initial mobility domain association. Allow + * for this, but verify that other parts of the RSN IEs are + * identical. + */ + if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || + wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) + return -1; + if (ie1d.proto == ie2d.proto && + ie1d.pairwise_cipher == ie2d.pairwise_cipher && + ie1d.group_cipher == ie2d.group_cipher && + ie1d.key_mgmt == ie2d.key_mgmt && + ie1d.capabilities == ie2d.capabilities && + ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) + return 0; + } +#endif /* CONFIG_IEEE80211R */ + + return -1; +} + + +#ifdef CONFIG_IEEE80211R +int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) +{ + u8 *start, *end, *rpos, *rend; + int added = 0; + + start = ies; + end = ies + ies_len; + + while (start < end) { + if (*start == WLAN_EID_RSN) + break; + start += 2 + start[1]; + } + if (start >= end) { + wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " + "IEs data"); + return -1; + } + wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", + start, 2 + start[1]); + + /* Find start of PMKID-Count */ + rpos = start + 2; + rend = rpos + start[1]; + + /* Skip Version and Group Data Cipher Suite */ + rpos += 2 + 4; + /* Skip Pairwise Cipher Suite Count and List */ + rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; + /* Skip AKM Suite Count and List */ + rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; + + if (rpos == rend) { + /* Add RSN Capabilities */ + os_memmove(rpos + 2, rpos, end - rpos); + *rpos++ = 0; + *rpos++ = 0; + } else { + /* Skip RSN Capabilities */ + rpos += 2; + if (rpos > rend) { + wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " + "IEs data"); + return -1; + } + } + + if (rpos == rend) { + /* No PMKID-Count field included; add it */ + os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); + WPA_PUT_LE16(rpos, 1); + rpos += 2; + os_memcpy(rpos, pmkid, PMKID_LEN); + added += 2 + PMKID_LEN; + start[1] += 2 + PMKID_LEN; + } else { + /* PMKID-Count was included; use it */ + if (WPA_GET_LE16(rpos) != 0) { + wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " + "in RSN IE in EAPOL-Key data"); + return -1; + } + WPA_PUT_LE16(rpos, 1); + rpos += 2; + os_memmove(rpos + PMKID_LEN, rpos, end - rpos); + os_memcpy(rpos, pmkid, PMKID_LEN); + added += PMKID_LEN; + start[1] += PMKID_LEN; + } + + wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " + "(PMKID inserted)", start, 2 + start[1]); + + return added; +} +#endif /* CONFIG_IEEE80211R */ diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 3074cd44a136..fd8a79fd602e 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -282,6 +282,12 @@ struct rsn_ftie { #define FTIE_SUBELEM_R0KH_ID 3 #define FTIE_SUBELEM_IGTK 4 +struct rsn_rdie { + u8 id; + u8 descr_count; + le16 status_code; +} STRUCT_PACKED; + #endif /* CONFIG_IEEE80211R */ #ifdef _MSC_VER @@ -332,4 +338,14 @@ struct wpa_ie_data { int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data); +void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, + u8 *pmkid, int use_sha256); + +const char * wpa_cipher_txt(int cipher); +const char * wpa_key_mgmt_txt(int key_mgmt, int proto); +int wpa_compare_rsn_ie(int ft_initial_assoc, + const u8 *ie1, size_t ie1len, + const u8 *ie2, size_t ie2len); +int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid); + #endif /* WPA_COMMON_H */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 1bfc0d645346..d770fd42d94f 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -40,14 +40,24 @@ extern "C" { #define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " /** EAP authentication started (EAP-Request/Identity received) */ #define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " +/** EAP method proposed by the server */ +#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD " /** EAP method selected */ #define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " +/** EAP peer certificate from TLS */ +#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT " +/** EAP TLS certificate chain validation error */ +#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR " /** EAP authentication completed successfully */ #define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " /** EAP authentication failed (EAP-Failure received) */ #define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " /** New scan results available */ #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " +/** A new BSS entry was added (followed by BSS entry id and BSSID) */ +#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED " +/** A BSS entry was removed (followed by BSS entry id and BSSID) */ +#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED " /** WPS overlap detected in PBC mode */ #define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED " @@ -69,11 +79,24 @@ extern "C" { /** WPS enrollment attempt timed out and was terminated */ #define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " +#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " + +/* WPS ER events */ +#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " +#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE " +#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD " +#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE " + /* hostapd control interface - fixed message prefixes */ #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " #define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS " #define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS " #define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED " +#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED " +#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED " +#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED " +#define AP_STA_CONNECTED "AP-STA-CONNECTED " +#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED " /* wpa_supplicant/hostapd control interface access */ diff --git a/src/crypto/.gitignore b/src/crypto/.gitignore new file mode 100644 index 000000000000..ee606048c417 --- /dev/null +++ b/src/crypto/.gitignore @@ -0,0 +1 @@ +libcrypto.a diff --git a/src/crypto/Makefile b/src/crypto/Makefile index cffba620da04..69aa16ac66b0 100644 --- a/src/crypto/Makefile +++ b/src/crypto/Makefile @@ -1,9 +1,56 @@ -all: - @echo Nothing to be made. +all: libcrypto.a clean: - for d in $(SUBDIRS); do make -C $$d clean; done - rm -f *~ *.o *.d + rm -f *~ *.o *.d libcrypto.a install: @echo Nothing to be made. + + +include ../lib.rules + +CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT +CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER +#CFLAGS += -DALL_DH_GROUPS + +LIB_OBJS= \ + aes-cbc.o \ + aes-ctr.o \ + aes-eax.o \ + aes-encblock.o \ + aes-internal.o \ + aes-internal-dec.o \ + aes-internal-enc.o \ + aes-omac1.o \ + aes-unwrap.o \ + aes-wrap.o \ + des-internal.o \ + dh_group5.o \ + dh_groups.o \ + md4-internal.o \ + md5.o \ + md5-internal.o \ + md5-non-fips.o \ + milenage.o \ + ms_funcs.o \ + rc4.o \ + sha1.o \ + sha1-internal.o \ + sha1-pbkdf2.o \ + sha1-tlsprf.o \ + sha1-tprf.o \ + sha256.o \ + sha256-internal.o + +LIB_OBJS += crypto_internal.o +LIB_OBJS += crypto_internal-cipher.o +LIB_OBJS += crypto_internal-modexp.o +LIB_OBJS += crypto_internal-rsa.o +LIB_OBJS += tls_internal.o +LIB_OBJS += fips_prf_internal.o + + +libcrypto.a: $(LIB_OBJS) + $(AR) crT $@ $? + +-include $(OBJS:%.o=%.d) diff --git a/src/crypto/aes-cbc.c b/src/crypto/aes-cbc.c new file mode 100644 index 000000000000..bd74769905e1 --- /dev/null +++ b/src/crypto/aes-cbc.c @@ -0,0 +1,86 @@ +/* + * AES-128 CBC + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +/** + * aes_128_cbc_encrypt - AES-128 CBC encryption + * @key: Encryption key + * @iv: Encryption IV for CBC mode (16 bytes) + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE]; + u8 *pos = data; + int i, j, blocks; + + ctx = aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + + blocks = data_len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + for (j = 0; j < AES_BLOCK_SIZE; j++) + cbc[j] ^= pos[j]; + aes_encrypt(ctx, cbc, cbc); + os_memcpy(pos, cbc, AES_BLOCK_SIZE); + pos += AES_BLOCK_SIZE; + } + aes_encrypt_deinit(ctx); + return 0; +} + + +/** + * aes_128_cbc_decrypt - AES-128 CBC decryption + * @key: Decryption key + * @iv: Decryption IV for CBC mode (16 bytes) + * @data: Data to decrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; + u8 *pos = data; + int i, j, blocks; + + ctx = aes_decrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + + blocks = data_len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, pos, AES_BLOCK_SIZE); + aes_decrypt(ctx, pos, pos); + for (j = 0; j < AES_BLOCK_SIZE; j++) + pos[j] ^= cbc[j]; + os_memcpy(cbc, tmp, AES_BLOCK_SIZE); + pos += AES_BLOCK_SIZE; + } + aes_decrypt_deinit(ctx); + return 0; +} diff --git a/src/crypto/aes-ctr.c b/src/crypto/aes-ctr.c new file mode 100644 index 000000000000..468f87741199 --- /dev/null +++ b/src/crypto/aes-ctr.c @@ -0,0 +1,61 @@ +/* + * AES-128 CTR + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +/** + * aes_128_ctr_encrypt - AES-128 CTR mode encryption + * @key: Key for encryption (16 bytes) + * @nonce: Nonce for counter mode (16 bytes) + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes + * Returns: 0 on success, -1 on failure + */ +int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, + u8 *data, size_t data_len) +{ + void *ctx; + size_t j, len, left = data_len; + int i; + u8 *pos = data; + u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE]; + + ctx = aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(counter, nonce, AES_BLOCK_SIZE); + + while (left > 0) { + aes_encrypt(ctx, counter, buf); + + len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE; + for (j = 0; j < len; j++) + pos[j] ^= buf[j]; + pos += len; + left -= len; + + for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) { + counter[i]++; + if (counter[i]) + break; + } + } + aes_encrypt_deinit(ctx); + return 0; +} diff --git a/src/crypto/aes-eax.c b/src/crypto/aes-eax.c new file mode 100644 index 000000000000..d5c397151d2e --- /dev/null +++ b/src/crypto/aes-eax.c @@ -0,0 +1,151 @@ +/* + * AES-128 EAX + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +/** + * aes_128_eax_encrypt - AES-128 EAX mode encryption + * @key: Key for encryption (16 bytes) + * @nonce: Nonce for counter mode + * @nonce_len: Nonce length in bytes + * @hdr: Header data to be authenticity protected + * @hdr_len: Length of the header data bytes + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes + * @tag: 16-byte tag value + * Returns: 0 on success, -1 on failure + */ +int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, + const u8 *hdr, size_t hdr_len, + u8 *data, size_t data_len, u8 *tag) +{ + u8 *buf; + size_t buf_len; + u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], + data_mac[AES_BLOCK_SIZE]; + int i, ret = -1; + + if (nonce_len > data_len) + buf_len = nonce_len; + else + buf_len = data_len; + if (hdr_len > buf_len) + buf_len = hdr_len; + buf_len += 16; + + buf = os_malloc(buf_len); + if (buf == NULL) + return -1; + + os_memset(buf, 0, 15); + + buf[15] = 0; + os_memcpy(buf + 16, nonce, nonce_len); + if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) + goto fail; + + buf[15] = 1; + os_memcpy(buf + 16, hdr, hdr_len); + if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) + goto fail; + + if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len)) + goto fail; + buf[15] = 2; + os_memcpy(buf + 16, data, data_len); + if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) + goto fail; + + for (i = 0; i < AES_BLOCK_SIZE; i++) + tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; + + ret = 0; +fail: + os_free(buf); + + return ret; +} + + +/** + * aes_128_eax_decrypt - AES-128 EAX mode decryption + * @key: Key for decryption (16 bytes) + * @nonce: Nonce for counter mode + * @nonce_len: Nonce length in bytes + * @hdr: Header data to be authenticity protected + * @hdr_len: Length of the header data bytes + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes + * @tag: 16-byte tag value + * Returns: 0 on success, -1 on failure, -2 if tag does not match + */ +int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, + const u8 *hdr, size_t hdr_len, + u8 *data, size_t data_len, const u8 *tag) +{ + u8 *buf; + size_t buf_len; + u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], + data_mac[AES_BLOCK_SIZE]; + int i; + + if (nonce_len > data_len) + buf_len = nonce_len; + else + buf_len = data_len; + if (hdr_len > buf_len) + buf_len = hdr_len; + buf_len += 16; + + buf = os_malloc(buf_len); + if (buf == NULL) + return -1; + + os_memset(buf, 0, 15); + + buf[15] = 0; + os_memcpy(buf + 16, nonce, nonce_len); + if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) { + os_free(buf); + return -1; + } + + buf[15] = 1; + os_memcpy(buf + 16, hdr, hdr_len); + if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) { + os_free(buf); + return -1; + } + + buf[15] = 2; + os_memcpy(buf + 16, data, data_len); + if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) { + os_free(buf); + return -1; + } + + os_free(buf); + + for (i = 0; i < AES_BLOCK_SIZE; i++) { + if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) + return -2; + } + + return aes_128_ctr_encrypt(key, nonce_mac, data, data_len); +} diff --git a/src/crypto/aes-encblock.c b/src/crypto/aes-encblock.c new file mode 100644 index 000000000000..8f35caa221e2 --- /dev/null +++ b/src/crypto/aes-encblock.c @@ -0,0 +1,38 @@ +/* + * AES encrypt_block + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +/** + * aes_128_encrypt_block - Perform one AES 128-bit block operation + * @key: Key for AES + * @in: Input data (16 bytes) + * @out: Output of the AES block operation (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) +{ + void *ctx; + ctx = aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + aes_encrypt(ctx, in, out); + aes_encrypt_deinit(ctx); + return 0; +} diff --git a/src/crypto/aes-internal-dec.c b/src/crypto/aes-internal-dec.c new file mode 100644 index 000000000000..2d32c03fbf4c --- /dev/null +++ b/src/crypto/aes-internal-dec.c @@ -0,0 +1,151 @@ +/* + * AES (Rijndael) cipher - decrypt + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "crypto.h" +#include "aes_i.h" + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[]) +{ + int Nr = 10, i, j; + u32 temp; + + /* expand the cipher key: */ + rijndaelKeySetupEnc(rk, cipherKey); + /* invert the order of the round keys: */ + for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the + * first and the last: */ + for (i = 1; i < Nr; i++) { + rk += 4; + for (j = 0; j < 4; j++) { + rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ + TD1_(TE4((rk[j] >> 16) & 0xff)) ^ + TD2_(TE4((rk[j] >> 8) & 0xff)) ^ + TD3_(TE4((rk[j] ) & 0xff)); + } + } +} + +void * aes_decrypt_init(const u8 *key, size_t len) +{ + u32 *rk; + if (len != 16) + return NULL; + rk = os_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + rijndaelKeySetupDec(rk, key); + return rk; +} + +static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; + const int Nr = 10; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ +d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ +d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ +d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] + +#ifdef FULL_UNROLL + + ROUND(1,t,s); + ROUND(2,s,t); + ROUND(3,t,s); + ROUND(4,s,t); + ROUND(5,t,s); + ROUND(6,s,t); + ROUND(7,t,s); + ROUND(8,s,t); + ROUND(9,t,s); + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1,t,s); + rk += 8; + if (--r == 0) + break; + ROUND(0,s,t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; + PUTU32(pt , s0); + s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; + PUTU32(pt + 4, s1); + s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; + PUTU32(pt + 8, s2); + s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; + PUTU32(pt + 12, s3); +} + +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + rijndaelDecrypt(ctx, crypt, plain); +} + + +void aes_decrypt_deinit(void *ctx) +{ + os_memset(ctx, 0, AES_PRIV_SIZE); + os_free(ctx); +} diff --git a/src/crypto/aes-internal-enc.c b/src/crypto/aes-internal-enc.c new file mode 100644 index 000000000000..2f198263bb84 --- /dev/null +++ b/src/crypto/aes-internal-enc.c @@ -0,0 +1,121 @@ +/* + * AES (Rijndael) cipher - encrypt + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "crypto.h" +#include "aes_i.h" + +void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; + const int Nr = 10; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ +d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ +d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ +d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] + +#ifdef FULL_UNROLL + + ROUND(1,t,s); + ROUND(2,s,t); + ROUND(3,t,s); + ROUND(4,s,t); + ROUND(5,t,s); + ROUND(6,s,t); + ROUND(7,t,s); + ROUND(8,s,t); + ROUND(9,t,s); + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1,t,s); + rk += 8; + if (--r == 0) + break; + ROUND(0,s,t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; + PUTU32(ct , s0); + s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; + PUTU32(ct + 4, s1); + s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; + PUTU32(ct + 8, s2); + s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; + PUTU32(ct + 12, s3); +} + + +void * aes_encrypt_init(const u8 *key, size_t len) +{ + u32 *rk; + if (len != 16) + return NULL; + rk = os_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + rijndaelKeySetupEnc(rk, key); + return rk; +} + + +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + rijndaelEncrypt(ctx, plain, crypt); +} + + +void aes_encrypt_deinit(void *ctx) +{ + os_memset(ctx, 0, AES_PRIV_SIZE); + os_free(ctx); +} diff --git a/src/crypto/aes.c b/src/crypto/aes-internal.c similarity index 82% rename from src/crypto/aes.c rename to src/crypto/aes-internal.c index 8b8f2a04dee2..416122022066 100644 --- a/src/crypto/aes.c +++ b/src/crypto/aes-internal.c @@ -24,10 +24,8 @@ #include "includes.h" #include "common.h" - -#ifdef INTERNAL_AES - #include "crypto.h" +#include "aes_i.h" /* * rijndael-alg-fst.c @@ -55,9 +53,6 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* #define FULL_UNROLL */ -#define AES_SMALL_TABLES - /* Te0[x] = S [x].[02, 01, 01, 03]; @@ -73,7 +68,7 @@ Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ -static const u32 Te0[256] = { +const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, @@ -140,7 +135,7 @@ static const u32 Te0[256] = { 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; #ifndef AES_SMALL_TABLES -static const u32 Te1[256] = { +const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, @@ -206,7 +201,7 @@ static const u32 Te1[256] = { 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; -static const u32 Te2[256] = { +const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, @@ -272,7 +267,7 @@ static const u32 Te2[256] = { 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; -static const u32 Te3[256] = { +const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, @@ -339,7 +334,7 @@ static const u32 Te3[256] = { 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; -static const u32 Te4[256] = { +const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, @@ -406,7 +401,7 @@ static const u32 Te4[256] = { 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; #endif /* AES_SMALL_TABLES */ -static const u32 Td0[256] = { +const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, @@ -473,7 +468,7 @@ static const u32 Td0[256] = { 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; #ifndef AES_SMALL_TABLES -static const u32 Td1[256] = { +const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, @@ -539,7 +534,7 @@ static const u32 Td1[256] = { 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; -static const u32 Td2[256] = { +const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, @@ -606,7 +601,7 @@ static const u32 Td2[256] = { 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; -static const u32 Td3[256] = { +const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, @@ -672,7 +667,7 @@ static const u32 Td3[256] = { 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; -static const u32 Td4[256] = { +const u32 Td4[256] = { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, @@ -738,13 +733,13 @@ static const u32 Td4[256] = { 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, }; -static const u32 rcon[] = { +const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #else /* AES_SMALL_TABLES */ -static const u8 Td4s[256] = { +const u8 Td4s[256] = { 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, @@ -778,95 +773,11 @@ static const u8 Td4s[256] = { 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, }; -static const u8 rcons[] = { +const u8 rcons[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #endif /* AES_SMALL_TABLES */ - - -#ifndef AES_SMALL_TABLES - -#define RCON(i) rcon[(i)] - -#define TE0(i) Te0[((i) >> 24) & 0xff] -#define TE1(i) Te1[((i) >> 16) & 0xff] -#define TE2(i) Te2[((i) >> 8) & 0xff] -#define TE3(i) Te3[(i) & 0xff] -#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) -#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) -#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) -#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) -#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) -#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) -#define TE4(i) (Te4[(i)] & 0x000000ff) - -#define TD0(i) Td0[((i) >> 24) & 0xff] -#define TD1(i) Td1[((i) >> 16) & 0xff] -#define TD2(i) Td2[((i) >> 8) & 0xff] -#define TD3(i) Td3[(i) & 0xff] -#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) -#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) -#define TD0_(i) Td0[(i) & 0xff] -#define TD1_(i) Td1[(i) & 0xff] -#define TD2_(i) Td2[(i) & 0xff] -#define TD3_(i) Td3[(i) & 0xff] - -#else /* AES_SMALL_TABLES */ - -#define RCON(i) (rcons[(i)] << 24) - -static inline u32 rotr(u32 val, int bits) -{ - return (val >> bits) | (val << (32 - bits)); -} - -#define TE0(i) Te0[((i) >> 24) & 0xff] -#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) -#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) -#define TE3(i) rotr(Te0[(i) & 0xff], 24) -#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) -#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) -#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) -#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) -#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) -#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) -#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) - -#define TD0(i) Td0[((i) >> 24) & 0xff] -#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) -#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) -#define TD3(i) rotr(Td0[(i) & 0xff], 24) -#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) -#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) -#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) -#define TD44(i) (Td4s[(i) & 0xff]) -#define TD0_(i) Td0[(i) & 0xff] -#define TD1_(i) rotr(Td0[(i) & 0xff], 8) -#define TD2_(i) rotr(Td0[(i) & 0xff], 16) -#define TD3_(i) rotr(Td0[(i) & 0xff], 24) - -#endif /* AES_SMALL_TABLES */ - -#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) - -#ifdef _MSC_VER -#define GETU32(p) SWAP(*((u32 *)(p))) -#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } -#else -#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ -((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) -#define PUTU32(ct, st) { \ -(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ -(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } -#endif - /** * Expand the cipher key into the encryption key schedule. * @@ -892,236 +803,3 @@ void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) rk += 4; } } - -#ifndef CONFIG_NO_AES_DECRYPT -/** - * Expand the cipher key into the decryption key schedule. - * - * @return the number of rounds for the given cipher key size. - */ -void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[]) -{ - int Nr = 10, i, j; - u32 temp; - - /* expand the cipher key: */ - rijndaelKeySetupEnc(rk, cipherKey); - /* invert the order of the round keys: */ - for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { - temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; - temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; - temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; - temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; - } - /* apply the inverse MixColumn transform to all round keys but the - * first and the last: */ - for (i = 1; i < Nr; i++) { - rk += 4; - for (j = 0; j < 4; j++) { - rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ - TD1_(TE4((rk[j] >> 16) & 0xff)) ^ - TD2_(TE4((rk[j] >> 8) & 0xff)) ^ - TD3_(TE4((rk[j] ) & 0xff)); - } - } -} -#endif /* CONFIG_NO_AES_DECRYPT */ - -#ifndef CONFIG_NO_AES_ENCRYPT -void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) -{ - u32 s0, s1, s2, s3, t0, t1, t2, t3; - const int Nr = 10; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(pt ) ^ rk[0]; - s1 = GETU32(pt + 4) ^ rk[1]; - s2 = GETU32(pt + 8) ^ rk[2]; - s3 = GETU32(pt + 12) ^ rk[3]; - -#define ROUND(i,d,s) \ -d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ -d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ -d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ -d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] - -#ifdef FULL_UNROLL - - ROUND(1,t,s); - ROUND(2,s,t); - ROUND(3,t,s); - ROUND(4,s,t); - ROUND(5,t,s); - ROUND(6,s,t); - ROUND(7,t,s); - ROUND(8,s,t); - ROUND(9,t,s); - - rk += Nr << 2; - -#else /* !FULL_UNROLL */ - - /* Nr - 1 full rounds: */ - r = Nr >> 1; - for (;;) { - ROUND(1,t,s); - rk += 8; - if (--r == 0) - break; - ROUND(0,s,t); - } - -#endif /* ?FULL_UNROLL */ - -#undef ROUND - - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; - PUTU32(ct , s0); - s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; - PUTU32(ct + 4, s1); - s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; - PUTU32(ct + 8, s2); - s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; - PUTU32(ct + 12, s3); -} -#endif /* CONFIG_NO_AES_ENCRYPT */ - -void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16]) -{ - u32 s0, s1, s2, s3, t0, t1, t2, t3; - const int Nr = 10; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(ct ) ^ rk[0]; - s1 = GETU32(ct + 4) ^ rk[1]; - s2 = GETU32(ct + 8) ^ rk[2]; - s3 = GETU32(ct + 12) ^ rk[3]; - -#define ROUND(i,d,s) \ -d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ -d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ -d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ -d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] - -#ifdef FULL_UNROLL - - ROUND(1,t,s); - ROUND(2,s,t); - ROUND(3,t,s); - ROUND(4,s,t); - ROUND(5,t,s); - ROUND(6,s,t); - ROUND(7,t,s); - ROUND(8,s,t); - ROUND(9,t,s); - - rk += Nr << 2; - -#else /* !FULL_UNROLL */ - - /* Nr - 1 full rounds: */ - r = Nr >> 1; - for (;;) { - ROUND(1,t,s); - rk += 8; - if (--r == 0) - break; - ROUND(0,s,t); - } - -#endif /* ?FULL_UNROLL */ - -#undef ROUND - - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; - PUTU32(pt , s0); - s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; - PUTU32(pt + 4, s1); - s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; - PUTU32(pt + 8, s2); - s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; - PUTU32(pt + 12, s3); -} - - - -/* Generic wrapper functions for AES functions */ - -#define AES_PRIV_SIZE (4 * 44) - -#ifndef CONFIG_NO_AES_ENCRYPT -void * aes_encrypt_init(const u8 *key, size_t len) -{ - u32 *rk; - if (len != 16) - return NULL; - rk = os_malloc(AES_PRIV_SIZE); - if (rk == NULL) - return NULL; - rijndaelKeySetupEnc(rk, key); - return rk; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - rijndaelEncrypt(ctx, plain, crypt); -} - - -void aes_encrypt_deinit(void *ctx) -{ - os_memset(ctx, 0, AES_PRIV_SIZE); - os_free(ctx); -} -#endif /* CONFIG_NO_AES_ENCRYPT */ - - -#ifndef CONFIG_NO_AES_DECRYPT -void * aes_decrypt_init(const u8 *key, size_t len) -{ - u32 *rk; - if (len != 16) - return NULL; - rk = os_malloc(AES_PRIV_SIZE); - if (rk == NULL) - return NULL; - rijndaelKeySetupDec(rk, key); - return rk; -} - - -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -{ - rijndaelDecrypt(ctx, crypt, plain); -} - - -void aes_decrypt_deinit(void *ctx) -{ - os_memset(ctx, 0, AES_PRIV_SIZE); - os_free(ctx); -} -#endif /* CONFIG_NO_AES_DECRYPT */ - -#endif /* INTERNAL_AES */ diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c new file mode 100644 index 000000000000..f77529617a31 --- /dev/null +++ b/src/crypto/aes-omac1.c @@ -0,0 +1,124 @@ +/* + * One-key CBC MAC (OMAC1) hash with AES-128 + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +static void gf_mulx(u8 *pad) +{ + int i, carry; + + carry = pad[0] & 0x80; + for (i = 0; i < AES_BLOCK_SIZE - 1; i++) + pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); + pad[AES_BLOCK_SIZE - 1] <<= 1; + if (carry) + pad[AES_BLOCK_SIZE - 1] ^= 0x87; +} + + +/** + * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 + * @key: 128-bit key for the hash operation + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +int omac1_aes_128_vector(const u8 *key, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; + const u8 *pos, *end; + size_t i, e, left, total_len; + + ctx = aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memset(cbc, 0, AES_BLOCK_SIZE); + + total_len = 0; + for (e = 0; e < num_elem; e++) + total_len += len[e]; + left = total_len; + + e = 0; + pos = addr[0]; + end = pos + len[0]; + + while (left >= AES_BLOCK_SIZE) { + for (i = 0; i < AES_BLOCK_SIZE; i++) { + cbc[i] ^= *pos++; + if (pos >= end) { + e++; + pos = addr[e]; + end = pos + len[e]; + } + } + if (left > AES_BLOCK_SIZE) + aes_encrypt(ctx, cbc, cbc); + left -= AES_BLOCK_SIZE; + } + + os_memset(pad, 0, AES_BLOCK_SIZE); + aes_encrypt(ctx, pad, pad); + gf_mulx(pad); + + if (left || total_len == 0) { + for (i = 0; i < left; i++) { + cbc[i] ^= *pos++; + if (pos >= end) { + e++; + pos = addr[e]; + end = pos + len[e]; + } + } + cbc[left] ^= 0x80; + gf_mulx(pad); + } + + for (i = 0; i < AES_BLOCK_SIZE; i++) + pad[i] ^= cbc[i]; + aes_encrypt(ctx, pad, mac); + aes_encrypt_deinit(ctx); + return 0; +} + + +/** + * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) + * @key: 128-bit key for the hash operation + * @data: Data buffer for which a MAC is determined + * @data_len: Length of data buffer in bytes + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_128_vector(key, 1, &data, &data_len, mac); +} diff --git a/src/crypto/aes-unwrap.c b/src/crypto/aes-unwrap.c new file mode 100644 index 000000000000..f233ffa4c04c --- /dev/null +++ b/src/crypto/aes-unwrap.c @@ -0,0 +1,79 @@ +/* + * AES key unwrap (128-bit KEK, RFC3394) + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +/** + * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * @kek: Key encryption key (KEK) + * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 + * bytes + * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits + * @plain: Plaintext key, n * 64 bits + * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) + */ +int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) +{ + u8 a[8], *r, b[16]; + int i, j; + void *ctx; + + /* 1) Initialize variables. */ + os_memcpy(a, cipher, 8); + r = plain; + os_memcpy(r, cipher + 8, 8 * n); + + ctx = aes_decrypt_init(kek, 16); + if (ctx == NULL) + return -1; + + /* 2) Compute intermediate values. + * For j = 5 to 0 + * For i = n to 1 + * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + * A = MSB(64, B) + * R[i] = LSB(64, B) + */ + for (j = 5; j >= 0; j--) { + r = plain + (n - 1) * 8; + for (i = n; i >= 1; i--) { + os_memcpy(b, a, 8); + b[7] ^= n * j + i; + + os_memcpy(b + 8, r, 8); + aes_decrypt(ctx, b, b); + os_memcpy(a, b, 8); + os_memcpy(r, b + 8, 8); + r -= 8; + } + } + aes_decrypt_deinit(ctx); + + /* 3) Output results. + * + * These are already in @plain due to the location of temporary + * variables. Just verify that the IV matches with the expected value. + */ + for (i = 0; i < 8; i++) { + if (a[i] != 0xa6) + return -1; + } + + return 0; +} diff --git a/src/crypto/aes-wrap.c b/src/crypto/aes-wrap.c new file mode 100644 index 000000000000..28d0c89e88f0 --- /dev/null +++ b/src/crypto/aes-wrap.c @@ -0,0 +1,76 @@ +/* + * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "aes.h" +#include "aes_wrap.h" + +/** + * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * @kek: 16-octet Key encryption key (KEK) + * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 + * bytes + * @plain: Plaintext key to be wrapped, n * 64 bits + * @cipher: Wrapped key, (n + 1) * 64 bits + * Returns: 0 on success, -1 on failure + */ +int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) +{ + u8 *a, *r, b[16]; + int i, j; + void *ctx; + + a = cipher; + r = cipher + 8; + + /* 1) Initialize variables. */ + os_memset(a, 0xa6, 8); + os_memcpy(r, plain, 8 * n); + + ctx = aes_encrypt_init(kek, 16); + if (ctx == NULL) + return -1; + + /* 2) Calculate intermediate values. + * For j = 0 to 5 + * For i=1 to n + * B = AES(K, A | R[i]) + * A = MSB(64, B) ^ t where t = (n*j)+i + * R[i] = LSB(64, B) + */ + for (j = 0; j <= 5; j++) { + r = cipher + 8; + for (i = 1; i <= n; i++) { + os_memcpy(b, a, 8); + os_memcpy(b + 8, r, 8); + aes_encrypt(ctx, b, b); + os_memcpy(a, b, 8); + a[7] ^= n * j + i; + os_memcpy(r, b + 8, 8); + r += 8; + } + } + aes_encrypt_deinit(ctx); + + /* 3) Output the results. + * + * These are already in @cipher due to the location of temporary + * variables. + */ + + return 0; +} diff --git a/src/crypto/aes.h b/src/crypto/aes.h index 6b9f4147afb1..ba384a9dae37 100644 --- a/src/crypto/aes.h +++ b/src/crypto/aes.h @@ -15,6 +15,8 @@ #ifndef AES_H #define AES_H +#define AES_BLOCK_SIZE 16 + void * aes_encrypt_init(const u8 *key, size_t len); void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); void aes_encrypt_deinit(void *ctx); diff --git a/src/crypto/aes_i.h b/src/crypto/aes_i.h new file mode 100644 index 000000000000..6b40bc781651 --- /dev/null +++ b/src/crypto/aes_i.h @@ -0,0 +1,122 @@ +/* + * AES (Rijndael) cipher + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 AES_I_H +#define AES_I_H + +#include "aes.h" + +/* #define FULL_UNROLL */ +#define AES_SMALL_TABLES + +extern const u32 Te0[256]; +extern const u32 Te1[256]; +extern const u32 Te2[256]; +extern const u32 Te3[256]; +extern const u32 Te4[256]; +extern const u32 Td0[256]; +extern const u32 Td1[256]; +extern const u32 Td2[256]; +extern const u32 Td3[256]; +extern const u32 Td4[256]; +extern const u32 rcon[10]; +extern const u8 Td4s[256]; +extern const u8 rcons[10]; + +#ifndef AES_SMALL_TABLES + +#define RCON(i) rcon[(i)] + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) Te1[((i) >> 16) & 0xff] +#define TE2(i) Te2[((i) >> 8) & 0xff] +#define TE3(i) Te3[(i) & 0xff] +#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) +#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) +#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) +#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) +#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) +#define TE4(i) (Te4[(i)] & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) Td1[((i) >> 16) & 0xff] +#define TD2(i) Td2[((i) >> 8) & 0xff] +#define TD3(i) Td3[(i) & 0xff] +#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) +#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) Td1[(i) & 0xff] +#define TD2_(i) Td2[(i) & 0xff] +#define TD3_(i) Td3[(i) & 0xff] + +#else /* AES_SMALL_TABLES */ + +#define RCON(i) (rcons[(i)] << 24) + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) +#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) +#define TE3(i) rotr(Te0[(i) & 0xff], 24) +#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) +#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) +#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) +#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) +#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) +#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) +#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) +#define TD3(i) rotr(Td0[(i) & 0xff], 24) +#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) +#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) +#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) +#define TD44(i) (Td4s[(i) & 0xff]) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) rotr(Td0[(i) & 0xff], 8) +#define TD2_(i) rotr(Td0[(i) & 0xff], 16) +#define TD3_(i) rotr(Td0[(i) & 0xff], 24) + +#endif /* AES_SMALL_TABLES */ + +#ifdef _MSC_VER +#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +#define GETU32(p) SWAP(*((u32 *)(p))) +#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } +#else +#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ +((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +#define PUTU32(ct, st) { \ +(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ +(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } +#endif + +#define AES_PRIV_SIZE (4 * 44) + +void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]); + +#endif /* AES_I_H */ diff --git a/src/crypto/aes_wrap.c b/src/crypto/aes_wrap.c deleted file mode 100644 index b1448b0d9a8d..000000000000 --- a/src/crypto/aes_wrap.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * AES-based functions - * - * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * - One-Key CBC MAC (OMAC1, i.e., CMAC) hash with AES-128 - * - AES-128 CTR mode encryption - * - AES-128 EAX mode encryption/decryption - * - AES-128 CBC - * - * Copyright (c) 2003-2007, Jouni Malinen - * - * 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 "aes_wrap.h" -#include "crypto.h" - -#ifndef CONFIG_NO_AES_WRAP - -/** - * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: 16-octet Key encryption key (KEK) - * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 - * bytes - * @plain: Plaintext key to be wrapped, n * 64 bits - * @cipher: Wrapped key, (n + 1) * 64 bits - * Returns: 0 on success, -1 on failure - */ -int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) -{ - u8 *a, *r, b[16]; - int i, j; - void *ctx; - - a = cipher; - r = cipher + 8; - - /* 1) Initialize variables. */ - os_memset(a, 0xa6, 8); - os_memcpy(r, plain, 8 * n); - - ctx = aes_encrypt_init(kek, 16); - if (ctx == NULL) - return -1; - - /* 2) Calculate intermediate values. - * For j = 0 to 5 - * For i=1 to n - * B = AES(K, A | R[i]) - * A = MSB(64, B) ^ t where t = (n*j)+i - * R[i] = LSB(64, B) - */ - for (j = 0; j <= 5; j++) { - r = cipher + 8; - for (i = 1; i <= n; i++) { - os_memcpy(b, a, 8); - os_memcpy(b + 8, r, 8); - aes_encrypt(ctx, b, b); - os_memcpy(a, b, 8); - a[7] ^= n * j + i; - os_memcpy(r, b + 8, 8); - r += 8; - } - } - aes_encrypt_deinit(ctx); - - /* 3) Output the results. - * - * These are already in @cipher due to the location of temporary - * variables. - */ - - return 0; -} - -#endif /* CONFIG_NO_AES_WRAP */ - - -#ifndef CONFIG_NO_AES_UNWRAP - -/** - * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: Key encryption key (KEK) - * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 - * bytes - * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits - * @plain: Plaintext key, n * 64 bits - * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) - */ -int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) -{ - u8 a[8], *r, b[16]; - int i, j; - void *ctx; - - /* 1) Initialize variables. */ - os_memcpy(a, cipher, 8); - r = plain; - os_memcpy(r, cipher + 8, 8 * n); - - ctx = aes_decrypt_init(kek, 16); - if (ctx == NULL) - return -1; - - /* 2) Compute intermediate values. - * For j = 5 to 0 - * For i = n to 1 - * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i - * A = MSB(64, B) - * R[i] = LSB(64, B) - */ - for (j = 5; j >= 0; j--) { - r = plain + (n - 1) * 8; - for (i = n; i >= 1; i--) { - os_memcpy(b, a, 8); - b[7] ^= n * j + i; - - os_memcpy(b + 8, r, 8); - aes_decrypt(ctx, b, b); - os_memcpy(a, b, 8); - os_memcpy(r, b + 8, 8); - r -= 8; - } - } - aes_decrypt_deinit(ctx); - - /* 3) Output results. - * - * These are already in @plain due to the location of temporary - * variables. Just verify that the IV matches with the expected value. - */ - for (i = 0; i < 8; i++) { - if (a[i] != 0xa6) - return -1; - } - - return 0; -} - -#endif /* CONFIG_NO_AES_UNWRAP */ - - -#define BLOCK_SIZE 16 - -#ifndef CONFIG_NO_AES_OMAC1 - -static void gf_mulx(u8 *pad) -{ - int i, carry; - - carry = pad[0] & 0x80; - for (i = 0; i < BLOCK_SIZE - 1; i++) - pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); - pad[BLOCK_SIZE - 1] <<= 1; - if (carry) - pad[BLOCK_SIZE - 1] ^= 0x87; -} - - -/** - * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 - * @key: 128-bit key for the hash operation - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) - * Returns: 0 on success, -1 on failure - * - * This is a mode for using block cipher (AES in this case) for authentication. - * OMAC1 was standardized with the name CMAC by NIST in a Special Publication - * (SP) 800-38B. - */ -int omac1_aes_128_vector(const u8 *key, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) -{ - void *ctx; - u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE]; - const u8 *pos, *end; - size_t i, e, left, total_len; - - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memset(cbc, 0, BLOCK_SIZE); - - total_len = 0; - for (e = 0; e < num_elem; e++) - total_len += len[e]; - left = total_len; - - e = 0; - pos = addr[0]; - end = pos + len[0]; - - while (left >= BLOCK_SIZE) { - for (i = 0; i < BLOCK_SIZE; i++) { - cbc[i] ^= *pos++; - if (pos >= end) { - e++; - pos = addr[e]; - end = pos + len[e]; - } - } - if (left > BLOCK_SIZE) - aes_encrypt(ctx, cbc, cbc); - left -= BLOCK_SIZE; - } - - os_memset(pad, 0, BLOCK_SIZE); - aes_encrypt(ctx, pad, pad); - gf_mulx(pad); - - if (left || total_len == 0) { - for (i = 0; i < left; i++) { - cbc[i] ^= *pos++; - if (pos >= end) { - e++; - pos = addr[e]; - end = pos + len[e]; - } - } - cbc[left] ^= 0x80; - gf_mulx(pad); - } - - for (i = 0; i < BLOCK_SIZE; i++) - pad[i] ^= cbc[i]; - aes_encrypt(ctx, pad, mac); - aes_encrypt_deinit(ctx); - return 0; -} - - -/** - * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) - * @key: 128-bit key for the hash operation - * @data: Data buffer for which a MAC is determined - * @data_len: Length of data buffer in bytes - * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) - * Returns: 0 on success, -1 on failure - * - * This is a mode for using block cipher (AES in this case) for authentication. - * OMAC1 was standardized with the name CMAC by NIST in a Special Publication - * (SP) 800-38B. - */ -int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) -{ - return omac1_aes_128_vector(key, 1, &data, &data_len, mac); -} - -#endif /* CONFIG_NO_AES_OMAC1 */ - - -#ifndef CONFIG_NO_AES_ENCRYPT_BLOCK -/** - * aes_128_encrypt_block - Perform one AES 128-bit block operation - * @key: Key for AES - * @in: Input data (16 bytes) - * @out: Output of the AES block operation (16 bytes) - * Returns: 0 on success, -1 on failure - */ -int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) -{ - void *ctx; - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - aes_encrypt(ctx, in, out); - aes_encrypt_deinit(ctx); - return 0; -} -#endif /* CONFIG_NO_AES_ENCRYPT_BLOCK */ - - -#ifndef CONFIG_NO_AES_CTR - -/** - * aes_128_ctr_encrypt - AES-128 CTR mode encryption - * @key: Key for encryption (16 bytes) - * @nonce: Nonce for counter mode (16 bytes) - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes - * Returns: 0 on success, -1 on failure - */ -int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, - u8 *data, size_t data_len) -{ - void *ctx; - size_t j, len, left = data_len; - int i; - u8 *pos = data; - u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE]; - - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memcpy(counter, nonce, BLOCK_SIZE); - - while (left > 0) { - aes_encrypt(ctx, counter, buf); - - len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE; - for (j = 0; j < len; j++) - pos[j] ^= buf[j]; - pos += len; - left -= len; - - for (i = BLOCK_SIZE - 1; i >= 0; i--) { - counter[i]++; - if (counter[i]) - break; - } - } - aes_encrypt_deinit(ctx); - return 0; -} - -#endif /* CONFIG_NO_AES_CTR */ - - -#ifndef CONFIG_NO_AES_EAX - -/** - * aes_128_eax_encrypt - AES-128 EAX mode encryption - * @key: Key for encryption (16 bytes) - * @nonce: Nonce for counter mode - * @nonce_len: Nonce length in bytes - * @hdr: Header data to be authenticity protected - * @hdr_len: Length of the header data bytes - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes - * @tag: 16-byte tag value - * Returns: 0 on success, -1 on failure - */ -int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, u8 *tag) -{ - u8 *buf; - size_t buf_len; - u8 nonce_mac[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[BLOCK_SIZE]; - int i, ret = -1; - - if (nonce_len > data_len) - buf_len = nonce_len; - else - buf_len = data_len; - if (hdr_len > buf_len) - buf_len = hdr_len; - buf_len += 16; - - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - - os_memset(buf, 0, 15); - - buf[15] = 0; - os_memcpy(buf + 16, nonce, nonce_len); - if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) - goto fail; - - buf[15] = 1; - os_memcpy(buf + 16, hdr, hdr_len); - if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) - goto fail; - - if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len)) - goto fail; - buf[15] = 2; - os_memcpy(buf + 16, data, data_len); - if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) - goto fail; - - for (i = 0; i < BLOCK_SIZE; i++) - tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; - - ret = 0; -fail: - os_free(buf); - - return ret; -} - - -/** - * aes_128_eax_decrypt - AES-128 EAX mode decryption - * @key: Key for decryption (16 bytes) - * @nonce: Nonce for counter mode - * @nonce_len: Nonce length in bytes - * @hdr: Header data to be authenticity protected - * @hdr_len: Length of the header data bytes - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes - * @tag: 16-byte tag value - * Returns: 0 on success, -1 on failure, -2 if tag does not match - */ -int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, const u8 *tag) -{ - u8 *buf; - size_t buf_len; - u8 nonce_mac[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[BLOCK_SIZE]; - int i; - - if (nonce_len > data_len) - buf_len = nonce_len; - else - buf_len = data_len; - if (hdr_len > buf_len) - buf_len = hdr_len; - buf_len += 16; - - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - - os_memset(buf, 0, 15); - - buf[15] = 0; - os_memcpy(buf + 16, nonce, nonce_len); - if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) { - os_free(buf); - return -1; - } - - buf[15] = 1; - os_memcpy(buf + 16, hdr, hdr_len); - if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) { - os_free(buf); - return -1; - } - - buf[15] = 2; - os_memcpy(buf + 16, data, data_len); - if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) { - os_free(buf); - return -1; - } - - os_free(buf); - - for (i = 0; i < BLOCK_SIZE; i++) { - if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) - return -2; - } - - return aes_128_ctr_encrypt(key, nonce_mac, data, data_len); -} - -#endif /* CONFIG_NO_AES_EAX */ - - -#ifndef CONFIG_NO_AES_CBC - -/** - * aes_128_cbc_encrypt - AES-128 CBC encryption - * @key: Encryption key - * @iv: Encryption IV for CBC mode (16 bytes) - * @data: Data to encrypt in-place - * @data_len: Length of data in bytes (must be divisible by 16) - * Returns: 0 on success, -1 on failure - */ -int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) -{ - void *ctx; - u8 cbc[BLOCK_SIZE]; - u8 *pos = data; - int i, j, blocks; - - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memcpy(cbc, iv, BLOCK_SIZE); - - blocks = data_len / BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - for (j = 0; j < BLOCK_SIZE; j++) - cbc[j] ^= pos[j]; - aes_encrypt(ctx, cbc, cbc); - os_memcpy(pos, cbc, BLOCK_SIZE); - pos += BLOCK_SIZE; - } - aes_encrypt_deinit(ctx); - return 0; -} - - -/** - * aes_128_cbc_decrypt - AES-128 CBC decryption - * @key: Decryption key - * @iv: Decryption IV for CBC mode (16 bytes) - * @data: Data to decrypt in-place - * @data_len: Length of data in bytes (must be divisible by 16) - * Returns: 0 on success, -1 on failure - */ -int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) -{ - void *ctx; - u8 cbc[BLOCK_SIZE], tmp[BLOCK_SIZE]; - u8 *pos = data; - int i, j, blocks; - - ctx = aes_decrypt_init(key, 16); - if (ctx == NULL) - return -1; - os_memcpy(cbc, iv, BLOCK_SIZE); - - blocks = data_len / BLOCK_SIZE; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, pos, BLOCK_SIZE); - aes_decrypt(ctx, pos, pos); - for (j = 0; j < BLOCK_SIZE; j++) - pos[j] ^= cbc[j]; - os_memcpy(cbc, tmp, BLOCK_SIZE); - pos += BLOCK_SIZE; - } - aes_decrypt_deinit(ctx); - return 0; -} - -#endif /* CONFIG_NO_AES_CBC */ diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index a5129bbd050a..587b5a95747f 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / wrapper functions for crypto libraries - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -33,8 +33,9 @@ * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure */ -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); /** * md5_vector - MD5 hash for data vector @@ -42,8 +43,25 @@ void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure */ -void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); + +#ifdef CONFIG_FIPS +/** + * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed) + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); +#else /* CONFIG_FIPS */ +#define md5_vector_non_fips_allow md5_vector +#endif /* CONFIG_FIPS */ + /** * sha1_vector - SHA-1 hash for data vector @@ -51,9 +69,10 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure */ -void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac); +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); /** * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF @@ -76,9 +95,10 @@ int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure */ -void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac); +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); /** * des_encrypt - Encrypt one block with DES @@ -275,6 +295,7 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); * crypto_private_key_import - Import an RSA private key * @key: Key buffer (DER encoded RSA private key) * @len: Key buffer length in bytes + * @passwd: Key encryption password or %NULL if key is not encrypted * Returns: Pointer to the private key or %NULL on failure * * This function is only used with internal TLSv1 implementation @@ -282,7 +303,8 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); * to implement this. */ struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len); + size_t len, + const char *passwd); /** * crypto_public_key_from_cert - Import an RSA public key from a certificate @@ -428,4 +450,20 @@ int __must_check crypto_mod_exp(const u8 *base, size_t base_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len); +/** + * rc4_skip - XOR RC4 stream to given data with skip-stream-start + * @key: RC4 key + * @keylen: RC4 key length + * @skip: number of bytes to skip from the beginning of the RC4 stream + * @data: data to be XOR'ed with RC4 stream + * @data_len: buf length + * Returns: 0 on success, -1 on failure + * + * Generate RC4 pseudo random stream for the given key, skip beginning of the + * stream, and XOR the end result with the data buffer to perform RC4 + * encryption/decryption. + */ +int rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len); + #endif /* CRYPTO_H */ diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c index 45333dd2e396..2a8d2001b173 100644 --- a/src/crypto/crypto_cryptoapi.c +++ b/src/crypto/crypto_cryptoapi.c @@ -33,7 +33,6 @@ L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" #define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) #endif -#ifdef CONFIG_TLS_INTERNAL #ifdef __MINGW32_VERSION /* * MinGW does not yet include all the needed definitions for CryptoAPI, so @@ -83,7 +82,6 @@ static int mingw_load_crypto_func(void) } #endif /* __MINGW32_VERSION */ -#endif /* CONFIG_TLS_INTERNAL */ static void cryptoapi_report_error(const char *msg) @@ -152,9 +150,9 @@ int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, } -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { - cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); + return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); } @@ -223,16 +221,15 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) } -#ifdef EAP_TLS_FUNCS -void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { - cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); + return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); } -void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { - cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); + return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); } @@ -349,7 +346,6 @@ void aes_decrypt_deinit(void *ctx) aes_encrypt_deinit(ctx); } -#ifdef CONFIG_TLS_INTERNAL struct crypto_hash { enum crypto_hash_alg alg; @@ -657,7 +653,8 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len) + size_t len, + const char *passwd) { /* TODO */ return NULL; @@ -781,6 +778,12 @@ void crypto_global_deinit(void) { } -#endif /* CONFIG_TLS_INTERNAL */ -#endif /* EAP_TLS_FUNCS */ +int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + /* TODO */ + return -1; +} diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c index 8f8611c0fb33..0998cca54672 100644 --- a/src/crypto/crypto_gnutls.c +++ b/src/crypto/crypto_gnutls.c @@ -18,20 +18,21 @@ #include "common.h" #include "crypto.h" -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; size_t i; if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR) - return; + return -1; for (i = 0; i < num_elem; i++) gcry_md_write(hd, addr[i], len[i]); p = gcry_md_read(hd, GCRY_MD_MD4); if (p) memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4)); gcry_md_close(hd); + return 0; } @@ -57,49 +58,42 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) } -void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; size_t i; if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR) - return; + return -1; for (i = 0; i < num_elem; i++) gcry_md_write(hd, addr[i], len[i]); p = gcry_md_read(hd, GCRY_MD_MD5); if (p) memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5)); gcry_md_close(hd); + return 0; } -void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { gcry_md_hd_t hd; unsigned char *p; size_t i; if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR) - return; + return -1; for (i = 0; i < num_elem; i++) gcry_md_write(hd, addr[i], len[i]); p = gcry_md_read(hd, GCRY_MD_SHA1); if (p) memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1)); gcry_md_close(hd); + return 0; } -#ifndef CONFIG_NO_FIPS186_2_PRF -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - /* FIX: how to do this with libgcrypt? */ - return -1; -} -#endif /* CONFIG_NO_FIPS186_2_PRF */ - - void * aes_encrypt_init(const u8 *key, size_t len) { gcry_cipher_hd_t hd; diff --git a/src/crypto/crypto_internal-cipher.c b/src/crypto/crypto_internal-cipher.c new file mode 100644 index 000000000000..75134f09a403 --- /dev/null +++ b/src/crypto/crypto_internal-cipher.c @@ -0,0 +1,256 @@ +/* + * Crypto wrapper for internal crypto implementation - Cipher wrappers + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 "crypto.h" +#include "aes.h" +#include "des_i.h" + + +struct crypto_cipher { + enum crypto_cipher_alg alg; + union { + struct { + size_t used_bytes; + u8 key[16]; + size_t keylen; + } rc4; + struct { + u8 cbc[32]; + size_t block_size; + void *ctx_enc; + void *ctx_dec; + } aes; + struct { + struct des3_key_s key; + u8 cbc[8]; + } des3; + struct { + u32 ek[32]; + u32 dk[32]; + u8 cbc[8]; + } des; + } u; +}; + + +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + struct crypto_cipher *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->alg = alg; + + switch (alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (key_len > sizeof(ctx->u.rc4.key)) { + os_free(ctx); + return NULL; + } + ctx->u.rc4.keylen = key_len; + os_memcpy(ctx->u.rc4.key, key, key_len); + break; + case CRYPTO_CIPHER_ALG_AES: + if (key_len > sizeof(ctx->u.aes.cbc)) { + os_free(ctx); + return NULL; + } + ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); + if (ctx->u.aes.ctx_enc == NULL) { + os_free(ctx); + return NULL; + } + ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); + if (ctx->u.aes.ctx_dec == NULL) { + aes_encrypt_deinit(ctx->u.aes.ctx_enc); + os_free(ctx); + return NULL; + } + ctx->u.aes.block_size = key_len; + os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size); + break; + case CRYPTO_CIPHER_ALG_3DES: + if (key_len != 24) { + os_free(ctx); + return NULL; + } + des3_key_setup(key, &ctx->u.des3.key); + os_memcpy(ctx->u.des3.cbc, iv, 8); + break; + case CRYPTO_CIPHER_ALG_DES: + if (key_len != 8) { + os_free(ctx); + return NULL; + } + des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk); + os_memcpy(ctx->u.des.cbc, iv, 8); + break; + default: + os_free(ctx); + return NULL; + } + + return ctx; +} + + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + size_t i, j, blocks; + + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (plain != crypt) + os_memcpy(crypt, plain, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, crypt, len); + ctx->u.rc4.used_bytes += len; + break; + case CRYPTO_CIPHER_ALG_AES: + if (len % ctx->u.aes.block_size) + return -1; + blocks = len / ctx->u.aes.block_size; + for (i = 0; i < blocks; i++) { + for (j = 0; j < ctx->u.aes.block_size; j++) + ctx->u.aes.cbc[j] ^= plain[j]; + aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, + ctx->u.aes.cbc); + os_memcpy(crypt, ctx->u.aes.cbc, + ctx->u.aes.block_size); + plain += ctx->u.aes.block_size; + crypt += ctx->u.aes.block_size; + } + break; + case CRYPTO_CIPHER_ALG_3DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + for (j = 0; j < 8; j++) + ctx->u.des3.cbc[j] ^= plain[j]; + des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, + ctx->u.des3.cbc); + os_memcpy(crypt, ctx->u.des3.cbc, 8); + plain += 8; + crypt += 8; + } + break; + case CRYPTO_CIPHER_ALG_DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + for (j = 0; j < 8; j++) + ctx->u.des3.cbc[j] ^= plain[j]; + des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek, + ctx->u.des.cbc); + os_memcpy(crypt, ctx->u.des.cbc, 8); + plain += 8; + crypt += 8; + } + break; + default: + return -1; + } + + return 0; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + size_t i, j, blocks; + u8 tmp[32]; + + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_RC4: + if (plain != crypt) + os_memcpy(plain, crypt, len); + rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, + ctx->u.rc4.used_bytes, plain, len); + ctx->u.rc4.used_bytes += len; + break; + case CRYPTO_CIPHER_ALG_AES: + if (len % ctx->u.aes.block_size) + return -1; + blocks = len / ctx->u.aes.block_size; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, ctx->u.aes.block_size); + aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); + for (j = 0; j < ctx->u.aes.block_size; j++) + plain[j] ^= ctx->u.aes.cbc[j]; + os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size); + plain += ctx->u.aes.block_size; + crypt += ctx->u.aes.block_size; + } + break; + case CRYPTO_CIPHER_ALG_3DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, 8); + des3_decrypt(crypt, &ctx->u.des3.key, plain); + for (j = 0; j < 8; j++) + plain[j] ^= ctx->u.des3.cbc[j]; + os_memcpy(ctx->u.des3.cbc, tmp, 8); + plain += 8; + crypt += 8; + } + break; + case CRYPTO_CIPHER_ALG_DES: + if (len % 8) + return -1; + blocks = len / 8; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, crypt, 8); + des_block_decrypt(crypt, ctx->u.des.dk, plain); + for (j = 0; j < 8; j++) + plain[j] ^= ctx->u.des.cbc[j]; + os_memcpy(ctx->u.des.cbc, tmp, 8); + plain += 8; + crypt += 8; + } + break; + default: + return -1; + } + + return 0; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + switch (ctx->alg) { + case CRYPTO_CIPHER_ALG_AES: + aes_encrypt_deinit(ctx->u.aes.ctx_enc); + aes_decrypt_deinit(ctx->u.aes.ctx_dec); + break; + case CRYPTO_CIPHER_ALG_3DES: + break; + default: + break; + } + os_free(ctx); +} diff --git a/src/crypto/crypto_internal-modexp.c b/src/crypto/crypto_internal-modexp.c new file mode 100644 index 000000000000..3124742e87cd --- /dev/null +++ b/src/crypto/crypto_internal-modexp.c @@ -0,0 +1,55 @@ +/* + * Crypto wrapper for internal crypto implementation - modexp + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 "tls/bignum.h" +#include "crypto.h" + + +int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; + int ret = -1; + + bn_base = bignum_init(); + bn_exp = bignum_init(); + bn_modulus = bignum_init(); + bn_result = bignum_init(); + + if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || + bn_result == NULL) + goto error; + + if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || + bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || + bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) + goto error; + + if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) + goto error; + + ret = bignum_get_unsigned_bin(bn_result, result, result_len); + +error: + bignum_deinit(bn_base); + bignum_deinit(bn_exp); + bignum_deinit(bn_modulus); + bignum_deinit(bn_result); + return ret; +} diff --git a/src/crypto/crypto_internal-rsa.c b/src/crypto/crypto_internal-rsa.c new file mode 100644 index 000000000000..205042cf3631 --- /dev/null +++ b/src/crypto/crypto_internal-rsa.c @@ -0,0 +1,115 @@ +/* + * Crypto wrapper for internal crypto implementation - RSA parts + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 "crypto.h" +#include "tls/rsa.h" +#include "tls/bignum.h" +#include "tls/pkcs1.h" +#include "tls/pkcs8.h" + +/* Dummy structures; these are just typecast to struct crypto_rsa_key */ +struct crypto_public_key; +struct crypto_private_key; + + +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) +{ + return (struct crypto_public_key *) + crypto_rsa_import_public_key(key, len); +} + + +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len, + const char *passwd) +{ + struct crypto_private_key *res; + + /* First, check for possible PKCS #8 encoding */ + res = pkcs8_key_import(key, len); + if (res) + return res; + + if (passwd) { + /* Try to parse as encrypted PKCS #8 */ + res = pkcs8_enc_key_import(key, len, passwd); + if (res) + return res; + } + + /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */ + wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private " + "key"); + return (struct crypto_private_key *) + crypto_rsa_import_private_key(key, len); +} + + +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len) +{ + /* No X.509 support in crypto_internal.c */ + return NULL; +} + + +int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return pkcs1_encrypt(2, (struct crypto_rsa_key *) key, + 0, in, inlen, out, outlen); +} + + +int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key, + in, inlen, out, outlen); +} + + +int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + return pkcs1_encrypt(1, (struct crypto_rsa_key *) key, + 1, in, inlen, out, outlen); +} + + +void crypto_public_key_free(struct crypto_public_key *key) +{ + crypto_rsa_free((struct crypto_rsa_key *) key); +} + + +void crypto_private_key_free(struct crypto_private_key *key) +{ + crypto_rsa_free((struct crypto_rsa_key *) key); +} + + +int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len) +{ + return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key, + crypt, crypt_len, plain, plain_len); +} diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c index cddfb4de8ea9..8fdba6580275 100644 --- a/src/crypto/crypto_internal.c +++ b/src/crypto/crypto_internal.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / Crypto wrapper for internal crypto implementation - * Copyright (c) 2006-2007, Jouni Malinen + * Crypto wrapper for internal crypto implementation + * Copyright (c) 2006-2009, Jouni Malinen * * 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 @@ -16,42 +16,8 @@ #include "common.h" #include "crypto.h" -#include "md5.h" -#include "sha1.h" -#include "rc4.h" -#include "aes.h" -#include "tls/rsa.h" -#include "tls/bignum.h" -#include "tls/asn1.h" - - -#ifdef CONFIG_CRYPTO_INTERNAL - -#ifdef CONFIG_TLS_INTERNAL - -/* from des.c */ -struct des3_key_s { - u32 ek[3][32]; - u32 dk[3][32]; -}; - -void des3_key_setup(const u8 *key, struct des3_key_s *dkey); -void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); -void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); - - -struct MD5Context { - u32 buf[4]; - u32 bits[2]; - u8 in[64]; -}; - -struct SHA1Context { - u32 state[5]; - u32 count[2]; - unsigned char buffer[64]; -}; - +#include "sha1_i.h" +#include "md5_i.h" struct crypto_hash { enum crypto_hash_alg alg; @@ -228,559 +194,6 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) } -struct crypto_cipher { - enum crypto_cipher_alg alg; - union { - struct { - size_t used_bytes; - u8 key[16]; - size_t keylen; - } rc4; - struct { - u8 cbc[32]; - size_t block_size; - void *ctx_enc; - void *ctx_dec; - } aes; - struct { - struct des3_key_s key; - u8 cbc[8]; - } des3; - } u; -}; - - -struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, - const u8 *iv, const u8 *key, - size_t key_len) -{ - struct crypto_cipher *ctx; - - ctx = os_zalloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->alg = alg; - - switch (alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (key_len > sizeof(ctx->u.rc4.key)) { - os_free(ctx); - return NULL; - } - ctx->u.rc4.keylen = key_len; - os_memcpy(ctx->u.rc4.key, key, key_len); - break; - case CRYPTO_CIPHER_ALG_AES: - if (key_len > sizeof(ctx->u.aes.cbc)) { - os_free(ctx); - return NULL; - } - ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); - if (ctx->u.aes.ctx_enc == NULL) { - os_free(ctx); - return NULL; - } - ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); - if (ctx->u.aes.ctx_dec == NULL) { - aes_encrypt_deinit(ctx->u.aes.ctx_enc); - os_free(ctx); - return NULL; - } - ctx->u.aes.block_size = key_len; - os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size); - break; - case CRYPTO_CIPHER_ALG_3DES: - if (key_len != 24) { - os_free(ctx); - return NULL; - } - des3_key_setup(key, &ctx->u.des3.key); - os_memcpy(ctx->u.des3.cbc, iv, 8); - break; - default: - os_free(ctx); - return NULL; - } - - return ctx; -} - - -int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, - u8 *crypt, size_t len) -{ - size_t i, j, blocks; - - switch (ctx->alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (plain != crypt) - os_memcpy(crypt, plain, len); - rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, - ctx->u.rc4.used_bytes, crypt, len); - ctx->u.rc4.used_bytes += len; - break; - case CRYPTO_CIPHER_ALG_AES: - if (len % ctx->u.aes.block_size) - return -1; - blocks = len / ctx->u.aes.block_size; - for (i = 0; i < blocks; i++) { - for (j = 0; j < ctx->u.aes.block_size; j++) - ctx->u.aes.cbc[j] ^= plain[j]; - aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, - ctx->u.aes.cbc); - os_memcpy(crypt, ctx->u.aes.cbc, - ctx->u.aes.block_size); - plain += ctx->u.aes.block_size; - crypt += ctx->u.aes.block_size; - } - break; - case CRYPTO_CIPHER_ALG_3DES: - if (len % 8) - return -1; - blocks = len / 8; - for (i = 0; i < blocks; i++) { - for (j = 0; j < 8; j++) - ctx->u.des3.cbc[j] ^= plain[j]; - des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, - ctx->u.des3.cbc); - os_memcpy(crypt, ctx->u.des3.cbc, 8); - plain += 8; - crypt += 8; - } - break; - default: - return -1; - } - - return 0; -} - - -int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, - u8 *plain, size_t len) -{ - size_t i, j, blocks; - u8 tmp[32]; - - switch (ctx->alg) { - case CRYPTO_CIPHER_ALG_RC4: - if (plain != crypt) - os_memcpy(plain, crypt, len); - rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, - ctx->u.rc4.used_bytes, plain, len); - ctx->u.rc4.used_bytes += len; - break; - case CRYPTO_CIPHER_ALG_AES: - if (len % ctx->u.aes.block_size) - return -1; - blocks = len / ctx->u.aes.block_size; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, ctx->u.aes.block_size); - aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); - for (j = 0; j < ctx->u.aes.block_size; j++) - plain[j] ^= ctx->u.aes.cbc[j]; - os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size); - plain += ctx->u.aes.block_size; - crypt += ctx->u.aes.block_size; - } - break; - case CRYPTO_CIPHER_ALG_3DES: - if (len % 8) - return -1; - blocks = len / 8; - for (i = 0; i < blocks; i++) { - os_memcpy(tmp, crypt, 8); - des3_decrypt(crypt, &ctx->u.des3.key, plain); - for (j = 0; j < 8; j++) - plain[j] ^= ctx->u.des3.cbc[j]; - os_memcpy(ctx->u.des3.cbc, tmp, 8); - plain += 8; - crypt += 8; - } - break; - default: - return -1; - } - - return 0; -} - - -void crypto_cipher_deinit(struct crypto_cipher *ctx) -{ - switch (ctx->alg) { - case CRYPTO_CIPHER_ALG_AES: - aes_encrypt_deinit(ctx->u.aes.ctx_enc); - aes_decrypt_deinit(ctx->u.aes.ctx_dec); - break; - case CRYPTO_CIPHER_ALG_3DES: - break; - default: - break; - } - os_free(ctx); -} - - -/* Dummy structures; these are just typecast to struct crypto_rsa_key */ -struct crypto_public_key; -struct crypto_private_key; - - -struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -{ - return (struct crypto_public_key *) - crypto_rsa_import_public_key(key, len); -} - - -#ifdef EAP_TLS_FUNCS -static struct crypto_private_key * -crypto_pkcs8_key_import(const u8 *buf, size_t len) -{ - struct asn1_hdr hdr; - const u8 *pos, *end; - struct bignum *zero; - struct asn1_oid oid; - char obuf[80]; - - /* PKCS #8, Chapter 6 */ - - /* PrivateKeyInfo ::= SEQUENCE */ - if (asn1_get_next(buf, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " - "header (SEQUENCE); assume PKCS #8 not used"); - return NULL; - } - pos = hdr.payload; - end = pos + hdr.length; - - /* version Version (Version ::= INTEGER) */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found " - "class %d tag 0x%x; assume PKCS #8 not used", - hdr.class, hdr.tag); - return NULL; - } - - zero = bignum_init(); - if (zero == NULL) - return NULL; - - if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER"); - bignum_deinit(zero); - return NULL; - } - pos = hdr.payload + hdr.length; - - if (bignum_cmp_d(zero, 0) != 0) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the " - "beginning of private key; not found; assume " - "PKCS #8 not used"); - bignum_deinit(zero); - return NULL; - } - bignum_deinit(zero); - - /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier - * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */ - if (asn1_get_next(pos, len, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_SEQUENCE) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " - "(AlgorithmIdentifier) - found class %d tag 0x%x; " - "assume PKCS #8 not used", - hdr.class, hdr.tag); - return NULL; - } - - if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) { - wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID " - "(algorithm); assume PKCS #8 not used"); - return NULL; - } - - asn1_oid_to_str(&oid, obuf, sizeof(obuf)); - wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf); - - if (oid.len != 7 || - oid.oid[0] != 1 /* iso */ || - oid.oid[1] != 2 /* member-body */ || - oid.oid[2] != 840 /* us */ || - oid.oid[3] != 113549 /* rsadsi */ || - oid.oid[4] != 1 /* pkcs */ || - oid.oid[5] != 1 /* pkcs-1 */ || - oid.oid[6] != 1 /* rsaEncryption */) { - wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key " - "algorithm %s", obuf); - return NULL; - } - - pos = hdr.payload + hdr.length; - - /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */ - if (asn1_get_next(pos, end - pos, &hdr) < 0 || - hdr.class != ASN1_CLASS_UNIVERSAL || - hdr.tag != ASN1_TAG_OCTETSTRING) { - wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " - "(privateKey) - found class %d tag 0x%x", - hdr.class, hdr.tag); - return NULL; - } - wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey"); - - return (struct crypto_private_key *) - crypto_rsa_import_private_key(hdr.payload, hdr.length); -} -#endif /* EAP_TLS_FUNCS */ - - -struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len) -{ - struct crypto_private_key *res; - - /* First, check for possible PKCS #8 encoding */ - res = crypto_pkcs8_key_import(key, len); - if (res) - return res; - - /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */ - wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private " - "key"); - return (struct crypto_private_key *) - crypto_rsa_import_private_key(key, len); -} - - -struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, - size_t len) -{ - /* No X.509 support in crypto_internal.c */ - return NULL; -} - - -static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - size_t ps_len; - u8 *pos; - - /* - * PKCS #1 v1.5, 8.1: - * - * EB = 00 || BT || PS || 00 || D - * BT = 00 or 01 for private-key operation; 02 for public-key operation - * PS = k-3-||D||; at least eight octets - * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) - * k = length of modulus in octets (modlen) - */ - - if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " - "lengths (modlen=%lu outlen=%lu inlen=%lu)", - __func__, (unsigned long) modlen, - (unsigned long) *outlen, - (unsigned long) inlen); - return -1; - } - - pos = out; - *pos++ = 0x00; - *pos++ = block_type; /* BT */ - ps_len = modlen - inlen - 3; - switch (block_type) { - case 0: - os_memset(pos, 0x00, ps_len); - pos += ps_len; - break; - case 1: - os_memset(pos, 0xff, ps_len); - pos += ps_len; - break; - case 2: - if (os_get_random(pos, ps_len) < 0) { - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " - "random data for PS", __func__); - return -1; - } - while (ps_len--) { - if (*pos == 0x00) - *pos = 0x01; - pos++; - } - break; - default: - wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " - "%d", __func__, block_type); - return -1; - } - *pos++ = 0x00; - os_memcpy(pos, in, inlen); /* D */ - - return 0; -} - - -static int crypto_rsa_encrypt_pkcs1(int block_type, struct crypto_rsa_key *key, - int use_private, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - size_t modlen; - - modlen = crypto_rsa_get_modulus_len(key); - - if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, - out, outlen) < 0) - return -1; - - return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); -} - - -int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return crypto_rsa_encrypt_pkcs1(2, (struct crypto_rsa_key *) key, - 0, in, inlen, out, outlen); -} - - -int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - struct crypto_rsa_key *rkey = (struct crypto_rsa_key *) key; - int res; - u8 *pos, *end; - - res = crypto_rsa_exptmod(in, inlen, out, outlen, rkey, 1); - if (res) - return res; - - if (*outlen < 2 || out[0] != 0 || out[1] != 2) - return -1; - - /* Skip PS (pseudorandom non-zero octets) */ - pos = out + 2; - end = out + *outlen; - while (*pos && pos < end) - pos++; - if (pos == end) - return -1; - pos++; - - *outlen -= pos - out; - - /* Strip PKCS #1 header */ - os_memmove(out, pos, *outlen); - - return 0; -} - - -int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, - const u8 *in, size_t inlen, - u8 *out, size_t *outlen) -{ - return crypto_rsa_encrypt_pkcs1(1, (struct crypto_rsa_key *) key, - 1, in, inlen, out, outlen); -} - - -void crypto_public_key_free(struct crypto_public_key *key) -{ - crypto_rsa_free((struct crypto_rsa_key *) key); -} - - -void crypto_private_key_free(struct crypto_private_key *key) -{ - crypto_rsa_free((struct crypto_rsa_key *) key); -} - - -int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, - const u8 *crypt, size_t crypt_len, - u8 *plain, size_t *plain_len) -{ - size_t len; - u8 *pos; - - len = *plain_len; - if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, - (struct crypto_rsa_key *) key, 0) < 0) - return -1; - - /* - * PKCS #1 v1.5, 8.1: - * - * EB = 00 || BT || PS || 00 || D - * BT = 00 or 01 - * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) - * k = length of modulus in octets - */ - - if (len < 3 + 8 + 16 /* min hash len */ || - plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " - "structure"); - return -1; - } - - pos = plain + 3; - if (plain[1] == 0x00) { - /* BT = 00 */ - if (plain[2] != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=00)"); - return -1; - } - while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) - pos++; - } else { - /* BT = 01 */ - if (plain[2] != 0xff) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=01)"); - return -1; - } - while (pos < plain + len && *pos == 0xff) - pos++; - } - - if (pos - plain - 2 < 8) { - /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ - wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " - "padding"); - return -1; - } - - if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " - "structure (2)"); - return -1; - } - pos++; - len -= pos - plain; - - /* Strip PKCS #1 header */ - os_memmove(plain, pos, len); - *plain_len = len; - - return 0; -} - - int crypto_global_init(void) { return 0; @@ -790,47 +203,3 @@ int crypto_global_init(void) void crypto_global_deinit(void) { } -#endif /* CONFIG_TLS_INTERNAL */ - - -#if defined(EAP_FAST) || defined(CONFIG_WPS) - -int crypto_mod_exp(const u8 *base, size_t base_len, - const u8 *power, size_t power_len, - const u8 *modulus, size_t modulus_len, - u8 *result, size_t *result_len) -{ - struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; - int ret = -1; - - bn_base = bignum_init(); - bn_exp = bignum_init(); - bn_modulus = bignum_init(); - bn_result = bignum_init(); - - if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || - bn_result == NULL) - goto error; - - if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || - bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || - bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) - goto error; - - if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) - goto error; - - ret = bignum_get_unsigned_bin(bn_result, result, result_len); - -error: - bignum_deinit(bn_base); - bignum_deinit(bn_exp); - bignum_deinit(bn_modulus); - bignum_deinit(bn_result); - return ret; -} - -#endif /* EAP_FAST || CONFIG_WPS */ - - -#endif /* CONFIG_CRYPTO_INTERNAL */ diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c index e82097f10a00..52b67a713d69 100644 --- a/src/crypto/crypto_libtomcrypt.c +++ b/src/crypto/crypto_libtomcrypt.c @@ -16,7 +16,6 @@ #include #include "common.h" -#include "rc4.h" #include "crypto.h" #ifndef mp_init_multi @@ -29,7 +28,7 @@ #endif -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { hash_state md; size_t i; @@ -38,6 +37,7 @@ void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) for (i = 0; i < num_elem; i++) md4_process(&md, addr[i], len[i]); md4_done(&md, mac); + return 0; } @@ -62,8 +62,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) } -#ifdef EAP_TLS_FUNCS -void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { hash_state md; size_t i; @@ -72,10 +71,11 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) for (i = 0; i < num_elem; i++) md5_process(&md, addr[i], len[i]); md5_done(&md, mac); + return 0; } -void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { hash_state md; size_t i; @@ -84,6 +84,7 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) for (i = 0; i < num_elem; i++) sha1_process(&md, addr[i], len[i]); sha1_done(&md, mac); + return 0; } @@ -145,8 +146,6 @@ void aes_decrypt_deinit(void *ctx) } -#ifdef CONFIG_TLS_INTERNAL - struct crypto_hash { enum crypto_hash_alg alg; int error; @@ -451,7 +450,8 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) struct crypto_private_key * crypto_private_key_import(const u8 *key, - size_t len) + size_t len, + const char *passwd) { int res; struct crypto_private_key *pk; @@ -697,7 +697,7 @@ void crypto_global_deinit(void) } -#ifdef EAP_FAST +#ifdef CONFIG_MODEXP int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, @@ -729,8 +729,4 @@ fail: return -1; } -#endif /* EAP_FAST */ - -#endif /* CONFIG_TLS_INTERNAL */ - -#endif /* EAP_TLS_FUNCS */ +#endif /* CONFIG_MODEXP */ diff --git a/src/crypto/crypto_none.c b/src/crypto/crypto_none.c index f18c2a8ded95..9f43775a6462 100644 --- a/src/crypto/crypto_none.c +++ b/src/crypto/crypto_none.c @@ -18,8 +18,9 @@ #include "crypto.h" -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { + return 0; } diff --git a/src/crypto/crypto_nss.c b/src/crypto/crypto_nss.c new file mode 100644 index 000000000000..fee4195ca4e3 --- /dev/null +++ b/src/crypto/crypto_nss.c @@ -0,0 +1,213 @@ +/* + * Crypto wrapper functions for NSS + * Copyright (c) 2009, Jouni Malinen + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "crypto.h" + + +static int nss_hash(HASH_HashType type, unsigned int max_res_len, + size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + HASHContext *ctx; + size_t i; + unsigned int reslen; + + ctx = HASH_Create(type); + if (ctx == NULL) + return -1; + + HASH_Begin(ctx); + for (i = 0; i < num_elem; i++) + HASH_Update(ctx, addr[i], len[i]); + HASH_End(ctx, mac, &reslen, max_res_len); + HASH_Destroy(ctx); + + return 0; +} + + +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) +{ + PK11Context *ctx = NULL; + PK11SlotInfo *slot; + SECItem *param = NULL; + PK11SymKey *symkey = NULL; + SECItem item; + int olen; + u8 pkey[8], next, tmp; + int i; + + /* Add parity bits to the key */ + next = 0; + for (i = 0; i < 7; i++) { + tmp = key[i]; + pkey[i] = (tmp >> i) | next | 1; + next = tmp << (7 - i); + } + pkey[i] = next | 1; + + slot = PK11_GetBestSlot(CKM_DES_ECB, NULL); + if (slot == NULL) { + wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed"); + goto out; + } + + item.type = siBuffer; + item.data = pkey; + item.len = 8; + symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive, + CKA_ENCRYPT, &item, NULL); + if (symkey == NULL) { + wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed"); + goto out; + } + + param = PK11_GenerateNewParam(CKM_DES_ECB, symkey); + if (param == NULL) { + wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed"); + goto out; + } + + ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT, + symkey, param); + if (ctx == NULL) { + wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey(" + "CKM_DES_ECB) failed"); + goto out; + } + + if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) != + SECSuccess) { + wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed"); + goto out; + } + +out: + if (ctx) + PK11_DestroyContext(ctx, PR_TRUE); + if (symkey) + PK11_FreeSymKey(symkey); + if (param) + SECITEM_FreeItem(param, PR_TRUE); +} + + +int rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len) +{ + return -1; +} + + +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac); +} + + +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac); +} + + +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac); +} + + +void * aes_encrypt_init(const u8 *key, size_t len) +{ + return NULL; +} + + +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ +} + + +void aes_encrypt_deinit(void *ctx) +{ +} + + +void * aes_decrypt_init(const u8 *key, size_t len) +{ + return NULL; +} + + +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ +} + + +void aes_decrypt_deinit(void *ctx) +{ +} + + +int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + return -1; +} + + +struct crypto_cipher { +}; + + +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + return NULL; +} + + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + return -1; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + return -1; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ +} diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index a4c3415c4d18..08c98aff4ba1 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / wrapper functions for libcrypto - * Copyright (c) 2004-2005, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -14,15 +14,16 @@ #include "includes.h" #include -#include -#include -#include +#include #include #include #include #include +#include #include "common.h" +#include "wpabuf.h" +#include "dh_group5.h" #include "crypto.h" #if OPENSSL_VERSION_NUMBER < 0x00907000 @@ -33,16 +34,87 @@ des_ecb_encrypt((input), (output), *(ks), (enc)) #endif /* openssl < 0.9.7 */ - -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +static BIGNUM * get_group5_prime(void) { - MD4_CTX ctx; - size_t i; +#if OPENSSL_VERSION_NUMBER < 0x00908000 + static const unsigned char RFC3526_PRIME_1536[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + }; + return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL); +#else /* openssl < 0.9.8 */ + return get_rfc3526_prime_1536(NULL); +#endif /* openssl < 0.9.8 */ +} - MD4_Init(&ctx); - for (i = 0; i < num_elem; i++) - MD4_Update(&ctx, addr[i], len[i]); - MD4_Final(mac, &ctx); +#if OPENSSL_VERSION_NUMBER < 0x00908000 +#ifndef OPENSSL_NO_SHA256 +#ifndef OPENSSL_FIPS +#define NO_SHA256_WRAPPER +#endif +#endif + +#endif /* openssl < 0.9.8 */ + +#ifdef OPENSSL_NO_SHA256 +#define NO_SHA256_WRAPPER +#endif + +static int openssl_digest_vector(const EVP_MD *type, int non_fips, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + EVP_MD_CTX ctx; + size_t i; + unsigned int mac_len; + + EVP_MD_CTX_init(&ctx); +#ifdef CONFIG_FIPS +#ifdef OPENSSL_FIPS + if (non_fips) + EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif /* OPENSSL_FIPS */ +#endif /* CONFIG_FIPS */ + if (!EVP_DigestInit_ex(&ctx, type, NULL)) { + wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + for (i = 0; i < num_elem; i++) { + if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) { + wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate " + "failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + } + if (!EVP_DigestFinal(&ctx, mac, &mac_len)) { + wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + return 0; +} + + +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac); } @@ -67,94 +139,72 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) } -void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len) { - MD5_CTX ctx; - size_t i; +#ifdef OPENSSL_NO_RC4 + return -1; +#else /* OPENSSL_NO_RC4 */ + EVP_CIPHER_CTX ctx; + int outl; + int res = -1; + unsigned char skip_buf[16]; - MD5_Init(&ctx); - for (i = 0; i < num_elem; i++) - MD5_Update(&ctx, addr[i], len[i]); - MD5_Final(mac, &ctx); -} + EVP_CIPHER_CTX_init(&ctx); + if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) || + !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) || + !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) || + !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1)) + goto out; - -void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - SHA_CTX ctx; - size_t i; - - SHA1_Init(&ctx); - for (i = 0; i < num_elem; i++) - SHA1_Update(&ctx, addr[i], len[i]); - SHA1_Final(mac, &ctx); -} - - -#ifndef CONFIG_NO_FIPS186_2_PRF -static void sha1_transform(u8 *state, const u8 data[64]) -{ - SHA_CTX context; - os_memset(&context, 0, sizeof(context)); - os_memcpy(&context.h0, state, 5 * 4); - SHA1_Transform(&context, data); - os_memcpy(state, &context.h0, 5 * 4); -} - - -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - u8 xkey[64]; - u32 t[5], _t[5]; - int i, j, m, k; - u8 *xpos = x; - u32 carry; - - if (seed_len > sizeof(xkey)) - seed_len = sizeof(xkey); - - /* FIPS 186-2 + change notice 1 */ - - os_memcpy(xkey, seed, seed_len); - os_memset(xkey + seed_len, 0, 64 - seed_len); - t[0] = 0x67452301; - t[1] = 0xEFCDAB89; - t[2] = 0x98BADCFE; - t[3] = 0x10325476; - t[4] = 0xC3D2E1F0; - - m = xlen / 40; - for (j = 0; j < m; j++) { - /* XSEED_j = 0 */ - for (i = 0; i < 2; i++) { - /* XVAL = (XKEY + XSEED_j) mod 2^b */ - - /* w_i = G(t, XVAL) */ - os_memcpy(_t, t, 20); - sha1_transform((u8 *) _t, xkey); - _t[0] = host_to_be32(_t[0]); - _t[1] = host_to_be32(_t[1]); - _t[2] = host_to_be32(_t[2]); - _t[3] = host_to_be32(_t[3]); - _t[4] = host_to_be32(_t[4]); - os_memcpy(xpos, _t, 20); - - /* XKEY = (1 + XKEY + w_i) mod 2^b */ - carry = 1; - for (k = 19; k >= 0; k--) { - carry += xkey[k] + xpos[k]; - xkey[k] = carry & 0xff; - carry >>= 8; - } - - xpos += 20; - } - /* x_j = w_0|w_1 */ + while (skip >= sizeof(skip_buf)) { + size_t len = skip; + if (len > sizeof(skip_buf)) + len = sizeof(skip_buf); + if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len)) + goto out; + skip -= len; } - return 0; + if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len)) + res = 0; + +out: + EVP_CIPHER_CTX_cleanup(&ctx); + return res; +#endif /* OPENSSL_NO_RC4 */ } -#endif /* CONFIG_NO_FIPS186_2_PRF */ + + +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac); +} + + +#ifdef CONFIG_FIPS +int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac); +} +#endif /* CONFIG_FIPS */ + + +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac); +} + + +#ifndef NO_SHA256_WRAPPER +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len, + mac); +} +#endif /* NO_SHA256_WRAPPER */ void * aes_encrypt_init(const u8 *key, size_t len) @@ -310,7 +360,7 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, EVP_CIPHER_CTX_set_padding(&ctx->enc, 0); if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) || !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) || - !EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, key, iv)) { + !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) { EVP_CIPHER_CTX_cleanup(&ctx->enc); os_free(ctx); return NULL; @@ -320,7 +370,7 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, EVP_CIPHER_CTX_set_padding(&ctx->dec, 0); if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) || !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) || - !EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, key, iv)) { + !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) { EVP_CIPHER_CTX_cleanup(&ctx->enc); EVP_CIPHER_CTX_cleanup(&ctx->dec); os_free(ctx); @@ -358,3 +408,98 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) EVP_CIPHER_CTX_cleanup(&ctx->dec); os_free(ctx); } + + +void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) +{ + DH *dh; + struct wpabuf *pubkey = NULL, *privkey = NULL; + size_t publen, privlen; + + *priv = NULL; + *publ = NULL; + + dh = DH_new(); + if (dh == NULL) + return NULL; + + dh->g = BN_new(); + if (dh->g == NULL || BN_set_word(dh->g, 2) != 1) + goto err; + + dh->p = get_group5_prime(); + if (dh->p == NULL) + goto err; + + if (DH_generate_key(dh) != 1) + goto err; + + publen = BN_num_bytes(dh->pub_key); + pubkey = wpabuf_alloc(publen); + if (pubkey == NULL) + goto err; + privlen = BN_num_bytes(dh->priv_key); + privkey = wpabuf_alloc(privlen); + if (privkey == NULL) + goto err; + + BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen)); + BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen)); + + *priv = privkey; + *publ = pubkey; + return dh; + +err: + wpabuf_free(pubkey); + wpabuf_free(privkey); + DH_free(dh); + return NULL; +} + + +struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private) +{ + BIGNUM *pub_key; + struct wpabuf *res = NULL; + size_t rlen; + DH *dh = ctx; + int keylen; + + if (ctx == NULL) + return NULL; + + pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public), + NULL); + if (pub_key == NULL) + return NULL; + + rlen = DH_size(dh); + res = wpabuf_alloc(rlen); + if (res == NULL) + goto err; + + keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh); + if (keylen < 0) + goto err; + wpabuf_put(res, keylen); + BN_free(pub_key); + + return res; + +err: + BN_free(pub_key); + wpabuf_free(res); + return NULL; +} + + +void dh5_free(void *ctx) +{ + DH *dh; + if (ctx == NULL) + return; + dh = ctx; + DH_free(dh); +} diff --git a/src/crypto/des.c b/src/crypto/des-internal.c similarity index 95% rename from src/crypto/des.c rename to src/crypto/des-internal.c index 103e592461a7..ccea9503216e 100644 --- a/src/crypto/des.c +++ b/src/crypto/des-internal.c @@ -2,7 +2,7 @@ * DES and 3DES-EDE ciphers * * Modifications to LibTomCrypt implementation: - * Copyright (c) 2006, Jouni Malinen + * Copyright (c) 2006-2009, Jouni Malinen * * 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 @@ -18,9 +18,7 @@ #include "common.h" #include "crypto.h" - - -#ifdef INTERNAL_DES +#include "des_i.h" /* * This implementation is based on a DES implementation included in @@ -432,10 +430,34 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) } -struct des3_key_s { - u32 ek[3][32]; - u32 dk[3][32]; -}; +void des_key_setup(const u8 *key, u32 *ek, u32 *dk) +{ + deskey(key, 0, ek); + deskey(key, 1, dk); +} + + +void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt) +{ + u32 work[2]; + work[0] = WPA_GET_BE32(plain); + work[1] = WPA_GET_BE32(plain + 4); + desfunc(work, ek); + WPA_PUT_BE32(crypt, work[0]); + WPA_PUT_BE32(crypt + 4, work[1]); +} + + +void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain) +{ + u32 work[2]; + work[0] = WPA_GET_BE32(crypt); + work[1] = WPA_GET_BE32(crypt + 4); + desfunc(work, dk); + WPA_PUT_BE32(plain, work[0]); + WPA_PUT_BE32(plain + 4, work[1]); +} + void des3_key_setup(const u8 *key, struct des3_key_s *dkey) { @@ -475,5 +497,3 @@ void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain) WPA_PUT_BE32(plain, work[0]); WPA_PUT_BE32(plain + 4, work[1]); } - -#endif /* INTERNAL_DES */ diff --git a/src/crypto/des_i.h b/src/crypto/des_i.h new file mode 100644 index 000000000000..6f274144a0e6 --- /dev/null +++ b/src/crypto/des_i.h @@ -0,0 +1,31 @@ +/* + * DES and 3DES-EDE ciphers + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 DES_I_H +#define DES_I_H + +struct des3_key_s { + u32 ek[3][32]; + u32 dk[3][32]; +}; + +void des_key_setup(const u8 *key, u32 *ek, u32 *dk); +void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt); +void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain); + +void des3_key_setup(const u8 *key, struct des3_key_s *dkey); +void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); +void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); + +#endif /* DES_I_H */ diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c new file mode 100644 index 000000000000..8c475bf94ae9 --- /dev/null +++ b/src/crypto/dh_group5.c @@ -0,0 +1,40 @@ +/* + * Diffie-Hellman group 5 operations + * Copyright (c) 2009, Jouni Malinen + * + * 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 "dh_groups.h" +#include "dh_group5.h" + + +void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) +{ + *publ = dh_init(dh_groups_get(5), priv); + if (*publ == 0) + return NULL; + return (void *) 1; +} + + +struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private) +{ + return dh_derive_shared(peer_public, own_private, dh_groups_get(5)); +} + + +void dh5_free(void *ctx) +{ +} diff --git a/src/crypto/dh_group5.h b/src/crypto/dh_group5.h new file mode 100644 index 000000000000..595f1114fe2b --- /dev/null +++ b/src/crypto/dh_group5.h @@ -0,0 +1,23 @@ +/* + * Diffie-Hellman group 5 operations + * Copyright (c) 2009, Jouni Malinen + * + * 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 DH_GROUP5_H +#define DH_GROUP5_H + +void * dh5_init(struct wpabuf **priv, struct wpabuf **publ); +struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private); +void dh5_free(void *ctx); + +#endif /* DH_GROUP5_H */ diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c index 5f6008a6e2a2..7bd2fb7b4e21 100644 --- a/src/crypto/dh_groups.c +++ b/src/crypto/dh_groups.c @@ -619,11 +619,12 @@ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), wpabuf_head(own_private), wpabuf_len(own_private), dh->prime, dh->prime_len, - wpabuf_put(shared, shared_len), &shared_len) < 0) { + wpabuf_mhead(shared), &shared_len) < 0) { wpabuf_free(shared); wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); return NULL; } + wpabuf_put(shared, shared_len); wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared); return shared; diff --git a/src/crypto/fips_prf_cryptoapi.c b/src/crypto/fips_prf_cryptoapi.c new file mode 100644 index 000000000000..17d3116e8b57 --- /dev/null +++ b/src/crypto/fips_prf_cryptoapi.c @@ -0,0 +1,25 @@ +/* + * FIPS 186-2 PRF for Microsoft CryptoAPI + * Copyright (c) 2009, Jouni Malinen + * + * 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 "crypto.h" + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + /* FIX: how to do this with CryptoAPI? */ + return -1; +} diff --git a/src/crypto/fips_prf_gnutls.c b/src/crypto/fips_prf_gnutls.c new file mode 100644 index 000000000000..f742e98589f2 --- /dev/null +++ b/src/crypto/fips_prf_gnutls.c @@ -0,0 +1,26 @@ +/* + * FIPS 186-2 PRF for libgcrypt + * Copyright (c) 2004-2009, Jouni Malinen + * + * 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 + +#include "common.h" +#include "crypto.h" + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + /* FIX: how to do this with libgcrypt? */ + return -1; +} diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c new file mode 100644 index 000000000000..a85cb14d7424 --- /dev/null +++ b/src/crypto/fips_prf_internal.c @@ -0,0 +1,74 @@ +/* + * FIPS 186-2 PRF for internal crypto implementation + * Copyright (c) 2006-2007, Jouni Malinen + * + * 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 "sha1.h" +#include "sha1_i.h" +#include "crypto.h" + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + u8 xkey[64]; + u32 t[5], _t[5]; + int i, j, m, k; + u8 *xpos = x; + u32 carry; + + if (seed_len > sizeof(xkey)) + seed_len = sizeof(xkey); + + /* FIPS 186-2 + change notice 1 */ + + os_memcpy(xkey, seed, seed_len); + os_memset(xkey + seed_len, 0, 64 - seed_len); + t[0] = 0x67452301; + t[1] = 0xEFCDAB89; + t[2] = 0x98BADCFE; + t[3] = 0x10325476; + t[4] = 0xC3D2E1F0; + + m = xlen / 40; + for (j = 0; j < m; j++) { + /* XSEED_j = 0 */ + for (i = 0; i < 2; i++) { + /* XVAL = (XKEY + XSEED_j) mod 2^b */ + + /* w_i = G(t, XVAL) */ + os_memcpy(_t, t, 20); + SHA1Transform(_t, xkey); + _t[0] = host_to_be32(_t[0]); + _t[1] = host_to_be32(_t[1]); + _t[2] = host_to_be32(_t[2]); + _t[3] = host_to_be32(_t[3]); + _t[4] = host_to_be32(_t[4]); + os_memcpy(xpos, _t, 20); + + /* XKEY = (1 + XKEY + w_i) mod 2^b */ + carry = 1; + for (k = 19; k >= 0; k--) { + carry += xkey[k] + xpos[k]; + xkey[k] = carry & 0xff; + carry >>= 8; + } + + xpos += SHA1_MAC_LEN; + } + /* x_j = w_0|w_1 */ + } + + return 0; +} diff --git a/src/crypto/fips_prf_nss.c b/src/crypto/fips_prf_nss.c new file mode 100644 index 000000000000..f941983c43c3 --- /dev/null +++ b/src/crypto/fips_prf_nss.c @@ -0,0 +1,25 @@ +/* + * FIPS 186-2 PRF for NSS + * Copyright (c) 2009, Jouni Malinen + * + * 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 + +#include "common.h" +#include "crypto.h" + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + return -1; +} diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c new file mode 100644 index 000000000000..d0af98355f65 --- /dev/null +++ b/src/crypto/fips_prf_openssl.c @@ -0,0 +1,83 @@ +/* + * FIPS 186-2 PRF for libcrypto + * Copyright (c) 2004-2005, Jouni Malinen + * + * 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 + +#include "common.h" +#include "crypto.h" + + +static void sha1_transform(u8 *state, const u8 data[64]) +{ + SHA_CTX context; + os_memset(&context, 0, sizeof(context)); + os_memcpy(&context.h0, state, 5 * 4); + SHA1_Transform(&context, data); + os_memcpy(state, &context.h0, 5 * 4); +} + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + u8 xkey[64]; + u32 t[5], _t[5]; + int i, j, m, k; + u8 *xpos = x; + u32 carry; + + if (seed_len > sizeof(xkey)) + seed_len = sizeof(xkey); + + /* FIPS 186-2 + change notice 1 */ + + os_memcpy(xkey, seed, seed_len); + os_memset(xkey + seed_len, 0, 64 - seed_len); + t[0] = 0x67452301; + t[1] = 0xEFCDAB89; + t[2] = 0x98BADCFE; + t[3] = 0x10325476; + t[4] = 0xC3D2E1F0; + + m = xlen / 40; + for (j = 0; j < m; j++) { + /* XSEED_j = 0 */ + for (i = 0; i < 2; i++) { + /* XVAL = (XKEY + XSEED_j) mod 2^b */ + + /* w_i = G(t, XVAL) */ + os_memcpy(_t, t, 20); + sha1_transform((u8 *) _t, xkey); + _t[0] = host_to_be32(_t[0]); + _t[1] = host_to_be32(_t[1]); + _t[2] = host_to_be32(_t[2]); + _t[3] = host_to_be32(_t[3]); + _t[4] = host_to_be32(_t[4]); + os_memcpy(xpos, _t, 20); + + /* XKEY = (1 + XKEY + w_i) mod 2^b */ + carry = 1; + for (k = 19; k >= 0; k--) { + carry += xkey[k] + xpos[k]; + xkey[k] = carry & 0xff; + carry >>= 8; + } + + xpos += 20; + } + /* x_j = w_0|w_1 */ + } + + return 0; +} diff --git a/src/crypto/md4.c b/src/crypto/md4-internal.c similarity index 98% rename from src/crypto/md4.c rename to src/crypto/md4-internal.c index 41c84a3a7b5d..d9f499f1d07b 100644 --- a/src/crypto/md4.c +++ b/src/crypto/md4-internal.c @@ -17,9 +17,6 @@ #include "common.h" #include "crypto.h" - -#ifdef INTERNAL_MD4 - #define MD4_BLOCK_LENGTH 64 #define MD4_DIGEST_LENGTH 16 @@ -35,7 +32,7 @@ static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len); static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx); -void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { MD4_CTX ctx; size_t i; @@ -44,6 +41,7 @@ void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) for (i = 0; i < num_elem; i++) MD4Update(&ctx, addr[i], len[i]); MD4Final(mac, &ctx); + return 0; } @@ -278,5 +276,3 @@ MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]) state[3] += d; } /* ===== end - public domain MD4 implementation ===== */ - -#endif /* INTERNAL_MD4 */ diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c new file mode 100644 index 000000000000..f8692a9557ae --- /dev/null +++ b/src/crypto/md5-internal.c @@ -0,0 +1,293 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "md5.h" +#include "md5_i.h" +#include "crypto.h" + + +static void MD5Transform(u32 buf[4], u32 const in[16]); + + +typedef struct MD5Context MD5_CTX; + + +/** + * md5_vector - MD5 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + MD5_CTX ctx; + size_t i; + + MD5Init(&ctx); + for (i = 0; i < num_elem; i++) + MD5Update(&ctx, addr[i], len[i]); + MD5Final(mac, &ctx); + return 0; +} + + +/* ===== start - public domain MD5 implementation ===== */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#ifndef WORDS_BIGENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + u32 t; + do { + t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(u32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + os_memcpy(p, buf, len); + return; + } + os_memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + os_memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + os_memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + os_memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + os_memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + os_memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((u32 *) ctx->in)[14] = ctx->bits[0]; + ((u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + os_memcpy(digest, ctx->buf, 16); + os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(u32 buf[4], u32 const in[16]) +{ + register u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +/* ===== end - public domain MD5 implementation ===== */ diff --git a/src/crypto/md5-non-fips.c b/src/crypto/md5-non-fips.c new file mode 100644 index 000000000000..6f2920145a1e --- /dev/null +++ b/src/crypto/md5-non-fips.c @@ -0,0 +1,113 @@ +/* + * MD5 hash implementation and interface functions (non-FIPS allowed cases) + * Copyright (c) 2003-2009, Jouni Malinen + * + * 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 "md5.h" +#include "crypto.h" + + +/** + * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + u8 k_pad[64]; /* padding - key XORd with ipad/opad */ + u8 tk[16]; + const u8 *_addr[6]; + size_t i, _len[6]; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return -1; + } + + /* if key is longer than 64 bytes reset it to key = MD5(key) */ + if (key_len > 64) { + if (md5_vector_non_fips_allow(1, &key, &key_len, tk)) + return -1; + key = tk; + key_len = 16; + } + + /* the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner MD5 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac)) + return -1; + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer MD5 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = MD5_MAC_LEN; + return md5_vector_non_fips_allow(2, _addr, _len, mac); +} + + +/** + * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data, + &data_len, mac); +} diff --git a/src/crypto/md5.c b/src/crypto/md5.c index a7db7aa9a771..7f14e9b2ec16 100644 --- a/src/crypto/md5.c +++ b/src/crypto/md5.c @@ -27,9 +27,10 @@ * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure */ -void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) +int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) { u8 k_pad[64]; /* padding - key XORd with ipad/opad */ u8 tk[16]; @@ -41,12 +42,13 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ - return; + return -1; } /* if key is longer than 64 bytes reset it to key = MD5(key) */ if (key_len > 64) { - md5_vector(1, &key, &key_len, tk); + if (md5_vector(1, &key, &key_len, tk)) + return -1; key = tk; key_len = 16; } @@ -75,7 +77,8 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } - md5_vector(1 + num_elem, _addr, _len, mac); + if (md5_vector(1 + num_elem, _addr, _len, mac)) + return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); @@ -88,7 +91,7 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, _len[0] = 64; _addr[1] = mac; _len[1] = MD5_MAC_LEN; - md5_vector(2, _addr, _len, mac); + return md5_vector(2, _addr, _len, mac); } @@ -99,296 +102,10 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure */ -void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, +int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { - hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); + return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); } - - -#ifdef INTERNAL_MD5 - -struct MD5Context { - u32 buf[4]; - u32 bits[2]; - u8 in[64]; -}; - -#ifndef CONFIG_CRYPTO_INTERNAL -static void MD5Init(struct MD5Context *context); -static void MD5Update(struct MD5Context *context, unsigned char const *buf, - unsigned len); -static void MD5Final(unsigned char digest[16], struct MD5Context *context); -#endif /* CONFIG_CRYPTO_INTERNAL */ -static void MD5Transform(u32 buf[4], u32 const in[16]); - - -typedef struct MD5Context MD5_CTX; - - -/** - * md5_vector - MD5 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - */ -void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -{ - MD5_CTX ctx; - size_t i; - - MD5Init(&ctx); - for (i = 0; i < num_elem; i++) - MD5Update(&ctx, addr[i], len[i]); - MD5Final(mac, &ctx); -} - - -/* ===== start - public domain MD5 implementation ===== */ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#ifndef WORDS_BIGENDIAN -#define byteReverse(buf, len) /* Nothing */ -#else -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - u32 t; - do { - t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(u32 *) buf = t; - buf += 4; - } while (--longs); -} -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Init(struct MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) -{ - u32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((u32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - os_memcpy(p, buf, len); - return; - } - os_memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - os_memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - os_memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Final(unsigned char digest[16], struct MD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - os_memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - os_memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - os_memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((u32 *) ctx->in)[14] = ctx->bits[0]; - ((u32 *) ctx->in)[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (u32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - os_memcpy(digest, ctx->buf, 16); - os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(u32 buf[4], u32 const in[16]) -{ - register u32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} -/* ===== end - public domain MD5 implementation ===== */ - -#endif /* INTERNAL_MD5 */ diff --git a/src/crypto/md5.h b/src/crypto/md5.h index e82f3969ed08..8952590782a3 100644 --- a/src/crypto/md5.h +++ b/src/crypto/md5.h @@ -1,6 +1,6 @@ /* * MD5 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen + * Copyright (c) 2003-2009, Jouni Malinen * * 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 @@ -17,18 +17,19 @@ #define MD5_MAC_LEN 16 -void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac); -void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, - u8 *mac); - -#ifdef CONFIG_CRYPTO_INTERNAL -struct MD5Context; - -void MD5Init(struct MD5Context *context); -void MD5Update(struct MD5Context *context, unsigned char const *buf, - unsigned len); -void MD5Final(unsigned char digest[16], struct MD5Context *context); -#endif /* CONFIG_CRYPTO_INTERNAL */ +int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac); +int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac); +#ifdef CONFIG_FIPS +int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); +int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac); +#else /* CONFIG_FIPS */ +#define hmac_md5_vector_non_fips_allow hmac_md5_vector +#define hmac_md5_non_fips_allow hmac_md5 +#endif /* CONFIG_FIPS */ #endif /* MD5_H */ diff --git a/src/crypto/md5_i.h b/src/crypto/md5_i.h new file mode 100644 index 000000000000..b7f6596052a6 --- /dev/null +++ b/src/crypto/md5_i.h @@ -0,0 +1,29 @@ +/* + * MD5 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 MD5_I_H +#define MD5_I_H + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); + +#endif /* MD5_I_H */ diff --git a/src/crypto/milenage.c b/src/crypto/milenage.c new file mode 100644 index 000000000000..cf0c60e5510f --- /dev/null +++ b/src/crypto/milenage.c @@ -0,0 +1,329 @@ +/* + * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) + * Copyright (c) 2006-2007 + * + * 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. + * + * This file implements an example authentication algorithm defined for 3GPP + * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow + * EAP-AKA to be tested properly with real USIM cards. + * + * This implementations assumes that the r1..r5 and c1..c5 constants defined in + * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, + * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to + * be AES (Rijndael). + */ + +#include "includes.h" + +#include "common.h" +#include "crypto/aes_wrap.h" +#include "milenage.h" + + +/** + * milenage_f1 - Milenage f1 and f1* algorithms + * @opc: OPc = 128-bit value derived from OP and K + * @k: K = 128-bit subscriber key + * @_rand: RAND = 128-bit random challenge + * @sqn: SQN = 48-bit sequence number + * @amf: AMF = 16-bit authentication management field + * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL + * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL + * Returns: 0 on success, -1 on failure + */ +int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, + const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) +{ + u8 tmp1[16], tmp2[16], tmp3[16]; + int i; + + /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ + for (i = 0; i < 16; i++) + tmp1[i] = _rand[i] ^ opc[i]; + if (aes_128_encrypt_block(k, tmp1, tmp1)) + return -1; + + /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ + os_memcpy(tmp2, sqn, 6); + os_memcpy(tmp2 + 6, amf, 2); + os_memcpy(tmp2 + 8, tmp2, 8); + + /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ + + /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ + for (i = 0; i < 16; i++) + tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; + /* XOR with TEMP = E_K(RAND XOR OP_C) */ + for (i = 0; i < 16; i++) + tmp3[i] ^= tmp1[i]; + /* XOR with c1 (= ..00, i.e., NOP) */ + + /* f1 || f1* = E_K(tmp3) XOR OP_c */ + if (aes_128_encrypt_block(k, tmp3, tmp1)) + return -1; + for (i = 0; i < 16; i++) + tmp1[i] ^= opc[i]; + if (mac_a) + os_memcpy(mac_a, tmp1, 8); /* f1 */ + if (mac_s) + os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ + return 0; +} + + +/** + * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms + * @opc: OPc = 128-bit value derived from OP and K + * @k: K = 128-bit subscriber key + * @_rand: RAND = 128-bit random challenge + * @res: Buffer for RES = 64-bit signed response (f2), or %NULL + * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL + * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL + * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL + * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL + * Returns: 0 on success, -1 on failure + */ +int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, + u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) +{ + u8 tmp1[16], tmp2[16], tmp3[16]; + int i; + + /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ + for (i = 0; i < 16; i++) + tmp1[i] = _rand[i] ^ opc[i]; + if (aes_128_encrypt_block(k, tmp1, tmp2)) + return -1; + + /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ + /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ + /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ + /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ + + /* f2 and f5 */ + /* rotate by r2 (= 0, i.e., NOP) */ + for (i = 0; i < 16; i++) + tmp1[i] = tmp2[i] ^ opc[i]; + tmp1[15] ^= 1; /* XOR c2 (= ..01) */ + /* f5 || f2 = E_K(tmp1) XOR OP_c */ + if (aes_128_encrypt_block(k, tmp1, tmp3)) + return -1; + for (i = 0; i < 16; i++) + tmp3[i] ^= opc[i]; + if (res) + os_memcpy(res, tmp3 + 8, 8); /* f2 */ + if (ak) + os_memcpy(ak, tmp3, 6); /* f5 */ + + /* f3 */ + if (ck) { + /* rotate by r3 = 0x20 = 4 bytes */ + for (i = 0; i < 16; i++) + tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; + tmp1[15] ^= 2; /* XOR c3 (= ..02) */ + if (aes_128_encrypt_block(k, tmp1, ck)) + return -1; + for (i = 0; i < 16; i++) + ck[i] ^= opc[i]; + } + + /* f4 */ + if (ik) { + /* rotate by r4 = 0x40 = 8 bytes */ + for (i = 0; i < 16; i++) + tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; + tmp1[15] ^= 4; /* XOR c4 (= ..04) */ + if (aes_128_encrypt_block(k, tmp1, ik)) + return -1; + for (i = 0; i < 16; i++) + ik[i] ^= opc[i]; + } + + /* f5* */ + if (akstar) { + /* rotate by r5 = 0x60 = 12 bytes */ + for (i = 0; i < 16; i++) + tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; + tmp1[15] ^= 8; /* XOR c5 (= ..08) */ + if (aes_128_encrypt_block(k, tmp1, tmp1)) + return -1; + for (i = 0; i < 6; i++) + akstar[i] = tmp1[i] ^ opc[i]; + } + + return 0; +} + + +/** + * milenage_generate - Generate AKA AUTN,IK,CK,RES + * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) + * @amf: AMF = 16-bit authentication management field + * @k: K = 128-bit subscriber key + * @sqn: SQN = 48-bit sequence number + * @_rand: RAND = 128-bit random challenge + * @autn: Buffer for AUTN = 128-bit authentication token + * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL + * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL + * @res: Buffer for RES = 64-bit signed response (f2), or %NULL + * @res_len: Max length for res; set to used length or 0 on failure + */ +void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, + const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, + u8 *ck, u8 *res, size_t *res_len) +{ + int i; + u8 mac_a[8], ak[6]; + + if (*res_len < 8) { + *res_len = 0; + return; + } + if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || + milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { + *res_len = 0; + return; + } + *res_len = 8; + + /* AUTN = (SQN ^ AK) || AMF || MAC */ + for (i = 0; i < 6; i++) + autn[i] = sqn[i] ^ ak[i]; + os_memcpy(autn + 6, amf, 2); + os_memcpy(autn + 8, mac_a, 8); +} + + +/** + * milenage_auts - Milenage AUTS validation + * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) + * @k: K = 128-bit subscriber key + * @_rand: RAND = 128-bit random challenge + * @auts: AUTS = 112-bit authentication token from client + * @sqn: Buffer for SQN = 48-bit sequence number + * Returns: 0 = success (sqn filled), -1 on failure + */ +int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, + u8 *sqn) +{ + u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ + u8 ak[6], mac_s[8]; + int i; + + if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) + return -1; + for (i = 0; i < 6; i++) + sqn[i] = auts[i] ^ ak[i]; + if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || + memcmp(mac_s, auts + 6, 8) != 0) + return -1; + return 0; +} + + +/** + * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet + * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) + * @k: K = 128-bit subscriber key + * @_rand: RAND = 128-bit random challenge + * @sres: Buffer for SRES = 32-bit SRES + * @kc: Buffer for Kc = 64-bit Kc + * Returns: 0 on success, -1 on failure + */ +int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) +{ + u8 res[8], ck[16], ik[16]; + int i; + + if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) + return -1; + + for (i = 0; i < 8; i++) + kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; + +#ifdef GSM_MILENAGE_ALT_SRES + os_memcpy(sres, res, 4); +#else /* GSM_MILENAGE_ALT_SRES */ + for (i = 0; i < 4; i++) + sres[i] = res[i] ^ res[i + 4]; +#endif /* GSM_MILENAGE_ALT_SRES */ + return 0; +} + + +/** + * milenage_generate - Generate AKA AUTN,IK,CK,RES + * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) + * @k: K = 128-bit subscriber key + * @sqn: SQN = 48-bit sequence number + * @_rand: RAND = 128-bit random challenge + * @autn: AUTN = 128-bit authentication token + * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL + * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL + * @res: Buffer for RES = 64-bit signed response (f2), or %NULL + * @res_len: Variable that will be set to RES length + * @auts: 112-bit buffer for AUTS + * Returns: 0 on success, -1 on failure, or -2 on synchronization failure + */ +int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, + const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, + u8 *auts) +{ + int i; + u8 mac_a[8], ak[6], rx_sqn[6]; + const u8 *amf; + + wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); + wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); + + if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) + return -1; + + *res_len = 8; + wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); + wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); + wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); + wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); + + /* AUTN = (SQN ^ AK) || AMF || MAC */ + for (i = 0; i < 6; i++) + rx_sqn[i] = autn[i] ^ ak[i]; + wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); + + if (os_memcmp(rx_sqn, sqn, 6) <= 0) { + u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ + if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) + return -1; + wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); + for (i = 0; i < 6; i++) + auts[i] = sqn[i] ^ ak[i]; + if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) + return -1; + wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); + return -2; + } + + amf = autn + 6; + wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); + if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) + return -1; + + wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); + + if (os_memcmp(mac_a, autn + 8, 8) != 0) { + wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); + wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", + autn + 8, 8); + return -1; + } + + return 0; +} diff --git a/src/hlr_auc_gw/milenage.h b/src/crypto/milenage.h similarity index 81% rename from src/hlr_auc_gw/milenage.h rename to src/crypto/milenage.h index b35603ca8698..d5054d6dcca6 100644 --- a/src/hlr_auc_gw/milenage.h +++ b/src/crypto/milenage.h @@ -25,5 +25,9 @@ int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, u8 *auts); +int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, + const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s); +int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, + u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar); #endif /* MILENAGE_H */ diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c index 7e2f0fa37710..dae15ab915fe 100644 --- a/src/crypto/ms_funcs.c +++ b/src/crypto/ms_funcs.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -18,7 +18,6 @@ #include "sha1.h" #include "ms_funcs.h" #include "crypto.h" -#include "rc4.h" /** @@ -28,10 +27,11 @@ * @username: 0-to-256-char UserName (IN) * @username_len: Length of username * @challenge: 8-octet Challenge (OUT) + * Returns: 0 on success, -1 on failure */ -static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, - const u8 *username, size_t username_len, - u8 *challenge) +static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, + const u8 *username, size_t username_len, + u8 *challenge) { u8 hash[SHA1_MAC_LEN]; const unsigned char *addr[3]; @@ -44,8 +44,10 @@ static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, addr[2] = username; len[2] = username_len; - sha1_vector(3, addr, len, hash); + if (sha1_vector(3, addr, len, hash)) + return -1; os_memcpy(challenge, hash, 8); + return 0; } @@ -54,8 +56,9 @@ static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @password_hash: 16-octet PasswordHash (OUT) + * Returns: 0 on success, -1 on failure */ -void nt_password_hash(const u8 *password, size_t password_len, +int nt_password_hash(const u8 *password, size_t password_len, u8 *password_hash) { u8 buf[512], *pos; @@ -72,7 +75,7 @@ void nt_password_hash(const u8 *password, size_t password_len, len = password_len * 2; pos = buf; - md4_vector(1, (const u8 **) &pos, &len, password_hash); + return md4_vector(1, (const u8 **) &pos, &len, password_hash); } @@ -80,11 +83,12 @@ void nt_password_hash(const u8 *password, size_t password_len, * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4 * @password_hash: 16-octet PasswordHash (IN) * @password_hash_hash: 16-octet PasswordHashHash (OUT) + * Returns: 0 on success, -1 on failure */ -void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) +int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) { size_t len = 16; - md4_vector(1, &password_hash, &len, password_hash_hash); + return md4_vector(1, &password_hash, &len, password_hash_hash); } @@ -116,19 +120,22 @@ void challenge_response(const u8 *challenge, const u8 *password_hash, * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @response: 24-octet Response (OUT) + * Returns: 0 on success, -1 on failure */ -void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password, size_t password_len, - u8 *response) +int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, + const u8 *username, size_t username_len, + const u8 *password, size_t password_len, + u8 *response) { u8 challenge[8]; u8 password_hash[16]; challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge); - nt_password_hash(password, password_len, password_hash); + if (nt_password_hash(password, password_len, password_hash)) + return -1; challenge_response(challenge, password_hash, response); + return 0; } @@ -140,18 +147,22 @@ void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, * @username_len: Length of username * @password_hash: 16-octet PasswordHash (IN) * @response: 24-octet Response (OUT) + * Returns: 0 on success, -1 on failure */ -void generate_nt_response_pwhash(const u8 *auth_challenge, - const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password_hash, - u8 *response) +int generate_nt_response_pwhash(const u8 *auth_challenge, + const u8 *peer_challenge, + const u8 *username, size_t username_len, + const u8 *password_hash, + u8 *response) { u8 challenge[8]; - challenge_hash(peer_challenge, auth_challenge, username, username_len, - challenge); + if (challenge_hash(peer_challenge, auth_challenge, + username, username_len, + challenge)) + return -1; challenge_response(challenge, password_hash, response); + return 0; } @@ -165,8 +176,9 @@ void generate_nt_response_pwhash(const u8 *auth_challenge, * @username_len: Length of username * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually * encoded as a 42-octet ASCII string (S=hexdump_of_response) + * Returns: 0 on success, -1 on failure */ -void generate_authenticator_response_pwhash( +int generate_authenticator_response_pwhash( const u8 *password_hash, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, @@ -200,12 +212,14 @@ void generate_authenticator_response_pwhash( addr2[1] = challenge; addr2[2] = magic2; - hash_nt_password_hash(password_hash, password_hash_hash); - sha1_vector(3, addr1, len1, response); + if (hash_nt_password_hash(password_hash, password_hash_hash)) + return -1; + if (sha1_vector(3, addr1, len1, response)) + return -1; challenge_hash(peer_challenge, auth_challenge, username, username_len, challenge); - sha1_vector(3, addr2, len2, response); + return sha1_vector(3, addr2, len2, response); } @@ -220,19 +234,20 @@ void generate_authenticator_response_pwhash( * @username_len: Length of username * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually * encoded as a 42-octet ASCII string (S=hexdump_of_response) + * Returns: 0 on success, -1 on failure */ -void generate_authenticator_response(const u8 *password, size_t password_len, - const u8 *peer_challenge, - const u8 *auth_challenge, - const u8 *username, size_t username_len, - const u8 *nt_response, u8 *response) +int generate_authenticator_response(const u8 *password, size_t password_len, + const u8 *peer_challenge, + const u8 *auth_challenge, + const u8 *username, size_t username_len, + const u8 *nt_response, u8 *response) { u8 password_hash[16]; - nt_password_hash(password, password_len, password_hash); - generate_authenticator_response_pwhash(password_hash, - peer_challenge, auth_challenge, - username, username_len, - nt_response, response); + if (nt_password_hash(password, password_len, password_hash)) + return -1; + return generate_authenticator_response_pwhash( + password_hash, peer_challenge, auth_challenge, + username, username_len, nt_response, response); } @@ -242,13 +257,16 @@ void generate_authenticator_response(const u8 *password, size_t password_len, * @password: 0-to-256-unicode-char Password (IN; ASCII) * @password_len: Length of password * @response: 24-octet Response (OUT) + * Returns: 0 on success, -1 on failure */ -void nt_challenge_response(const u8 *challenge, const u8 *password, - size_t password_len, u8 *response) +int nt_challenge_response(const u8 *challenge, const u8 *password, + size_t password_len, u8 *response) { u8 password_hash[16]; - nt_password_hash(password, password_len, password_hash); + if (nt_password_hash(password, password_len, password_hash)) + return -1; challenge_response(challenge, password_hash, response); + return 0; } @@ -257,9 +275,10 @@ void nt_challenge_response(const u8 *challenge, const u8 *password, * @password_hash_hash: 16-octet PasswordHashHash (IN) * @nt_response: 24-octet NTResponse (IN) * @master_key: 16-octet MasterKey (OUT) + * Returns: 0 on success, -1 on failure */ -void get_master_key(const u8 *password_hash_hash, const u8 *nt_response, - u8 *master_key) +int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, + u8 *master_key) { static const u8 magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, @@ -274,8 +293,10 @@ void get_master_key(const u8 *password_hash_hash, const u8 *nt_response, addr[1] = nt_response; addr[2] = magic1; - sha1_vector(3, addr, len, hash); + if (sha1_vector(3, addr, len, hash)) + return -1; os_memcpy(master_key, hash, 16); + return 0; } @@ -286,10 +307,11 @@ void get_master_key(const u8 *password_hash_hash, const u8 *nt_response, * @session_key_len: SessionKeyLength (Length of session_key) (IN) * @is_send: IsSend (IN, BOOLEAN) * @is_server: IsServer (IN, BOOLEAN) + * Returns: 0 on success, -1 on failure */ -void get_asymetric_start_key(const u8 *master_key, u8 *session_key, - size_t session_key_len, int is_send, - int is_server) +int get_asymetric_start_key(const u8 *master_key, u8 *session_key, + size_t session_key_len, int is_send, + int is_server) { static const u8 magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, @@ -339,11 +361,13 @@ void get_asymetric_start_key(const u8 *master_key, u8 *session_key, } addr[3] = shs_pad2; - sha1_vector(4, addr, len, digest); + if (sha1_vector(4, addr, len, digest)) + return -1; if (session_key_len > SHA1_MAC_LEN) session_key_len = SHA1_MAC_LEN; os_memcpy(session_key, digest, session_key_len); + return 0; } @@ -400,7 +424,8 @@ int new_password_encrypted_with_old_nt_password_hash( { u8 password_hash[16]; - nt_password_hash(old_password, old_password_len, password_hash); + if (nt_password_hash(old_password, old_password_len, password_hash)) + return -1; if (encrypt_pw_block_with_password_hash(new_password, new_password_len, password_hash, encrypted_pw_block)) @@ -430,17 +455,22 @@ void nt_password_hash_encrypted_with_block(const u8 *password_hash, * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) * @old_password_len: Length of old_password * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) + * Returns: 0 on success, -1 on failure */ -void old_nt_password_hash_encrypted_with_new_nt_password_hash( +int old_nt_password_hash_encrypted_with_new_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_password_hash) { u8 old_password_hash[16], new_password_hash[16]; - nt_password_hash(old_password, old_password_len, old_password_hash); - nt_password_hash(new_password, new_password_len, new_password_hash); + if (nt_password_hash(old_password, old_password_len, + old_password_hash) || + nt_password_hash(new_password, new_password_len, + new_password_hash)) + return -1; nt_password_hash_encrypted_with_block(old_password_hash, new_password_hash, encrypted_password_hash); + return 0; } diff --git a/src/crypto/ms_funcs.h b/src/crypto/ms_funcs.h index 6205bf68d3ec..298dbcf4fee3 100644 --- a/src/crypto/ms_funcs.h +++ b/src/crypto/ms_funcs.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -15,38 +15,38 @@ #ifndef MS_FUNCS_H #define MS_FUNCS_H -void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password, size_t password_len, - u8 *response); -void generate_nt_response_pwhash(const u8 *auth_challenge, - const u8 *peer_challenge, - const u8 *username, size_t username_len, - const u8 *password_hash, - u8 *response); -void generate_authenticator_response(const u8 *password, size_t password_len, - const u8 *peer_challenge, - const u8 *auth_challenge, - const u8 *username, size_t username_len, - const u8 *nt_response, u8 *response); -void generate_authenticator_response_pwhash( +int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, + const u8 *username, size_t username_len, + const u8 *password, size_t password_len, + u8 *response); +int generate_nt_response_pwhash(const u8 *auth_challenge, + const u8 *peer_challenge, + const u8 *username, size_t username_len, + const u8 *password_hash, + u8 *response); +int generate_authenticator_response(const u8 *password, size_t password_len, + const u8 *peer_challenge, + const u8 *auth_challenge, + const u8 *username, size_t username_len, + const u8 *nt_response, u8 *response); +int generate_authenticator_response_pwhash( const u8 *password_hash, const u8 *peer_challenge, const u8 *auth_challenge, const u8 *username, size_t username_len, const u8 *nt_response, u8 *response); -void nt_challenge_response(const u8 *challenge, const u8 *password, - size_t password_len, u8 *response); +int nt_challenge_response(const u8 *challenge, const u8 *password, + size_t password_len, u8 *response); void challenge_response(const u8 *challenge, const u8 *password_hash, u8 *response); -void nt_password_hash(const u8 *password, size_t password_len, - u8 *password_hash); -void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash); -void get_master_key(const u8 *password_hash_hash, const u8 *nt_response, - u8 *master_key); -void get_asymetric_start_key(const u8 *master_key, u8 *session_key, - size_t session_key_len, int is_send, - int is_server); +int nt_password_hash(const u8 *password, size_t password_len, + u8 *password_hash); +int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash); +int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, + u8 *master_key); +int get_asymetric_start_key(const u8 *master_key, u8 *session_key, + size_t session_key_len, int is_send, + int is_server); int __must_check encrypt_pw_block_with_password_hash( const u8 *password, size_t password_len, const u8 *password_hash, u8 *pw_block); @@ -56,7 +56,7 @@ int __must_check new_password_encrypted_with_old_nt_password_hash( u8 *encrypted_pw_block); void nt_password_hash_encrypted_with_block(const u8 *password_hash, const u8 *block, u8 *cypher); -void old_nt_password_hash_encrypted_with_new_nt_password_hash( +int old_nt_password_hash_encrypted_with_new_nt_password_hash( const u8 *new_password, size_t new_password_len, const u8 *old_password, size_t old_password_len, u8 *encrypted_password_hash); diff --git a/src/crypto/rc4.c b/src/crypto/rc4.c index 70c790e364f7..5ab1be191e9a 100644 --- a/src/crypto/rc4.c +++ b/src/crypto/rc4.c @@ -15,24 +15,12 @@ #include "includes.h" #include "common.h" -#include "rc4.h" +#include "crypto.h" #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) -/** - * rc4 - XOR RC4 stream to given data with skip-stream-start - * @key: RC4 key - * @keylen: RC4 key length - * @skip: number of bytes to skip from the beginning of the RC4 stream - * @data: data to be XOR'ed with RC4 stream - * @data_len: buf length - * - * Generate RC4 pseudo random stream for the given key, skip beginning of the - * stream, and XOR the end result with the data buffer to perform RC4 - * encryption/decryption. - */ -void rc4_skip(const u8 *key, size_t keylen, size_t skip, - u8 *data, size_t data_len) +int rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len) { u32 i, j, k; u8 S[256], *pos; @@ -67,4 +55,6 @@ void rc4_skip(const u8 *key, size_t keylen, size_t skip, S_SWAP(i, j); *pos++ ^= S[(S[i] + S[j]) & 0xff]; } + + return 0; } diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c new file mode 100644 index 000000000000..3f05ca113125 --- /dev/null +++ b/src/crypto/sha1-internal.c @@ -0,0 +1,308 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "sha1.h" +#include "sha1_i.h" +#include "md5.h" +#include "crypto.h" + +typedef struct SHA1Context SHA1_CTX; + +void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + SHA1_CTX ctx; + size_t i; + + SHA1Init(&ctx); + for (i = 0; i < num_elem; i++) + SHA1Update(&ctx, addr[i], len[i]); + SHA1Final(mac, &ctx); + return 0; +} + + +/* ===== start - public domain SHA1 implementation ===== */ + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 4/01 +By Jouni Malinen +Minor changes to match the coding style used in Dynamics. + +Modified September 24, 2004 +By Jouni Malinen +Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. + +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define SHA1HANDSOFF + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef WORDS_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w=rol(w, 30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg) +{ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u32 state[5], const unsigned char buffer[64]) +{ + u32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + u32 l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; +#ifdef SHA1HANDSOFF + CHAR64LONG16 workspace; + block = &workspace; + os_memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + os_memset(block, 0, 64); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) +{ + u32 i, j; + const unsigned char *data = _data; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + os_memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + os_memcpy(&context->buffer[j], &data[i], len - i); +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + u32 i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) + ((context->count[(i >= 4 ? 0 : 1)] >> + ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *) "\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *) "\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() + */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & + 255); + } + /* Wipe variables */ + i = 0; + os_memset(context->buffer, 0, 64); + os_memset(context->state, 0, 20); + os_memset(context->count, 0, 8); + os_memset(finalcount, 0, 8); +} + +/* ===== end - public domain SHA1 implementation ===== */ diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c new file mode 100644 index 000000000000..11323de7a01e --- /dev/null +++ b/src/crypto/sha1-pbkdf2.c @@ -0,0 +1,100 @@ +/* + * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "sha1.h" +#include "md5.h" +#include "crypto.h" + +static int pbkdf2_sha1_f(const char *passphrase, const char *ssid, + size_t ssid_len, int iterations, unsigned int count, + u8 *digest) +{ + unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; + int i, j; + unsigned char count_buf[4]; + const u8 *addr[2]; + size_t len[2]; + size_t passphrase_len = os_strlen(passphrase); + + addr[0] = (u8 *) ssid; + len[0] = ssid_len; + addr[1] = count_buf; + len[1] = 4; + + /* F(P, S, c, i) = U1 xor U2 xor ... Uc + * U1 = PRF(P, S || i) + * U2 = PRF(P, U1) + * Uc = PRF(P, Uc-1) + */ + + count_buf[0] = (count >> 24) & 0xff; + count_buf[1] = (count >> 16) & 0xff; + count_buf[2] = (count >> 8) & 0xff; + count_buf[3] = count & 0xff; + if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, + tmp)) + return -1; + os_memcpy(digest, tmp, SHA1_MAC_LEN); + + for (i = 1; i < iterations; i++) { + if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, + SHA1_MAC_LEN, tmp2)) + return -1; + os_memcpy(tmp, tmp2, SHA1_MAC_LEN); + for (j = 0; j < SHA1_MAC_LEN; j++) + digest[j] ^= tmp2[j]; + } + + return 0; +} + + +/** + * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * @passphrase: ASCII passphrase + * @ssid: SSID + * @ssid_len: SSID length in bytes + * @iterations: Number of iterations to run + * @buf: Buffer for the generated key + * @buflen: Length of the buffer in bytes + * Returns: 0 on success, -1 of failure + * + * This function is used to derive PSK for WPA-PSK. For this protocol, + * iterations is set to 4096 and buflen to 32. This function is described in + * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. + */ +int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + unsigned int count = 0; + unsigned char *pos = buf; + size_t left = buflen, plen; + unsigned char digest[SHA1_MAC_LEN]; + + while (left > 0) { + count++; + if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, + count, digest)) + return -1; + plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; + os_memcpy(pos, digest, plen); + pos += plen; + left -= plen; + } + + return 0; +} diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c new file mode 100644 index 000000000000..2c8c029ecf49 --- /dev/null +++ b/src/crypto/sha1-tlsprf.c @@ -0,0 +1,109 @@ +/* + * TLS PRF (SHA1 + MD5) + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "sha1.h" +#include "md5.h" +#include "crypto.h" + + +/** + * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) + * @secret: Key for PRF + * @secret_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @seed: Seed value to bind into the key + * @seed_len: Length of the seed + * @out: Buffer for the generated pseudo-random key + * @outlen: Number of bytes of key to generate + * Returns: 0 on success, -1 on failure. + * + * This function is used to derive new, cryptographically separate keys from a + * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. + */ +int tls_prf(const u8 *secret, size_t secret_len, const char *label, + const u8 *seed, size_t seed_len, u8 *out, size_t outlen) +{ + size_t L_S1, L_S2, i; + const u8 *S1, *S2; + u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; + u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; + int MD5_pos, SHA1_pos; + const u8 *MD5_addr[3]; + size_t MD5_len[3]; + const unsigned char *SHA1_addr[3]; + size_t SHA1_len[3]; + + if (secret_len & 1) + return -1; + + MD5_addr[0] = A_MD5; + MD5_len[0] = MD5_MAC_LEN; + MD5_addr[1] = (unsigned char *) label; + MD5_len[1] = os_strlen(label); + MD5_addr[2] = seed; + MD5_len[2] = seed_len; + + SHA1_addr[0] = A_SHA1; + SHA1_len[0] = SHA1_MAC_LEN; + SHA1_addr[1] = (unsigned char *) label; + SHA1_len[1] = os_strlen(label); + SHA1_addr[2] = seed; + SHA1_len[2] = seed_len; + + /* RFC 2246, Chapter 5 + * A(0) = seed, A(i) = HMAC(secret, A(i-1)) + * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. + * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) + */ + + L_S1 = L_S2 = (secret_len + 1) / 2; + S1 = secret; + S2 = secret + L_S1; + if (secret_len & 1) { + /* The last byte of S1 will be shared with S2 */ + S2--; + } + + hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], + A_MD5); + hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); + + MD5_pos = MD5_MAC_LEN; + SHA1_pos = SHA1_MAC_LEN; + for (i = 0; i < outlen; i++) { + if (MD5_pos == MD5_MAC_LEN) { + hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr, + MD5_len, P_MD5); + MD5_pos = 0; + hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN, + A_MD5); + } + if (SHA1_pos == SHA1_MAC_LEN) { + hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, + P_SHA1); + SHA1_pos = 0; + hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); + } + + out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; + + MD5_pos++; + SHA1_pos++; + } + + return 0; +} diff --git a/src/crypto/sha1-tprf.c b/src/crypto/sha1-tprf.c new file mode 100644 index 000000000000..4a80e96f0193 --- /dev/null +++ b/src/crypto/sha1-tprf.c @@ -0,0 +1,76 @@ +/* + * SHA1 T-PRF for EAP-FAST + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 "sha1.h" +#include "crypto.h" + +/** + * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) + * @key: Key for PRF + * @key_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @seed: Seed value to bind into the key + * @seed_len: Length of the seed + * @buf: Buffer for the generated pseudo-random key + * @buf_len: Number of bytes of key to generate + * Returns: 0 on success, -1 of failure + * + * This function is used to derive new, cryptographically separate keys from a + * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5. + */ +int sha1_t_prf(const u8 *key, size_t key_len, const char *label, + const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len) +{ + unsigned char counter = 0; + size_t pos, plen; + u8 hash[SHA1_MAC_LEN]; + size_t label_len = os_strlen(label); + u8 output_len[2]; + const unsigned char *addr[5]; + size_t len[5]; + + addr[0] = hash; + len[0] = 0; + addr[1] = (unsigned char *) label; + len[1] = label_len + 1; + addr[2] = seed; + len[2] = seed_len; + addr[3] = output_len; + len[3] = 2; + addr[4] = &counter; + len[4] = 1; + + output_len[0] = (buf_len >> 8) & 0xff; + output_len[1] = buf_len & 0xff; + pos = 0; + while (pos < buf_len) { + counter++; + plen = buf_len - pos; + if (hmac_sha1_vector(key, key_len, 5, addr, len, hash)) + return -1; + if (plen >= SHA1_MAC_LEN) { + os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); + pos += SHA1_MAC_LEN; + } else { + os_memcpy(&buf[pos], hash, plen); + break; + } + len[0] = SHA1_MAC_LEN; + } + + return 0; +} diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c index 141e4f4ee60a..fe00bdbc5869 100644 --- a/src/crypto/sha1.c +++ b/src/crypto/sha1.c @@ -16,7 +16,6 @@ #include "common.h" #include "sha1.h" -#include "md5.h" #include "crypto.h" @@ -28,9 +27,10 @@ * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (20 bytes) + * Returns: 0 on success, -1 on failure */ -void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac) +int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[20]; @@ -42,12 +42,13 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ - return; + return -1; } /* if key is longer than 64 bytes reset it to key = SHA1(key) */ if (key_len > 64) { - sha1_vector(1, &key, &key_len, tk); + if (sha1_vector(1, &key, &key_len, tk)) + return -1; key = tk; key_len = 20; } @@ -75,7 +76,8 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } - sha1_vector(1 + num_elem, _addr, _len, mac); + if (sha1_vector(1 + num_elem, _addr, _len, mac)) + return -1; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); @@ -88,7 +90,7 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, _len[0] = 64; _addr[1] = mac; _len[1] = SHA1_MAC_LEN; - sha1_vector(2, _addr, _len, mac); + return sha1_vector(2, _addr, _len, mac); } @@ -99,11 +101,12 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) + * Returns: 0 on success, -1 of failure */ -void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, +int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { - hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); + return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); } @@ -116,12 +119,13 @@ void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate + * Returns: 0 on success, -1 of failure * * This function is used to derive new, cryptographically separate keys from a * given key (e.g., PMK in IEEE 802.11i). */ -void sha1_prf(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +int sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u8 counter = 0; size_t pos, plen; @@ -141,593 +145,19 @@ void sha1_prf(const u8 *key, size_t key_len, const char *label, while (pos < buf_len) { plen = buf_len - pos; if (plen >= SHA1_MAC_LEN) { - hmac_sha1_vector(key, key_len, 3, addr, len, - &buf[pos]); + if (hmac_sha1_vector(key, key_len, 3, addr, len, + &buf[pos])) + return -1; pos += SHA1_MAC_LEN; } else { - hmac_sha1_vector(key, key_len, 3, addr, len, - hash); + if (hmac_sha1_vector(key, key_len, 3, addr, len, + hash)) + return -1; os_memcpy(&buf[pos], hash, plen); break; } counter++; } -} - - -#ifndef CONFIG_NO_T_PRF -/** - * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) - * @key: Key for PRF - * @key_len: Length of the key in bytes - * @label: A unique label for each purpose of the PRF - * @seed: Seed value to bind into the key - * @seed_len: Length of the seed - * @buf: Buffer for the generated pseudo-random key - * @buf_len: Number of bytes of key to generate - * - * This function is used to derive new, cryptographically separate keys from a - * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5. - */ -void sha1_t_prf(const u8 *key, size_t key_len, const char *label, - const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len) -{ - unsigned char counter = 0; - size_t pos, plen; - u8 hash[SHA1_MAC_LEN]; - size_t label_len = os_strlen(label); - u8 output_len[2]; - const unsigned char *addr[5]; - size_t len[5]; - - addr[0] = hash; - len[0] = 0; - addr[1] = (unsigned char *) label; - len[1] = label_len + 1; - addr[2] = seed; - len[2] = seed_len; - addr[3] = output_len; - len[3] = 2; - addr[4] = &counter; - len[4] = 1; - - output_len[0] = (buf_len >> 8) & 0xff; - output_len[1] = buf_len & 0xff; - pos = 0; - while (pos < buf_len) { - counter++; - plen = buf_len - pos; - hmac_sha1_vector(key, key_len, 5, addr, len, hash); - if (plen >= SHA1_MAC_LEN) { - os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); - pos += SHA1_MAC_LEN; - } else { - os_memcpy(&buf[pos], hash, plen); - break; - } - len[0] = SHA1_MAC_LEN; - } -} -#endif /* CONFIG_NO_T_PRF */ - - -#ifndef CONFIG_NO_TLS_PRF -/** - * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) - * @secret: Key for PRF - * @secret_len: Length of the key in bytes - * @label: A unique label for each purpose of the PRF - * @seed: Seed value to bind into the key - * @seed_len: Length of the seed - * @out: Buffer for the generated pseudo-random key - * @outlen: Number of bytes of key to generate - * Returns: 0 on success, -1 on failure. - * - * This function is used to derive new, cryptographically separate keys from a - * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. - */ -int tls_prf(const u8 *secret, size_t secret_len, const char *label, - const u8 *seed, size_t seed_len, u8 *out, size_t outlen) -{ - size_t L_S1, L_S2, i; - const u8 *S1, *S2; - u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; - u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; - int MD5_pos, SHA1_pos; - const u8 *MD5_addr[3]; - size_t MD5_len[3]; - const unsigned char *SHA1_addr[3]; - size_t SHA1_len[3]; - - if (secret_len & 1) - return -1; - - MD5_addr[0] = A_MD5; - MD5_len[0] = MD5_MAC_LEN; - MD5_addr[1] = (unsigned char *) label; - MD5_len[1] = os_strlen(label); - MD5_addr[2] = seed; - MD5_len[2] = seed_len; - - SHA1_addr[0] = A_SHA1; - SHA1_len[0] = SHA1_MAC_LEN; - SHA1_addr[1] = (unsigned char *) label; - SHA1_len[1] = os_strlen(label); - SHA1_addr[2] = seed; - SHA1_len[2] = seed_len; - - /* RFC 2246, Chapter 5 - * A(0) = seed, A(i) = HMAC(secret, A(i-1)) - * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. - * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) - */ - - L_S1 = L_S2 = (secret_len + 1) / 2; - S1 = secret; - S2 = secret + L_S1; - if (secret_len & 1) { - /* The last byte of S1 will be shared with S2 */ - S2--; - } - - hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5); - hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); - - MD5_pos = MD5_MAC_LEN; - SHA1_pos = SHA1_MAC_LEN; - for (i = 0; i < outlen; i++) { - if (MD5_pos == MD5_MAC_LEN) { - hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5); - MD5_pos = 0; - hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5); - } - if (SHA1_pos == SHA1_MAC_LEN) { - hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, - P_SHA1); - SHA1_pos = 0; - hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); - } - - out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; - - MD5_pos++; - SHA1_pos++; - } return 0; } -#endif /* CONFIG_NO_TLS_PRF */ - - -#ifndef CONFIG_NO_PBKDF2 - -static void pbkdf2_sha1_f(const char *passphrase, const char *ssid, - size_t ssid_len, int iterations, unsigned int count, - u8 *digest) -{ - unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; - int i, j; - unsigned char count_buf[4]; - const u8 *addr[2]; - size_t len[2]; - size_t passphrase_len = os_strlen(passphrase); - - addr[0] = (u8 *) ssid; - len[0] = ssid_len; - addr[1] = count_buf; - len[1] = 4; - - /* F(P, S, c, i) = U1 xor U2 xor ... Uc - * U1 = PRF(P, S || i) - * U2 = PRF(P, U1) - * Uc = PRF(P, Uc-1) - */ - - count_buf[0] = (count >> 24) & 0xff; - count_buf[1] = (count >> 16) & 0xff; - count_buf[2] = (count >> 8) & 0xff; - count_buf[3] = count & 0xff; - hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp); - os_memcpy(digest, tmp, SHA1_MAC_LEN); - - for (i = 1; i < iterations; i++) { - hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN, - tmp2); - os_memcpy(tmp, tmp2, SHA1_MAC_LEN); - for (j = 0; j < SHA1_MAC_LEN; j++) - digest[j] ^= tmp2[j]; - } -} - - -/** - * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i - * @passphrase: ASCII passphrase - * @ssid: SSID - * @ssid_len: SSID length in bytes - * @iterations: Number of iterations to run - * @buf: Buffer for the generated key - * @buflen: Length of the buffer in bytes - * - * This function is used to derive PSK for WPA-PSK. For this protocol, - * iterations is set to 4096 and buflen to 32. This function is described in - * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. - */ -void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen) -{ - unsigned int count = 0; - unsigned char *pos = buf; - size_t left = buflen, plen; - unsigned char digest[SHA1_MAC_LEN]; - - while (left > 0) { - count++; - pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, - digest); - plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; - os_memcpy(pos, digest, plen); - pos += plen; - left -= plen; - } -} - -#endif /* CONFIG_NO_PBKDF2 */ - - -#ifdef INTERNAL_SHA1 - -struct SHA1Context { - u32 state[5]; - u32 count[2]; - unsigned char buffer[64]; -}; - -typedef struct SHA1Context SHA1_CTX; - -#ifndef CONFIG_CRYPTO_INTERNAL -static void SHA1Init(struct SHA1Context *context); -static void SHA1Update(struct SHA1Context *context, const void *data, u32 len); -static void SHA1Final(unsigned char digest[20], struct SHA1Context *context); -#endif /* CONFIG_CRYPTO_INTERNAL */ -static void SHA1Transform(u32 state[5], const unsigned char buffer[64]); - - -/** - * sha1_vector - SHA-1 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - */ -void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - SHA1_CTX ctx; - size_t i; - - SHA1Init(&ctx); - for (i = 0; i < num_elem; i++) - SHA1Update(&ctx, addr[i], len[i]); - SHA1Final(mac, &ctx); -} - - -#ifndef CONFIG_NO_FIPS186_2_PRF -int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -{ - u8 xkey[64]; - u32 t[5], _t[5]; - int i, j, m, k; - u8 *xpos = x; - u32 carry; - - if (seed_len > sizeof(xkey)) - seed_len = sizeof(xkey); - - /* FIPS 186-2 + change notice 1 */ - - os_memcpy(xkey, seed, seed_len); - os_memset(xkey + seed_len, 0, 64 - seed_len); - t[0] = 0x67452301; - t[1] = 0xEFCDAB89; - t[2] = 0x98BADCFE; - t[3] = 0x10325476; - t[4] = 0xC3D2E1F0; - - m = xlen / 40; - for (j = 0; j < m; j++) { - /* XSEED_j = 0 */ - for (i = 0; i < 2; i++) { - /* XVAL = (XKEY + XSEED_j) mod 2^b */ - - /* w_i = G(t, XVAL) */ - os_memcpy(_t, t, 20); - SHA1Transform(_t, xkey); - _t[0] = host_to_be32(_t[0]); - _t[1] = host_to_be32(_t[1]); - _t[2] = host_to_be32(_t[2]); - _t[3] = host_to_be32(_t[3]); - _t[4] = host_to_be32(_t[4]); - os_memcpy(xpos, _t, 20); - - /* XKEY = (1 + XKEY + w_i) mod 2^b */ - carry = 1; - for (k = 19; k >= 0; k--) { - carry += xkey[k] + xpos[k]; - xkey[k] = carry & 0xff; - carry >>= 8; - } - - xpos += SHA1_MAC_LEN; - } - /* x_j = w_0|w_1 */ - } - - return 0; -} -#endif /* CONFIG_NO_FIPS186_2_PRF */ - - -/* ===== start - public domain SHA1 implementation ===== */ - -/* -SHA-1 in C -By Steve Reid -100% Public Domain - ------------------ -Modified 7/98 -By James H. Brown -Still 100% Public Domain - -Corrected a problem which generated improper hash values on 16 bit machines -Routine SHA1Update changed from - void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int -len) -to - void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned -long len) - -The 'len' parameter was declared an int which works fine on 32 bit machines. -However, on 16 bit machines an int is too small for the shifts being done -against -it. This caused the hash function to generate incorrect values if len was -greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). - -Since the file IO in main() reads 16K at a time, any file 8K or larger would -be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million -"a"s). - -I also changed the declaration of variables i & j in SHA1Update to -unsigned long from unsigned int for the same reason. - -These changes should make no difference to any 32 bit implementations since -an -int and a long are the same size in those environments. - --- -I also corrected a few compiler warnings generated by Borland C. -1. Added #include for exit() prototype -2. Removed unused variable 'j' in SHA1Final -3. Changed exit(0) to return(0) at end of main. - -ALL changes I made can be located by searching for comments containing 'JHB' ------------------ -Modified 8/98 -By Steve Reid -Still 100% public domain - -1- Removed #include and used return() instead of exit() -2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) -3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net - ------------------ -Modified 4/01 -By Saul Kravitz -Still 100% PD -Modified to run on Compaq Alpha hardware. - ------------------ -Modified 4/01 -By Jouni Malinen -Minor changes to match the coding style used in Dynamics. - -Modified September 24, 2004 -By Jouni Malinen -Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. - -*/ - -/* -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -#define SHA1HANDSOFF - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifndef WORDS_BIGENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ - (rol(block->l[i], 8) & 0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ - block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) \ - z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ - w = rol(w, 30); -#define R1(v,w,x,y,z,i) \ - z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ - w = rol(w, 30); -#define R2(v,w,x,y,z,i) \ - z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); -#define R3(v,w,x,y,z,i) \ - z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ - w = rol(w, 30); -#define R4(v,w,x,y,z,i) \ - z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ - w=rol(w, 30); - - -#ifdef VERBOSE /* SAK */ -void SHAPrintContext(SHA1_CTX *context, char *msg) -{ - printf("%s (%d,%d) %x %x %x %x %x\n", - msg, - context->count[0], context->count[1], - context->state[0], - context->state[1], - context->state[2], - context->state[3], - context->state[4]); -} -#endif - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -static void SHA1Transform(u32 state[5], const unsigned char buffer[64]) -{ - u32 a, b, c, d, e; - typedef union { - unsigned char c[64]; - u32 l[16]; - } CHAR64LONG16; - CHAR64LONG16* block; -#ifdef SHA1HANDSOFF - CHAR64LONG16 workspace; - block = &workspace; - os_memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16 *) buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - os_memset(block, 0, 64); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) -{ - u32 i, j; - const unsigned char *data = _data; - -#ifdef VERBOSE - SHAPrintContext(context, "before"); -#endif - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) - context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - os_memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - os_memcpy(&context->buffer[j], &data[i], len - i); -#ifdef VERBOSE - SHAPrintContext(context, "after "); -#endif -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ - u32 i; - unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char) - ((context->count[(i >= 4 ? 0 : 1)] >> - ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (unsigned char *) "\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1Update(context, (unsigned char *) "\0", 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() - */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & - 255); - } - /* Wipe variables */ - i = 0; - os_memset(context->buffer, 0, 64); - os_memset(context->state, 0, 20); - os_memset(context->count, 0, 8); - os_memset(finalcount, 0, 8); -} - -/* ===== end - public domain SHA1 implementation ===== */ - -#endif /* INTERNAL_SHA1 */ diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h index 9c365e2677bb..c1a6233bb0fb 100644 --- a/src/crypto/sha1.h +++ b/src/crypto/sha1.h @@ -1,6 +1,6 @@ /* * SHA1 hash implementation and interface functions - * Copyright (c) 2003-2005, Jouni Malinen + * Copyright (c) 2003-2009, Jouni Malinen * * 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 @@ -17,26 +17,17 @@ #define SHA1_MAC_LEN 20 -void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, - const u8 *addr[], const size_t *len, u8 *mac); -void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, +int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac); +int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); -void sha1_prf(const u8 *key, size_t key_len, const char *label, - const u8 *data, size_t data_len, u8 *buf, size_t buf_len); -void sha1_t_prf(const u8 *key, size_t key_len, const char *label, - const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len); +int sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len); +int sha1_t_prf(const u8 *key, size_t key_len, const char *label, + const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len); int __must_check tls_prf(const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen); -void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen); - -#ifdef CONFIG_CRYPTO_INTERNAL -struct SHA1Context; - -void SHA1Init(struct SHA1Context *context); -void SHA1Update(struct SHA1Context *context, const void *data, u32 len); -void SHA1Final(unsigned char digest[20], struct SHA1Context *context); -#endif /* CONFIG_CRYPTO_INTERNAL */ - +int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen); #endif /* SHA1_H */ diff --git a/src/crypto/sha1_i.h b/src/crypto/sha1_i.h new file mode 100644 index 000000000000..ec2f82f75b96 --- /dev/null +++ b/src/crypto/sha1_i.h @@ -0,0 +1,29 @@ +/* + * SHA1 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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 SHA1_I_H +#define SHA1_I_H + +struct SHA1Context { + u32 state[5]; + u32 count[2]; + unsigned char buffer[64]; +}; + +void SHA1Init(struct SHA1Context *context); +void SHA1Update(struct SHA1Context *context, const void *data, u32 len); +void SHA1Final(unsigned char digest[20], struct SHA1Context *context); +void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + +#endif /* SHA1_I_H */ diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c new file mode 100644 index 000000000000..b0613739fbc6 --- /dev/null +++ b/src/crypto/sha256-internal.c @@ -0,0 +1,243 @@ +/* + * SHA-256 hash implementation and interface functions + * Copyright (c) 2003-2007, Jouni Malinen + * + * 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 "sha256.h" +#include "crypto.h" + +struct sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +}; + +static void sha256_init(struct sha256_state *md); +static int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen); +static int sha256_done(struct sha256_state *md, unsigned char *out); + + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + struct sha256_state ctx; + size_t i; + + sha256_init(&ctx); + for (i = 0; i < num_elem; i++) + if (sha256_process(&ctx, addr[i], len[i])) + return -1; + if (sha256_done(&ctx, mac)) + return -1; + return 0; +} + + +/* ===== start - public domain SHA256 implementation ===== */ + +/* This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. */ + +/* the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + + +/* Various logical functions */ +#define RORc(x, y) \ +( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ + ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/* compress 512-bits */ +static int sha256_compress(struct sha256_state *md, unsigned char *buf) +{ + u32 S[8], W[64], t0, t1; + u32 t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = WPA_GET_BE32(buf + (4 * i)); + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; ++i) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + return 0; +} + + +/* Initialize the hash state */ +static void sha256_init(struct sha256_state *md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +static int sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; +#define block_size 64 + + if (md->curlen > sizeof(md->buf)) + return -1; + + while (inlen > 0) { + if (md->curlen == 0 && inlen >= block_size) { + if (sha256_compress(md, (unsigned char *) in) < 0) + return -1; + md->length += block_size * 8; + in += block_size; + inlen -= block_size; + } else { + n = MIN(inlen, (block_size - md->curlen)); + os_memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == block_size) { + if (sha256_compress(md, md->buf) < 0) + return -1; + md->length += 8 * block_size; + md->curlen = 0; + } + } + } + + return 0; +} + + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +static int sha256_done(struct sha256_state *md, unsigned char *out) +{ + int i; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char) 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < 64) { + md->buf[md->curlen++] = (unsigned char) 0; + } + sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char) 0; + } + + /* store length */ + WPA_PUT_BE64(md->buf + 56, md->length); + sha256_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) + WPA_PUT_BE32(out + (4 * i), md->state[i]); + + return 0; +} + +/* ===== end - public domain SHA256 implementation ===== */ diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index 96dac0ea7159..7f320f9bfea5 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -155,228 +155,3 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label, counter++; } } - - -#ifdef INTERNAL_SHA256 - -struct sha256_state { - u64 length; - u32 state[8], curlen; - u8 buf[64]; -}; - -static void sha256_init(struct sha256_state *md); -static int sha256_process(struct sha256_state *md, const unsigned char *in, - unsigned long inlen); -static int sha256_done(struct sha256_state *md, unsigned char *out); - - -/** - * sha256_vector - SHA256 hash for data vector - * @num_elem: Number of elements in the data vector - * @addr: Pointers to the data areas - * @len: Lengths of the data blocks - * @mac: Buffer for the hash - */ -void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - struct sha256_state ctx; - size_t i; - - sha256_init(&ctx); - for (i = 0; i < num_elem; i++) - sha256_process(&ctx, addr[i], len[i]); - sha256_done(&ctx, mac); -} - - -/* ===== start - public domain SHA256 implementation ===== */ - -/* This is based on SHA256 implementation in LibTomCrypt that was released into - * public domain by Tom St Denis. */ - -/* the K array */ -static const unsigned long K[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, - 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, - 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, - 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, - 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, - 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, - 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, - 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, - 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, - 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - - -/* Various logical functions */ -#define RORc(x, y) \ -( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ - ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) RORc((x), (n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif - -/* compress 512-bits */ -static int sha256_compress(struct sha256_state *md, unsigned char *buf) -{ - u32 S[8], W[64], t0, t1; - u32 t; - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) { - S[i] = md->state[i]; - } - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) - W[i] = WPA_GET_BE32(buf + (4 * i)); - - /* fill W[16..63] */ - for (i = 16; i < 64; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + - W[i - 16]; - } - - /* Compress */ -#define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - for (i = 0; i < 64; ++i) { - RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); - t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; - S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; - } - - /* feedback */ - for (i = 0; i < 8; i++) { - md->state[i] = md->state[i] + S[i]; - } - return 0; -} - - -/* Initialize the hash state */ -static void sha256_init(struct sha256_state *md) -{ - md->curlen = 0; - md->length = 0; - md->state[0] = 0x6A09E667UL; - md->state[1] = 0xBB67AE85UL; - md->state[2] = 0x3C6EF372UL; - md->state[3] = 0xA54FF53AUL; - md->state[4] = 0x510E527FUL; - md->state[5] = 0x9B05688CUL; - md->state[6] = 0x1F83D9ABUL; - md->state[7] = 0x5BE0CD19UL; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -static int sha256_process(struct sha256_state *md, const unsigned char *in, - unsigned long inlen) -{ - unsigned long n; -#define block_size 64 - - if (md->curlen > sizeof(md->buf)) - return -1; - - while (inlen > 0) { - if (md->curlen == 0 && inlen >= block_size) { - if (sha256_compress(md, (unsigned char *) in) < 0) - return -1; - md->length += block_size * 8; - in += block_size; - inlen -= block_size; - } else { - n = MIN(inlen, (block_size - md->curlen)); - os_memcpy(md->buf + md->curlen, in, n); - md->curlen += n; - in += n; - inlen -= n; - if (md->curlen == block_size) { - if (sha256_compress(md, md->buf) < 0) - return -1; - md->length += 8 * block_size; - md->curlen = 0; - } - } - } - - return 0; -} - - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (32 bytes) - @return CRYPT_OK if successful -*/ -static int sha256_done(struct sha256_state *md, unsigned char *out) -{ - int i; - - if (md->curlen >= sizeof(md->buf)) - return -1; - - /* increase the length of the message */ - md->length += md->curlen * 8; - - /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char) 0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->curlen > 56) { - while (md->curlen < 64) { - md->buf[md->curlen++] = (unsigned char) 0; - } - sha256_compress(md, md->buf); - md->curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (md->curlen < 56) { - md->buf[md->curlen++] = (unsigned char) 0; - } - - /* store length */ - WPA_PUT_BE64(md->buf + 56, md->length); - sha256_compress(md, md->buf); - - /* copy output */ - for (i = 0; i < 8; i++) - WPA_PUT_BE32(out + (4 * i), md->state[i]); - - return 0; -} - -/* ===== end - public domain SHA256 implementation ===== */ - -#endif /* INTERNAL_SHA256 */ diff --git a/src/crypto/tls.h b/src/crypto/tls.h index aafb79999320..0928b5ba43b7 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface definition - * Copyright (c) 2004-2007, Jouni Malinen + * SSL/TLS interface definition + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -28,10 +28,54 @@ struct tls_keys { size_t inner_secret_len; }; +enum tls_event { + TLS_CERT_CHAIN_FAILURE, + TLS_PEER_CERTIFICATE +}; + +/* + * Note: These are used as identifier with external programs and as such, the + * values must not be changed. + */ +enum tls_fail_reason { + TLS_FAIL_UNSPECIFIED = 0, + TLS_FAIL_UNTRUSTED = 1, + TLS_FAIL_REVOKED = 2, + TLS_FAIL_NOT_YET_VALID = 3, + TLS_FAIL_EXPIRED = 4, + TLS_FAIL_SUBJECT_MISMATCH = 5, + TLS_FAIL_ALTSUBJECT_MISMATCH = 6, + TLS_FAIL_BAD_CERTIFICATE = 7, + TLS_FAIL_SERVER_CHAIN_PROBE = 8 +}; + +union tls_event_data { + struct { + int depth; + const char *subject; + enum tls_fail_reason reason; + const char *reason_txt; + const struct wpabuf *cert; + } cert_fail; + + struct { + int depth; + const char *subject; + const struct wpabuf *cert; + const u8 *hash; + size_t hash_len; + } peer_cert; +}; + struct tls_config { const char *opensc_engine_path; const char *pkcs11_engine_path; const char *pkcs11_module_path; + int fips_mode; + + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; }; #define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0) @@ -292,17 +336,14 @@ int __must_check tls_connection_prf(void *tls_ctx, * tls_connection_handshake - Process TLS handshake (client side) * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @in_data: Input data from TLS peer - * @in_len: Input data length - * @out_len: Length of the output buffer. + * @in_data: Input data from TLS server * @appl_data: Pointer to application data pointer, or %NULL if dropped - * @appl_data_len: Pointer to variable that is set to appl_data length - * Returns: Pointer to output data, %NULL on failure + * Returns: Output data, %NULL on failure * - * Caller is responsible for freeing returned output data. If the final + * The caller is responsible for freeing the returned output data. If the final * handshake message includes application data, this is decrypted and - * appl_data (if not %NULL) is set to point this data. Caller is responsible - * for freeing appl_data. + * appl_data (if not %NULL) is set to point this data. The caller is + * responsible for freeing appl_data. * * This function is used during TLS handshake. The first call is done with * in_data == %NULL and the library is expected to return ClientHello packet. @@ -318,62 +359,55 @@ int __must_check tls_connection_prf(void *tls_ctx, * tls_connection_established() should return 1 once the TLS handshake has been * completed successfully. */ -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len); +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data); /** * tls_connection_server_handshake - Process TLS handshake (server side) * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @in_data: Input data from TLS peer - * @in_len: Input data length - * @out_len: Length of the output buffer. - * Returns: pointer to output data, %NULL on failure + * @appl_data: Pointer to application data pointer, or %NULL if dropped + * Returns: Output data, %NULL on failure * - * Caller is responsible for freeing returned output data. + * The caller is responsible for freeing the returned output data. */ -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len); +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data); /** * tls_connection_encrypt - Encrypt data into TLS tunnel * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @in_data: Pointer to plaintext data to be encrypted - * @in_len: Input buffer length - * @out_data: Pointer to output buffer (encrypted TLS data) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure + * @in_data: Plaintext data to be encrypted + * Returns: Encrypted TLS data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to - * send data in the encrypted tunnel. + * send data in the encrypted tunnel. The caller is responsible for freeing the + * returned output data. */ -int __must_check tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data); /** * tls_connection_decrypt - Decrypt data from TLS tunnel * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @in_data: Pointer to input buffer (encrypted TLS data) - * @in_len: Input buffer length - * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure + * @in_data: Encrypted TLS data + * Returns: Decrypted TLS data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to - * receive data from the encrypted tunnel. + * receive data from the encrypted tunnel. The caller is responsible for + * freeing the returned output data. */ -int __must_check tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data); /** * tls_connection_resumed - Was session resumption used @@ -493,16 +527,13 @@ unsigned int tls_capabilities(void *tls_ctx); * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished - * @out_data: Pointer to output buffer (encrypted TLS/IA data) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data on success, -1 on failure + * Returns: Encrypted TLS/IA data, %NULL on failure * * This function is used to send the TLS/IA end phase message, e.g., when the * EAP server completes EAP-TTLSv1. */ -int __must_check tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final, - u8 *out_data, size_t out_len); +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final); /** * tls_connection_ia_final_phase_finished - Has final phase been completed diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index 2c5c5a2b6406..c3a7358c0e77 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for openssl - * Copyright (c) 2004-2007, Jouni Malinen + * SSL/TLS interface functions for GnuTLS + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -112,8 +112,9 @@ struct tls_connection { int established; int verify_peer; - u8 *push_buf, *pull_buf, *pull_buf_offset; - size_t push_buf_len, pull_buf_len; + struct wpabuf *push_buf; + struct wpabuf *pull_buf; + const u8 *pull_buf_offset; int params_set; gnutls_certificate_credentials_t xcred; @@ -241,22 +242,22 @@ static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *) ptr; - u8 *end; + const u8 *end; if (conn->pull_buf == NULL) { errno = EWOULDBLOCK; return -1; } - end = conn->pull_buf + conn->pull_buf_len; + end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf); if ((size_t) (end - conn->pull_buf_offset) < len) len = end - conn->pull_buf_offset; os_memcpy(buf, conn->pull_buf_offset, len); conn->pull_buf_offset += len; if (conn->pull_buf_offset == end) { wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); - os_free(conn->pull_buf); - conn->pull_buf = conn->pull_buf_offset = NULL; - conn->pull_buf_len = 0; + wpabuf_free(conn->pull_buf); + conn->pull_buf = NULL; + conn->pull_buf_offset = NULL; } else { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", __func__, @@ -270,16 +271,12 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, size_t len) { struct tls_connection *conn = (struct tls_connection *) ptr; - u8 *nbuf; - nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len); - if (nbuf == NULL) { + if (wpabuf_resize(&conn->push_buf, len) < 0) { errno = ENOMEM; return -1; } - os_memcpy(nbuf + conn->push_buf_len, buf, len); - conn->push_buf = nbuf; - conn->push_buf_len += len; + wpabuf_put_data(conn->push_buf, buf, len); return len; } @@ -383,8 +380,8 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) os_free(conn->pre_shared_secret); os_free(conn->subject_match); os_free(conn->altsubject_match); - os_free(conn->push_buf); - os_free(conn->pull_buf); + wpabuf_free(conn->push_buf); + wpabuf_free(conn->pull_buf); os_free(conn); } @@ -407,9 +404,8 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) * because the connection was already terminated in practice * and "close notify" shutdown alert would confuse AS. */ gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); - os_free(conn->push_buf); + wpabuf_free(conn->push_buf); conn->push_buf = NULL; - conn->push_buf_len = 0; conn->established = 0; conn->final_phase_finished = 0; #ifdef GNUTLS_IA @@ -979,31 +975,56 @@ static int tls_connection_verify_peer(struct tls_connection *conn, } -u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) { - struct tls_global *global = ssl_ctx; - u8 *out_data; + int res; + struct wpabuf *ad; + wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); + ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); + if (ad == NULL) + return NULL; + + res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), + wpabuf_size(ad)); + wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); + if (res < 0) { + wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " + "(%s)", __func__, (int) res, + gnutls_strerror(res)); + wpabuf_free(ad); + return NULL; + } + + wpabuf_put(ad, res); + wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", + res); + return ad; +} + + +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + struct tls_global *global = tls_ctx; + struct wpabuf *out_data; int ret; if (appl_data) *appl_data = NULL; - if (in_data && in_len) { + if (in_data && wpabuf_len(in_data) > 0) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, - (unsigned long) conn->pull_buf_len); - os_free(conn->pull_buf); + (unsigned long) wpabuf_len(conn->pull_buf)); + wpabuf_free(conn->pull_buf); } - conn->pull_buf = os_malloc(in_len); + conn->pull_buf = wpabuf_dup(in_data); if (conn->pull_buf == NULL) return NULL; - os_memcpy(conn->pull_buf, in_data, in_len); - conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = in_len; + conn->pull_buf_offset = wpabuf_head(conn->pull_buf); } ret = gnutls_handshake(conn->session); @@ -1014,7 +1035,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, conn->push_buf == NULL) { /* Need to return something to trigger * completion of EAP-TLS. */ - conn->push_buf = os_malloc(1); + conn->push_buf = wpabuf_alloc(0); } break; case GNUTLS_E_FATAL_ALERT_RECEIVED: @@ -1058,7 +1079,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, conn->established = 1; if (conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ - conn->push_buf = os_malloc(1); + conn->push_buf = wpabuf_alloc(0); } gnutls_session_get_data(conn->session, NULL, &size); @@ -1073,90 +1094,88 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, global->session_data, &global->session_data_size); } + + if (conn->pull_buf && appl_data) + *appl_data = gnutls_get_appl_data(conn); } out: out_data = conn->push_buf; - *out_len = conn->push_buf_len; conn->push_buf = NULL; - conn->push_buf_len = 0; return out_data; } -u8 * tls_connection_server_handshake(void *ssl_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { - return tls_connection_handshake(ssl_ctx, conn, in_data, in_len, - out_len, NULL, NULL); + return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); } -int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { ssize_t res; + struct wpabuf *buf; #ifdef GNUTLS_IA if (conn->tls_ia) - res = gnutls_ia_send(conn->session, (char *) in_data, in_len); + res = gnutls_ia_send(conn->session, wpabuf_head(in_data), + wpabuf_len(in_data)); else #endif /* GNUTLS_IA */ - res = gnutls_record_send(conn->session, in_data, in_len); + res = gnutls_record_send(conn->session, wpabuf_head(in_data), + wpabuf_len(in_data)); if (res < 0) { wpa_printf(MSG_INFO, "%s: Encryption failed: %s", __func__, gnutls_strerror(res)); - return -1; + return NULL; } - if (conn->push_buf == NULL) - return -1; - if (conn->push_buf_len < out_len) - out_len = conn->push_buf_len; - else if (conn->push_buf_len > out_len) { - wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for " - "encrypted message (in_len=%lu push_buf_len=%lu " - "out_len=%lu", - (unsigned long) in_len, - (unsigned long) conn->push_buf_len, - (unsigned long) out_len); - } - os_memcpy(out_data, conn->push_buf, out_len); - os_free(conn->push_buf); + + buf = conn->push_buf; conn->push_buf = NULL; - conn->push_buf_len = 0; - return out_len; + return buf; } -int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { ssize_t res; + struct wpabuf *out; if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, - (unsigned long) conn->pull_buf_len); - os_free(conn->pull_buf); + (unsigned long) wpabuf_len(conn->pull_buf)); + wpabuf_free(conn->pull_buf); } - conn->pull_buf = os_malloc(in_len); + conn->pull_buf = wpabuf_dup(in_data); if (conn->pull_buf == NULL) - return -1; - os_memcpy(conn->pull_buf, in_data, in_len); - conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = in_len; + return NULL; + conn->pull_buf_offset = wpabuf_head(conn->pull_buf); + + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (out == NULL) + return NULL; #ifdef GNUTLS_IA if (conn->tls_ia) { - res = gnutls_ia_recv(conn->session, (char *) out_data, - out_len); - if (out_len >= 12 && - (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || - res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) { + res = gnutls_ia_recv(conn->session, wpabuf_mhead(out), + wpabuf_size(out)); + if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || + res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED; wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished", __func__, final ? "Final" : "Intermediate"); @@ -1175,11 +1194,12 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, wpa_printf(MSG_DEBUG, "%s: Failed to permute " "inner secret: %s", __func__, gnutls_strerror(res)); - return -1; + wpabuf_free(out); + return NULL; } res = gnutls_ia_verify_endphase(conn->session, - (char *) out_data); + wpabuf_head(out)); if (res == 0) { wpa_printf(MSG_DEBUG, "%s: Correct endphase " "checksum", __func__); @@ -1187,31 +1207,39 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, wpa_printf(MSG_INFO, "%s: Endphase " "verification failed: %s", __func__, gnutls_strerror(res)); - return -1; + wpabuf_free(out); + return NULL; } if (final) conn->final_phase_finished = 1; - return 0; + return out; } if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); + wpabuf_free(out); + return NULL; } - return res; + wpabuf_put(out, res); + return out; } #endif /* GNUTLS_IA */ - res = gnutls_record_recv(conn->session, out_data, out_len); + res = gnutls_record_recv(conn->session, wpabuf_mhead(out), + wpabuf_size(out)); if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); + wpabuf_free(out); + return NULL; } + wpabuf_put(out, res); - return res; + return out; } @@ -1243,7 +1271,7 @@ int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, int tls_connection_enable_workaround(void *ssl_ctx, struct tls_connection *conn) { - /* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */ + gnutls_record_disable_padding(conn->session); return 0; } @@ -1338,16 +1366,15 @@ int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, } -int tls_connection_ia_send_phase_finished(void *tls_ctx, - struct tls_connection *conn, - int final, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final) { #ifdef GNUTLS_IA int ret; + struct wpabuf *buf; if (conn == NULL || conn->session == NULL || !conn->tls_ia) - return -1; + return NULL; ret = gnutls_ia_permute_inner_secret(conn->session, conn->session_keys_len, @@ -1361,27 +1388,21 @@ int tls_connection_ia_send_phase_finished(void *tls_ctx, if (ret) { wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s", __func__, gnutls_strerror(ret)); - return -1; + return NULL; } ret = gnutls_ia_endphase_send(conn->session, final); if (ret) { wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s", __func__, gnutls_strerror(ret)); - return -1; + return NULL; } - if (conn->push_buf == NULL) - return -1; - if (conn->push_buf_len < out_len) - out_len = conn->push_buf_len; - os_memcpy(out_data, conn->push_buf, out_len); - os_free(conn->push_buf); + buf = conn->push_buf; conn->push_buf = NULL; - conn->push_buf_len = 0; - return out_len; + return buf; #else /* GNUTLS_IA */ - return -1; + return NULL; #endif /* GNUTLS_IA */ } @@ -1426,3 +1447,11 @@ int tls_connection_ia_permute_inner_secret(void *tls_ctx, return -1; #endif /* GNUTLS_IA */ } + + +int tls_connection_set_session_ticket_cb(void *tls_ctx, + struct tls_connection *conn, + tls_session_ticket_cb cb, void *ctx) +{ + return -1; +} diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 42120c8a882e..64124d8a8e3e 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / TLS interface functions and an internal TLS implementation - * Copyright (c) 2004-2007, Jouni Malinen + * TLS interface functions and an internal TLS implementation + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -331,45 +331,77 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT + u8 *res, *ad; + size_t res_len, ad_len; + struct wpabuf *out; + if (conn->client == NULL) return NULL; - if (appl_data) - *appl_data = NULL; + ad = NULL; + res = tlsv1_client_handshake(conn->client, + in_data ? wpabuf_head(in_data) : NULL, + in_data ? wpabuf_len(in_data) : 0, + &res_len, &ad, &ad_len); + if (res == NULL) + return NULL; + out = wpabuf_alloc_ext_data(res, res_len); + if (out == NULL) { + os_free(res); + os_free(ad); + return NULL; + } + if (appl_data) { + if (ad) { + *appl_data = wpabuf_alloc_ext_data(ad, ad_len); + if (*appl_data == NULL) + os_free(ad); + } else + *appl_data = NULL; + } else + os_free(ad); - wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)", - __func__, in_data, (unsigned long) in_len); - return tlsv1_client_handshake(conn->client, in_data, in_len, out_len, - appl_data, appl_data_len); + return out; #else /* CONFIG_TLS_INTERNAL_CLIENT */ return NULL; #endif /* CONFIG_TLS_INTERNAL_CLIENT */ } -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { #ifdef CONFIG_TLS_INTERNAL_SERVER - u8 *out; + u8 *res; + size_t res_len; + struct wpabuf *out; + if (conn->server == NULL) return NULL; - wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)", - __func__, in_data, (unsigned long) in_len); - out = tlsv1_server_handshake(conn->server, in_data, in_len, out_len); - if (out == NULL && tlsv1_server_established(conn->server)) { - out = os_malloc(1); - *out_len = 0; + if (appl_data) + *appl_data = NULL; + + res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data), + wpabuf_len(in_data), &res_len); + if (res == NULL && tlsv1_server_established(conn->server)) + return wpabuf_alloc(0); + if (res == NULL) + return NULL; + out = wpabuf_alloc_ext_data(res, res_len); + if (out == NULL) { + os_free(res); + return NULL; } + return out; #else /* CONFIG_TLS_INTERNAL_SERVER */ return NULL; @@ -377,43 +409,95 @@ u8 * tls_connection_server_handshake(void *tls_ctx, } -int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - return tlsv1_client_encrypt(conn->client, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { - return tlsv1_server_encrypt(conn->server, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; + return NULL; } -int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - return tlsv1_client_decrypt(conn->client, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { - return tlsv1_server_decrypt(conn->server, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; + return NULL; } @@ -524,12 +608,10 @@ unsigned int tls_capabilities(void *tls_ctx) } -int tls_connection_ia_send_phase_finished(void *tls_ctx, - struct tls_connection *conn, - int final, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final) { - return -1; + return NULL; } diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index f731628b0e38..0c836bb63187 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for no TLS case - * Copyright (c) 2004, Jouni Malinen + * SSL/TLS interface functions for no TLS case + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -22,13 +22,12 @@ void * tls_init(const struct tls_config *conf) return (void *) 1; } + void tls_deinit(void *ssl_ctx) { } -#ifdef EAP_TLS_NONE - int tls_get_errors(void *tls_ctx) { return 0; @@ -107,37 +106,37 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - return -1; + return NULL; } -int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - return -1; + return NULL; } @@ -208,12 +207,10 @@ unsigned int tls_capabilities(void *tls_ctx) } -int tls_connection_ia_send_phase_finished(void *tls_ctx, - struct tls_connection *conn, - int final, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final) { - return -1; + return NULL; } @@ -230,5 +227,3 @@ int tls_connection_ia_permute_inner_secret(void *tls_ctx, { return -1; } - -#endif /* EAP_TLS_NONE */ diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c new file mode 100644 index 000000000000..ad834b649337 --- /dev/null +++ b/src/crypto/tls_nss.c @@ -0,0 +1,680 @@ +/* + * SSL/TLS interface functions for NSS + * Copyright (c) 2009, Jouni Malinen + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "tls.h" + +static int tls_nss_ref_count = 0; + +static PRDescIdentity nss_layer_id; + + +struct tls_connection { + PRFileDesc *fd; + + int established; + int verify_peer; + u8 *push_buf, *pull_buf, *pull_buf_offset; + size_t push_buf_len, pull_buf_len; +}; + + +static PRStatus nss_io_close(PRFileDesc *fd) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O close"); + return PR_SUCCESS; +} + + +static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount); + return PR_FAILURE; +} + + +static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount); + return PR_FAILURE; +} + + +static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size); + return PR_FAILURE; +} + + +static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + struct tls_connection *conn = (struct tls_connection *) fd->secret; + u8 *end; + + wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount); + + if (conn->pull_buf == NULL) { + wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet"); + return PR_FAILURE; + } + + end = conn->pull_buf + conn->pull_buf_len; + if (end - conn->pull_buf_offset < amount) + amount = end - conn->pull_buf_offset; + os_memcpy(buf, conn->pull_buf_offset, amount); + conn->pull_buf_offset += amount; + if (conn->pull_buf_offset == end) { + wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); + os_free(conn->pull_buf); + conn->pull_buf = conn->pull_buf_offset = NULL; + conn->pull_buf_len = 0; + } else { + wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", + __func__, + (unsigned long) (end - conn->pull_buf_offset)); + } + return amount; +} + + +static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + struct tls_connection *conn = (struct tls_connection *) fd->secret; + u8 *nbuf; + + wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); + wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount); + + nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount); + if (nbuf == NULL) { + wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the " + "data to be sent"); + return PR_FAILURE; + } + os_memcpy(nbuf + conn->push_buf_len, buf, amount); + conn->push_buf = nbuf; + conn->push_buf_len += amount; + + return amount; +} + + +static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, + PRIntervalTime timeout) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); + return PR_FAILURE; +} + + +static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, + PRIntervalTime timeout) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); + return PR_FAILURE; +} + + +static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr) +{ + wpa_printf(MSG_DEBUG, "NSS: I/O getpeername"); + + /* + * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a + * fake IPv4 address to work around this even though we are not really + * using TCP. + */ + os_memset(addr, 0, sizeof(*addr)); + addr->inet.family = PR_AF_INET; + + return PR_SUCCESS; +} + + +static PRStatus nss_io_getsocketoption(PRFileDesc *fd, + PRSocketOptionData *data) +{ + switch (data->option) { + case PR_SockOpt_Nonblocking: + wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)"); + data->value.non_blocking = PR_TRUE; + return PR_SUCCESS; + default: + wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)", + data->option); + return PR_FAILURE; + } +} + + +static const PRIOMethods nss_io = { + PR_DESC_LAYERED, + nss_io_close, + nss_io_read, + nss_io_write, + NULL /* available */, + NULL /* available64 */, + NULL /* fsync */, + NULL /* fseek */, + NULL /* fseek64 */, + NULL /* fileinfo */, + NULL /* fileinfo64 */, + nss_io_writev, + NULL /* connect */, + NULL /* accept */, + NULL /* bind */, + NULL /* listen */, + NULL /* shutdown */, + nss_io_recv, + nss_io_send, + nss_io_recvfrom, + nss_io_sendto, + NULL /* poll */, + NULL /* acceptread */, + NULL /* transmitfile */, + NULL /* getsockname */, + nss_io_getpeername, + NULL /* reserved_fn_6 */, + NULL /* reserved_fn_5 */, + nss_io_getsocketoption, + NULL /* setsocketoption */, + NULL /* sendfile */, + NULL /* connectcontinue */, + NULL /* reserved_fn_3 */, + NULL /* reserved_fn_2 */, + NULL /* reserved_fn_1 */, + NULL /* reserved_fn_0 */ +}; + + +static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); + return NULL; +} + + +void * tls_init(const struct tls_config *conf) +{ + char *dir; + + tls_nss_ref_count++; + if (tls_nss_ref_count > 1) + return (void *) 1; + + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant"); + + PK11_SetPasswordFunc(nss_password_cb); + + dir = getenv("SSL_DIR"); + if (dir) { + if (NSS_Init(dir) != SECSuccess) { + wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) " + "failed", dir); + return NULL; + } + } else { + if (NSS_NoDB_Init(NULL) != SECSuccess) { + wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) " + "failed"); + return NULL; + } + } + + if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != + SECSuccess || + SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess || + SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess || + SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) { + wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed"); + return NULL; + } + + if (NSS_SetDomesticPolicy() != SECSuccess) { + wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed"); + return NULL; + } + + return (void *) 1; +} + +void tls_deinit(void *ssl_ctx) +{ + tls_nss_ref_count--; + if (tls_nss_ref_count == 0) { + if (NSS_Shutdown() != SECSuccess) + wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed"); + } +} + + +int tls_get_errors(void *tls_ctx) +{ + return 0; +} + + +static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd) +{ + struct tls_connection *conn = arg; + SECStatus res = SECSuccess; + PRErrorCode err; + CERTCertificate *cert; + char *subject, *issuer; + + err = PR_GetError(); + if (IS_SEC_ERROR(err)) + wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err " + "%d)", err - SEC_ERROR_BASE); + else + wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)", + err); + cert = SSL_PeerCertificate(fd); + subject = CERT_NameToAscii(&cert->subject); + issuer = CERT_NameToAscii(&cert->issuer); + wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'", + subject, issuer); + CERT_DestroyCertificate(cert); + PR_Free(subject); + PR_Free(issuer); + if (conn->verify_peer) + res = SECFailure; + + return res; +} + + +static void nss_handshake_cb(PRFileDesc *fd, void *client_data) +{ + struct tls_connection *conn = client_data; + wpa_printf(MSG_DEBUG, "NSS: Handshake completed"); + conn->established = 1; +} + + +struct tls_connection * tls_connection_init(void *tls_ctx) +{ + struct tls_connection *conn; + + conn = os_zalloc(sizeof(*conn)); + if (conn == NULL) + return NULL; + + conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io); + if (conn->fd == NULL) { + os_free(conn); + return NULL; + } + conn->fd->secret = (void *) conn; + + conn->fd = SSL_ImportFD(NULL, conn->fd); + if (conn->fd == NULL) { + os_free(conn); + return NULL; + } + + if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess || + SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != + SECSuccess || + SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != + SECSuccess || + SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess || + SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess || + SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) != + SECSuccess) { + wpa_printf(MSG_ERROR, "NSS: Failed to set options"); + PR_Close(conn->fd); + os_free(conn); + return NULL; + } + + SSL_ResetHandshake(conn->fd, PR_FALSE); + + return conn; +} + + +void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) +{ + PR_Close(conn->fd); + os_free(conn->push_buf); + os_free(conn->pull_buf); + os_free(conn); +} + + +int tls_connection_established(void *tls_ctx, struct tls_connection *conn) +{ + return conn->established; +} + + +int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) +{ + return -1; +} + + +int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, + const struct tls_connection_params *params) +{ + wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); + return 0; +} + + +int tls_global_set_params(void *tls_ctx, + const struct tls_connection_params *params) +{ + return -1; +} + + +int tls_global_set_verify(void *tls_ctx, int check_crl) +{ + return -1; +} + + +int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, + int verify_peer) +{ + conn->verify_peer = verify_peer; + return 0; +} + + +int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, + int tls_ia) +{ + return -1; +} + + +int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, + struct tls_keys *keys) +{ + /* NSS does not export master secret or client/server random. */ + return -1; +} + + +int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, + const char *label, int server_random_first, + u8 *out, size_t out_len) +{ + if (conn == NULL || server_random_first) { + wpa_printf(MSG_INFO, "NSS: Unsupported PRF request " + "(server_random_first=%d)", + server_random_first); + return -1; + } + + if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) != + SECSuccess) { + wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor " + "(label='%s' out_len=%d", label, (int) out_len); + return -1; + } + + return 0; +} + + +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + struct wpabuf *out_data; + + wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u", + in_data ? (unsigned int) wpabuf_len(in_data) : 0); + + if (appl_data) + *appl_data = NULL; + + if (in_data && wpabuf_len(in_data) > 0) { + if (conn->pull_buf) { + wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " + "pull_buf", __func__, + (unsigned long) conn->pull_buf_len); + os_free(conn->pull_buf); + } + conn->pull_buf = os_malloc(wpabuf_len(in_data)); + if (conn->pull_buf == NULL) + return NULL; + os_memcpy(conn->pull_buf, wpabuf_head(in_data), + wpabuf_len(in_data)); + conn->pull_buf_offset = conn->pull_buf; + conn->pull_buf_len = wpabuf_len(in_data); + } + + SSL_ForceHandshake(conn->fd); + + if (conn->established && conn->push_buf == NULL) { + /* Need to return something to get final TLS ACK. */ + conn->push_buf = os_malloc(1); + } + + if (conn->push_buf == NULL) + return NULL; + out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); + if (out_data == NULL) + os_free(conn->push_buf); + conn->push_buf = NULL; + conn->push_buf_len = 0; + return out_data; +} + + +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return NULL; +} + + +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + PRInt32 res; + struct wpabuf *buf; + + wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", + (int) wpabuf_len(in_data)); + res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0, + 0); + if (res < 0) { + wpa_printf(MSG_ERROR, "NSS: Encryption failed"); + return NULL; + } + if (conn->push_buf == NULL) + return NULL; + buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); + if (buf == NULL) + os_free(conn->push_buf); + conn->push_buf = NULL; + conn->push_buf_len = 0; + return buf; +} + + +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + PRInt32 res; + struct wpabuf *out; + + wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", + (int) wpabuf_len(in_data)); + if (conn->pull_buf) { + wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " + "pull_buf", __func__, + (unsigned long) conn->pull_buf_len); + os_free(conn->pull_buf); + } + conn->pull_buf = os_malloc(wpabuf_len(in_data)); + if (conn->pull_buf == NULL) + return NULL; + os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); + conn->pull_buf_offset = conn->pull_buf; + conn->pull_buf_len = wpabuf_len(in_data); + + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (out == NULL) + return NULL; + + res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); + wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); + if (res < 0) { + wpabuf_free(out); + return NULL; + } + wpabuf_put(out, res); + + return out; +} + + +int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) +{ + return 0; +} + + +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, + u8 *ciphers) +{ + return -1; +} + + +int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, + char *buf, size_t buflen) +{ + return -1; +} + + +int tls_connection_enable_workaround(void *tls_ctx, + struct tls_connection *conn) +{ + return -1; +} + + +int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, + int ext_type, const u8 *data, + size_t data_len) +{ + return -1; +} + + +int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) +{ + return 0; +} + + +int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) +{ + return 0; +} + + +int tls_connection_get_write_alerts(void *tls_ctx, + struct tls_connection *conn) +{ + return 0; +} + + +int tls_connection_get_keyblock_size(void *tls_ctx, + struct tls_connection *conn) +{ + return -1; +} + + +unsigned int tls_capabilities(void *tls_ctx) +{ + return 0; +} + + +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final) +{ + return NULL; +} + + +int tls_connection_ia_final_phase_finished(void *tls_ctx, + struct tls_connection *conn) +{ + return -1; +} + + +int tls_connection_ia_permute_inner_secret(void *tls_ctx, + struct tls_connection *conn, + const u8 *key, size_t key_len) +{ + return -1; +} + + +int tls_connection_set_session_ticket_cb(void *tls_ctx, + struct tls_connection *conn, + tls_session_ticket_cb cb, + void *ctx) +{ + return -1; +} diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index b5a1d64f53bd..c0a40f95617c 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for openssl - * Copyright (c) 2004-2008, Jouni Malinen + * SSL/TLS interface functions for OpenSSL + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -29,6 +29,7 @@ #endif /* OPENSSL_NO_ENGINE */ #include "common.h" +#include "crypto.h" #include "tls.h" #if OPENSSL_VERSION_NUMBER >= 0x0090800fL @@ -49,6 +50,15 @@ static int tls_openssl_ref_count = 0; +struct tls_global { + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; +}; + +static struct tls_global *tls_global = NULL; + + struct tls_connection { SSL *ssl; BIO *ssl_in, *ssl_out; @@ -65,6 +75,12 @@ struct tls_connection { /* SessionTicket received from OpenSSL hello_extension_cb (server) */ u8 *session_ticket; size_t session_ticket_len; + + unsigned int ca_cert_verify:1; + unsigned int cert_probe:1; + unsigned int server_cert_only:1; + + u8 srv_cert_hash[32]; }; @@ -665,6 +681,34 @@ void * tls_init(const struct tls_config *conf) SSL_CTX *ssl; if (tls_openssl_ref_count == 0) { + tls_global = os_zalloc(sizeof(*tls_global)); + if (tls_global == NULL) + return NULL; + if (conf) { + tls_global->event_cb = conf->event_cb; + tls_global->cb_ctx = conf->cb_ctx; + } + +#ifdef CONFIG_FIPS +#ifdef OPENSSL_FIPS + if (conf && conf->fips_mode) { + if (!FIPS_mode_set(1)) { + wpa_printf(MSG_ERROR, "Failed to enable FIPS " + "mode"); + ERR_load_crypto_strings(); + ERR_print_errors_fp(stderr); + return NULL; + } else + wpa_printf(MSG_INFO, "Running in FIPS mode"); + } +#else /* OPENSSL_FIPS */ + if (conf && conf->fips_mode) { + wpa_printf(MSG_ERROR, "FIPS mode requested, but not " + "supported"); + return NULL; + } +#endif /* OPENSSL_FIPS */ +#endif /* CONFIG_FIPS */ SSL_load_error_strings(); SSL_library_init(); #ifndef OPENSSL_NO_SHA256 @@ -730,6 +774,8 @@ void tls_deinit(void *ssl_ctx) ERR_remove_state(0); ERR_free_strings(); EVP_cleanup(); + os_free(tls_global); + tls_global = NULL; } } @@ -996,6 +1042,124 @@ static int tls_match_altsubject(X509 *cert, const char *match) } +static enum tls_fail_reason openssl_tls_fail_reason(int err) +{ + switch (err) { + case X509_V_ERR_CERT_REVOKED: + return TLS_FAIL_REVOKED; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + return TLS_FAIL_NOT_YET_VALID; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_HAS_EXPIRED: + return TLS_FAIL_EXPIRED; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_CA: + return TLS_FAIL_UNTRUSTED; + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case X509_V_ERR_CERT_UNTRUSTED: + case X509_V_ERR_CERT_REJECTED: + return TLS_FAIL_BAD_CERTIFICATE; + default: + return TLS_FAIL_UNSPECIFIED; + } +} + + +static struct wpabuf * get_x509_cert(X509 *cert) +{ + struct wpabuf *buf; + u8 *tmp; + + int cert_len = i2d_X509(cert, NULL); + if (cert_len <= 0) + return NULL; + + buf = wpabuf_alloc(cert_len); + if (buf == NULL) + return NULL; + + tmp = wpabuf_put(buf, cert_len); + i2d_X509(cert, &tmp); + return buf; +} + + +static void openssl_tls_fail_event(struct tls_connection *conn, + X509 *err_cert, int err, int depth, + const char *subject, const char *err_str, + enum tls_fail_reason reason) +{ + union tls_event_data ev; + struct wpabuf *cert = NULL; + + if (tls_global->event_cb == NULL) + return; + + cert = get_x509_cert(err_cert); + os_memset(&ev, 0, sizeof(ev)); + ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? + reason : openssl_tls_fail_reason(err); + ev.cert_fail.depth = depth; + ev.cert_fail.subject = subject; + ev.cert_fail.reason_txt = err_str; + ev.cert_fail.cert = cert; + tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); + wpabuf_free(cert); +} + + +static void openssl_tls_cert_event(struct tls_connection *conn, + X509 *err_cert, int depth, + const char *subject) +{ + struct wpabuf *cert = NULL; + union tls_event_data ev; +#ifdef CONFIG_SHA256 + u8 hash[32]; +#endif /* CONFIG_SHA256 */ + + if (tls_global->event_cb == NULL) + return; + + os_memset(&ev, 0, sizeof(ev)); + if (conn->cert_probe) { + cert = get_x509_cert(err_cert); + ev.peer_cert.cert = cert; + } +#ifdef CONFIG_SHA256 + if (cert) { + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) == 0) { + ev.peer_cert.hash = hash; + ev.peer_cert.hash_len = sizeof(hash); + } + } +#endif /* CONFIG_SHA256 */ + ev.peer_cert.depth = depth; + ev.peer_cert.subject = subject; + tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev); + wpabuf_free(cert); +} + + static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) { char buf[256]; @@ -1004,6 +1168,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) SSL *ssl; struct tls_connection *conn; char *match, *altmatch; + const char *err_str; err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); err = X509_STORE_CTX_get_error(x509_ctx); @@ -1016,25 +1181,76 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) match = conn ? conn->subject_match : NULL; altmatch = conn ? conn->altsubject_match : NULL; + if (!preverify_ok && !conn->ca_cert_verify) + preverify_ok = 1; + if (!preverify_ok && depth > 0 && conn->server_cert_only) + preverify_ok = 1; + + err_str = X509_verify_cert_error_string(err); + +#ifdef CONFIG_SHA256 + if (preverify_ok && depth == 0 && conn->server_cert_only) { + struct wpabuf *cert; + cert = get_x509_cert(err_cert); + if (!cert) { + wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " + "server certificate data"); + preverify_ok = 0; + } else { + u8 hash[32]; + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) < 0 || + os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { + err_str = "Server certificate mismatch"; + err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; + preverify_ok = 0; + } + wpabuf_free(cert); + } + } +#endif /* CONFIG_SHA256 */ + if (!preverify_ok) { wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," - " error %d (%s) depth %d for '%s'", err, - X509_verify_cert_error_string(err), depth, buf); - } else { - wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " - "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", - preverify_ok, err, - X509_verify_cert_error_string(err), depth, buf); - if (depth == 0 && match && os_strstr(buf, match) == NULL) { - wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " - "match with '%s'", buf, match); - preverify_ok = 0; - } else if (depth == 0 && altmatch && - !tls_match_altsubject(err_cert, altmatch)) { - wpa_printf(MSG_WARNING, "TLS: altSubjectName match " - "'%s' not found", altmatch); - preverify_ok = 0; - } + " error %d (%s) depth %d for '%s'", err, err_str, + depth, buf); + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + err_str, TLS_FAIL_UNSPECIFIED); + return preverify_ok; + } + + wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " + "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", + preverify_ok, err, err_str, + conn->ca_cert_verify, depth, buf); + if (depth == 0 && match && os_strstr(buf, match) == NULL) { + wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " + "match with '%s'", buf, match); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Subject mismatch", + TLS_FAIL_SUBJECT_MISMATCH); + } else if (depth == 0 && altmatch && + !tls_match_altsubject(err_cert, altmatch)) { + wpa_printf(MSG_WARNING, "TLS: altSubjectName match " + "'%s' not found", altmatch); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "AltSubject mismatch", + TLS_FAIL_ALTSUBJECT_MISMATCH); + } else + openssl_tls_cert_event(conn, err_cert, depth, buf); + + if (conn->cert_probe && preverify_ok && depth == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " + "on probe-only run"); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Server certificate chain probe", + TLS_FAIL_SERVER_CHAIN_PROBE); } return preverify_ok; @@ -1092,6 +1308,47 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, return -1; } + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); + conn->ca_cert_verify = 1; + + if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " + "chain"); + conn->cert_probe = 1; + conn->ca_cert_verify = 0; + return 0; + } + + if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { +#ifdef CONFIG_SHA256 + const char *pos = ca_cert + 7; + if (os_strncmp(pos, "server/sha256/", 14) != 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " + "hash value '%s'", ca_cert); + return -1; + } + pos += 14; + if (os_strlen(pos) != 32 * 2) { + wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " + "hash length in ca_cert '%s'", ca_cert); + return -1; + } + if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " + "value in ca_cert '%s'", ca_cert); + return -1; + } + conn->server_cert_only = 1; + wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " + "certificate match"); + return 0; +#else /* CONFIG_SHA256 */ + wpa_printf(MSG_INFO, "No SHA256 included in the build - " + "cannot validate server certificate hash"); + return -1; +#endif /* CONFIG_SHA256 */ + } + if (ca_cert_blob) { X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, ca_cert_blob_len); @@ -1120,7 +1377,6 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, X509_free(cert); wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " "to certificate store", __func__); - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); return 0; } @@ -1129,7 +1385,6 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " "system certificate store"); - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); return 0; } #endif /* CONFIG_NATIVE_WINDOWS */ @@ -1152,7 +1407,6 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, "certificate(s) loaded"); tls_get_errors(ssl_ctx); } - SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); #else /* OPENSSL_NO_STDIO */ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); @@ -1161,7 +1415,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, } else { /* No ca_cert configured - do not try to verify server * certificate */ - SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); + conn->ca_cert_verify = 0; } return 0; @@ -1246,10 +1500,12 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, return -1; if (verify_peer) { + conn->ca_cert_verify = 1; SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); } else { + conn->ca_cert_verify = 0; SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); } @@ -1979,30 +2235,30 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +static struct wpabuf * +openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, + int server) { int res; - u8 *out_data; - - if (appl_data) - *appl_data = NULL; + struct wpabuf *out_data; /* * Give TLS handshake data from the server (if available) to OpenSSL * for processing. */ if (in_data && - BIO_write(conn->ssl_in, in_data, in_len) < 0) { + BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) + < 0) { tls_show_errors(MSG_INFO, __func__, "Handshake failed - BIO_write"); return NULL; } /* Initiate TLS handshake or continue the existing handshake */ - res = SSL_connect(conn->ssl); + if (server) + res = SSL_accept(conn->ssl); + else + res = SSL_connect(conn->ssl); if (res != 1) { int err = SSL_get_error(conn->ssl, res); if (err == SSL_ERROR_WANT_READ) @@ -2020,7 +2276,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, /* Get the TLS handshake data to be sent to the server */ res = BIO_ctrl_pending(conn->ssl_out); wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); - out_data = os_malloc(res == 0 ? 1 : res); + out_data = wpabuf_alloc(res); if (out_data == NULL) { wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " "handshake output (%d bytes)", res); @@ -2028,10 +2284,10 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); } - *out_len = 0; return NULL; } - res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res); + res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), + res); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Handshake failed - BIO_read"); @@ -2039,169 +2295,169 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); } - *out_len = 0; + wpabuf_free(out_data); return NULL; } - *out_len = res; - - if (SSL_is_init_finished(conn->ssl) && appl_data) { - *appl_data = os_malloc(in_len); - if (*appl_data) { - res = SSL_read(conn->ssl, *appl_data, in_len); - if (res < 0) { - int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ || - err == SSL_ERROR_WANT_WRITE) { - wpa_printf(MSG_DEBUG, - "SSL: No Application Data " - "included"); - } else { - tls_show_errors(MSG_INFO, __func__, - "Failed to read " - "possible " - "Application Data"); - } - os_free(*appl_data); - *appl_data = NULL; - } else { - *appl_data_len = res; - wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application" - " Data in Finish message", - *appl_data, *appl_data_len); - } - } - } + wpabuf_put(out_data, res); return out_data; } -u8 * tls_connection_server_handshake(void *ssl_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +static struct wpabuf * +openssl_get_appl_data(struct tls_connection *conn, size_t max_len) { + struct wpabuf *appl_data; int res; - u8 *out_data; - /* - * Give TLS handshake data from the client (if available) to OpenSSL - * for processing. - */ - if (in_data && - BIO_write(conn->ssl_in, in_data, in_len) < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_write"); + appl_data = wpabuf_alloc(max_len + 100); + if (appl_data == NULL) return NULL; - } - /* Initiate TLS handshake or continue the existing handshake */ - res = SSL_accept(conn->ssl); - if (res != 1) { + res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), + wpabuf_size(appl_data)); + if (res < 0) { int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ) - wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want " - "more data"); - else if (err == SSL_ERROR_WANT_WRITE) - wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want to " - "write"); - else { - tls_show_errors(MSG_INFO, __func__, "SSL_accept"); - return NULL; + if (err == SSL_ERROR_WANT_READ || + err == SSL_ERROR_WANT_WRITE) { + wpa_printf(MSG_DEBUG, "SSL: No Application Data " + "included"); + } else { + tls_show_errors(MSG_INFO, __func__, + "Failed to read possible " + "Application Data"); } + wpabuf_free(appl_data); + return NULL; } - /* Get the TLS handshake data to be sent to the client */ - res = BIO_ctrl_pending(conn->ssl_out); - wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); - out_data = os_malloc(res == 0 ? 1 : res); - if (out_data == NULL) { - wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " - "handshake output (%d bytes)", res); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - *out_len = 0; + wpabuf_put(appl_data, res); + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " + "message", appl_data); + + return appl_data; +} + + +static struct wpabuf * +openssl_connection_handshake(struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, int server) +{ + struct wpabuf *out_data; + + if (appl_data) + *appl_data = NULL; + + out_data = openssl_handshake(conn, in_data, server); + if (out_data == NULL) return NULL; - } - res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_read"); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - *out_len = 0; - return NULL; - } - *out_len = res; + + if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) + *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); + return out_data; } -int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * +tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 0); +} + + +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 1); +} + + +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { int res; + struct wpabuf *buf; if (conn == NULL) - return -1; + return NULL; /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ if ((res = BIO_reset(conn->ssl_in)) < 0 || (res = BIO_reset(conn->ssl_out)) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return res; + return NULL; } - res = SSL_write(conn->ssl, in_data, in_len); + res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Encryption failed - SSL_write"); - return res; + return NULL; } /* Read encrypted data to be sent to the server */ - res = BIO_read(conn->ssl_out, out_data, out_len); + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Encryption failed - BIO_read"); - return res; + wpabuf_free(buf); + return NULL; } + wpabuf_put(buf, res); - return res; + return buf; } -int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { int res; + struct wpabuf *buf; /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ - res = BIO_write(conn->ssl_in, in_data, in_len); + res = BIO_write(conn->ssl_in, wpabuf_head(in_data), + wpabuf_len(in_data)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Decryption failed - BIO_write"); - return res; + return NULL; } if (BIO_reset(conn->ssl_out) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return res; + return NULL; } /* Read decrypted data for further processing */ - res = SSL_read(conn->ssl, out_data, out_len); + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Decryption failed - SSL_read"); - return res; + wpabuf_free(buf); + return NULL; } + wpabuf_put(buf, res); - return res; + return buf; } @@ -2292,7 +2548,7 @@ int tls_connection_enable_workaround(void *ssl_ctx, } -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) /* ClientHello TLS extensions require a patch to openssl, so this function is * commented out unless explicitly needed for EAP-FAST in order to be able to * build this file with unmodified openssl. */ @@ -2315,7 +2571,7 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, return 0; } -#endif /* EAP_FAST || EAP_FAST_DYNAMIC */ +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) @@ -2482,12 +2738,10 @@ int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, } -int tls_connection_ia_send_phase_finished(void *tls_ctx, - struct tls_connection *conn, - int final, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final) { - return -1; + return NULL; } @@ -2506,7 +2760,7 @@ int tls_connection_ia_permute_inner_secret(void *tls_ctx, } -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) /* Pre-shared secred requires a patch to openssl, so this function is * commented out unless explicitly needed for EAP-FAST in order to be able to * build this file with unmodified openssl. */ @@ -2619,7 +2873,7 @@ static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) } #endif /* SSL_OP_NO_TICKET */ #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -#endif /* EAP_FAST || EAP_FAST_DYNAMIC */ +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ int tls_connection_set_session_ticket_cb(void *tls_ctx, @@ -2627,7 +2881,7 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx, tls_session_ticket_cb cb, void *ctx) { -#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) conn->session_ticket_cb = cb; conn->session_ticket_cb_ctx = ctx; @@ -2665,7 +2919,7 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx, } return 0; -#else /* EAP_FAST || EAP_FAST_DYNAMIC */ +#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ return -1; -#endif /* EAP_FAST || EAP_FAST_DYNAMIC */ +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ } diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c index 87e74353dcf9..4a94e9911982 100644 --- a/src/crypto/tls_schannel.c +++ b/src/crypto/tls_schannel.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for Microsoft Schannel - * Copyright (c) 2005, Jouni Malinen + * SSL/TLS interface functions for Microsoft Schannel + * Copyright (c) 2005-2009, Jouni Malinen * * 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 @@ -215,9 +215,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -static u8 * tls_conn_hs_clienthello(struct tls_global *global, - struct tls_connection *conn, - size_t *out_len) +static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global, + struct tls_connection *conn) { DWORD sspi_flags, sspi_flags_out; SecBufferDesc outbuf; @@ -260,15 +259,14 @@ static u8 * tls_conn_hs_clienthello(struct tls_global *global, } if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { - u8 *buf; + struct wpabuf *buf; wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello", outbufs[0].pvBuffer, outbufs[0].cbBuffer); conn->start = 0; - *out_len = outbufs[0].cbBuffer; - buf = os_malloc(*out_len); + buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, + outbufs[0].cbBuffer); if (buf == NULL) return NULL; - os_memcpy(buf, outbufs[0].pvBuffer, *out_len); global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); return buf; } @@ -316,28 +314,27 @@ static int tls_get_eap(struct tls_global *global, struct tls_connection *conn) } -u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { - struct tls_global *global = ssl_ctx; + struct tls_global *global = tls_ctx; DWORD sspi_flags, sspi_flags_out; SecBufferDesc inbuf, outbuf; SecBuffer inbufs[2], outbufs[1]; SECURITY_STATUS status; TimeStamp ts_expiry; - u8 *out_buf = NULL; + struct wpabuf *out_buf = NULL; if (appl_data) *appl_data = NULL; - if (conn->start) { - return tls_conn_hs_clienthello(global, conn, out_len); - } + if (conn->start) + return tls_conn_hs_clienthello(global, conn); wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process", - in_len); + (int) wpabuf_len(in_data)); sspi_flags = ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | @@ -346,8 +343,8 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, ISC_REQ_MANUAL_CRED_VALIDATION; /* Input buffer for Schannel */ - inbufs[0].pvBuffer = (u8 *) in_data; - inbufs[0].cbBuffer = in_len; + inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data); + inbufs[0].cbBuffer = wpabuf_len(in_data); inbufs[0].BufferType = SECBUFFER_TOKEN; /* Place for leftover data from Schannel */ @@ -392,11 +389,8 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { wpa_hexdump(MSG_MSGDUMP, "SChannel - output", outbufs[0].pvBuffer, outbufs[0].cbBuffer); - *out_len = outbufs[0].cbBuffer; - out_buf = os_malloc(*out_len); - if (out_buf) - os_memcpy(out_buf, outbufs[0].pvBuffer, - *out_len); + out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, + outbufs[0].cbBuffer); global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); outbufs[0].pvBuffer = NULL; if (out_buf == NULL) @@ -420,19 +414,16 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, /* Need to return something to get final TLS ACK. */ if (out_buf == NULL) - out_buf = os_malloc(1); + out_buf = wpabuf_alloc(0); if (inbufs[1].BufferType == SECBUFFER_EXTRA) { wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted " "application data", inbufs[1].pvBuffer, inbufs[1].cbBuffer); if (appl_data) { - *appl_data_len = outbufs[1].cbBuffer; - appl_data = os_malloc(*appl_data_len); - if (appl_data) - os_memcpy(appl_data, - outbufs[1].pvBuffer, - *appl_data_len); + *appl_data = wpabuf_alloc_copy( + outbufs[1].pvBuffer, + outbufs[1].cbBuffer); } global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); inbufs[1].pvBuffer = NULL; @@ -470,26 +461,26 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, } -u8 * tls_connection_server_handshake(void *ssl_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - struct tls_global *global = ssl_ctx; + struct tls_global *global = tls_ctx; SECURITY_STATUS status; SecBufferDesc buf; SecBuffer bufs[4]; SecPkgContext_StreamSizes sizes; int i; - size_t total_len; + struct wpabuf *out; status = global->sspi->QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, @@ -497,34 +488,27 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, if (status != SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed", __func__); - return -1; + return NULL; } wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u", __func__, (unsigned int) sizes.cbHeader, (unsigned int) sizes.cbTrailer); - total_len = sizes.cbHeader + in_len + sizes.cbTrailer; - - if (out_len < total_len) { - wpa_printf(MSG_DEBUG, "%s: too short out_data (out_len=%lu " - "in_len=%lu total_len=%lu)", __func__, - (unsigned long) out_len, (unsigned long) in_len, - (unsigned long) total_len); - return -1; - } + out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) + + sizes.cbTrailer); os_memset(&bufs, 0, sizeof(bufs)); - bufs[0].pvBuffer = out_data; + bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader); bufs[0].cbBuffer = sizes.cbHeader; bufs[0].BufferType = SECBUFFER_STREAM_HEADER; - os_memcpy(out_data + sizes.cbHeader, in_data, in_len); - bufs[1].pvBuffer = out_data + sizes.cbHeader; - bufs[1].cbBuffer = in_len; + bufs[1].pvBuffer = wpabuf_put(out, 0); + wpabuf_put_buf(out, in_data); + bufs[1].cbBuffer = wpabuf_len(in_data); bufs[1].BufferType = SECBUFFER_DATA; - bufs[2].pvBuffer = out_data + sizes.cbHeader + in_len; + bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer); bufs[2].cbBuffer = sizes.cbTrailer; bufs[2].BufferType = SECBUFFER_STREAM_TRAILER; @@ -543,7 +527,7 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, (int) bufs[2].cbBuffer, (int) bufs[2].BufferType); wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: " "out_data=%p bufs %p %p %p", - out_data, bufs[0].pvBuffer, bufs[1].pvBuffer, + wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer, bufs[2].pvBuffer); for (i = 0; i < 3; i++) { @@ -556,39 +540,37 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, if (status == SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); - wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Encrypted data from " - "EncryptMessage", out_data, total_len); - return total_len; + wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data " + "from EncryptMessage", out); + return out; } wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", __func__, (int) status); - return -1; + wpabuf_free(out); + return NULL; } -int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - struct tls_global *global = ssl_ctx; + struct tls_global *global = tls_ctx; SECURITY_STATUS status; SecBufferDesc buf; SecBuffer bufs[4]; int i; + struct wpabuf *out, *tmp; - if (out_len < in_len) { - wpa_printf(MSG_DEBUG, "%s: out_len=%lu < in_len=%lu", __func__, - (unsigned long) out_len, (unsigned long) in_len); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "Schannel: Encrypted data to DecryptMessage", - in_data, in_len); + wpa_hexdump_buf(MSG_MSGDUMP, + "Schannel: Encrypted data to DecryptMessage", in_data); os_memset(&bufs, 0, sizeof(bufs)); - os_memcpy(out_data, in_data, in_len); - bufs[0].pvBuffer = out_data; - bufs[0].cbBuffer = in_len; + tmp = wpabuf_dup(in_data); + if (tmp == NULL) + return NULL; + bufs[0].pvBuffer = wpabuf_mhead(tmp); + bufs[0].cbBuffer = wpabuf_len(in_data); bufs[0].BufferType = SECBUFFER_DATA; bufs[1].BufferType = SECBUFFER_EMPTY; @@ -611,7 +593,7 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, (int) bufs[3].cbBuffer, (int) bufs[3].BufferType); wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: " "out_data=%p bufs %p %p %p %p", - out_data, bufs[0].pvBuffer, bufs[1].pvBuffer, + wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer, bufs[2].pvBuffer, bufs[3].pvBuffer); switch (status) { @@ -628,23 +610,21 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, if (i == 4) { wpa_printf(MSG_DEBUG, "%s: No output data from " "DecryptMessage", __func__); - return -1; + wpabuf_free(tmp); + return NULL; } wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from " "DecryptMessage", bufs[i].pvBuffer, bufs[i].cbBuffer); - if (bufs[i].cbBuffer > out_len) { - wpa_printf(MSG_DEBUG, "%s: Too long output data", - __func__); - return -1; - } - os_memmove(out_data, bufs[i].pvBuffer, bufs[i].cbBuffer); - return bufs[i].cbBuffer; + out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer); + wpabuf_free(tmp); + return out; } wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", __func__, (int) status); - return -1; + wpabuf_free(tmp); + return NULL; } @@ -765,12 +745,10 @@ int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, } -int tls_connection_ia_send_phase_finished(void *tls_ctx, - struct tls_connection *conn, - int final, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_ia_send_phase_finished( + void *tls_ctx, struct tls_connection *conn, int final); { - return -1; + return NULL; } diff --git a/src/drivers/.gitignore b/src/drivers/.gitignore new file mode 100644 index 000000000000..1d9e0e661afe --- /dev/null +++ b/src/drivers/.gitignore @@ -0,0 +1,2 @@ +build.wpa_supplicant +build.hostapd diff --git a/src/drivers/Makefile b/src/drivers/Makefile index cffba620da04..07600e52c2fd 100644 --- a/src/drivers/Makefile +++ b/src/drivers/Makefile @@ -2,8 +2,8 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d + rm -f build.wpa_supplicant build.hostapd install: @echo Nothing to be made. diff --git a/src/drivers/driver.h b/src/drivers/driver.h index c2975d2c1215..fa49da454e83 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1,6 +1,6 @@ /* - * WPA Supplicant - driver interface definition - * Copyright (c) 2003-2008, Jouni Malinen + * Driver interface definition + * Copyright (c) 2003-2010, Jouni Malinen * * 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 @@ -10,79 +10,117 @@ * license. * * See README and COPYING for more details. + * + * This file defines a driver interface used by both %wpa_supplicant and + * hostapd. The first part of the file defines data structures used in various + * driver operations. This is followed by the struct wpa_driver_ops that each + * driver wrapper will beed to define with callback functions for requesting + * driver operations. After this, there are definitions for driver event + * reporting with wpa_supplicant_event() and some convenience helper functions + * that can be used to report events. */ #ifndef DRIVER_H #define DRIVER_H -#define WPA_SUPPLICANT_DRIVER_VERSION 3 +#define WPA_SUPPLICANT_DRIVER_VERSION 4 -#include "defs.h" +#include "common/defs.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 - Channel information + */ +struct hostapd_channel_data { + /** + * chan - Channel number (IEEE 802.11) + */ + short chan; + + /** + * freq - Frequency in MHz + */ + short freq; + + /** + * flag - Channel flags (HOSTAPD_CHAN_*) + */ + int flag; + + /** + * max_tx_power - maximum transmit power in dBm + */ + u8 max_tx_power; +}; + +/** + * struct hostapd_hw_modes - Supported hardware mode information + */ +struct hostapd_hw_modes { + /** + * mode - Hardware mode + */ + enum hostapd_hw_mode mode; + + /** + * num_channels - Number of entries in the channels array + */ + int num_channels; + + /** + * channels - Array of supported channels + */ + struct hostapd_channel_data *channels; + + /** + * num_rates - Number of entries in the rates array + */ + int num_rates; + + /** + * rates - Array of supported rates in 100 kbps units + */ + int *rates; + + /** + * ht_capab - HT (IEEE 802.11n) capabilities + */ + u16 ht_capab; + + /** + * mcs_set - MCS (IEEE 802.11n) rate parameters + */ + u8 mcs_set[16]; + + /** + * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters + */ + u8 a_mpdu_params; +}; -#define AUTH_ALG_OPEN_SYSTEM 0x01 -#define AUTH_ALG_SHARED_KEY 0x02 -#define AUTH_ALG_LEAP 0x04 #define IEEE80211_MODE_INFRA 0 #define IEEE80211_MODE_IBSS 1 +#define IEEE80211_MODE_AP 2 #define IEEE80211_CAP_ESS 0x0001 #define IEEE80211_CAP_IBSS 0x0002 #define IEEE80211_CAP_PRIVACY 0x0010 -#define SSID_MAX_WPA_IE_LEN 40 -/** - * struct wpa_scan_result - Scan results (old structure) - * @bssid: BSSID - * @ssid: SSID - * @ssid_len: length of the ssid - * @wpa_ie: WPA IE - * @wpa_ie_len: length of the wpa_ie - * @rsn_ie: RSN IE - * @rsn_ie_len: length of the RSN IE - * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) - * @caps: capability information field in host byte order - * @qual: signal quality - * @noise: noise level - * @level: signal level - * @maxrate: maximum supported rate - * @mdie_present: Whether MDIE was included in Beacon/ProbeRsp frame - * @mdie: Mobility domain identifier IE (IEEE 802.11r MDIE) (starting from - * IE type field) - * @tsf: Timestamp - * - * This structure is used as a generic format for scan results from the - * driver. Each driver interface implementation is responsible for converting - * the driver or OS specific scan results into this format. - * - * This structure is the old data structure used for scan results. It is - * obsoleted by the new struct wpa_scan_res structure and the old version is - * only included for backwards compatibility with existing driver wrapper - * implementations. New implementations are encouraged to implement for struct - * wpa_scan_res. The old structure will be removed at some point. - */ -struct wpa_scan_result { - u8 bssid[ETH_ALEN]; - u8 ssid[32]; - size_t ssid_len; - u8 wpa_ie[SSID_MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[SSID_MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - int freq; - u16 caps; - int qual; - int noise; - int level; - int maxrate; - int mdie_present; - u8 mdie[5]; - u64 tsf; -}; - +#define WPA_SCAN_QUAL_INVALID BIT(0) +#define WPA_SCAN_NOISE_INVALID BIT(1) +#define WPA_SCAN_LEVEL_INVALID BIT(2) +#define WPA_SCAN_LEVEL_DBM BIT(3) +#define WPA_SCAN_AUTHENTICATED BIT(4) +#define WPA_SCAN_ASSOCIATED BIT(5) /** * struct wpa_scan_res - Scan result for an BSS/IBSS + * @flags: information flags about the BSS/IBSS (WPA_SCAN_*) * @bssid: BSSID * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) * @beacon_int: beacon interval in TUs (host byte order) @@ -91,7 +129,10 @@ struct wpa_scan_result { * @noise: noise level * @level: signal level * @tsf: Timestamp + * @age: Age of the information in milliseconds (i.e., how many milliseconds + * ago the last Beacon or Probe Response frame was received) * @ie_len: length of the following IE field in octets + * @beacon_ie_len: length of the following Beacon IE field in octets * * This structure is used as a generic format for scan results from the * driver. Each driver interface implementation is responsible for converting @@ -103,6 +144,7 @@ struct wpa_scan_result { * report all IEs to make it easier to support future additions. */ struct wpa_scan_res { + unsigned int flags; u8 bssid[ETH_ALEN]; int freq; u16 beacon_int; @@ -111,8 +153,16 @@ struct wpa_scan_res { int noise; int level; u64 tsf; + unsigned int age; size_t ie_len; - /* followed by ie_len octets of IEs */ + size_t beacon_ie_len; + /* + * Followed by ie_len octets of IEs from Probe Response frame (or if + * the driver does not indicate source of IEs, these may also be from + * Beacon frame). After the first set of IEs, another set of IEs may + * follow (with beacon_ie_len octets of data) if the driver provides + * both IE sets. + */ }; /** @@ -142,6 +192,95 @@ struct wpa_interface_info { const char *drv_name; }; +#define WPAS_MAX_SCAN_SSIDS 4 + +/** + * struct wpa_driver_scan_params - Scan parameters + * Data for struct wpa_driver_ops::scan2(). + */ +struct wpa_driver_scan_params { + /** + * ssids - SSIDs to scan for + */ + struct wpa_driver_scan_ssid { + /** + * ssid - specific SSID to scan for (ProbeReq) + * %NULL or zero-length SSID is used to indicate active scan + * with wildcard SSID. + */ + const u8 *ssid; + /** + * ssid_len: Length of the SSID in octets + */ + size_t ssid_len; + } ssids[WPAS_MAX_SCAN_SSIDS]; + + /** + * num_ssids - Number of entries in ssids array + * Zero indicates a request for a passive scan. + */ + size_t num_ssids; + + /** + * extra_ies - Extra IE(s) to add into Probe Request or %NULL + */ + const u8 *extra_ies; + + /** + * extra_ies_len - Length of extra_ies in octets + */ + size_t extra_ies_len; + + /** + * freqs - Array of frequencies to scan or %NULL for all frequencies + * + * The frequency is set in MHz. The array is zero-terminated. + */ + int *freqs; + + /** + * filter_ssids - Filter for reporting SSIDs + * + * This optional parameter can be used to request the driver wrapper to + * filter scan results to include only the specified SSIDs. %NULL + * indicates that no filtering is to be done. This can be used to + * reduce memory needs for scan results in environments that have large + * number of APs with different SSIDs. + * + * The driver wrapper is allowed to take this allocated buffer into its + * own use by setting the pointer to %NULL. In that case, the driver + * wrapper is responsible for freeing the buffer with os_free() once it + * is not needed anymore. + */ + struct wpa_driver_scan_filter { + u8 ssid[32]; + size_t ssid_len; + } *filter_ssids; + + /** + * num_filter_ssids - Number of entries in filter_ssids array + */ + size_t num_filter_ssids; +}; + +/** + * struct wpa_driver_auth_params - Authentication parameters + * Data for struct wpa_driver_ops::authenticate(). + */ +struct wpa_driver_auth_params { + int freq; + const u8 *bssid; + const u8 *ssid; + size_t ssid_len; + int auth_alg; + const u8 *ie; + size_t ie_len; + const u8 *wep_key[4]; + size_t wep_key_len[4]; + int wep_tx_keyidx; + int local_state_change; +}; + /** * struct wpa_driver_associate_params - Association parameters * Data for struct wpa_driver_ops::associate(). @@ -157,6 +296,10 @@ struct wpa_driver_associate_params { * ssid - The selected SSID */ const u8 *ssid; + + /** + * ssid_len - Length of the SSID (1..32) + */ size_t ssid_len; /** @@ -185,20 +328,36 @@ struct wpa_driver_associate_params { * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE. */ const u8 *wpa_ie; + /** * wpa_ie_len - length of the wpa_ie */ size_t wpa_ie_len; - /* The selected pairwise/group cipher and key management - * suites. These are usually ignored if @wpa_ie is used. */ - wpa_cipher pairwise_suite; - wpa_cipher group_suite; - wpa_key_mgmt key_mgmt_suite; + /** + * pairwise_suite - Selected pairwise cipher suite + * + * This is usually ignored if @wpa_ie is used. + */ + enum wpa_cipher pairwise_suite; + + /** + * group_suite - Selected group cipher suite + * + * This is usually ignored if @wpa_ie is used. + */ + enum wpa_cipher group_suite; + + /** + * key_mgmt_suite - Selected key management suite + * + * This is usually ignored if @wpa_ie is used. + */ + enum wpa_key_mgmt key_mgmt_suite; /** * auth_alg - Allowed authentication algorithms - * Bit field of AUTH_ALG_* + * Bit field of WPA_AUTH_ALG_* */ int auth_alg; @@ -225,11 +384,7 @@ struct wpa_driver_associate_params { /** * mgmt_frame_protection - IEEE 802.11w management frame protection */ - enum { - NO_MGMT_FRAME_PROTECTION, - MGMT_FRAME_PROTECTION_OPTIONAL, - MGMT_FRAME_PROTECTION_REQUIRED - } mgmt_frame_protection; + enum mfp_options mgmt_frame_protection; /** * ft_ies - IEEE 802.11r / FT information elements @@ -288,6 +443,23 @@ struct wpa_driver_associate_params { * be prepared to handle %NULL value as an error. */ const u8 *psk; + + /** + * drop_unencrypted - Enable/disable unencrypted frame filtering + * + * Configure the driver to drop all non-EAPOL frames (both receive and + * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must + * still be allowed for key negotiation. + */ + int drop_unencrypted; + + /** + * prev_bssid - Previously used BSSID in this ESS + * + * When not %NULL, this is a request to use reassociation instead of + * association. + */ + const u8 *prev_bssid; }; /** @@ -316,59 +488,119 @@ struct wpa_driver_capa { /* Driver generated WPA/RSN IE */ #define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001 +/* Driver needs static WEP key setup after association command */ #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002 #define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004 /* Driver takes care of RSN 4-way handshake internally; PMK is configured with * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */ #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008 +#define WPA_DRIVER_FLAGS_WIRED 0x00000010 +/* Driver provides separate commands for authentication and association (SME in + * wpa_supplicant). */ +#define WPA_DRIVER_FLAGS_SME 0x00000020 +/* Driver supports AP mode */ +#define WPA_DRIVER_FLAGS_AP 0x00000040 +/* Driver needs static WEP key setup after association has been completed */ +#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080 unsigned int flags; + + int max_scan_ssids; + + /** + * max_remain_on_chan - Maximum remain-on-channel duration in msec + */ + unsigned int max_remain_on_chan; }; -#define WPA_CHAN_W_SCAN 0x00000001 -#define WPA_CHAN_W_ACTIVE_SCAN 0x00000002 -#define WPA_CHAN_W_IBSS 0x00000004 +struct hostapd_data; -struct wpa_channel_data { - short chan; /* channel number (IEEE 802.11) */ - short freq; /* frequency in MHz */ - int flag; /* flag for user space use (WPA_CHAN_*) */ +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; }; -#define WPA_RATE_ERP 0x00000001 -#define WPA_RATE_BASIC 0x00000002 -#define WPA_RATE_PREAMBLE2 0x00000004 -#define WPA_RATE_SUPPORTED 0x00000010 -#define WPA_RATE_OFDM 0x00000020 -#define WPA_RATE_CCK 0x00000040 -#define WPA_RATE_MANDATORY 0x00000100 - -struct wpa_rate_data { - int rate; /* rate in 100 kbps */ - int flags; /* WPA_RATE_ flags */ +struct hostapd_sta_add_params { + const u8 *addr; + u16 aid; + u16 capability; + const u8 *supp_rates; + size_t supp_rates_len; + u16 listen_interval; + const struct ieee80211_ht_capabilities *ht_capabilities; }; -typedef enum { - WPA_MODE_IEEE80211B, - WPA_MODE_IEEE80211G, - WPA_MODE_IEEE80211A, - NUM_WPA_MODES -} wpa_hw_mode; +struct hostapd_freq_params { + int mode; + int freq; + int channel; + int ht_enabled; + int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, + * secondary channel below primary, 1 = HT40 + * enabled, secondary channel above primary */ +}; -struct wpa_hw_modes { - wpa_hw_mode mode; - int num_channels; - struct wpa_channel_data *channels; - int num_rates; - struct wpa_rate_data *rates; +enum wpa_driver_if_type { + /** + * WPA_IF_STATION - Station mode interface + */ + WPA_IF_STATION, + + /** + * WPA_IF_AP_VLAN - AP mode VLAN interface + * + * This interface shares its address and Beacon frame with the main + * BSS. + */ + WPA_IF_AP_VLAN, + + /** + * WPA_IF_AP_BSS - AP mode BSS interface + * + * This interface has its own address and Beacon frame. + */ + WPA_IF_AP_BSS, +}; + +struct wpa_init_params { + const u8 *bssid; + const char *ifname; + const u8 *ssid; + size_t ssid_len; + const char *test_socket; + int use_pae_group_addr; + char **bridge; + size_t num_bridge; + + u8 *own_addr; /* buffer for writing own MAC address */ }; -struct ieee80211_rx_status { - int channel; - int ssi; +struct wpa_bss_params { + /** Interface name (for multi-SSID/VLAN support) */ + const char *ifname; + /** Whether IEEE 802.1X or WPA/WPA2 is enabled */ + int enabled; + + int wpa; + int ieee802_1x; + int wpa_group; + int wpa_pairwise; + int wpa_key_mgmt; + int rsn_preauth; }; +#define WPA_STA_AUTHORIZED BIT(0) +#define WPA_STA_WMM BIT(1) +#define WPA_STA_SHORT_PREAMBLE BIT(2) +#define WPA_STA_MFP BIT(3) /** * struct wpa_driver_ops - Driver interface API definition @@ -413,32 +645,9 @@ struct wpa_driver_ops { */ int (*get_ssid)(void *priv, u8 *ssid); - /** - * set_wpa - Enable/disable WPA support (OBSOLETE) - * @priv: private driver interface data - * @enabled: 1 = enable, 0 = disable - * - * Returns: 0 on success, -1 on failure - * - * Note: This function is included for backwards compatibility. This is - * called only just after init and just before deinit, so these - * functions can be used to implement same functionality and the driver - * interface need not define this function. - * - * Configure the kernel driver to enable/disable WPA support. This may - * be empty function, if WPA support is always enabled. Common - * configuration items are WPA IE (clearing it when WPA support is - * disabled), Privacy flag configuration for capability field (note: - * this the value need to set in associate handler to allow plaintext - * mode to be used) when trying to associate with, roaming mode (can - * allow wpa_supplicant to control roaming if ap_scan=1 is used; - * however, drivers can also implement roaming if desired, especially - * ap_scan=2 mode is used for this). - */ - int (*set_wpa)(void *priv, int enabled); - /** * set_key - Configure encryption key + * @ifname: Interface name (for multi-SSID/VLAN support) * @priv: private driver interface data * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); @@ -480,8 +689,9 @@ struct wpa_driver_ops { * in driver_*.c set_key() implementation, see driver_ndis.c for an * example on how this can be done. */ - int (*set_key)(void *priv, wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, const u8 *seq, size_t seq_len, + int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg, + const u8 *addr, int key_idx, int set_tx, + const u8 *seq, size_t seq_len, const u8 *key, size_t key_len); /** @@ -542,55 +752,6 @@ struct wpa_driver_ops { */ int (*set_countermeasures)(void *priv, int enabled); - /** - * set_drop_unencrypted - Enable/disable unencrypted frame filtering - * @priv: private driver interface data - * @enabled: 1 = unencrypted Tx/Rx frames will be dropped, 0 = disabled - * - * Returns: 0 on success, -1 on failure - * - * Configure the driver to drop all non-EAPOL frames (both receive and - * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must - * still be allowed for key negotiation. - */ - int (*set_drop_unencrypted)(void *priv, int enabled); - - /** - * scan - Request the driver to initiate scan - * @priv: private driver interface data - * @ssid: specific SSID to scan for (ProbeReq) or %NULL to scan for - * all SSIDs (either active scan with broadcast SSID or passive - * scan - * @ssid_len: length of the SSID - * - * Returns: 0 on success, -1 on failure - * - * Once the scan results are ready, the driver should report scan - * results event for wpa_supplicant which will eventually request the - * results with wpa_driver_get_scan_results(). - */ - int (*scan)(void *priv, const u8 *ssid, size_t ssid_len); - - /** - * get_scan_results - Fetch the latest scan results (old version) - * @priv: private driver interface data - * @results: pointer to buffer for scan results - * @max_size: maximum number of entries (buffer size) - * - * Returns: Number of scan result entries used on success, -1 on - * failure - * - * If scan results include more than max_size BSSes, max_size will be - * returned and the remaining entries will not be included in the - * buffer. - * - * This function is depracated. New driver wrapper implementations - * should implement support for get_scan_results2(). - */ - int (*get_scan_results)(void *priv, - struct wpa_scan_result *results, - size_t max_size); - /** * deauthenticate - Request driver to deauthenticate * @priv: private driver interface data @@ -623,27 +784,6 @@ struct wpa_driver_ops { int (*associate)(void *priv, struct wpa_driver_associate_params *params); - /** - * set_auth_alg - Set IEEE 802.11 authentication algorithm - * @priv: private driver interface data - * @auth_alg: bit field of AUTH_ALG_* - * - * If the driver supports more than one authentication algorithm at the - * same time, it should configure all supported algorithms. If not, one - * algorithm needs to be selected arbitrarily. Open System - * authentication should be ok for most cases and it is recommended to - * be used if other options are not supported. Static WEP configuration - * may also use Shared Key authentication and LEAP requires its own - * algorithm number. For LEAP, user can make sure that only one - * algorithm is used at a time by configuring LEAP as the only - * supported EAP method. This information is also available in - * associate() params, so set_auth_alg may not be needed in case of - * most drivers. - * - * Returns: 0 on success, -1 on failure - */ - int (*set_auth_alg)(void *priv, int auth_alg); - /** * add_pmkid - Add PMKSA cache entry to the driver * @priv: private driver interface data @@ -764,9 +904,9 @@ struct wpa_driver_ops { * with driver specific functionality. If this function pointer is set, * l2_packet module is not used at all and the driver interface code is * responsible for receiving and sending all EAPOL packets. The - * received EAPOL packets are sent to core code by calling - * wpa_supplicant_rx_eapol(). The driver interface is required to - * implement get_mac_addr() handler if send_eapol() is used. + * received EAPOL packets are sent to core code with EVENT_EAPOL_RX + * event. The driver interface is required to implement get_mac_addr() + * handler if send_eapol() is used. */ int (*send_eapol)(void *priv, const u8 *dest, u16 proto, const u8 *data, size_t data_len); @@ -813,16 +953,16 @@ struct wpa_driver_ops { * failure. Caller is responsible for freeing this. * * This function is only needed for drivers that export MLME - * (management frame processing) to wpa_supplicant. + * (management frame processing) to %wpa_supplicant or hostapd. */ - struct wpa_hw_modes * (*get_hw_feature_data)(void *priv, - u16 *num_modes, - u16 *flags); + struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv, + u16 *num_modes, + u16 *flags); /** * set_channel - Set channel * @priv: Private driver interface data - * @phymode: WPA_MODE_IEEE80211B, .. + * @phymode: HOSTAPD_MODE_IEEE80211B, .. * @chan: IEEE 802.11 channel number * @freq: Frequency of the channel in MHz * Returns: 0 on success, -1 on failure @@ -830,7 +970,7 @@ struct wpa_driver_ops { * This function is only needed for drivers that export MLME * (management frame processing) to wpa_supplicant. */ - int (*set_channel)(void *priv, wpa_hw_mode phymode, int chan, + int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan, int freq); /** @@ -940,29 +1080,6 @@ struct wpa_driver_ops { */ struct wpa_scan_results * (*get_scan_results2)(void *priv); - /** - * set_probe_req_ie - Set information element(s) for Probe Request - * @priv: private driver interface data - * @ies: Information elements to append or %NULL to remove extra IEs - * @ies_len: Length of the IE buffer in octets - * Returns: 0 on success, -1 on failure - */ - int (*set_probe_req_ie)(void *priv, const u8 *ies, size_t ies_len); - - /** - * set_mode - Request driver to set the operating mode - * @priv: private driver interface data - * @mode: Operation mode (infra/ibss) IEEE80211_MODE_* - * - * This handler will be called before any key configuration and call to - * associate() handler in order to allow the operation mode to be - * configured as early as possible. This information is also available - * in associate() params and as such, some driver wrappers may not need - * to implement set_mode() handler. - * Returns: 0 on success, -1 on failure - */ - int (*set_mode)(void *priv, int mode); - /** * set_country - Set country * @priv: Private driver interface data @@ -1017,19 +1134,644 @@ struct wpa_driver_ops { * failure */ struct wpa_interface_info * (*get_interfaces)(void *global_priv); + + /** + * scan2 - Request the driver to initiate scan + * @priv: private driver interface data + * @params: Scan parameters + * + * Returns: 0 on success, -1 on failure + * + * Once the scan results are ready, the driver should report scan + * results event for wpa_supplicant which will eventually request the + * results with wpa_driver_get_scan_results2(). + */ + int (*scan2)(void *priv, struct wpa_driver_scan_params *params); + + /** + * authenticate - Request driver to authenticate + * @priv: private driver interface data + * @params: authentication parameters + * Returns: 0 on success, -1 on failure + * + * This is an optional function that can be used with drivers that + * support separate authentication and association steps, i.e., when + * wpa_supplicant can act as the SME. If not implemented, associate() + * function is expected to take care of IEEE 802.11 authentication, + * too. + */ + int (*authenticate)(void *priv, + struct wpa_driver_auth_params *params); + + /** + * set_beacon - Set Beacon frame template + * @priv: Private driver interface data + * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE + * @head_len: Length of the head buffer in octets + * @tail: Beacon tail following TIM IE + * @tail_len: Length of the tail buffer in octets + * @dtim_period: DTIM period + * @beacon_int: Beacon interval + * Returns: 0 on success, -1 on failure + * + * This function is used to configure Beacon template for the driver in + * AP mode. The driver is responsible for building the full Beacon + * frame by concatenating the head part with TIM IE generated by the + * driver/firmware and finishing with the tail part. + */ + int (*set_beacon)(void *priv, const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, int dtim_period, + int beacon_int); + + /** + * hapd_init - Initialize driver interface (hostapd only) + * @hapd: Pointer to hostapd context + * @params: Configuration for the driver wrapper + * Returns: Pointer to private data, %NULL on failure + * + * This function is used instead of init() or init2() when the driver + * wrapper is used withh hostapd. + */ + void * (*hapd_init)(struct hostapd_data *hapd, + struct wpa_init_params *params); + + /** + * hapd_deinit - Deinitialize driver interface (hostapd only) + * @priv: Private driver interface data from hapd_init() + */ + void (*hapd_deinit)(void *priv); + + /** + * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only) + * @priv: Private driver interface data + * @params: BSS parameters + * Returns: 0 on success, -1 on failure + * + * This is an optional function to configure the kernel driver to + * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This + * can be left undefined (set to %NULL) if IEEE 802.1X support is + * always enabled and the driver uses set_beacon() to set WPA/RSN IE + * for Beacon frames. + */ + int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params); + + /** + * set_privacy - Enable/disable privacy (AP only) + * @priv: Private driver interface data + * @enabled: 1 = privacy enabled, 0 = disabled + * Returns: 0 on success, -1 on failure + * + * This is an optional function to configure privacy field in the + * kernel driver for Beacon frames. This can be left undefined (set to + * %NULL) if the driver uses the Beacon template from set_beacon(). + */ + int (*set_privacy)(void *priv, int enabled); + + /** + * get_seqnum - Fetch the current TSC/packet number (AP only) + * @ifname: The interface name (main or virtual) + * @priv: Private driver interface data + * @addr: MAC address of the station or %NULL for group keys + * @idx: Key index + * @seq: Buffer for returning the latest used TSC/packet number + * Returns: 0 on success, -1 on failure + * + * This function is used to fetch the last used TSC/packet number for + * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so + * there is no strict requirement on implementing support for unicast + * keys (i.e., addr != %NULL). + */ + int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr, + int idx, u8 *seq); + + /** + * flush - Flush all association stations (AP only) + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + * + * This function requests the driver to disassociate all associated + * stations. This function does not need to be implemented if the + * driver does not process association frames internally. + */ + int (*flush)(void *priv); + + /** + * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP) + * @priv: Private driver interface data + * @elem: Information elements + * @elem_len: Length of the elem buffer in octets + * Returns: 0 on success, -1 on failure + * + * This is an optional function to add information elements in the + * kernel driver for Beacon and Probe Response frames. This can be left + * undefined (set to %NULL) if the driver uses the Beacon template from + * set_beacon(). + */ + int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len); + + /** + * read_sta_data - Fetch station data (AP only) + * @priv: Private driver interface data + * @data: Buffer for returning station information + * @addr: MAC address of the station + * Returns: 0 on success, -1 on failure + */ + int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data, + const u8 *addr); + + /** + * hapd_send_eapol - Send an EAPOL packet (AP only) + * @priv: private driver interface data + * @addr: Destination MAC address + * @data: EAPOL packet starting with IEEE 802.1X header + * @data_len: Length of the EAPOL packet in octets + * @encrypt: Whether the frame should be encrypted + * @own_addr: Source MAC address + * + * Returns: 0 on success, -1 on failure + */ + int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, + const u8 *own_addr); + + /** + * sta_deauth - Deauthenticate a station (AP only) + * @priv: Private driver interface data + * @own_addr: Source address and BSSID for the Deauthentication frame + * @addr: MAC address of the station to deauthenticate + * @reason: Reason code for the Deauthentiation frame + * Returns: 0 on success, -1 on failure + * + * This function requests a specific station to be deauthenticated and + * a Deauthentication frame to be sent to it. + */ + int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr, + int reason); + + /** + * sta_disassoc - Disassociate a station (AP only) + * @priv: Private driver interface data + * @own_addr: Source address and BSSID for the Disassociation frame + * @addr: MAC address of the station to disassociate + * @reason: Reason code for the Disassociation frame + * Returns: 0 on success, -1 on failure + * + * This function requests a specific station to be disassociated and + * a Disassociation frame to be sent to it. + */ + int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr, + int reason); + + /** + * sta_remove - Remove a station entry (AP only) + * @priv: Private driver interface data + * @addr: MAC address of the station to be removed + * Returns: 0 on success, -1 on failure + */ + int (*sta_remove)(void *priv, const u8 *addr); + + /** + * hapd_get_ssid - Get the current SSID (AP only) + * @priv: Private driver interface data + * @buf: Buffer for returning the SSID + * @len: Maximum length of the buffer + * Returns: Length of the SSID on success, -1 on failure + * + * This function need not be implemented if the driver uses Beacon + * template from set_beacon() and does not reply to Probe Request + * frames. + */ + int (*hapd_get_ssid)(void *priv, u8 *buf, int len); + + /** + * hapd_set_ssid - Set SSID (AP only) + * @priv: Private driver interface data + * @buf: SSID + * @len: Length of the SSID in octets + * Returns: 0 on success, -1 on failure + */ + int (*hapd_set_ssid)(void *priv, const u8 *buf, int len); + + /** + * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP) + * @priv: Private driver interface data + * @enabled: 1 = countermeasures enabled, 0 = disabled + * Returns: 0 on success, -1 on failure + * + * This need not be implemented if the driver does not take care of + * association processing. + */ + int (*hapd_set_countermeasures)(void *priv, int enabled); + + /** + * sta_add - Add a station entry + * @priv: Private driver interface data + * @params: Station parameters + * Returns: 0 on success, -1 on failure + * + * This function is used to add a station entry to the driver once the + * station has completed association. This is only used if the driver + * does not take care of association processing. + */ + int (*sta_add)(void *priv, struct hostapd_sta_add_params *params); + + /** + * get_inact_sec - Get station inactivity duration (AP only) + * @priv: Private driver interface data + * @addr: Station address + * Returns: Number of seconds station has been inactive, -1 on failure + */ + int (*get_inact_sec)(void *priv, const u8 *addr); + + /** + * sta_clear_stats - Clear station statistics (AP only) + * @priv: Private driver interface data + * @addr: Station address + * Returns: 0 on success, -1 on failure + */ + int (*sta_clear_stats)(void *priv, const u8 *addr); + + /** + * set_freq - Set channel/frequency (AP only) + * @priv: Private driver interface data + * @freq: Channel parameters + * Returns: 0 on success, -1 on failure + */ + int (*set_freq)(void *priv, struct hostapd_freq_params *freq); + + /** + * set_rts - Set RTS threshold + * @priv: Private driver interface data + * @rts: RTS threshold in octets + * Returns: 0 on success, -1 on failure + */ + int (*set_rts)(void *priv, int rts); + + /** + * set_frag - Set fragmentation threshold + * @priv: Private driver interface data + * @frag: Fragmentation threshold in octets + * Returns: 0 on success, -1 on failure + */ + int (*set_frag)(void *priv, int frag); + + /** + * sta_set_flags - Set station flags (AP only) + * @priv: Private driver interface data + * @addr: Station address + * @total_flags: Bitmap of all WPA_STA_* flags currently set + * @flags_or: Bitmap of WPA_STA_* flags to add + * @flags_and: Bitmap of WPA_STA_* flags to us as a mask + * Returns: 0 on success, -1 on failure + */ + int (*sta_set_flags)(void *priv, const u8 *addr, + int total_flags, int flags_or, int flags_and); + + /** + * set_rate_sets - Set supported and basic rate sets (AP only) + * @priv: Private driver interface data + * @supp_rates: -1 terminated array of supported rates in 100 kbps + * @basic_rates: -1 terminated array of basic rates in 100 kbps + * @mode: hardware mode (HOSTAPD_MODE_*) + * Returns: 0 on success, -1 on failure + */ + int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates, + int mode); + + /** + * set_cts_protect - Set CTS protection mode (AP only) + * @priv: Private driver interface data + * @value: Whether CTS protection is enabled + * Returns: 0 on success, -1 on failure + */ + int (*set_cts_protect)(void *priv, int value); + + /** + * set_preamble - Set preamble mode (AP only) + * @priv: Private driver interface data + * @value: Whether short preamble is enabled + * Returns: 0 on success, -1 on failure + */ + int (*set_preamble)(void *priv, int value); + + /** + * set_short_slot_time - Set short slot time (AP only) + * @priv: Private driver interface data + * @value: Whether short slot time is enabled + * Returns: 0 on success, -1 on failure + */ + int (*set_short_slot_time)(void *priv, int value); + + /** + * set_tx_queue_params - Set TX queue parameters + * @priv: Private driver interface data + * @queue: Queue number + * @aifs: AIFS + * @cw_min: cwMin + * @cw_max: cwMax + * @burst_time: Maximum length for bursting in 0.1 msec units + */ + int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min, + int cw_max, int burst_time); + + /** + * valid_bss_mask - Validate BSSID mask + * @priv: Private driver interface data + * @addr: Address + * @mask: Mask + * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can + * be used, but the main interface address must be the first address in + * the block if mask is applied + */ + int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask); + + /** + * if_add - Add a virtual interface + * @priv: Private driver interface data + * @type: Interface type + * @ifname: Interface name for the new virtual interface + * @addr: Local address to use for the interface or %NULL to use the + * parent interface address + * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces + * @drv_priv: Pointer for overwriting the driver context or %NULL if + * not allowed (applies only to %WPA_IF_AP_BSS type) + * @force_ifname: Buffer for returning an interface name that the + * driver ended up using if it differs from the requested ifname + * @if_addr: Buffer for returning the allocated interface address + * (this may differ from the requested addr if the driver cannot + * change interface address) + * Returns: 0 on success, -1 on failure + */ + int (*if_add)(void *priv, enum wpa_driver_if_type type, + const char *ifname, const u8 *addr, void *bss_ctx, + void **drv_priv, char *force_ifname, u8 *if_addr); + + /** + * if_remove - Remove a virtual interface + * @priv: Private driver interface data + * @type: Interface type + * @ifname: Interface name of the virtual interface to be removed + * Returns: 0 on success, -1 on failure + */ + int (*if_remove)(void *priv, enum wpa_driver_if_type type, + const char *ifname); + + /** + * set_sta_vlan - Bind a station into a specific interface (AP only) + * @priv: Private driver interface data + * @ifname: Interface (main or virtual BSS or VLAN) + * @addr: MAC address of the associated station + * @vlan_id: VLAN ID + * Returns: 0 on success, -1 on failure + * + * This function is used to bind a station to a specific virtual + * interface. It is only used if when virtual interfaces are supported, + * e.g., to assign stations to different VLAN interfaces based on + * information from a RADIUS server. This allows separate broadcast + * domains to be used with a single BSS. + */ + int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname, + int vlan_id); + + /** + * commit - Optional commit changes handler (AP only) + * @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); + + /** + * send_ether - Send an ethernet packet (AP only) + * @priv: private driver interface data + * @dst: Destination MAC address + * @src: Source MAC address + * @proto: Ethertype + * @data: EAPOL packet starting with IEEE 802.1X header + * @data_len: Length of the EAPOL packet in octets + * Returns: 0 on success, -1 on failure + */ + int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto, + const u8 *data, size_t data_len); + + /** + * set_radius_acl_auth - Notification of RADIUS ACL change + * @priv: Private driver interface data + * @mac: MAC address of the station + * @accepted: Whether the station was accepted + * @session_timeout: Session timeout for the station + * Returns: 0 on success, -1 on failure + */ + int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, + u32 session_timeout); + + /** + * set_radius_acl_expire - Notification of RADIUS ACL expiration + * @priv: Private driver interface data + * @mac: MAC address of the station + * Returns: 0 on success, -1 on failure + */ + int (*set_radius_acl_expire)(void *priv, const u8 *mac); + + /** + * set_ht_params - Set HT parameters (AP only) + * @priv: Private driver interface data + * @ht_capab: HT Capabilities IE + * @ht_capab_len: Length of ht_capab in octets + * @ht_oper: HT Operation IE + * @ht_oper_len: Length of ht_oper in octets + * Returns: 0 on success, -1 on failure + */ + int (*set_ht_params)(void *priv, + const u8 *ht_capab, size_t ht_capab_len, + const u8 *ht_oper, size_t ht_oper_len); + + /** + * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP) + * @priv: Private driver interface data + * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s) + * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove + * extra IE(s) + * Returns: 0 on success, -1 on failure + * + * This is an optional function to add WPS IE in the kernel driver for + * Beacon and Probe Response frames. This can be left undefined (set + * to %NULL) if the driver uses the Beacon template from set_beacon() + * and does not process Probe Request frames. + */ + int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp); + + /** + * set_supp_port - Set IEEE 802.1X Supplicant Port status + * @priv: Private driver interface data + * @authorized: Whether the port is authorized + * Returns: 0 on success, -1 on failure + */ + int (*set_supp_port)(void *priv, int authorized); + + /** + * set_wds_sta - Bind a station into a 4-address WDS (AP only) + * @priv: Private driver interface data + * @addr: MAC address of the associated station + * @aid: Association ID + * @val: 1 = bind to 4-address WDS; 0 = unbind + * Returns: 0 on success, -1 on failure + */ + int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val); + + /** + * send_action - Transmit an Action frame + * @priv: Private driver interface data + * @freq: Frequency (in MHz) of the channel + * @dst: Destination MAC address (Address 1) + * @src: Source MAC address (Address 2) + * @bssid: BSSID (Address 3) + * @data: Frame body + * @data_len: data length in octets + * Returns: 0 on success, -1 on failure + * + * This command can be used to request the driver to transmit an action + * frame to the specified destination. If a remain-on-channel duration + * is in progress, the frame is transmitted on that channel. Otherwise, + * the frame is transmitted on the current operational channel if in + * associated state in station mode or if operating as an AP. If none + * of these conditions is in effect, send_action() cannot be used. + */ + int (*send_action)(void *priv, unsigned int freq, + const u8 *dst, const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len); + + /** + * remain_on_channel - Remain awake on a channel + * @priv: Private driver interface data + * @freq: Frequency (in MHz) of the channel + * @duration: Duration in milliseconds + * Returns: 0 on success, -1 on failure + * + * This command is used to request the driver to remain awake on the + * specified channel for the specified duration and report received + * Action frames with EVENT_RX_ACTION events. Optionally, received + * Probe Request frames may also be requested to be reported by calling + * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ. + * + * The driver may not be at the requested channel when this function + * returns, i.e., the return code is only indicating whether the + * request was accepted. The caller will need to wait until the + * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has + * completed the channel change. This may take some time due to other + * need for the radio and the caller should be prepared to timing out + * its wait since there are no guarantees on when this request can be + * executed. + */ + int (*remain_on_channel)(void *priv, unsigned int freq, + unsigned int duration); + + /** + * cancel_remain_on_channel - Cancel remain-on-channel operation + * @priv: Private driver interface data + * + * This command can be used to cancel a remain-on-channel operation + * before its originally requested duration has passed. This could be + * used, e.g., when remain_on_channel() is used to request extra time + * to receive a response to an Action frame and the response is + * received when there is still unneeded time remaining on the + * remain-on-channel operation. + */ + int (*cancel_remain_on_channel)(void *priv); + + /** + * probe_req_report - Request Probe Request frames to be indicated + * @priv: Private driver interface data + * @report: Whether to report received Probe Request frames + * Returns: 0 on success, -1 on failure (or if not supported) + * + * This command can be used to request the driver to indicate when + * Probe Request frames are received with EVENT_RX_PROBE_REQ events. + * Since this operation may require extra resources, e.g., due to less + * optimal hardware/firmware RX filtering, many drivers may disable + * Probe Request reporting at least in station mode. This command is + * used to notify the driver when the Probe Request frames need to be + * reported, e.g., during remain-on-channel operations. + */ + int (*probe_req_report)(void *priv, int report); + + /** + * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX + * @priv: Private driver interface data + * @disabled: Whether IEEE 802.11b rates are disabled + * Returns: 0 on success, -1 on failure (or if not supported) + * + * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and + * 11 Mbps) as TX rates for data and management frames. This can be + * used to optimize channel use when there is no need to support IEEE + * 802.11b-only devices. + */ + int (*disable_11b_rates)(void *priv, int disabled); + + /** + * deinit_ap - Deinitialize AP mode + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure (or if not supported) + * + * This optional function can be used to disable AP mode related + * configuration and change the driver mode to station mode to allow + * normal station operations like scanning to be completed. + */ + int (*deinit_ap)(void *priv); + + /** + * suspend - Notification on system suspend/hibernate event + * @priv: Private driver interface data + */ + void (*suspend)(void *priv); + + /** + * resume - Notification on system resume/thaw event + * @priv: Private driver interface data + */ + void (*resume)(void *priv); + + /** + * signal_monitor - Set signal monitoring parameters + * @priv: Private driver interface data + * @threshold: Threshold value for signal change events; 0 = disabled + * @hysteresis: Minimum change in signal strength before indicating a + * new event + * Returns: 0 on success, -1 on failure (or if not supported) + * + * This function can be used to configure monitoring of signal strength + * with the current AP. Whenever signal strength drops below the + * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event + * should be generated assuming the signal strength has changed at + * least %hysteresis from the previously indicated signal change event. + */ + int (*signal_monitor)(void *priv, int threshold, int hysteresis); + + /** + * send_frame - Send IEEE 802.11 frame (testing use only) + * @priv: Private driver interface data + * @data: IEEE 802.11 frame with IEEE 802.11 header + * @data_len: Size of the frame + * @encrypt: Whether to encrypt the frame (if keys are set) + * Returns: 0 on success, -1 on failure + * + * This function is only used for debugging purposes and is not + * required to be implemented for normal operations. + */ + int (*send_frame)(void *priv, const u8 *data, size_t data_len, + int encrypt); }; -/* Function to check whether a driver is for wired connections */ -static inline int IS_WIRED(const struct wpa_driver_ops *drv) -{ - return os_strcmp(drv->name, "wired") == 0 || - os_strcmp(drv->name, "roboswitch") == 0; -} /** * enum wpa_event_type - Event type for wpa_supplicant_event() calls */ -typedef enum wpa_event_type { +enum wpa_event_type { /** * EVENT_ASSOC - Association completed * @@ -1049,7 +1791,10 @@ typedef enum wpa_event_type { * * This event should be called when association is lost either due to * receiving deauthenticate or disassociate frame from the AP or when - * sending either of these frames to the current AP. + * sending either of these frames to the current AP. If the driver + * supports separate deauthentication event, EVENT_DISASSOC should only + * be used for disassociation and EVENT_DEAUTH for deauthentication. + * In AP mode, union wpa_event_data::disassoc_info is required. */ EVENT_DISASSOC, @@ -1075,7 +1820,8 @@ typedef enum wpa_event_type { * EVENT_SCAN_RESULTS call. If such event is not available from the * driver, the driver wrapper code is expected to use a registered * timeout to generate EVENT_SCAN_RESULTS call after the time that the - * scan is expected to be completed. + * scan is expected to be completed. Optional information about + * completed scan can be provided with union wpa_event_data::scan_info. */ EVENT_SCAN_RESULTS, @@ -1147,8 +1893,161 @@ typedef enum wpa_event_type { * FT authentication sequence from the AP. The FT IEs are included in * the extra information in union wpa_event_data::ft_ies. */ - EVENT_FT_RESPONSE -} wpa_event_type; + EVENT_FT_RESPONSE, + + /** + * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS + * + * The driver can use this event to inform wpa_supplicant about a STA + * in an IBSS with which protected frames could be exchanged. This + * event starts RSN authentication with the other STA to authenticate + * the STA and set up encryption keys with it. + */ + EVENT_IBSS_RSN_START, + + /** + * EVENT_AUTH - Authentication result + * + * This event should be called when authentication attempt has been + * completed. This is only used if the driver supports separate + * authentication step (struct wpa_driver_ops::authenticate). + * Information about authentication result is included in + * union wpa_event_data::auth. + */ + EVENT_AUTH, + + /** + * EVENT_DEAUTH - Authentication lost + * + * This event should be called when authentication is lost either due + * to receiving deauthenticate frame from the AP or when sending that + * frame to the current AP. + * In AP mode, union wpa_event_data::deauth_info is required. + */ + EVENT_DEAUTH, + + /** + * EVENT_ASSOC_REJECT - Association rejected + * + * This event should be called when (re)association attempt has been + * rejected by the AP. Information about authentication result is + * included in union wpa_event_data::assoc_reject. + */ + EVENT_ASSOC_REJECT, + + /** + * EVENT_AUTH_TIMED_OUT - Authentication timed out + */ + EVENT_AUTH_TIMED_OUT, + + /** + * EVENT_ASSOC_TIMED_OUT - Association timed out + */ + EVENT_ASSOC_TIMED_OUT, + + /** + * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received + */ + EVENT_FT_RRB_RX, + + /** + * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS + */ + EVENT_WPS_BUTTON_PUSHED, + + /** + * EVENT_TX_STATUS - Report TX status + */ + EVENT_TX_STATUS, + + /** + * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA + */ + EVENT_RX_FROM_UNKNOWN, + + /** + * EVENT_RX_MGMT - Report RX of a management frame + */ + EVENT_RX_MGMT, + + /** + * EVENT_RX_ACTION - Action frame received + * + * This event is used to indicate when an Action frame has been + * received. Information about the received frame is included in + * union wpa_event_data::rx_action. + */ + EVENT_RX_ACTION, + + /** + * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started + * + * This event is used to indicate when the driver has started the + * requested remain-on-channel duration. Information about the + * operation is included in union wpa_event_data::remain_on_channel. + */ + EVENT_REMAIN_ON_CHANNEL, + + /** + * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out + * + * This event is used to indicate when the driver has completed + * remain-on-channel duration, i.e., may noot be available on the + * requested channel anymore. Information about the + * operation is included in union wpa_event_data::remain_on_channel. + */ + EVENT_CANCEL_REMAIN_ON_CHANNEL, + + /** + * EVENT_MLME_RX - Report reception of frame for MLME (test use only) + * + * This event is used only by driver_test.c and userspace MLME. + */ + EVENT_MLME_RX, + + /** + * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame + * + * This event is used to indicate when a Probe Request frame has been + * received. Information about the received frame is included in + * union wpa_event_data::rx_probe_req. The driver is required to report + * these events only after successfully completed probe_req_report() + * commands to request the events (i.e., report parameter is non-zero) + * in station mode. In AP mode, Probe Request frames should always be + * reported. + */ + EVENT_RX_PROBE_REQ, + + /** + * EVENT_NEW_STA - New wired device noticed + * + * This event is used to indicate that a new device has been detected + * in a network that does not use association-like functionality (i.e., + * mainly wired Ethernet). This can be used to start EAPOL + * authenticator when receiving a frame from a device. The address of + * the device is included in union wpa_event_data::new_sta. + */ + EVENT_NEW_STA, + + /** + * EVENT_EAPOL_RX - Report received EAPOL frame + * + * When in AP mode with hostapd, this event is required to be used to + * deliver the receive EAPOL frames from the driver. With + * %wpa_supplicant, this event is used only if the send_eapol() handler + * is used to override the use of l2_packet for EAPOL frame TX. + */ + EVENT_EAPOL_RX, + + /** + * EVENT_SIGNAL_CHANGE - Indicate change in signal strength + * + * This event is used to indicate changes in the signal strength + * observed in frames received from the current AP if signal strength + * monitoring has been enabled with signal_monitor(). + */ + EVENT_SIGNAL_CHANGE +}; /** @@ -1175,7 +2074,7 @@ union wpa_event_data { * This should start with the first IE (fixed fields before IEs * are not included). */ - u8 *req_ies; + const u8 *req_ies; /** * req_ies_len - Length of req_ies in bytes @@ -1193,7 +2092,7 @@ union wpa_event_data { * This should start with the first IE (fixed fields before IEs * are not included). */ - u8 *resp_ies; + const u8 *resp_ies; /** * resp_ies_len - Length of resp_ies in bytes @@ -1216,18 +2115,61 @@ union wpa_event_data { * This should start with the first IE (fixed fields before IEs * are not included). */ - u8 *beacon_ies; + const u8 *beacon_ies; /** * beacon_ies_len - Length of beacon_ies */ size_t beacon_ies_len; + + /** + * freq - Frequency of the operational channel in MHz + */ + unsigned int freq; + + /** + * addr - Station address (for AP mode) + */ + const u8 *addr; } assoc_info; + /** + * struct disassoc_info - Data for EVENT_DISASSOC events + */ + struct disassoc_info { + /** + * addr - Station address (for AP mode) + */ + const u8 *addr; + + /** + * reason_code - Reason Code (host byte order) used in + * Deauthentication frame + */ + u16 reason_code; + } disassoc_info; + + /** + * struct deauth_info - Data for EVENT_DEAUTH events + */ + struct deauth_info { + /** + * addr - Station address (for AP mode) + */ + const u8 *addr; + + /** + * reason_code - Reason Code (host byte order) used in + * Deauthentication frame + */ + u16 reason_code; + } deauth_info; + /** * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE */ struct michael_mic_failure { int unicast; + const u8 *src; } michael_mic_failure; /** @@ -1273,7 +2215,228 @@ union wpa_event_data { size_t ies_len; int ft_action; u8 target_ap[ETH_ALEN]; + /** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */ + const u8 *ric_ies; + /** Length of ric_ies buffer in octets */ + size_t ric_ies_len; } ft_ies; + + /** + * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START + */ + struct ibss_rsn_start { + u8 peer[ETH_ALEN]; + } ibss_rsn_start; + + /** + * struct auth_info - Data for EVENT_AUTH events + */ + struct auth_info { + u8 peer[ETH_ALEN]; + u16 auth_type; + u16 status_code; + const u8 *ies; + size_t ies_len; + } auth; + + /** + * struct assoc_reject - Data for EVENT_ASSOC_REJECT events + */ + struct assoc_reject { + /** + * resp_ies - (Re)Association Response IEs + * + * Optional association data from the driver. This data is not + * required WPA, but may be useful for some protocols and as + * such, should be reported if this is available to the driver + * interface. + * + * This should start with the first IE (fixed fields before IEs + * are not included). + */ + u8 *resp_ies; + + /** + * resp_ies_len - Length of resp_ies in bytes + */ + size_t resp_ies_len; + + /** + * status_code - Status Code from (Re)association Response + */ + u16 status_code; + } assoc_reject; + + struct timeout_event { + u8 addr[ETH_ALEN]; + } timeout_event; + + /** + * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events + */ + struct ft_rrb_rx { + const u8 *src; + const u8 *data; + size_t data_len; + } ft_rrb_rx; + + /** + * struct tx_status - Data for EVENT_TX_STATUS events + */ + struct tx_status { + u16 type; + u16 stype; + const u8 *dst; + const u8 *data; + size_t data_len; + int ack; + } tx_status; + + /** + * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events + */ + struct rx_from_unknown { + const u8 *frame; + size_t len; + } rx_from_unknown; + + /** + * struct rx_mgmt - Data for EVENT_RX_MGMT events + */ + struct rx_mgmt { + const u8 *frame; + size_t frame_len; + u32 datarate; + u32 ssi_signal; + } rx_mgmt; + + /** + * struct rx_action - Data for EVENT_RX_ACTION events + */ + struct rx_action { + /** + * da - Destination address of the received Action frame + */ + const u8 *da; + + /** + * sa - Source address of the received Action frame + */ + const u8 *sa; + + /** + * bssid - Address 3 of the received Action frame + */ + const u8 *bssid; + + /** + * category - Action frame category + */ + u8 category; + + /** + * data - Action frame body after category field + */ + const u8 *data; + + /** + * len - Length of data in octets + */ + size_t len; + + /** + * freq - Frequency (in MHz) on which the frame was received + */ + int freq; + } rx_action; + + /** + * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events + * + * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events. + */ + struct remain_on_channel { + /** + * freq - Channel frequency in MHz + */ + unsigned int freq; + + /** + * duration - Duration to remain on the channel in milliseconds + */ + unsigned int duration; + } remain_on_channel; + + /** + * struct scan_info - Optional data for EVENT_SCAN_RESULTS events + * @aborted: Whether the scan was aborted + * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned) + * @num_freqs: Number of entries in freqs array + * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard + * SSID) + * @num_ssids: Number of entries in ssids array + */ + struct scan_info { + int aborted; + const int *freqs; + size_t num_freqs; + struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS]; + size_t num_ssids; + } scan_info; + + /** + * struct mlme_rx - Data for EVENT_MLME_RX events + */ + struct mlme_rx { + const u8 *buf; + size_t len; + int freq; + int channel; + int ssi; + } mlme_rx; + + /** + * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events + */ + struct rx_probe_req { + /** + * sa - Source address of the received Probe Request frame + */ + const u8 *sa; + + /** + * ie - IEs from the Probe Request body + */ + const u8 *ie; + + /** + * ie_len - Length of ie buffer in octets + */ + size_t ie_len; + } rx_probe_req; + + /** + * struct new_sta - Data for EVENT_NEW_STA events + */ + struct new_sta { + const u8 *addr; + } new_sta; + + /** + * struct eapol_rx - Data for EVENT_EAPOL_RX events + */ + struct eapol_rx { + const u8 *src; + const u8 *data; + size_t data_len; + } eapol_rx; + + /** + * struct signal_change - Data for EVENT_SIGNAL_CHANGE events + */ + struct signal_change { + int above_threshold; + } signal_change; }; /** @@ -1286,40 +2449,43 @@ union wpa_event_data { * Driver wrapper code should call this function whenever an event is received * from the driver. */ -void wpa_supplicant_event(void *ctx, wpa_event_type event, +void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data); -/** - * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant - * @ctx: Context pointer (wpa_s); this is the ctx variable registered - * with struct wpa_driver_ops::init() - * @src_addr: Source address of the EAPOL frame - * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header) - * @len: Length of the EAPOL data - * - * This function is called for each received EAPOL frame. Most driver - * interfaces rely on more generic OS mechanism for receiving frames through - * l2_packet, but if such a mechanism is not available, the driver wrapper may - * take care of received EAPOL frames and deliver them to the core supplicant - * code by calling this function. + +/* + * The following inline functions are provided for convenience to simplify + * event indication for some of the common events. */ -void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); -void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len, - struct ieee80211_rx_status *rx_status); -void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features, - size_t num_hw_features); +static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie, + size_t ielen) +{ + union wpa_event_data event; + os_memset(&event, 0, sizeof(event)); + event.assoc_info.req_ies = ie; + event.assoc_info.req_ies_len = ielen; + event.assoc_info.addr = addr; + wpa_supplicant_event(ctx, EVENT_ASSOC, &event); +} -const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie); -#define WPA_IE_VENDOR_TYPE 0x0050f201 -#define WPS_IE_VENDOR_TYPE 0x0050f204 -const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, - u32 vendor_type); -struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, - u32 vendor_type); -int wpa_scan_get_max_rate(const struct wpa_scan_res *res); -void wpa_scan_results_free(struct wpa_scan_results *res); -void wpa_scan_sort_results(struct wpa_scan_results *res); +static inline void drv_event_disassoc(void *ctx, const u8 *addr) +{ + union wpa_event_data event; + os_memset(&event, 0, sizeof(event)); + event.disassoc_info.addr = addr; + wpa_supplicant_event(ctx, EVENT_DISASSOC, &event); +} + +static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, + size_t data_len) +{ + union wpa_event_data event; + os_memset(&event, 0, sizeof(event)); + event.eapol_rx.src = src; + event.eapol_rx.data = data; + event.eapol_rx.data_len = data_len; + wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event); +} #endif /* DRIVER_H */ diff --git a/hostapd/driver_atheros.c b/src/drivers/driver_atheros.c similarity index 67% rename from hostapd/driver_atheros.c rename to src/drivers/driver_atheros.c index 558a8bbf2b47..5c25f00b1643 100644 --- a/hostapd/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -28,44 +28,32 @@ #endif #endif /* _BYTE_ORDER */ -#include -#include -#include - /* * Note, the ATH_WPS_IE setting must match with the driver build.. If the * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail. */ #define ATH_WPS_IE -#include + +#include "os/linux/include/ieee80211_external.h" + #ifdef CONFIG_WPS -#ifdef IEEE80211_IOCTL_FILTERFRAME #include #ifndef ETH_P_80211_RAW #define ETH_P_80211_RAW 0x0019 #endif -#endif /* IEEE80211_IOCTL_FILTERFRAME */ #endif /* CONFIG_WPS */ -/* - * Avoid conflicts with hostapd definitions by undefining couple of defines - * from madwifi header files. - */ -#undef WPA_OUI_TYPE -#undef WME_OUI_TYPE - #include "wireless_copy.h" -#include "hostapd.h" #include "driver.h" #include "eloop.h" #include "priv_netlink.h" #include "l2_packet/l2_packet.h" - -#include "wps_hostapd.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" +#include "netlink.h" +#include "linux_ioctl.h" struct madwifi_driver_data { @@ -76,7 +64,7 @@ struct madwifi_driver_data { struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ struct l2_packet_data *sock_recv; /* raw packet recv socket */ int ioctl_sock; /* socket for ioctl() use */ - int wext_sock; /* socket for wireless events */ + struct netlink_data *netlink; int we_version; u8 acct_mac[ETH_ALEN]; struct hostap_sta_driver_data acct_data; @@ -84,127 +72,112 @@ struct madwifi_driver_data { struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ }; -static int madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code); +static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code); +static int madwifi_set_privacy(void *priv, int enabled); -/* hostapd 0.7.x compatibility - START */ -#include "ieee802_1x.h" -#include "sta_info.h" -#include "wpa.h" -#include "radius/radius.h" -#include "ieee802_11.h" -#include "accounting.h" - -static int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ielen) +static const char * athr_get_ioctl_name(int op) { - struct sta_info *sta; - int new_assoc, res; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "associated"); - - sta = ap_get_sta(hapd, addr); - if (sta) { - accounting_sta_stop(hapd, sta); - } else { - sta = ap_sta_add(hapd, addr); - if (sta == NULL) - return -1; + switch (op) { + case IEEE80211_IOCTL_SETPARAM: + return "SETPARAM"; + case IEEE80211_IOCTL_GETPARAM: + return "GETPARAM"; + case IEEE80211_IOCTL_SETKEY: + return "SETKEY"; + case IEEE80211_IOCTL_SETWMMPARAMS: + return "SETWMMPARAMS"; + case IEEE80211_IOCTL_DELKEY: + return "DELKEY"; + case IEEE80211_IOCTL_GETWMMPARAMS: + return "GETWMMPARAMS"; + case IEEE80211_IOCTL_SETMLME: + return "SETMLME"; + case IEEE80211_IOCTL_GETCHANINFO: + return "GETCHANINFO"; + case IEEE80211_IOCTL_SETOPTIE: + return "SETOPTIE"; + case IEEE80211_IOCTL_GETOPTIE: + return "GETOPTIE"; + case IEEE80211_IOCTL_ADDMAC: + return "ADDMAC"; + case IEEE80211_IOCTL_DELMAC: + return "DELMAC"; + case IEEE80211_IOCTL_GETCHANLIST: + return "GETCHANLIST"; + case IEEE80211_IOCTL_SETCHANLIST: + return "SETCHANLIST"; + case IEEE80211_IOCTL_KICKMAC: + return "KICKMAC"; + case IEEE80211_IOCTL_CHANSWITCH: + return "CHANSWITCH"; + case IEEE80211_IOCTL_GETMODE: + return "GETMODE"; + case IEEE80211_IOCTL_SETMODE: + return "SETMODE"; + case IEEE80211_IOCTL_GET_APPIEBUF: + return "GET_APPIEBUF"; + case IEEE80211_IOCTL_SET_APPIEBUF: + return "SET_APPIEBUF"; + case IEEE80211_IOCTL_SET_ACPARAMS: + return "SET_ACPARAMS"; + case IEEE80211_IOCTL_FILTERFRAME: + return "FILTERFRAME"; + case IEEE80211_IOCTL_SET_RTPARAMS: + return "SET_RTPARAMS"; + case IEEE80211_IOCTL_SENDADDBA: + return "SENDADDBA"; + case IEEE80211_IOCTL_GETADDBASTATUS: + return "GETADDBASTATUS"; + case IEEE80211_IOCTL_SENDDELBA: + return "SENDDELBA"; + case IEEE80211_IOCTL_SET_MEDENYENTRY: + return "SET_MEDENYENTRY"; + case IEEE80211_IOCTL_SET_ADDBARESP: + return "SET_ADDBARESP"; + case IEEE80211_IOCTL_GET_MACADDR: + return "GET_MACADDR"; + case IEEE80211_IOCTL_SET_HBRPARAMS: + return "SET_HBRPARAMS"; + case IEEE80211_IOCTL_SET_RXTIMEOUT: + return "SET_RXTIMEOUT"; + case IEEE80211_IOCTL_STA_STATS: + return "STA_STATS"; + case IEEE80211_IOCTL_GETWPAIE: + return "GETWPAIE"; + default: + return "??"; } - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); +} - if (hapd->conf->wpa) { - if (ie == NULL || ielen == 0) { - if (hapd->conf->wps_state) { - wpa_printf(MSG_DEBUG, "STA did not include " - "WPA/RSN IE in (Re)Association " - "Request - possible WPS use"); - sta->flags |= WLAN_STA_MAYBE_WPS; - goto skip_wpa_check; - } - wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); - return -1; - } - if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && - os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { - sta->flags |= WLAN_STA_WPS; - goto skip_wpa_check; - } - - 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_ERROR, "Failed to initialize WPA state " - "machine"); - return -1; - } - res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, - ie, ielen, NULL, 0); - if (res != WPA_IE_OK) { - wpa_printf(MSG_DEBUG, "WPA/RSN information element " - "rejected? (res %u)", res); - wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); - return -1; - } - } else if (hapd->conf->wps_state) { - if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && - os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { - sta->flags |= WLAN_STA_WPS; - } else - sta->flags |= WLAN_STA_MAYBE_WPS; +static const char * athr_get_param_name(int op) +{ + switch (op) { + case IEEE80211_IOC_MCASTCIPHER: + return "MCASTCIPHER"; + case IEEE80211_PARAM_MCASTKEYLEN: + return "MCASTKEYLEN"; + case IEEE80211_PARAM_UCASTCIPHERS: + return "UCASTCIPHERS"; + case IEEE80211_PARAM_KEYMGTALGS: + return "KEYMGTALGS"; + case IEEE80211_PARAM_RSNCAPS: + return "RSNCAPS"; + case IEEE80211_PARAM_WPA: + return "WPA"; + case IEEE80211_PARAM_AUTHMODE: + return "AUTHMODE"; + case IEEE80211_PARAM_PRIVACY: + return "PRIVACY"; + case IEEE80211_PARAM_COUNTERMEASURES: + return "COUNTERMEASURES"; + default: + return "??"; } -skip_wpa_check: - - new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); - - hostapd_new_assoc_sta(hapd, sta, !new_assoc); - - ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - - return 0; } -static void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta; - - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated"); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Disassociation notification for " - "unknown STA " MACSTR, MAC2STR(addr)); - return; - } - - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); -} - - -static void hostapd_eapol_receive(struct hostapd_data *hapd, const u8 *sa, - const u8 *buf, size_t len) -{ - ieee802_1x_receive(hapd, sa, buf, len); -} - - -static void hostapd_michael_mic_failure(struct hostapd_data *hapd, - const u8 *addr) -{ - ieee80211_michael_mic_failure(hapd, addr, 1); -} -/* hostapd 0.7.x compatibility - END */ - static int set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) { @@ -234,40 +207,11 @@ set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) } if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { - int first = IEEE80211_IOCTL_SETPARAM; - static const char *opnames[] = { - "ioctl[IEEE80211_IOCTL_SETPARAM]", - "ioctl[IEEE80211_IOCTL_GETPARAM]", - "ioctl[IEEE80211_IOCTL_SETKEY]", - "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]", - "ioctl[IEEE80211_IOCTL_DELKEY]", - "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]", - "ioctl[IEEE80211_IOCTL_SETMLME]", - "ioctl[IEEE80211_IOCTL_GETCHANINFO]", - "ioctl[IEEE80211_IOCTL_SETOPTIE]", - "ioctl[IEEE80211_IOCTL_GETOPTIE]", - "ioctl[IEEE80211_IOCTL_ADDMAC]", - "ioctl[IEEE80211_IOCTL_DELMAC]", - "ioctl[IEEE80211_IOCTL_GETCHANLIST]", - "ioctl[IEEE80211_IOCTL_SETCHANLIST]", - "ioctl[IEEE80211_IOCTL_KICKMAC]", - "ioctl[IEEE80211_IOCTL_CHANSWITCH]", - "ioctl[IEEE80211_IOCTL_GETMODE]", - "ioctl[IEEE80211_IOCTL_SETMODE]", - "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]", - "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", - NULL, - "ioctl[IEEE80211_IOCTL_FILTERFRAME]", - }; - int idx = op - first; - if (first <= op && - idx < (int) (sizeof(opnames) / sizeof(opnames[0])) && - opnames[idx]) - perror(opnames[idx]); - else { - perror("ioctl[unknown???]"); - wpa_printf(MSG_DEBUG, "Failed ioctl: 0x%x", op); - } + wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x " + "(%s) len=%d failed: %d (%s)", + __func__, drv->iface, op, + athr_get_ioctl_name(op), + len, errno, strerror(errno)); return -1; } return 0; @@ -285,8 +229,9 @@ set80211param(struct madwifi_driver_data *drv, int op, int arg) if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); - wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d " - "arg %d)", __func__, op, arg); + wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d " + "(%s) arg %d)", __func__, drv->iface, op, + athr_get_param_name(op), arg); return -1; } return 0; @@ -310,13 +255,12 @@ ether_sprintf(const u8 *addr) * Configure WPA parameters. */ static int -madwifi_configure_wpa(struct madwifi_driver_data *drv) +madwifi_configure_wpa(struct madwifi_driver_data *drv, + struct wpa_bss_params *params) { - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; int v; - switch (conf->wpa_group) { + switch (params->wpa_group) { case WPA_CIPHER_CCMP: v = IEEE80211_CIPHER_AES_CCM; break; @@ -334,7 +278,7 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv) break; default: wpa_printf(MSG_ERROR, "Unknown group key cipher %u", - conf->wpa_group); + params->wpa_group); return -1; } wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); @@ -344,7 +288,7 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv) } if (v == IEEE80211_CIPHER_WEP) { /* key length is done only for specific ciphers */ - v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); + v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { printf("Unable to set group key length to %u\n", v); return -1; @@ -352,11 +296,11 @@ madwifi_configure_wpa(struct madwifi_driver_data *drv) } v = 0; - if (conf->wpa_pairwise & WPA_CIPHER_CCMP) + if (params->wpa_pairwise & WPA_CIPHER_CCMP) v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) + if (params->wpa_pairwise & WPA_CIPHER_TKIP) v |= 1<wpa_pairwise & WPA_CIPHER_NONE) + if (params->wpa_pairwise & WPA_CIPHER_NONE) v |= 1<wpa_key_mgmt); - if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, conf->wpa_key_mgmt)) { + __func__, params->wpa_key_mgmt); + if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, + params->wpa_key_mgmt)) { printf("Unable to set key management algorithms to 0x%x\n", - conf->wpa_key_mgmt); + params->wpa_key_mgmt); return -1; } v = 0; - if (conf->rsn_preauth) + if (params->rsn_preauth) v |= BIT(0); wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", - __func__, conf->rsn_preauth); + __func__, params->rsn_preauth); if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { printf("Unable to set RSN capabilities to 0x%x\n", v); return -1; } - wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, conf->wpa); - if (set80211param(drv, IEEE80211_PARAM_WPA, conf->wpa)) { - printf("Unable to set WPA to %u\n", conf->wpa); + wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); + if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { + printf("Unable to set WPA to %u\n", params->wpa); return -1; } return 0; } - static int -madwifi_set_iface_flags(void *priv, int dev_up) +madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) { struct madwifi_driver_data *drv = priv; - struct ifreq ifr; - wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up); + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); - if (drv->ioctl_sock < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - if (dev_up) { - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - ifr.ifr_mtu = HOSTAPD_MTU; - if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { - perror("ioctl[SIOCSIFMTU]"); - printf("Setting MTU failed - trying to survive with " - "current value\n"); - } - } - - return 0; -} - -static int -madwifi_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct madwifi_driver_data *drv = priv; - struct hostapd_data *hapd = drv->hapd; - struct hostapd_bss_config *conf = hapd->conf; - - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - - if (!enabled) { + if (!params->enabled) { /* XXX restore state */ - return set80211param(priv, IEEE80211_PARAM_AUTHMODE, - IEEE80211_AUTH_AUTO); + if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, + IEEE80211_AUTH_AUTO) < 0) + return -1; + /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ + return madwifi_set_privacy(drv, 0); } - if (!conf->wpa && !conf->ieee802_1x) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, + if (!params->wpa && !params->ieee802_1x) { + hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); return -1; } - if (conf->wpa && madwifi_configure_wpa(drv) != 0) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, + if (params->wpa && madwifi_configure_wpa(drv, params) != 0) { + hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); return -1; } if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, - (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, + (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { + hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); return -1; } @@ -469,7 +371,7 @@ madwifi_set_ieee8021x(const char *ifname, void *priv, int enabled) } static int -madwifi_set_privacy(const char *ifname, void *priv, int enabled) +madwifi_set_privacy(void *priv, int enabled) { struct madwifi_driver_data *drv = priv; @@ -504,13 +406,13 @@ madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) } static int -madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags, - int flags_or, int flags_and) +madwifi_sta_set_flags(void *priv, const u8 *addr, + int total_flags, int flags_or, int flags_and) { /* For now, only support setting Authorized flag */ - if (flags_or & WLAN_STA_AUTHORIZED) + if (flags_or & WPA_STA_AUTHORIZED) return madwifi_set_sta_authorized(priv, addr, 1); - if (!(flags_and & WLAN_STA_AUTHORIZED)) + if (!(flags_and & WPA_STA_AUTHORIZED)) return madwifi_set_sta_authorized(priv, addr, 0); return 0; } @@ -544,29 +446,33 @@ madwifi_del_key(void *priv, const u8 *addr, int key_idx) } static int -madwifi_set_key(const char *ifname, void *priv, const char *alg, - const u8 *addr, int key_idx, - const u8 *key, size_t key_len, int txkey) +madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, + const u8 *addr, int key_idx, int set_tx, const u8 *seq, + size_t seq_len, const u8 *key, size_t key_len) { struct madwifi_driver_data *drv = priv; struct ieee80211req_key wk; u_int8_t cipher; int ret; - if (strcmp(alg, "none") == 0) + if (alg == WPA_ALG_NONE) return madwifi_del_key(drv, addr, key_idx); - wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d", + wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", __func__, alg, ether_sprintf(addr), key_idx); - if (strcmp(alg, "WEP") == 0) + switch (alg) { + case WPA_ALG_WEP: cipher = IEEE80211_CIPHER_WEP; - else if (strcmp(alg, "TKIP") == 0) + break; + case WPA_ALG_TKIP: cipher = IEEE80211_CIPHER_TKIP; - else if (strcmp(alg, "CCMP") == 0) + break; + case WPA_ALG_CCMP: cipher = IEEE80211_CIPHER_AES_CCM; - else { - printf("%s: unknown/unsupported algorithm %s\n", + break; + default: + printf("%s: unknown/unsupported algorithm %d\n", __func__, alg); return -1; } @@ -594,9 +500,9 @@ madwifi_set_key(const char *ifname, void *priv, const char *alg, ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); if (ret < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" - " key_idx %d alg '%s' key_len %lu txkey %d)", + " key_idx %d alg %d key_len %lu set_tx %d)", __func__, ether_sprintf(wk.ik_macaddr), key_idx, - alg, (unsigned long) key_len, txkey); + alg, (unsigned long) key_len, set_tx); } return ret; @@ -634,6 +540,9 @@ madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, * swap it to match with the byte order used in WPA. */ int i; +#ifndef WPA_KEY_RSC_LEN +#define WPA_KEY_RSC_LEN 8 +#endif u8 tmp[WPA_KEY_RSC_LEN]; memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); for (i = 0; i < WPA_KEY_RSC_LEN; i++) { @@ -652,7 +561,8 @@ madwifi_flush(void *priv) { u8 allsta[IEEE80211_ADDR_LEN]; memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return madwifi_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE); + return madwifi_sta_deauth(priv, NULL, allsta, + IEEE80211_REASON_AUTH_LEAVE); } @@ -714,7 +624,7 @@ madwifi_sta_clear_stats(void *priv, const u8 *addr) static int -madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len) +madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) { /* * Do nothing; we setup parameters at startup that define the @@ -724,7 +634,8 @@ madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len) } static int -madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code) +madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code) { struct madwifi_driver_data *drv = priv; struct ieee80211req_mlme mlme; @@ -747,7 +658,8 @@ madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code) } static int -madwifi_sta_disassoc(void *priv, const u8 *addr, int reason_code) +madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code) { struct madwifi_driver_data *drv = priv; struct ieee80211req_mlme mlme; @@ -775,9 +687,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, { struct madwifi_driver_data *drv = ctx; const struct ieee80211_mgmt *mgmt; - const u8 *end, *ie; u16 fc; - size_t ie_len; + union wpa_event_data event; /* Send Probe Request information to WPS processing */ @@ -790,11 +701,12 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) return; - end = buf + len; - ie = mgmt->u.probe_req.variable; - ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); - - hostapd_wps_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len); + os_memset(&event, 0, sizeof(event)); + event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.ie = mgmt->u.probe_req.variable; + event.rx_probe_req.ie_len = + len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); + wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); } #endif /* CONFIG_WPS */ @@ -841,30 +753,28 @@ madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) } static int -madwifi_set_wps_beacon_ie(const char *ifname, void *priv, const u8 *ie, - size_t len) +madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp) { - return madwifi_set_wps_ie(priv, ie, len, IEEE80211_APPIE_FRAME_BEACON); -} - -static int -madwifi_set_wps_probe_resp_ie(const char *ifname, void *priv, const u8 *ie, - size_t len) -{ - return madwifi_set_wps_ie(priv, ie, len, + if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, + beacon ? wpabuf_len(beacon) : 0, + IEEE80211_APPIE_FRAME_BEACON)) + return -1; + return madwifi_set_wps_ie(priv, + proberesp ? wpabuf_head(proberesp) : NULL, + proberesp ? wpabuf_len(proberesp): 0, IEEE80211_APPIE_FRAME_PROBE_RESP); } #else /* CONFIG_WPS */ -#define madwifi_set_wps_beacon_ie NULL -#define madwifi_set_wps_probe_resp_ie NULL +#define madwifi_set_ap_wps_ie NULL #endif /* CONFIG_WPS */ -static int +static void madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct ieee80211req_wpaie ie; - int ielen = 0, res; + int ielen = 0; u8 *iebuf = NULL; /* @@ -905,15 +815,13 @@ madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) ielen += 2; no_ie: - res = hostapd_notif_assoc(hapd, addr, iebuf, ielen); + drv_event_assoc(hapd, addr, iebuf, ielen); if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { /* Cached accounting data is not valid anymore. */ memset(drv->acct_mac, 0, ETH_ALEN); memset(&drv->acct_data, 0, sizeof(drv->acct_data)); } - - return res; } static void @@ -934,7 +842,12 @@ madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, } pos += 5; if (hwaddr_aton(pos, addr) == 0) { - hostapd_michael_mic_failure(drv->hapd, addr); + union wpa_event_data data; + os_memset(&data, 0, sizeof(data)); + data.michael_mic_failure.unicast = 1; + data.michael_mic_failure.src = addr; + wpa_supplicant_event(drv->hapd, + EVENT_MICHAEL_MIC_FAILURE, &data); } else { wpa_printf(MSG_DEBUG, "MLME-MICHAELMICFAILURE.indication " @@ -969,7 +882,7 @@ madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, /* PROBLEM! this event is received for ALL BSSs ... * so all are enabled for WPS... ugh. */ - hostapd_wps_button_pushed(drv->hapd); + wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { /* * Atheros driver uses a hack to pass Probe Request frames as a @@ -1026,8 +939,8 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, switch (iwe->cmd) { case IWEVEXPIRED: - hostapd_notif_disassoc(drv->hapd, - (u8 *) iwe->u.addr.sa_data); + drv_event_disassoc(drv->hapd, + (u8 *) iwe->u.addr.sa_data); break; case IWEVREGISTERED: madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data); @@ -1057,28 +970,18 @@ madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, static void -madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv, - struct nlmsghdr *h, int len) +madwifi_wireless_event_rtm_newlink(void *ctx, + struct ifinfomsg *ifi, u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; - - if (len < (int) sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); + struct madwifi_driver_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; if (ifi->ifi_index != drv->ifindex) return; - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { @@ -1092,55 +995,6 @@ madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv, } -static void -madwifi_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx) -{ - char buf[256]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - struct madwifi_driver_data *drv = eloop_ctx; - - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - printf("Malformed netlink message: " - "len=%d left=%d plen=%d\n", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - madwifi_wireless_event_rtm_newlink(drv, h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - printf("%d extra bytes in the end of netlink message\n", left); - } -} - - static int madwifi_get_we_version(struct madwifi_driver_data *drv) { @@ -1188,52 +1042,27 @@ madwifi_get_we_version(struct madwifi_driver_data *drv) static int -madwifi_wireless_event_init(void *priv) +madwifi_wireless_event_init(struct madwifi_driver_data *drv) { - struct madwifi_driver_data *drv = priv; - int s; - struct sockaddr_nl local; + struct netlink_config *cfg; madwifi_get_we_version(drv); - drv->wext_sock = -1; - - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + return -1; + cfg->ctx = drv; + cfg->newlink_cb = madwifi_wireless_event_rtm_newlink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); return -1; } - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - eloop_register_read_sock(s, madwifi_wireless_event_receive, drv, NULL); - drv->wext_sock = s; - return 0; } -static void -madwifi_wireless_event_deinit(void *priv) -{ - struct madwifi_driver_data *drv = priv; - - if (drv != NULL) { - if (drv->wext_sock < 0) - return; - eloop_unregister_read_sock(drv->wext_sock); - close(drv->wext_sock); - } -} - - static int madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, const u8 *own_addr) @@ -1279,17 +1108,17 @@ static void handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct madwifi_driver_data *drv = ctx; - hostapd_eapol_receive(drv->hapd, src_addr, - buf + sizeof(struct l2_ethhdr), - len - sizeof(struct l2_ethhdr)); + drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), + len - sizeof(struct l2_ethhdr)); } static void * -madwifi_init(struct hostapd_data *hapd) +madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) { struct madwifi_driver_data *drv; struct ifreq ifr; struct iwreq iwr; + char brname[IFNAMSIZ]; drv = os_zalloc(sizeof(struct madwifi_driver_data)); if (drv == NULL) { @@ -1303,7 +1132,7 @@ madwifi_init(struct hostapd_data *hapd) perror("socket[PF_INET,SOCK_DGRAM]"); goto bad; } - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); + memcpy(drv->iface, params->ifname, sizeof(drv->iface)); memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); @@ -1317,16 +1146,23 @@ madwifi_init(struct hostapd_data *hapd) handle_read, drv, 1); if (drv->sock_xmit == NULL) goto bad; - if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr)) + if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) goto bad; - if (hapd->conf->bridge[0] != '\0') { + if (params->bridge[0]) { wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", - hapd->conf->bridge); - drv->sock_recv = l2_packet_init(hapd->conf->bridge, NULL, + params->bridge[0]); + drv->sock_recv = l2_packet_init(params->bridge[0], NULL, ETH_P_EAPOL, handle_read, drv, 1); if (drv->sock_recv == NULL) goto bad; + } else if (linux_br_get(brname, drv->iface) == 0) { + wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " + "EAPOL receive", brname); + drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, + handle_read, drv, 1); + if (drv->sock_recv == NULL) + goto bad; } else drv->sock_recv = drv->sock_xmit; @@ -1341,13 +1177,19 @@ madwifi_init(struct hostapd_data *hapd) goto bad; } - madwifi_set_iface_flags(drv, 0); /* mark down during setup */ - madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */ + /* mark down during setup */ + linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); + madwifi_set_privacy(drv, 0); /* default to no privacy */ madwifi_receive_probe_req(drv); + if (madwifi_wireless_event_init(drv)) + goto bad; + return drv; bad: + if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) + l2_packet_deinit(drv->sock_recv); if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); if (drv->ioctl_sock >= 0) @@ -1363,7 +1205,8 @@ madwifi_deinit(void *priv) { struct madwifi_driver_data *drv = priv; - (void) madwifi_set_iface_flags(drv, 0); + netlink_deinit(drv->netlink); + (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); if (drv->ioctl_sock >= 0) close(drv->ioctl_sock); if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) @@ -1376,7 +1219,7 @@ madwifi_deinit(void *priv) } static int -madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len) +madwifi_set_ssid(void *priv, const u8 *buf, int len) { struct madwifi_driver_data *drv = priv; struct iwreq iwr; @@ -1396,7 +1239,7 @@ madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len) } static int -madwifi_get_ssid(const char *ifname, void *priv, u8 *buf, int len) +madwifi_get_ssid(void *priv, u8 *buf, int len) { struct madwifi_driver_data *drv = priv; struct iwreq iwr; @@ -1427,31 +1270,29 @@ madwifi_set_countermeasures(void *priv, int enabled) static int madwifi_commit(void *priv) { - return madwifi_set_iface_flags(priv, 1); + struct madwifi_driver_data *drv = priv; + return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); } const struct wpa_driver_ops wpa_driver_atheros_ops = { .name = "atheros", - .init = madwifi_init, - .deinit = madwifi_deinit, + .hapd_init = madwifi_init, + .hapd_deinit = madwifi_deinit, .set_ieee8021x = madwifi_set_ieee8021x, .set_privacy = madwifi_set_privacy, - .set_encryption = madwifi_set_key, + .set_key = madwifi_set_key, .get_seqnum = madwifi_get_seqnum, .flush = madwifi_flush, .set_generic_elem = madwifi_set_opt_ie, - .wireless_event_init = madwifi_wireless_event_init, - .wireless_event_deinit = madwifi_wireless_event_deinit, .sta_set_flags = madwifi_sta_set_flags, .read_sta_data = madwifi_read_sta_driver_data, - .send_eapol = madwifi_send_eapol, + .hapd_send_eapol = madwifi_send_eapol, .sta_disassoc = madwifi_sta_disassoc, .sta_deauth = madwifi_sta_deauth, - .set_ssid = madwifi_set_ssid, - .get_ssid = madwifi_get_ssid, + .hapd_set_ssid = madwifi_set_ssid, + .hapd_get_ssid = madwifi_get_ssid, .set_countermeasures = madwifi_set_countermeasures, .sta_clear_stats = madwifi_sta_clear_stats, .commit = madwifi_commit, - .set_wps_beacon_ie = madwifi_set_wps_beacon_ie, - .set_wps_probe_resp_ie = madwifi_set_wps_probe_resp_ie, + .set_ap_wps_ie = madwifi_set_ap_wps_ie, }; diff --git a/src/drivers/driver_atmel.c b/src/drivers/driver_atmel.c index 0a7a66ddb5f2..cbec6c38d78d 100644 --- a/src/drivers/driver_atmel.c +++ b/src/drivers/driver_atmel.c @@ -188,9 +188,10 @@ static int wpa_driver_atmel_set_wpa(void *priv, int enabled) } -static int wpa_driver_atmel_set_key(void *priv, wpa_alg alg, - const u8 *addr, int key_idx, - int set_tx, const u8 *seq, size_t seq_len, +static int wpa_driver_atmel_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct wpa_driver_atmel_data *drv = priv; @@ -273,16 +274,6 @@ static int wpa_driver_atmel_set_countermeasures(void *priv, } -static int wpa_driver_atmel_set_drop_unencrypted(void *priv, - int enabled) -{ - /* FIX */ - printf("wpa_driver_atmel_set_drop_unencrypted - not yet " - "implemented\n"); - return 0; -} - - static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd, int reason_code) { @@ -347,7 +338,7 @@ static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr, #if 0 /* Atmel driver uses specific values for each cipher suite */ -static int convertSuiteToDriver(wpa_cipher suite) +static int convertSuiteToDriver(enum wpa_cipher suite) { u8 suite_type; @@ -430,10 +421,11 @@ static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid) } -static int wpa_driver_atmel_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_atmel_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_atmel_data *drv = priv; - return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); + return wpa_driver_wext_scan(drv->wext, params); } @@ -473,6 +465,8 @@ static void * wpa_driver_atmel_init(void *ctx, const char *ifname) return NULL; } + wpa_driver_atmel_set_wpa(drv, 1); + return drv; } @@ -480,6 +474,7 @@ static void * wpa_driver_atmel_init(void *ctx, const char *ifname) static void wpa_driver_atmel_deinit(void *priv) { struct wpa_driver_atmel_data *drv = priv; + wpa_driver_atmel_set_wpa(drv, 0); wpa_driver_wext_deinit(drv->wext); close(drv->sock); os_free(drv); @@ -491,13 +486,11 @@ const struct wpa_driver_ops wpa_driver_atmel_ops = { .desc = "ATMEL AT76C5XXx (USB, PCMCIA)", .get_bssid = wpa_driver_atmel_get_bssid, .get_ssid = wpa_driver_atmel_get_ssid, - .set_wpa = wpa_driver_atmel_set_wpa, .set_key = wpa_driver_atmel_set_key, .init = wpa_driver_atmel_init, .deinit = wpa_driver_atmel_deinit, .set_countermeasures = wpa_driver_atmel_set_countermeasures, - .set_drop_unencrypted = wpa_driver_atmel_set_drop_unencrypted, - .scan = wpa_driver_atmel_scan, + .scan2 = wpa_driver_atmel_scan, .get_scan_results2 = wpa_driver_atmel_get_scan_results, .deauthenticate = wpa_driver_atmel_deauthenticate, .disassociate = wpa_driver_atmel_disassociate, diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c index 3600dae11046..cb88543c2c36 100644 --- a/src/drivers/driver_broadcom.c +++ b/src/drivers/driver_broadcom.c @@ -162,7 +162,8 @@ static int wpa_driver_broadcom_set_wpa(void *priv, int enable) return 0; } -static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg, +static int wpa_driver_broadcom_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -232,7 +233,8 @@ static void wpa_driver_broadcom_event_receive(int sock, void *ctx, int left; wl_wpa_header_t *wwh; union wpa_event_data data; - + u8 *resp_ies = NULL; + if ((left = recv(sock, buf, sizeof buf, 0)) < 0) return; @@ -256,21 +258,16 @@ static void wpa_driver_broadcom_event_receive(int sock, void *ctx, wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)", left); if (left > 0) { - data.assoc_info.resp_ies = os_malloc(left); - if (data.assoc_info.resp_ies == NULL) + resp_ies = os_malloc(left); + if (resp_ies == NULL) return; - os_memcpy(data.assoc_info.resp_ies, - buf + WL_WPA_HEADER_LEN, left); + os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left); + data.assoc_info.resp_ies = resp_ies; data.assoc_info.resp_ies_len = left; - wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes " - "into resp_ies", - data.assoc_info.resp_ies, left); } - /* data.assoc_info.req_ies = NULL; */ - /* data.assoc_info.req_ies_len = 0; */ - wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); + wpa_supplicant_event(ctx, EVENT_ASSOC, &data); + os_free(resp_ies); break; case WLC_DISASSOC_MSG: wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE"); @@ -291,7 +288,6 @@ static void wpa_driver_broadcom_event_receive(int sock, void *ctx, wwh->type); break; } - os_free(data.assoc_info.resp_ies); } static void * wpa_driver_broadcom_init(void *ctx, const char *ifname) @@ -348,6 +344,7 @@ static void * wpa_driver_broadcom_init(void *ctx, const char *ifname) eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx, NULL); drv->event_sock = s; + wpa_driver_broadcom_set_wpa(drv, 1); return drv; } @@ -355,6 +352,7 @@ static void * wpa_driver_broadcom_init(void *ctx, const char *ifname) static void wpa_driver_broadcom_deinit(void *priv) { struct wpa_driver_broadcom_data *drv = priv; + wpa_driver_broadcom_set_wpa(drv, 0); eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx); eloop_unregister_read_sock(drv->event_sock); close(drv->event_sock); @@ -379,12 +377,12 @@ static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled) { struct wpa_driver_broadcom_data *drv = priv; /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */ - int restrict = (enabled ? 1 : 0); + int _restrict = (enabled ? 1 : 0); if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, - &restrict, sizeof(restrict)) < 0 || + &_restrict, sizeof(_restrict)) < 0 || broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT, - &restrict, sizeof(restrict)) < 0) + &_restrict, sizeof(_restrict)) < 0) return -1; return 0; @@ -397,11 +395,13 @@ static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx, wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } -static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid, - size_t ssid_len) +static int wpa_driver_broadcom_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_broadcom_data *drv = priv; wlc_ssid_t wst = { 0, "" }; + const u8 *ssid = params->ssids[0].ssid; + size_t ssid_len = params->ssids[0].ssid_len; if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) { wst.SSID_len = ssid_len; @@ -431,20 +431,19 @@ struct bss_ie_hdr { /* u16 version; */ } __attribute__ ((packed)); -static int -wpa_driver_broadcom_get_scan_results(void *priv, - struct wpa_scan_result *results, - size_t max_size) +static struct wpa_scan_results * +wpa_driver_broadcom_get_scan_results(void *priv) { struct wpa_driver_broadcom_data *drv = priv; char *buf; wl_scan_results_t *wsr; wl_bss_info_t *wbi; size_t ap_num; + struct wpa_scan_results *res; buf = os_malloc(WLC_IOCTL_MAXLEN); if (buf == NULL) - return -1; + return NULL; wsr = (wl_scan_results_t *) buf; @@ -454,40 +453,34 @@ wpa_driver_broadcom_get_scan_results(void *priv, if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) { os_free(buf); - return -1; + return NULL; } - os_memset(results, 0, max_size * sizeof(struct wpa_scan_result)); + res = os_zalloc(sizeof(*res)); + if (res == NULL) { + os_free(buf); + return NULL; + } + + res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *)); + if (res->res == NULL) { + os_free(res); + os_free(buf); + return NULL; + } for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) { - int left; - struct bss_ie_hdr *ie; - - os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN); - os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len); - results[ap_num].ssid_len = wbi->SSID_len; - results[ap_num].freq = frequency_list[wbi->channel - 1]; - /* get ie's */ - wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs", - (u8 *) wbi + sizeof(*wbi), wbi->ie_length); - ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi)); - for (left = wbi->ie_length; left > 0; - left -= (ie->len + 2), ie = (struct bss_ie_hdr *) - ((u8 *) ie + 2 + ie->len)) { - wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d", - ie->elem_id, ie->len); - if (ie->len >= 3) - wpa_printf(MSG_MSGDUMP, - "BROADCOM: oui:%02x%02x%02x", - ie->oui[0], ie->oui[1], ie->oui[2]); - if (ie->elem_id != 0xdd || - ie->len < 6 || - os_memcmp(ie->oui, WPA_OUI, 3) != 0) - continue; - os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2); - results[ap_num].wpa_ie_len = ie->len + 2; + struct wpa_scan_res *r; + r = os_malloc(sizeof(*r) + wbi->ie_length); + if (r == NULL) break; - } + res->res[res->num++] = r; + + os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN); + r->freq = frequency_list[wbi->channel - 1]; + /* get ie's */ + os_memcpy(r + 1, wbi + 1, wbi->ie_length); + r->ie_len = wbi->ie_length; wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length); } @@ -497,8 +490,8 @@ wpa_driver_broadcom_get_scan_results(void *priv, wsr->buflen, (unsigned long) ap_num); os_free(buf); - return ap_num; -} + return res; + } static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr, int reason_code) @@ -516,7 +509,7 @@ static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr, int reason_code) { struct wpa_driver_broadcom_data *drv = priv; - return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0); + return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0); } static int @@ -530,7 +523,11 @@ wpa_driver_broadcom_associate(void *priv, int wsec = 4; int dummy; int wpa_auth; - + int ret; + + ret = wpa_driver_broadcom_set_drop_unencrypted( + drv, params->drop_unencrypted); + s.SSID_len = params->ssid_len; os_memcpy(s.SSID, params->ssid, params->ssid_len); @@ -582,7 +579,7 @@ wpa_driver_broadcom_associate(void *priv, broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0) return -1; - return 0; + return ret; } const struct wpa_driver_ops wpa_driver_broadcom_ops = { @@ -590,14 +587,12 @@ const struct wpa_driver_ops wpa_driver_broadcom_ops = { .desc = "Broadcom wl.o driver", .get_bssid = wpa_driver_broadcom_get_bssid, .get_ssid = wpa_driver_broadcom_get_ssid, - .set_wpa = wpa_driver_broadcom_set_wpa, .set_key = wpa_driver_broadcom_set_key, .init = wpa_driver_broadcom_init, .deinit = wpa_driver_broadcom_deinit, .set_countermeasures = wpa_driver_broadcom_set_countermeasures, - .set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted, - .scan = wpa_driver_broadcom_scan, - .get_scan_results = wpa_driver_broadcom_get_scan_results, + .scan2 = wpa_driver_broadcom_scan, + .get_scan_results2 = wpa_driver_broadcom_get_scan_results, .deauthenticate = wpa_driver_broadcom_deauthenticate, .disassociate = wpa_driver_broadcom_disassociate, .associate = wpa_driver_broadcom_associate, diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index 218d913869fd..99de6c7ff48e 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -1,6 +1,7 @@ /* * WPA Supplicant - driver interaction with BSD net80211 layer * Copyright (c) 2004, Sam Leffler + * Copyright (c) 2004, 2Wire, Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,194 +19,887 @@ #include "common.h" #include "driver.h" #include "eloop.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include +#include #ifdef __NetBSD__ #include -#define COMPAT_FREEBSD_NET80211 #else #include #endif +#include +#ifdef __DragonFly__ +#include +#include +#else /* __DragonFly__ */ +#ifdef __GLIBC__ +#include +#endif /* __GLIBC__ */ #include -#include #include +#include +#endif /* __DragonFly__ || __GLIBC__ */ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include +#endif +#if __NetBSD__ +#include +#endif + +#include "l2_packet/l2_packet.h" + +struct bsd_driver_data { + struct hostapd_data *hapd; /* back pointer */ -struct wpa_driver_bsd_data { int sock; /* open socket for 802.11 ioctls */ + struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ int route; /* routing socket for events */ char ifname[IFNAMSIZ+1]; /* interface name */ unsigned int ifindex; /* interface index */ void *ctx; - int prev_roaming; /* roaming state to restore on deinit */ - int prev_privacy; /* privacy state to restore on deinit */ - int prev_wpa; /* wpa state to restore on deinit */ + struct wpa_driver_capa capa; /* driver capability */ + int is_ap; /* Access point mode */ + int prev_roaming; /* roaming state to restore on deinit */ + int prev_privacy; /* privacy state to restore on deinit */ + int prev_wpa; /* wpa state to restore on deinit */ }; +/* Generic functions for hostapd and wpa_supplicant */ + static int -set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len) +bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) { + struct bsd_driver_data *drv = priv; struct ieee80211req ireq; os_memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ); + os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); ireq.i_type = op; - ireq.i_len = arg_len; + ireq.i_val = val; ireq.i_data = (void *) arg; + ireq.i_len = arg_len; if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { - fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n", - op, arg_len, strerror(errno)); + wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " + "arg_len=%u]: %s", op, val, arg_len, + strerror(errno)); return -1; } return 0; } static int -get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len) +bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, + int arg_len) +{ + struct bsd_driver_data *drv = priv; + + os_memset(ireq, 0, sizeof(*ireq)); + os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); + ireq->i_type = op; + ireq->i_len = arg_len; + ireq->i_data = arg; + + if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { + wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " + "arg_len=%u]: %s", op, arg_len, strerror(errno)); + return -1; + } + return 0; +} + +static int +get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) { struct ieee80211req ireq; - os_memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ); - ireq.i_type = op; - ireq.i_len = arg_len; - ireq.i_data = arg; - - if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) { - fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n", - op, arg_len, strerror(errno)); + if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) return -1; - } return ireq.i_len; } static int -set80211param(struct wpa_driver_bsd_data *drv, int op, int arg) +set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) { - struct ieee80211req ireq; + return bsd_set80211(drv, op, 0, arg, arg_len); +} - os_memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ); - ireq.i_type = op; - ireq.i_val = arg; +static int +set80211param(struct bsd_driver_data *drv, int op, int arg) +{ + return bsd_set80211(drv, op, arg, NULL, 0); +} - if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { - fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n", - op, arg, strerror(errno)); +static int +bsd_get_ssid(void *priv, u8 *ssid, int len) +{ + struct bsd_driver_data *drv = priv; +#ifdef SIOCG80211NWID + struct ieee80211_nwid nwid; + struct ifreq ifr; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (void *)&nwid; + if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || + nwid.i_len > IEEE80211_NWID_LEN) + return -1; + os_memcpy(ssid, nwid.i_nwid, nwid.i_len); + return nwid.i_len; +#else + return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); +#endif +} + +static int +bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) +{ + struct bsd_driver_data *drv = priv; +#ifdef SIOCS80211NWID + struct ieee80211_nwid nwid; + struct ifreq ifr; + + os_memcpy(nwid.i_nwid, ssid, ssid_len); + nwid.i_len = ssid_len; + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (void *)&nwid; + return ioctl(drv->sock, SIOCS80211NWID, &ifr); +#else + return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); +#endif +} + +static int +bsd_get_if_media(void *priv) +{ + struct bsd_driver_data *drv = priv; + struct ifmediareq ifmr; + + os_memset(&ifmr, 0, sizeof(ifmr)); + os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); + + if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { + wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, + strerror(errno)); + return -1; + } + + return ifmr.ifm_current; +} + +static int +bsd_set_if_media(void *priv, int media) +{ + struct bsd_driver_data *drv = priv; + struct ifreq ifr; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_media = media; + + if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { + wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, + strerror(errno)); + return -1; + } + + return 0; +} + +static int +bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) +{ + int media = bsd_get_if_media(priv); + + if (media < 0) + return -1; + media &= ~mask; + media |= mode; + if (bsd_set_if_media(priv, media) < 0) + return -1; + return 0; +} + +static int +bsd_del_key(void *priv, const u8 *addr, int key_idx) +{ + struct ieee80211req_del_key wk; + + os_memset(&wk, 0, sizeof(wk)); + if (addr == NULL) { + wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); + wk.idk_keyix = key_idx; + } else { + wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, + MAC2STR(addr)); + os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); + wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ + } + + return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); +} + +static int +bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) +{ + struct ieee80211req_mlme mlme; + + os_memset(&mlme, 0, sizeof(mlme)); + mlme.im_op = op; + mlme.im_reason = reason; + os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); +} + +static int +bsd_ctrl_iface(void *priv, int enable) +{ + struct bsd_driver_data *drv = priv; + struct ifreq ifr; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + + if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { + perror("ioctl[SIOCGIFFLAGS]"); + return -1; + } + + if (enable) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; + + if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { + perror("ioctl[SIOCSIFFLAGS]"); + return -1; + } + + return 0; +} + +static int +bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, + const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, + size_t seq_len, const u8 *key, size_t key_len) +{ + struct ieee80211req_key wk; + + wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " + "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, + set_tx, seq_len, key_len); + + if (alg == WPA_ALG_NONE) { +#ifndef HOSTAPD + if (addr == NULL || + os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", + IEEE80211_ADDR_LEN) == 0) + return bsd_del_key(priv, NULL, key_idx); + else +#endif /* HOSTAPD */ + return bsd_del_key(priv, addr, key_idx); + } + + os_memset(&wk, 0, sizeof(wk)); + switch (alg) { + case WPA_ALG_WEP: + wk.ik_type = IEEE80211_CIPHER_WEP; + break; + case WPA_ALG_TKIP: + wk.ik_type = IEEE80211_CIPHER_TKIP; + break; + case WPA_ALG_CCMP: + wk.ik_type = IEEE80211_CIPHER_AES_CCM; + break; + default: + wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); + return -1; + } + + wk.ik_flags = IEEE80211_KEY_RECV; + if (set_tx) + wk.ik_flags |= IEEE80211_KEY_XMIT; + + if (addr == NULL) { + os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + wk.ik_keyix = key_idx; + } else { + os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + /* + * Deduce whether group/global or unicast key by checking + * the address (yech). Note also that we can only mark global + * keys default; doing this for a unicast key is an error. + */ + if (os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", + IEEE80211_ADDR_LEN) == 0) { + wk.ik_flags |= IEEE80211_KEY_GROUP; + wk.ik_keyix = key_idx; + } else { + wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : + key_idx; + } + } + if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) + wk.ik_flags |= IEEE80211_KEY_DEFAULT; + wk.ik_keylen = key_len; + os_memcpy(&wk.ik_keyrsc, seq, seq_len); + os_memcpy(wk.ik_keydata, key, key_len); + + return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); +} + +static int +bsd_configure_wpa(void *priv, struct wpa_bss_params *params) +{ +#ifndef IEEE80211_IOC_APPIE + static const char *ciphernames[] = + { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; + int v; + + switch (params->wpa_group) { + case WPA_CIPHER_CCMP: + v = IEEE80211_CIPHER_AES_CCM; + break; + case WPA_CIPHER_TKIP: + v = IEEE80211_CIPHER_TKIP; + break; + case WPA_CIPHER_WEP104: + v = IEEE80211_CIPHER_WEP; + break; + case WPA_CIPHER_WEP40: + v = IEEE80211_CIPHER_WEP; + break; + case WPA_CIPHER_NONE: + v = IEEE80211_CIPHER_NONE; + break; + default: + printf("Unknown group key cipher %u\n", + params->wpa_group); + return -1; + } + wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", + __func__, ciphernames[v], v); + if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { + printf("Unable to set group key cipher to %u (%s)\n", + v, ciphernames[v]); + return -1; + } + if (v == IEEE80211_CIPHER_WEP) { + /* key length is done only for specific ciphers */ + v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); + if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { + printf("Unable to set group key length to %u\n", v); + return -1; + } + } + + v = 0; + if (params->wpa_pairwise & WPA_CIPHER_CCMP) + v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) + v |= 1<wpa_pairwise & WPA_CIPHER_NONE) + v |= 1<wpa_key_mgmt); + if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, + params->wpa_key_mgmt)) { + printf("Unable to set key management algorithms to 0x%x\n", + params->wpa_key_mgmt); + return -1; + } + + v = 0; + if (params->rsn_preauth) + v |= BIT(0); + wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", + __func__, params->rsn_preauth); + if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { + printf("Unable to set RSN capabilities to 0x%x\n", v); + return -1; + } +#endif /* IEEE80211_IOC_APPIE */ + + wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); + if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { + printf("Unable to set WPA to %u\n", params->wpa); return -1; } return 0; } static int -get80211param(struct wpa_driver_bsd_data *drv, int op) +bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) +{ + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); + + if (!params->enabled) { + /* XXX restore state */ + return set80211param(priv, IEEE80211_IOC_AUTHMODE, + IEEE80211_AUTH_AUTO); + } + if (!params->wpa && !params->ieee802_1x) { + wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", + __func__); + return -1; + } + if (params->wpa && bsd_configure_wpa(priv, params) != 0) { + wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", + __func__); + return -1; + } + if (set80211param(priv, IEEE80211_IOC_AUTHMODE, + (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { + wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", + __func__); + return -1; + } + return bsd_ctrl_iface(priv, 1); +} + +static int +bsd_set_sta_authorized(void *priv, const u8 *addr, + int total_flags, int flags_or, int flags_and) +{ + int authorized = -1; + + /* For now, only support setting Authorized flag */ + if (flags_or & WPA_STA_AUTHORIZED) + authorized = 1; + if (!(flags_and & WPA_STA_AUTHORIZED)) + authorized = 0; + + if (authorized < 0) + return 0; + + return bsd_send_mlme_param(priv, authorized ? + IEEE80211_MLME_AUTHORIZE : + IEEE80211_MLME_UNAUTHORIZE, 0, addr); +} + +static void +bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) +{ + struct ieee80211req_wpaie ie; + int ielen = 0; + u8 *iebuf = NULL; + + /* + * Fetch and validate any negotiated WPA/RSN parameters. + */ + memset(&ie, 0, sizeof(ie)); + memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); + if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { + printf("Failed to get WPA/RSN information element.\n"); + goto no_ie; + } + iebuf = ie.wpa_ie; + ielen = ie.wpa_ie[1]; + if (ielen == 0) + iebuf = NULL; + else + ielen += 2; + +no_ie: + drv_event_assoc(ctx, addr, iebuf, ielen); +} + +static int +bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, + int encrypt, const u8 *own_addr) +{ + struct bsd_driver_data *drv = priv; + + wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); + + return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, + data_len); +} + +static int +bsd_set_freq(void *priv, u16 channel) +{ + struct bsd_driver_data *drv = priv; +#ifdef SIOCS80211CHANNEL + struct ieee80211chanreq creq; +#endif /* SIOCS80211CHANNEL */ + u32 mode; + + if (channel < 14) + mode = IFM_IEEE80211_11G; + else if (channel == 14) + mode = IFM_IEEE80211_11B; + else + mode = IFM_IEEE80211_11A; + if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", + __func__); + return -1; + } + +#ifdef SIOCS80211CHANNEL + os_memset(&creq, 0, sizeof(creq)); + os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); + creq.i_channel = channel; + return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); +#else /* SIOCS80211CHANNEL */ + return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); +#endif /* SIOCS80211CHANNEL */ +} + +static int +bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) +{ +#ifdef IEEE80211_IOC_APPIE + wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, + (unsigned long)ie_len); + return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, + ie, ie_len); +#endif /* IEEE80211_IOC_APPIE */ + return 0; +} + + +#ifdef HOSTAPD + +/* + * Avoid conflicts with hostapd definitions by undefining couple of defines + * from net80211 header files. + */ +#undef RSN_VERSION +#undef WPA_VERSION +#undef WPA_OUI_TYPE + +static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code); + +static const char * +ether_sprintf(const u8 *addr) +{ + static char buf[sizeof(MACSTR)]; + + if (addr != NULL) + snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + else + snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); + return buf; +} + +static int +bsd_set_privacy(void *priv, int enabled) +{ + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); + + return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); +} + +static int +bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, + u8 *seq) +{ + struct ieee80211req_key wk; + + wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", + __func__, ether_sprintf(addr), idx); + + memset(&wk, 0, sizeof(wk)); + if (addr == NULL) + memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + else + memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + wk.ik_keyix = idx; + + if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { + printf("Failed to get encryption.\n"); + return -1; + } + +#ifdef WORDS_BIGENDIAN + { + /* + * wk.ik_keytsc is in host byte order (big endian), need to + * swap it to match with the byte order used in WPA. + */ + int i; + u8 tmp[WPA_KEY_RSC_LEN]; + memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + for (i = 0; i < WPA_KEY_RSC_LEN; i++) { + seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; + } + } +#else /* WORDS_BIGENDIAN */ + memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); +#endif /* WORDS_BIGENDIAN */ + return 0; +} + + +static int +bsd_flush(void *priv) +{ + u8 allsta[IEEE80211_ADDR_LEN]; + + memset(allsta, 0xff, IEEE80211_ADDR_LEN); + return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); +} + + +static int +bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct ieee80211req_sta_stats stats; + + memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); + if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) + > 0) { + /* XXX? do packets counts include non-data frames? */ + data->rx_packets = stats.is_stats.ns_rx_data; + data->rx_bytes = stats.is_stats.ns_rx_bytes; + data->tx_packets = stats.is_stats.ns_tx_data; + data->tx_bytes = stats.is_stats.ns_tx_bytes; + } + return 0; +} + +static int +bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) +{ + return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, + addr); +} + +static int +bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code) +{ + return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, + addr); +} + +static void +bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) +{ + struct bsd_driver_data *drv = ctx; + char buf[2048]; + struct if_announcemsghdr *ifan; + struct rt_msghdr *rtm; + struct ieee80211_michael_event *mic; + struct ieee80211_join_event *join; + struct ieee80211_leave_event *leave; + int n; + union wpa_event_data data; + + n = read(sock, buf, sizeof(buf)); + if (n < 0) { + if (errno != EINTR && errno != EAGAIN) + perror("read(PF_ROUTE)"); + return; + } + + rtm = (struct rt_msghdr *) buf; + if (rtm->rtm_version != RTM_VERSION) { + wpa_printf(MSG_DEBUG, "Routing message version %d not " + "understood\n", rtm->rtm_version); + return; + } + ifan = (struct if_announcemsghdr *) rtm; + switch (rtm->rtm_type) { + case RTM_IEEE80211: + switch (ifan->ifan_what) { + case RTM_IEEE80211_ASSOC: + case RTM_IEEE80211_REASSOC: + case RTM_IEEE80211_DISASSOC: + case RTM_IEEE80211_SCAN: + break; + case RTM_IEEE80211_LEAVE: + leave = (struct ieee80211_leave_event *) &ifan[1]; + drv_event_disassoc(drv->hapd, leave->iev_addr); + break; + case RTM_IEEE80211_JOIN: +#ifdef RTM_IEEE80211_REJOIN + case RTM_IEEE80211_REJOIN: +#endif + join = (struct ieee80211_join_event *) &ifan[1]; + bsd_new_sta(drv, drv->hapd, join->iev_addr); + break; + case RTM_IEEE80211_REPLAY: + /* ignore */ + break; + case RTM_IEEE80211_MICHAEL: + mic = (struct ieee80211_michael_event *) &ifan[1]; + wpa_printf(MSG_DEBUG, + "Michael MIC failure wireless event: " + "keyix=%u src_addr=" MACSTR, mic->iev_keyix, + MAC2STR(mic->iev_src)); + os_memset(&data, 0, sizeof(data)); + data.michael_mic_failure.unicast = 1; + data.michael_mic_failure.src = mic->iev_src; + wpa_supplicant_event(drv->hapd, + EVENT_MICHAEL_MIC_FAILURE, &data); + break; + } + break; + } +} + +static void +handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) +{ + struct bsd_driver_data *drv = ctx; + drv_event_eapol_rx(drv->hapd, src_addr, buf, len); +} + +static int +hostapd_bsd_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + return bsd_set_freq(priv, freq->channel); +} + +static void * +bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) +{ + struct bsd_driver_data *drv; + + drv = os_zalloc(sizeof(struct bsd_driver_data)); + if (drv == NULL) { + printf("Could not allocate memory for bsd driver data\n"); + goto bad; + } + + drv->hapd = hapd; + drv->sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->sock < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + goto bad; + } + os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); + + drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, + handle_read, drv, 0); + if (drv->sock_xmit == NULL) + goto bad; + if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) + goto bad; + + /* mark down during setup */ + if (bsd_ctrl_iface(drv, 0) < 0) + goto bad; + + drv->route = socket(PF_ROUTE, SOCK_RAW, 0); + if (drv->route < 0) { + perror("socket(PF_ROUTE,SOCK_RAW)"); + goto bad; + } + eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, + NULL); + + if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set operation mode", + __func__); + goto bad; + } + + return drv; +bad: + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); + if (drv->sock >= 0) + close(drv->sock); + if (drv != NULL) + os_free(drv); + return NULL; +} + + +static void +bsd_deinit(void *priv) +{ + struct bsd_driver_data *drv = priv; + + if (drv->route >= 0) { + eloop_unregister_read_sock(drv->route); + close(drv->route); + } + bsd_ctrl_iface(drv, 0); + if (drv->sock >= 0) + close(drv->sock); + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); + os_free(drv); +} + +#else /* HOSTAPD */ + +static int +get80211param(struct bsd_driver_data *drv, int op) { struct ieee80211req ireq; - os_memset(&ireq, 0, sizeof(ireq)); - os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ); - ireq.i_type = op; - - if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) { - fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n", - op, strerror(errno)); + if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) return -1; - } return ireq.i_val; } -static int -getifflags(struct wpa_driver_bsd_data *drv, int *flags) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { - perror("SIOCGIFFLAGS"); - return errno; - } - *flags = ifr.ifr_flags & 0xffff; - return 0; -} - -static int -setifflags(struct wpa_driver_bsd_data *drv, int flags) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); - ifr.ifr_flags = flags & 0xffff; - if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { - perror("SIOCSIFFLAGS"); - return errno; - } - return 0; -} - static int wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) { - struct wpa_driver_bsd_data *drv = priv; + struct bsd_driver_data *drv = priv; +#ifdef SIOCG80211BSSID + struct ieee80211_bssid bs; + os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); + if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) + return -1; + os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); + return 0; +#else return get80211var(drv, IEEE80211_IOC_BSSID, bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; -} - -#if 0 -static int -wpa_driver_bsd_set_bssid(void *priv, const char *bssid) -{ - struct wpa_driver_bsd_data *drv = priv; - - return set80211var(drv, IEEE80211_IOC_BSSID, - bssid, IEEE80211_ADDR_LEN); -} #endif +} static int wpa_driver_bsd_get_ssid(void *priv, u8 *ssid) { - struct wpa_driver_bsd_data *drv = priv; - - return get80211var(drv, IEEE80211_IOC_SSID, - ssid, IEEE80211_NWID_LEN); + struct bsd_driver_data *drv = priv; + return bsd_get_ssid(drv, ssid, 0); } static int -wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid, - size_t ssid_len) -{ - struct wpa_driver_bsd_data *drv = priv; - - return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); -} - -static int -wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv, - const u8 *wpa_ie, size_t wpa_ie_len) +wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, + size_t wpa_ie_len) { +#ifdef IEEE80211_IOC_APPIE + return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); +#else /* IEEE80211_IOC_APPIE */ return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); +#endif /* IEEE80211_IOC_APPIE */ } static int wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) { - struct wpa_driver_bsd_data *drv = priv; int ret = 0; wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", __FUNCTION__, wpa, privacy); - if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0) + if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) ret = -1; - if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) + if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) ret = -1; - if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0) + if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) ret = -1; return ret; @@ -219,170 +913,125 @@ wpa_driver_bsd_set_wpa(void *priv, int enabled) return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); } -static int -wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx, - const unsigned char *addr) -{ - struct ieee80211req_del_key wk; - - os_memset(&wk, 0, sizeof(wk)); - if (addr != NULL && - bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) { - struct ether_addr ea; - - os_memcpy(&ea, addr, IEEE80211_ADDR_LEN); - wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d", - __func__, ether_ntoa(&ea), key_idx); - os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); - wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE; - } else { - wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx); - wk.idk_keyix = key_idx; - } - return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); -} - -static int -wpa_driver_bsd_set_key(void *priv, wpa_alg alg, - const unsigned char *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct wpa_driver_bsd_data *drv = priv; - struct ieee80211req_key wk; - struct ether_addr ea; - char *alg_name; - u_int8_t cipher; - - if (alg == WPA_ALG_NONE) - return wpa_driver_bsd_del_key(drv, key_idx, addr); - - switch (alg) { - case WPA_ALG_WEP: - alg_name = "WEP"; - cipher = IEEE80211_CIPHER_WEP; - break; - case WPA_ALG_TKIP: - alg_name = "TKIP"; - cipher = IEEE80211_CIPHER_TKIP; - break; - case WPA_ALG_CCMP: - alg_name = "CCMP"; - cipher = IEEE80211_CIPHER_AES_CCM; - break; - default: - wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d", - __func__, alg); - return -1; - } - - os_memcpy(&ea, addr, IEEE80211_ADDR_LEN); - wpa_printf(MSG_DEBUG, - "%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu", - __func__, alg_name, ether_ntoa(&ea), key_idx, set_tx, - seq_len, key_len); - - if (seq_len > sizeof(u_int64_t)) { - wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big", - __func__, seq_len); - return -2; - } - if (key_len > sizeof(wk.ik_keydata)) { - wpa_printf(MSG_DEBUG, "%s: key length %zu too big", - __func__, key_len); - return -3; - } - - os_memset(&wk, 0, sizeof(wk)); - wk.ik_type = cipher; - wk.ik_flags = IEEE80211_KEY_RECV; - if (set_tx) - wk.ik_flags |= IEEE80211_KEY_XMIT; - os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); - /* - * Deduce whether group/global or unicast key by checking - * the address (yech). Note also that we can only mark global - * keys default; doing this for a unicast key is an error. - */ - if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) { - wk.ik_flags |= IEEE80211_KEY_GROUP; - wk.ik_keyix = key_idx; - } else { - wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx); - } - if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) - wk.ik_flags |= IEEE80211_KEY_DEFAULT; - wk.ik_keylen = key_len; - os_memcpy(&wk.ik_keyrsc, seq, seq_len); - os_memcpy(wk.ik_keydata, key, key_len); - - return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); -} - static int wpa_driver_bsd_set_countermeasures(void *priv, int enabled) { - struct wpa_driver_bsd_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled); + return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); } static int wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) { - struct wpa_driver_bsd_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); + return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); } static int wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) { - struct wpa_driver_bsd_data *drv = priv; - struct ieee80211req_mlme mlme; - - wpa_printf(MSG_DEBUG, "%s", __func__); - os_memset(&mlme, 0, sizeof(mlme)); - mlme.im_op = IEEE80211_MLME_DEAUTH; - mlme.im_reason = reason_code; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); + return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, + addr); } static int wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code) { - struct wpa_driver_bsd_data *drv = priv; - struct ieee80211req_mlme mlme; + return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, + addr); +} - wpa_printf(MSG_DEBUG, "%s", __func__); - os_memset(&mlme, 0, sizeof(mlme)); - mlme.im_op = IEEE80211_MLME_DISASSOC; - mlme.im_reason = reason_code; - os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); - return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); +static int +wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) +{ + int authmode; + + if ((auth_alg & WPA_AUTH_ALG_OPEN) && + (auth_alg & WPA_AUTH_ALG_SHARED)) + authmode = IEEE80211_AUTH_AUTO; + else if (auth_alg & WPA_AUTH_ALG_SHARED) + authmode = IEEE80211_AUTH_SHARED; + else + authmode = IEEE80211_AUTH_OPEN; + + return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode); +} + +static void +handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) +{ + struct bsd_driver_data *drv = ctx; + + drv_event_eapol_rx(drv->ctx, src_addr, buf, len); } static int wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) { - struct wpa_driver_bsd_data *drv = priv; + struct bsd_driver_data *drv = priv; struct ieee80211req_mlme mlme; + u32 mode; + u16 channel; int privacy; + int ret = 0; wpa_printf(MSG_DEBUG, "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" , __func__ - , params->ssid_len, params->ssid - , params->wpa_ie_len + , (unsigned int) params->ssid_len, params->ssid + , (unsigned int) params->wpa_ie_len , params->pairwise_suite , params->group_suite , params->key_mgmt_suite ); + switch (params->mode) { + case IEEE80211_MODE_INFRA: + mode = 0 /* STA */; + break; + case IEEE80211_MODE_IBSS: + mode = IFM_IEEE80211_IBSS; + break; + case IEEE80211_MODE_AP: + mode = IFM_IEEE80211_HOSTAP; + break; + default: + wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); + return -1; + } + if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set operation mode", + __func__); + return -1; + } + + if (params->mode == IEEE80211_MODE_AP) { + if (params->freq >= 2412 && params->freq <= 2472) + channel = (params->freq - 2407) / 5; + else if (params->freq == 2484) + channel = 14; + else if ((params->freq >= 5180 && params->freq <= 5240) || + (params->freq >= 5745 && params->freq <= 5825)) + channel = (params->freq - 5000) / 5; + else + channel = 0; + if (bsd_set_freq(drv, channel) < 0) + return -1; + + drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, + handle_read, drv, 0); + if (drv->sock_xmit == NULL) + return -1; + drv->is_ap = 1; + return 0; + } + + if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) + < 0) + ret = -1; + if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) + ret = -1; /* XXX error handling is wrong but unclear what to do... */ if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) return -1; @@ -410,62 +1059,89 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) return -1; - return 0; + return ret; } static int -wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) +wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) { - struct wpa_driver_bsd_data *drv = priv; - int authmode; + struct bsd_driver_data *drv = priv; +#ifdef IEEE80211_IOC_SCAN_MAX_SSID + struct ieee80211_scan_req sr; + int i; +#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ - if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) && - (auth_alg & AUTH_ALG_SHARED_KEY)) - authmode = IEEE80211_AUTH_AUTO; - else if (auth_alg & AUTH_ALG_SHARED_KEY) - authmode = IEEE80211_AUTH_SHARED; - else - authmode = IEEE80211_AUTH_OPEN; + if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set operation mode", + __func__); + return -1; + } - return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode); -} + if (set80211param(drv, IEEE80211_IOC_ROAMING, + IEEE80211_ROAMING_MANUAL) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set " + "wpa_supplicant-based roaming: %s", __func__, + strerror(errno)); + return -1; + } -static int -wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len) -{ - struct wpa_driver_bsd_data *drv = priv; - int flags; + if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, + strerror(errno)); + return -1; + } /* NB: interface must be marked UP to do a scan */ - if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0) + if (bsd_ctrl_iface(drv, 1) < 0) return -1; +#ifdef IEEE80211_IOC_SCAN_MAX_SSID + os_memset(&sr, 0, sizeof(sr)); + sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | + IEEE80211_IOC_SCAN_NOJOIN; + sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; + if (params->num_ssids > 0) { + sr.sr_nssid = params->num_ssids; +#if 0 + /* Boundary check is done by upper layer */ + if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) + sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; +#endif + + /* NB: check scan cache first */ + sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; + } + for (i = 0; i < sr.sr_nssid; i++) { + sr.sr_ssid[i].len = params->ssids[i].ssid_len; + os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, + sr.sr_ssid[i].len); + } + + /* NB: net80211 delivers a scan complete event so no need to poll */ + return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); +#else /* IEEE80211_IOC_SCAN_MAX_SSID */ /* set desired ssid before scan */ - if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0) + if (bsd_set_ssid(drv, params->ssids[0].ssid, + params->ssids[0].ssid_len) < 0) return -1; /* NB: net80211 delivers a scan complete event so no need to poll */ return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); +#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ } -#include -#if __FreeBSD__ -#include -#endif -#if __NetBSD__ -#include -#endif - static void wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) { - struct wpa_driver_bsd_data *drv = sock_ctx; + struct bsd_driver_data *drv = sock_ctx; char buf[2048]; struct if_announcemsghdr *ifan; struct if_msghdr *ifm; struct rt_msghdr *rtm; union wpa_event_data event; struct ieee80211_michael_event *mic; + struct ieee80211_leave_event *leave; + struct ieee80211_join_event *join; int n; n = read(sock, buf, sizeof(buf)); @@ -487,8 +1163,8 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) ifan = (struct if_announcemsghdr *) rtm; if (ifan->ifan_index != drv->ifindex) break; - strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); + os_strlcpy(event.interface_status.ifname, drv->ifname, + sizeof(event.interface_status.ifname)); switch (ifan->ifan_what) { case IFAN_DEPARTURE: event.interface_status.ievent = EVENT_INTERFACE_REMOVED; @@ -508,14 +1184,31 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) switch (ifan->ifan_what) { case RTM_IEEE80211_ASSOC: case RTM_IEEE80211_REASSOC: + if (drv->is_ap) + break; wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); break; case RTM_IEEE80211_DISASSOC: + if (drv->is_ap) + break; wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); break; case RTM_IEEE80211_SCAN: + if (drv->is_ap) + break; wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); break; + case RTM_IEEE80211_LEAVE: + leave = (struct ieee80211_leave_event *) &ifan[1]; + drv_event_disassoc(ctx, leave->iev_addr); + break; + case RTM_IEEE80211_JOIN: +#ifdef RTM_IEEE80211_REJOIN + case RTM_IEEE80211_REJOIN: +#endif + join = (struct ieee80211_join_event *) &ifan[1]; + bsd_new_sta(drv, ctx, join->iev_addr); + break; case RTM_IEEE80211_REPLAY: /* ignore */ break; @@ -539,8 +1232,8 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) if (ifm->ifm_index != drv->ifindex) break; if ((rtm->rtm_flags & RTF_UP) == 0) { - strlcpy(event.interface_status.ifname, drv->ifname, - sizeof(event.interface_status.ifname)); + os_strlcpy(event.interface_status.ifname, drv->ifname, + sizeof(event.interface_status.ifname)); event.interface_status.ievent = EVENT_INTERFACE_REMOVED; wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", event.interface_status.ifname); @@ -550,135 +1243,167 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) } } -/* Compare function for sorting scan results. Return >0 if @b is consider - * better. */ -static int -wpa_scan_result_compar(const void *a, const void *b) +static void +wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, + struct ieee80211req_scan_result *sr) { - const struct wpa_scan_result *wa = a; - const struct wpa_scan_result *wb = b; + struct wpa_scan_res *result, **tmp; + size_t extra_len; + u8 *pos; - /* WPA/WPA2 support preferred */ - if ((wb->wpa_ie_len || wb->rsn_ie_len) && - !(wa->wpa_ie_len || wa->rsn_ie_len)) - return 1; - if (!(wb->wpa_ie_len || wb->rsn_ie_len) && - (wa->wpa_ie_len || wa->rsn_ie_len)) - return -1; + extra_len = 2 + sr->isr_ssid_len; + extra_len += 2 + sr->isr_nrates; + extra_len += 3; /* ERP IE */ + extra_len += sr->isr_ie_len; - /* privacy support preferred */ - if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) && - (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0) - return 1; - if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 && - (wb->caps & IEEE80211_CAPINFO_PRIVACY)) - return -1; + result = os_zalloc(sizeof(*result) + extra_len); + if (result == NULL) + return; + os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); + result->freq = sr->isr_freq; + result->beacon_int = sr->isr_intval; + result->caps = sr->isr_capinfo; + result->qual = sr->isr_rssi; + result->noise = sr->isr_noise; - /* best/max rate preferred if signal level close enough XXX */ - if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5) - return wb->maxrate - wa->maxrate; + pos = (u8 *)(result + 1); - /* use freq for channel preference */ + *pos++ = WLAN_EID_SSID; + *pos++ = sr->isr_ssid_len; + os_memcpy(pos, sr + 1, sr->isr_ssid_len); + pos += sr->isr_ssid_len; - /* all things being equal, use signal level */ - return wb->level - wa->level; -} + /* + * Deal all rates as supported rate. + * Because net80211 doesn't report extended supported rate or not. + */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = sr->isr_nrates; + os_memcpy(pos, sr->isr_rates, sr->isr_nrates); + pos += sr->isr_nrates; -static int -getmaxrate(uint8_t rates[15], uint8_t nrates) -{ - int i, maxrate = -1; + *pos++ = WLAN_EID_ERP_INFO; + *pos++ = 1; + *pos++ = sr->isr_erp; - for (i = 0; i < nrates; i++) { - int rate = rates[i] & IEEE80211_RATE_VAL; - if (rate > maxrate) - rate = maxrate; + os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); + pos += sr->isr_ie_len; + + result->ie_len = pos - (u8 *)(result + 1); + + tmp = os_realloc(res->res, + (res->num + 1) * sizeof(struct wpa_scan_res *)); + if (tmp == NULL) { + os_free(result); + return; } - return maxrate; + tmp[res->num++] = result; + res->res = tmp; } -/* unalligned little endian access */ -#define LE_READ_4(p) \ - ((u_int32_t) \ - ((((const u_int8_t *)(p))[0] ) | \ - (((const u_int8_t *)(p))[1] << 8) | \ - (((const u_int8_t *)(p))[2] << 16) | \ - (((const u_int8_t *)(p))[3] << 24))) - -static int __inline -iswpaoui(const u_int8_t *frm) +struct wpa_scan_results * +wpa_driver_bsd_get_scan_results2(void *priv) { - return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); -} - -static int -wpa_driver_bsd_get_scan_results(void *priv, - struct wpa_scan_result *results, - size_t max_size) -{ -#define min(a,b) ((a)>(b)?(b):(a)) - struct wpa_driver_bsd_data *drv = priv; - uint8_t buf[24*1024]; - uint8_t *cp, *vp; struct ieee80211req_scan_result *sr; - struct wpa_scan_result *wsr; - int len, ielen; + struct wpa_scan_results *res; + int len, rest; + uint8_t buf[24*1024], *pos; - os_memset(results, 0, max_size * sizeof(struct wpa_scan_result)); - - len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf)); + len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); if (len < 0) - return -1; - cp = buf; - wsr = results; - while (len >= sizeof(struct ieee80211req_scan_result)) { - sr = (struct ieee80211req_scan_result *) cp; - os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN); - wsr->ssid_len = sr->isr_ssid_len; - wsr->freq = sr->isr_freq; - wsr->noise = sr->isr_noise; - wsr->qual = sr->isr_rssi; - wsr->level = 0; /* XXX? */ - wsr->caps = sr->isr_capinfo; - wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates); - vp = (u_int8_t *)(sr+1); - os_memcpy(wsr->ssid, vp, sr->isr_ssid_len); - if (sr->isr_ie_len > 0) { - vp += sr->isr_ssid_len; - ielen = sr->isr_ie_len; - while (ielen > 0) { - switch (vp[0]) { - case IEEE80211_ELEMID_VENDOR: - if (!iswpaoui(vp)) - break; - wsr->wpa_ie_len = - min(2+vp[1], SSID_MAX_WPA_IE_LEN); - os_memcpy(wsr->wpa_ie, vp, - wsr->wpa_ie_len); - break; - case IEEE80211_ELEMID_RSN: - wsr->rsn_ie_len = - min(2+vp[1], SSID_MAX_WPA_IE_LEN); - os_memcpy(wsr->rsn_ie, vp, - wsr->rsn_ie_len); - break; - } - ielen -= 2+vp[1]; - vp += 2+vp[1]; - } - } + return NULL; - cp += sr->isr_len, len -= sr->isr_len; - wsr++; + res = os_zalloc(sizeof(*res)); + if (res == NULL) + return NULL; + + pos = buf; + rest = len; + while (rest >= sizeof(struct ieee80211req_scan_result)) { + sr = (struct ieee80211req_scan_result *)pos; + wpa_driver_bsd_add_scan_entry(res, sr); + pos += sr->isr_len; + rest -= sr->isr_len; } - qsort(results, wsr - results, sizeof(struct wpa_scan_result), - wpa_scan_result_compar); - wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)", - len, wsr - results); + wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", + len, (unsigned long)res->num); - return wsr - results; -#undef min + return res; +} + +static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) +{ +#ifdef IEEE80211_IOC_DEVCAPS +/* kernel definitions copied from net80211/ieee80211_var.h */ +#define IEEE80211_CIPHER_WEP 0 +#define IEEE80211_CIPHER_TKIP 1 +#define IEEE80211_CIPHER_AES_CCM 3 +#define IEEE80211_CRYPTO_WEP (1<capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; + if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) + drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; + + if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) + drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | + WPA_DRIVER_CAPA_ENC_WEP104; + if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) + drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; + if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) + drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; + + if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) + drv->capa.flags |= WPA_DRIVER_FLAGS_AP; +#undef IEEE80211_CIPHER_WEP +#undef IEEE80211_CIPHER_TKIP +#undef IEEE80211_CIPHER_AES_CCM +#undef IEEE80211_CRYPTO_WEP +#undef IEEE80211_CRYPTO_TKIP +#undef IEEE80211_CRYPTO_AES_CCM +#undef IEEE80211_C_HOSTAP +#undef IEEE80211_C_WPA1 +#undef IEEE80211_C_WPA2 +#else /* IEEE80211_IOC_DEVCAPS */ + /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ + drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; + drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | + WPA_DRIVER_CAPA_ENC_WEP104 | + WPA_DRIVER_CAPA_ENC_TKIP | + WPA_DRIVER_CAPA_ENC_CCMP; + drv->capa.flags |= WPA_DRIVER_FLAGS_AP; +#endif /* IEEE80211_IOC_DEVCAPS */ +#ifdef IEEE80211_IOC_SCAN_MAX_SSID + drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; +#else /* IEEE80211_IOC_SCAN_MAX_SSID */ + drv->capa.max_scan_ssids = 1; +#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ + drv->capa.auth = WPA_DRIVER_AUTH_OPEN | + WPA_DRIVER_AUTH_SHARED | + WPA_DRIVER_AUTH_LEAP; + return 0; } static void * @@ -686,7 +1411,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) { #define GETPARAM(drv, param, v) \ (((v) = get80211param(drv, param)) != -1) - struct wpa_driver_bsd_data *drv; + struct bsd_driver_data *drv; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) @@ -715,6 +1440,10 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) drv->ctx = ctx; os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); + /* Down interface during setup. */ + if (bsd_ctrl_iface(drv, 0) < 0) + goto fail; + if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", __func__, strerror(errno)); @@ -730,17 +1459,9 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) __func__, strerror(errno)); goto fail; } - if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based " - "roaming: %s", __func__, strerror(errno)); - goto fail; - } - if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) { - wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s", - __func__, strerror(errno)); + if (wpa_driver_bsd_capa(drv)) goto fail; - } return drv; fail: @@ -754,41 +1475,68 @@ fail1: static void wpa_driver_bsd_deinit(void *priv) { - struct wpa_driver_bsd_data *drv = priv; - int flags; + struct bsd_driver_data *drv = priv; + wpa_driver_bsd_set_wpa(drv, 0); eloop_unregister_read_sock(drv->route); /* NB: mark interface down */ - if (getifflags(drv, &flags) == 0) - (void) setifflags(drv, flags &~ IFF_UP); + bsd_ctrl_iface(drv, 0); wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", __func__); + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); (void) close(drv->route); /* ioctl socket */ (void) close(drv->sock); /* event socket */ os_free(drv); } +static int +wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) +{ + struct bsd_driver_data *drv = priv; + + os_memcpy(capa, &drv->capa, sizeof(*capa)); + return 0; +} +#endif /* HOSTAPD */ + const struct wpa_driver_ops wpa_driver_bsd_ops = { .name = "bsd", - .desc = "BSD 802.11 support (Atheros, etc.)", + .desc = "BSD 802.11 support", +#ifdef HOSTAPD + .hapd_init = bsd_init, + .hapd_deinit = bsd_deinit, + .set_privacy = bsd_set_privacy, + .get_seqnum = bsd_get_seqnum, + .flush = bsd_flush, + .read_sta_data = bsd_read_sta_driver_data, + .sta_disassoc = bsd_sta_disassoc, + .sta_deauth = bsd_sta_deauth, + .set_freq = hostapd_bsd_set_freq, +#else /* HOSTAPD */ .init = wpa_driver_bsd_init, .deinit = wpa_driver_bsd_deinit, .get_bssid = wpa_driver_bsd_get_bssid, .get_ssid = wpa_driver_bsd_get_ssid, - .set_wpa = wpa_driver_bsd_set_wpa, - .set_key = wpa_driver_bsd_set_key, .set_countermeasures = wpa_driver_bsd_set_countermeasures, - .set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted, - .scan = wpa_driver_bsd_scan, - .get_scan_results = wpa_driver_bsd_get_scan_results, + .scan2 = wpa_driver_bsd_scan, + .get_scan_results2 = wpa_driver_bsd_get_scan_results2, .deauthenticate = wpa_driver_bsd_deauthenticate, .disassociate = wpa_driver_bsd_disassociate, .associate = wpa_driver_bsd_associate, - .set_auth_alg = wpa_driver_bsd_set_auth_alg, + .get_capa = wpa_driver_bsd_get_capa, +#endif /* HOSTAPD */ + .set_key = bsd_set_key, + .set_ieee8021x = bsd_set_ieee8021x, + .hapd_set_ssid = bsd_set_ssid, + .hapd_get_ssid = bsd_get_ssid, + .hapd_send_eapol = bsd_send_eapol, + .sta_set_flags = bsd_set_sta_authorized, + .set_generic_elem = bsd_set_opt_ie, }; diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c index 84ef3bdedc54..952f3891abde 100644 --- a/src/drivers/driver_hostap.c +++ b/src/drivers/driver_hostap.c @@ -1,5 +1,5 @@ /* - * WPA Supplicant - driver interaction with Linux Host AP driver + * Driver interaction with Linux Host AP driver * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify @@ -23,6 +23,1099 @@ #include "driver_hostap.h" +#ifdef HOSTAPD + +#include +#include + +#include "priv_netlink.h" +#include "netlink.h" +#include "linux_ioctl.h" +#include "common/ieee802_11_defs.h" + + +/* 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 + +static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +struct hostap_driver_data { + struct hostapd_data *hapd; + + char iface[IFNAMSIZ + 1]; + int sock; /* raw packet socket for driver access */ + int ioctl_sock; /* socket for ioctl() use */ + struct netlink_data *netlink; + + int we_version; + + u8 *generic_ie; + size_t generic_ie_len; + u8 *wps_ie; + size_t wps_ie_len; +}; + + +static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, + int len); +static int hostap_set_iface_flags(void *priv, int dev_up); + +static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len, + u16 stype) +{ + struct ieee80211_hdr *hdr; + u16 fc, ethertype; + u8 *pos, *sa; + size_t left; + union wpa_event_data event; + + if (len < sizeof(struct ieee80211_hdr)) + return; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) { + printf("Not ToDS data frame (fc=0x%04x)\n", fc); + return; + } + + sa = hdr->addr2; + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.frame = buf; + event.rx_from_unknown.len = len; + wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event); + + pos = (u8 *) (hdr + 1); + left = len - sizeof(*hdr); + + if (left < sizeof(rfc1042_header)) { + printf("Too short data frame\n"); + return; + } + + if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) { + printf("Data frame with no RFC1042 header\n"); + return; + } + pos += sizeof(rfc1042_header); + left -= sizeof(rfc1042_header); + + if (left < 2) { + printf("No ethertype in data frame\n"); + return; + } + + ethertype = WPA_GET_BE16(pos); + pos += 2; + left -= 2; + switch (ethertype) { + case ETH_P_PAE: + drv_event_eapol_rx(drv->hapd, sa, pos, left); + break; + + default: + printf("Unknown ethertype 0x%04x in data frame\n", ethertype); + break; + } +} + + +static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf, + size_t len, int ok) +{ + struct ieee80211_hdr *hdr; + u16 fc; + union wpa_event_data event; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = buf; + event.tx_status.data_len = len; + event.tx_status.ack = ok; + wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event); +} + + +static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) +{ + struct ieee80211_hdr *hdr; + u16 fc, extra_len, type, stype; + unsigned char *extra = NULL; + size_t data_len = len; + int ver; + union wpa_event_data event; + + /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass + * these to user space */ + if (len < 24) { + wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)", + (unsigned long) len); + return; + } + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) { + wpa_hexdump(MSG_MSGDUMP, "Received management frame", + buf, len); + } + + ver = fc & WLAN_FC_PVER; + + /* protocol version 3 is reserved for indicating extra data after the + * payload, version 2 for indicating ACKed frame (TX callbacks), and + * version 1 for indicating failed frame (no ACK, TX callbacks) */ + if (ver == 3) { + u8 *pos = buf + len - 2; + extra_len = WPA_GET_LE16(pos); + printf("extra data in frame (elen=%d)\n", extra_len); + if ((size_t) extra_len + 2 > len) { + printf(" extra data overflow\n"); + return; + } + len -= extra_len + 2; + extra = buf + len; + } else if (ver == 1 || ver == 2) { + handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); + return; + } else if (ver != 0) { + printf("unknown protocol version %d\n", ver); + return; + } + + switch (type) { + case WLAN_FC_TYPE_MGMT: + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = data_len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); + break; + case WLAN_FC_TYPE_CTRL: + wpa_printf(MSG_DEBUG, "CTRL"); + break; + case WLAN_FC_TYPE_DATA: + wpa_printf(MSG_DEBUG, "DATA"); + handle_data(drv, buf, data_len, stype); + break; + default: + wpa_printf(MSG_DEBUG, "unknown frame type %d", type); + break; + } +} + + +static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct hostap_driver_data *drv = eloop_ctx; + int len; + unsigned char buf[3000]; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + handle_frame(drv, buf, len); +} + + +static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) +{ + struct ifreq ifr; + struct sockaddr_ll addr; + + drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (drv->sock < 0) { + perror("socket[PF_PACKET,SOCK_RAW]"); + return -1; + } + + if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) { + printf("Could not register read socket\n"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); + if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { + perror("ioctl(SIOCGIFINDEX)"); + return -1; + } + + if (hostap_set_iface_flags(drv, 1)) { + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = ifr.ifr_ifindex; + wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", + addr.sll_ifindex); + + if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind"); + return -1; + } + + return linux_get_ifhwaddr(drv->sock, drv->iface, own_addr); +} + + +static int hostap_send_mlme(void *priv, const u8 *msg, size_t len) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; + int res; + + /* Request TX callback */ + hdr->frame_control |= host_to_le16(BIT(1)); + res = send(drv->sock, msg, len, 0); + hdr->frame_control &= ~host_to_le16(BIT(1)); + + return res; +} + + +static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, const u8 *own_addr) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_hdr *hdr; + size_t len; + u8 *pos; + int res; + + len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + printf("malloc() failed for hostapd_send_data(len=%lu)\n", + (unsigned long) len); + return -1; + } + + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); + hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); + if (encrypt) + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); + memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); + memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + + pos = (u8 *) (hdr + 1); + memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); + pos += sizeof(rfc1042_header); + *((u16 *) pos) = htons(ETH_P_PAE); + pos += 2; + memcpy(pos, data, data_len); + + res = hostap_send_mlme(drv, (u8 *) hdr, len); + if (res < 0) { + wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " + "failed: %d (%s)", + (unsigned long) len, errno, strerror(errno)); + } + free(hdr); + + return res; +} + + +static int hostap_sta_set_flags(void *priv, const u8 *addr, + int total_flags, int flags_or, int flags_and) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + if (flags_or & WPA_STA_AUTHORIZED) + flags_or = BIT(5); /* WLAN_STA_AUTHORIZED */ + if (!(flags_and & WPA_STA_AUTHORIZED)) + flags_and = ~BIT(5); + else + flags_and = ~0; + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + param.u.set_flags_sta.flags_or = flags_or; + param.u.set_flags_sta.flags_and = flags_and; + return hostapd_ioctl(drv, ¶m, sizeof(param)); +} + + +static int hostap_set_iface_flags(void *priv, int dev_up) +{ + struct hostap_driver_data *drv = priv; + struct ifreq ifr; + char ifname[IFNAMSIZ]; + + os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface); + if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0) + return -1; + + if (dev_up) { + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_mtu = HOSTAPD_MTU; + if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { + perror("ioctl[SIOCSIFMTU]"); + printf("Setting MTU failed - trying to survive with " + "current value\n"); + } + } + + return 0; +} + + +static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, + int len) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) param; + iwr.u.data.length = len; + + if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { + perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); + return -1; + } + + return 0; +} + + +static int wpa_driver_hostap_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param *param; + u8 *buf; + size_t blen; + int ret = 0; + + blen = sizeof(*param) + key_len; + buf = os_zalloc(blen); + if (buf == NULL) + return -1; + + param = (struct prism2_hostapd_param *) buf; + param->cmd = PRISM2_SET_ENCRYPTION; + if (addr == NULL) + memset(param->sta_addr, 0xff, ETH_ALEN); + else + memcpy(param->sta_addr, addr, ETH_ALEN); + switch (alg) { + case WPA_ALG_NONE: + os_strlcpy((char *) param->u.crypt.alg, "NONE", + HOSTAP_CRYPT_ALG_NAME_LEN); + break; + case WPA_ALG_WEP: + os_strlcpy((char *) param->u.crypt.alg, "WEP", + HOSTAP_CRYPT_ALG_NAME_LEN); + break; + case WPA_ALG_TKIP: + os_strlcpy((char *) param->u.crypt.alg, "TKIP", + HOSTAP_CRYPT_ALG_NAME_LEN); + break; + case WPA_ALG_CCMP: + os_strlcpy((char *) param->u.crypt.alg, "CCMP", + HOSTAP_CRYPT_ALG_NAME_LEN); + break; + default: + os_free(buf); + return -1; + } + param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; + param->u.crypt.idx = key_idx; + param->u.crypt.key_len = key_len; + memcpy((u8 *) (param + 1), key, key_len); + + if (hostapd_ioctl(drv, param, blen)) { + printf("Failed to set encryption.\n"); + ret = -1; + } + free(buf); + + return ret; +} + + +static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, + int idx, u8 *seq) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param *param; + u8 *buf; + size_t blen; + int ret = 0; + + blen = sizeof(*param) + 32; + buf = os_zalloc(blen); + if (buf == NULL) + return -1; + + param = (struct prism2_hostapd_param *) buf; + param->cmd = PRISM2_GET_ENCRYPTION; + if (addr == NULL) + memset(param->sta_addr, 0xff, ETH_ALEN); + else + memcpy(param->sta_addr, addr, ETH_ALEN); + param->u.crypt.idx = idx; + + if (hostapd_ioctl(drv, param, blen)) { + printf("Failed to get encryption.\n"); + ret = -1; + } else { + memcpy(seq, param->u.crypt.seq, 8); + } + free(buf); + + return ret; +} + + +static int hostap_ioctl_prism2param(void *priv, int param, int value) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + int *i; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + i = (int *) iwr.u.name; + *i++ = param; + *i++ = value; + + if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { + perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); + return -1; + } + + return 0; +} + + +static int hostap_set_ieee8021x(void *priv, struct wpa_bss_params *params) +{ + struct hostap_driver_data *drv = priv; + int enabled = params->enabled; + + /* enable kernel driver support for IEEE 802.1X */ + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) { + printf("Could not setup IEEE 802.1X support in kernel driver." + "\n"); + return -1; + } + + if (!enabled) + return 0; + + /* use host driver implementation of encryption to allow + * individual keys and passing plaintext EAPOL frames */ + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) || + hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) { + printf("Could not setup host-based encryption in kernel " + "driver.\n"); + return -1; + } + + return 0; +} + + +static int hostap_set_privacy(void *priv, int enabled) +{ + struct hostap_drvier_data *drv = priv; + + return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, + enabled); +} + + +static int hostap_set_ssid(void *priv, const u8 *buf, int len) +{ + struct hostap_driver_data *drv = priv; + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.essid.flags = 1; /* SSID active */ + iwr.u.essid.pointer = (caddr_t) buf; + iwr.u.essid.length = len + 1; + + if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { + perror("ioctl[SIOCSIWESSID]"); + printf("len=%d\n", len); + return -1; + } + + return 0; +} + + +static int hostap_flush(void *priv) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_FLUSH; + return hostapd_ioctl(drv, ¶m, sizeof(param)); +} + + +static int hostap_read_sta_data(void *priv, + struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + char buf[1024], line[128], *pos; + FILE *f; + unsigned long val; + + memset(data, 0, sizeof(*data)); + snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR, + drv->iface, MAC2STR(addr)); + + f = fopen(buf, "r"); + if (!f) + return -1; + /* Need to read proc file with in one piece, so use large enough + * buffer. */ + setbuffer(f, buf, sizeof(buf)); + + while (fgets(line, sizeof(line), f)) { + pos = strchr(line, '='); + if (!pos) + continue; + *pos++ = '\0'; + val = strtoul(pos, NULL, 10); + if (strcmp(line, "rx_packets") == 0) + data->rx_packets = val; + else if (strcmp(line, "tx_packets") == 0) + data->tx_packets = val; + else if (strcmp(line, "rx_bytes") == 0) + data->rx_bytes = val; + else if (strcmp(line, "tx_bytes") == 0) + data->tx_bytes = val; + } + + fclose(f); + + return 0; +} + + +static int hostap_sta_add(void *priv, struct hostapd_sta_add_params *params) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + int tx_supp_rates = 0; + size_t i; + +#define WLAN_RATE_1M BIT(0) +#define WLAN_RATE_2M BIT(1) +#define WLAN_RATE_5M5 BIT(2) +#define WLAN_RATE_11M BIT(3) + + for (i = 0; i < params->supp_rates_len; i++) { + if ((params->supp_rates[i] & 0x7f) == 2) + tx_supp_rates |= WLAN_RATE_1M; + if ((params->supp_rates[i] & 0x7f) == 4) + tx_supp_rates |= WLAN_RATE_2M; + if ((params->supp_rates[i] & 0x7f) == 11) + tx_supp_rates |= WLAN_RATE_5M5; + if ((params->supp_rates[i] & 0x7f) == 22) + tx_supp_rates |= WLAN_RATE_11M; + } + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_ADD_STA; + memcpy(param.sta_addr, params->addr, ETH_ALEN); + param.u.add_sta.aid = params->aid; + param.u.add_sta.capability = params->capability; + param.u.add_sta.tx_supp_rates = tx_supp_rates; + return hostapd_ioctl(drv, ¶m, sizeof(param)); +} + + +static int hostap_sta_remove(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + hostap_sta_set_flags(drv, addr, 0, 0, ~WPA_STA_AUTHORIZED); + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_REMOVE_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) { + printf("Could not remove station from kernel driver.\n"); + return -1; + } + return 0; +} + + +static int hostap_get_inact_sec(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) { + return -1; + } + + return param.u.get_info_sta.inactive_sec; +} + + +static int hostap_sta_clear_stats(void *priv, const u8 *addr) +{ + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + + memset(¶m, 0, sizeof(param)); + param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS; + memcpy(param.sta_addr, addr, ETH_ALEN); + if (hostapd_ioctl(drv, ¶m, sizeof(param))) { + return -1; + } + + return 0; +} + + +static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv) +{ + struct prism2_hostapd_param *param; + int res; + size_t blen, elem_len; + + elem_len = drv->generic_ie_len + drv->wps_ie_len; + blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len; + if (blen < sizeof(*param)) + blen = sizeof(*param); + + param = os_zalloc(blen); + if (param == NULL) + return -1; + + param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; + param->u.generic_elem.len = elem_len; + if (drv->generic_ie) { + os_memcpy(param->u.generic_elem.data, drv->generic_ie, + drv->generic_ie_len); + } + if (drv->wps_ie) { + os_memcpy(¶m->u.generic_elem.data[drv->generic_ie_len], + drv->wps_ie, drv->wps_ie_len); + } + wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE", + param->u.generic_elem.data, elem_len); + res = hostapd_ioctl(drv, param, blen); + + os_free(param); + + return res; +} + + +static int hostap_set_generic_elem(void *priv, + const u8 *elem, size_t elem_len) +{ + struct hostap_driver_data *drv = priv; + + os_free(drv->generic_ie); + drv->generic_ie = NULL; + drv->generic_ie_len = 0; + if (elem) { + drv->generic_ie = os_malloc(elem_len); + if (drv->generic_ie == NULL) + return -1; + os_memcpy(drv->generic_ie, elem, elem_len); + drv->generic_ie_len = elem_len; + } + + return hostapd_ioctl_set_generic_elem(drv); +} + + +static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp) +{ + struct hostap_driver_data *drv = priv; + + /* + * Host AP driver supports only one set of extra IEs, so we need to + * use the Probe Response IEs also for Beacon frames since they include + * more information. + */ + + os_free(drv->wps_ie); + drv->wps_ie = NULL; + drv->wps_ie_len = 0; + if (proberesp) { + drv->wps_ie = os_malloc(wpabuf_len(proberesp)); + if (drv->wps_ie == NULL) + return -1; + os_memcpy(drv->wps_ie, wpabuf_head(proberesp), + wpabuf_len(proberesp)); + drv->wps_ie_len = wpabuf_len(proberesp); + } + + return hostapd_ioctl_set_generic_elem(drv); +} + + +static void +hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv, + char *custom) +{ + wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); + + if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { + char *pos; + u8 addr[ETH_ALEN]; + pos = strstr(custom, "addr="); + if (pos == NULL) { + wpa_printf(MSG_DEBUG, + "MLME-MICHAELMICFAILURE.indication " + "without sender address ignored"); + return; + } + pos += 5; + if (hwaddr_aton(pos, addr) == 0) { + union wpa_event_data data; + os_memset(&data, 0, sizeof(data)); + data.michael_mic_failure.unicast = 1; + data.michael_mic_failure.src = addr; + wpa_supplicant_event(drv->hapd, + EVENT_MICHAEL_MIC_FAILURE, &data); + } else { + wpa_printf(MSG_DEBUG, + "MLME-MICHAELMICFAILURE.indication " + "with invalid MAC address"); + } + } +} + + +static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv, + char *data, int len) +{ + struct iw_event iwe_buf, *iwe = &iwe_buf; + char *pos, *end, *custom, *buf; + + pos = data; + end = data + len; + + while (pos + IW_EV_LCP_LEN <= end) { + /* Event data may be unaligned, so make a local, aligned copy + * before processing. */ + memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); + wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", + iwe->cmd, iwe->len); + if (iwe->len <= IW_EV_LCP_LEN) + return; + + custom = pos + IW_EV_POINT_LEN; + if (drv->we_version > 18 && + (iwe->cmd == IWEVMICHAELMICFAILURE || + iwe->cmd == IWEVCUSTOM)) { + /* WE-19 removed the pointer from struct iw_point */ + char *dpos = (char *) &iwe_buf.u.data.length; + int dlen = dpos - (char *) &iwe_buf; + memcpy(dpos, pos + IW_EV_LCP_LEN, + sizeof(struct iw_event) - dlen); + } else { + memcpy(&iwe_buf, pos, sizeof(struct iw_event)); + custom += IW_EV_POINT_OFF; + } + + switch (iwe->cmd) { + case IWEVCUSTOM: + if (custom + iwe->u.data.length > end) + return; + buf = malloc(iwe->u.data.length + 1); + if (buf == NULL) + return; + memcpy(buf, custom, iwe->u.data.length); + buf[iwe->u.data.length] = '\0'; + hostapd_wireless_event_wireless_custom(drv, buf); + free(buf); + break; + } + + pos += iwe->len; + } +} + + +static void hostapd_wireless_event_rtm_newlink(void *ctx, + struct ifinfomsg *ifi, + u8 *buf, size_t len) +{ + struct hostap_driver_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; + + /* TODO: use ifi->ifi_index to filter out wireless events from other + * interfaces */ + + attrlen = len; + attr = (struct rtattr *) buf; + + rta_len = RTA_ALIGN(sizeof(struct rtattr)); + while (RTA_OK(attr, attrlen)) { + if (attr->rta_type == IFLA_WIRELESS) { + hostapd_wireless_event_wireless( + drv, ((char *) attr) + rta_len, + attr->rta_len - rta_len); + } + attr = RTA_NEXT(attr, attrlen); + } +} + + +static int hostap_get_we_version(struct hostap_driver_data *drv) +{ + struct iw_range *range; + struct iwreq iwr; + int minlen; + size_t buflen; + + drv->we_version = 0; + + /* + * Use larger buffer than struct iw_range in order to allow the + * structure to grow in the future. + */ + buflen = sizeof(struct iw_range) + 500; + range = os_zalloc(buflen); + if (range == NULL) + return -1; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) range; + iwr.u.data.length = buflen; + + minlen = ((char *) &range->enc_capa) - (char *) range + + sizeof(range->enc_capa); + + if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { + perror("ioctl[SIOCGIWRANGE]"); + free(range); + return -1; + } else if (iwr.u.data.length >= minlen && + range->we_version_compiled >= 18) { + wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " + "WE(source)=%d enc_capa=0x%x", + range->we_version_compiled, + range->we_version_source, + range->enc_capa); + drv->we_version = range->we_version_compiled; + } + + free(range); + return 0; +} + + +static int hostap_wireless_event_init(struct hostap_driver_data *drv) +{ + struct netlink_config *cfg; + + hostap_get_we_version(drv); + + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + return -1; + cfg->ctx = drv; + cfg->newlink_cb = hostapd_wireless_event_rtm_newlink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); + return -1; + } + + return 0; +} + + +static void * hostap_init(struct hostapd_data *hapd, + struct wpa_init_params *params) +{ + struct hostap_driver_data *drv; + + drv = os_zalloc(sizeof(struct hostap_driver_data)); + if (drv == NULL) { + printf("Could not allocate memory for hostapd driver data\n"); + return NULL; + } + + drv->hapd = hapd; + drv->ioctl_sock = drv->sock = -1; + memcpy(drv->iface, params->ifname, sizeof(drv->iface)); + + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->ioctl_sock < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + free(drv); + return NULL; + } + + if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) { + printf("Could not enable hostapd mode for interface %s\n", + drv->iface); + close(drv->ioctl_sock); + free(drv); + return NULL; + } + + if (hostap_init_sockets(drv, params->own_addr) || + hostap_wireless_event_init(drv)) { + close(drv->ioctl_sock); + free(drv); + return NULL; + } + + return drv; +} + + +static void hostap_driver_deinit(void *priv) +{ + struct hostap_driver_data *drv = priv; + + netlink_deinit(drv->netlink); + (void) hostap_set_iface_flags(drv, 0); + (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0); + (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0); + + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + + if (drv->sock >= 0) + close(drv->sock); + + os_free(drv->generic_ie); + os_free(drv->wps_ie); + + free(drv); +} + + +static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_mgmt mgmt; + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DEAUTH); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); + mgmt.u.deauth.reason_code = host_to_le16(reason); + return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth)); +} + + +static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, + int reason) +{ + struct hostap_driver_data *drv = priv; + struct ieee80211_mgmt mgmt; + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DISASSOC); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); + mgmt.u.disassoc.reason_code = host_to_le16(reason); + return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + + sizeof(mgmt.u.disassoc)); +} + + +static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, + u16 *num_modes, + u16 *flags) +{ + struct hostapd_hw_modes *mode; + int i, clen, rlen; + const short chan2freq[14] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 + }; + + mode = os_zalloc(sizeof(struct hostapd_hw_modes)); + if (mode == NULL) + return NULL; + + *num_modes = 1; + *flags = 0; + + mode->mode = HOSTAPD_MODE_IEEE80211B; + mode->num_channels = 14; + mode->num_rates = 4; + + clen = mode->num_channels * sizeof(struct hostapd_channel_data); + rlen = mode->num_rates * sizeof(int); + + mode->channels = os_zalloc(clen); + mode->rates = os_zalloc(rlen); + if (mode->channels == NULL || mode->rates == NULL) { + os_free(mode->channels); + os_free(mode->rates); + os_free(mode); + return NULL; + } + + for (i = 0; i < 14; i++) { + mode->channels[i].chan = i + 1; + mode->channels[i].freq = chan2freq[i]; + /* TODO: Get allowed channel list from the driver */ + if (i >= 11) + mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; + } + + mode->rates[0] = 10; + mode->rates[1] = 20; + mode->rates[2] = 55; + mode->rates[3] = 110; + + return mode; +} + +#else /* HOSTAPD */ + struct wpa_driver_hostap_data { void *wext; /* private data for driver_wext */ void *ctx; @@ -32,6 +1125,9 @@ struct wpa_driver_hostap_data { }; +static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg); + + static int hostapd_ioctl(struct wpa_driver_hostap_data *drv, struct prism2_hostapd_param *param, int len, int show_err) @@ -45,7 +1141,7 @@ static int hostapd_ioctl(struct wpa_driver_hostap_data *drv, if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { int ret = errno; - if (show_err) + if (show_err) perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); return ret; } @@ -147,9 +1243,10 @@ static void show_set_key_error(struct prism2_hostapd_param *param) } -static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg, - const u8 *addr, int key_idx, - int set_tx, const u8 *seq, size_t seq_len, +static int wpa_driver_hostap_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct wpa_driver_hostap_data *drv = priv; @@ -232,14 +1329,6 @@ static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled) } -static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled) -{ - struct wpa_driver_hostap_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled); -} - - static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv, int type) { @@ -315,6 +1404,11 @@ wpa_driver_hostap_associate(void *priv, wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, + params->drop_unencrypted) < 0) + ret = -1; + if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0) + ret = -1; if (params->mode != drv->current_mode) { /* At the moment, Host AP driver requires host_roaming=2 for * infrastructure mode and host_roaming=0 for adhoc. */ @@ -365,18 +1459,21 @@ wpa_driver_hostap_associate(void *priv, } -static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_hostap_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_hostap_data *drv = priv; struct prism2_hostapd_param param; int ret; + const u8 *ssid = params->ssids[0].ssid; + size_t ssid_len = params->ssids[0].ssid_len; if (ssid == NULL) { /* Use standard Linux Wireless Extensions ioctl if possible * because some drivers using hostap code in wpa_supplicant * might not support Host AP specific scan request (with SSID * info). */ - return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); + return wpa_driver_wext_scan(drv->wext, params); } if (ssid_len > 32) @@ -404,11 +1501,11 @@ static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg) struct wpa_driver_hostap_data *drv = priv; int algs = 0; - if (auth_alg & AUTH_ALG_OPEN_SYSTEM) + if (auth_alg & WPA_AUTH_ALG_OPEN) algs |= 1; - if (auth_alg & AUTH_ALG_SHARED_KEY) + if (auth_alg & WPA_AUTH_ALG_SHARED) algs |= 2; - if (auth_alg & AUTH_ALG_LEAP) + if (auth_alg & WPA_AUTH_ALG_LEAP) algs |= 4; if (algs == 0) algs = 1; /* at least one algorithm should be set */ @@ -479,6 +1576,8 @@ static void * wpa_driver_hostap_init(void *ctx, const char *ifname) wpa_driver_wext_alternative_ifindex(drv->wext, ifname2); } + wpa_driver_hostap_set_wpa(drv, 1); + return drv; } @@ -486,28 +1585,51 @@ static void * wpa_driver_hostap_init(void *ctx, const char *ifname) static void wpa_driver_hostap_deinit(void *priv) { struct wpa_driver_hostap_data *drv = priv; + wpa_driver_hostap_set_wpa(drv, 0); wpa_driver_wext_deinit(drv->wext); close(drv->sock); os_free(drv); } +#endif /* HOSTAPD */ + const struct wpa_driver_ops wpa_driver_hostap_ops = { .name = "hostap", .desc = "Host AP driver (Intersil Prism2/2.5/3)", + .set_key = wpa_driver_hostap_set_key, +#ifdef HOSTAPD + .hapd_init = hostap_init, + .hapd_deinit = hostap_driver_deinit, + .set_ieee8021x = hostap_set_ieee8021x, + .set_privacy = hostap_set_privacy, + .get_seqnum = hostap_get_seqnum, + .flush = hostap_flush, + .set_generic_elem = hostap_set_generic_elem, + .read_sta_data = hostap_read_sta_data, + .hapd_send_eapol = hostap_send_eapol, + .sta_set_flags = hostap_sta_set_flags, + .sta_deauth = hostap_sta_deauth, + .sta_disassoc = hostap_sta_disassoc, + .sta_remove = hostap_sta_remove, + .hapd_set_ssid = hostap_set_ssid, + .send_mlme = hostap_send_mlme, + .sta_add = hostap_sta_add, + .get_inact_sec = hostap_get_inact_sec, + .sta_clear_stats = hostap_sta_clear_stats, + .get_hw_feature_data = hostap_get_hw_feature_data, + .set_ap_wps_ie = hostap_set_ap_wps_ie, +#else /* HOSTAPD */ .get_bssid = wpa_driver_hostap_get_bssid, .get_ssid = wpa_driver_hostap_get_ssid, - .set_wpa = wpa_driver_hostap_set_wpa, - .set_key = wpa_driver_hostap_set_key, .set_countermeasures = wpa_driver_hostap_set_countermeasures, - .set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted, - .scan = wpa_driver_hostap_scan, + .scan2 = wpa_driver_hostap_scan, .get_scan_results2 = wpa_driver_hostap_get_scan_results, .deauthenticate = wpa_driver_hostap_deauthenticate, .disassociate = wpa_driver_hostap_disassociate, .associate = wpa_driver_hostap_associate, - .set_auth_alg = wpa_driver_hostap_set_auth_alg, .init = wpa_driver_hostap_init, .deinit = wpa_driver_hostap_deinit, .set_operstate = wpa_driver_hostap_set_operstate, +#endif /* HOSTAPD */ }; diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h index a2508ed924f6..66b2bb39b849 100644 --- a/src/drivers/driver_hostap.h +++ b/src/drivers/driver_hostap.h @@ -1,6 +1,6 @@ /* - * WPA Supplicant - driver interaction with Linux Host AP driver - * Copyright (c) 2003-2005, Jouni Malinen + * Driver interaction with Linux Host AP driver + * Copyright (c) 2002-2006, Jouni Malinen * * 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 @@ -15,10 +15,32 @@ #ifndef HOSTAP_DRIVER_H #define HOSTAP_DRIVER_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 */ @@ -63,6 +85,47 @@ enum { 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, @@ -140,8 +203,8 @@ struct prism2_hostapd_param { } u; }; -#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01 -#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02 +#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 diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m index 8e64ffdcc08a..8213fdacc32e 100644 --- a/src/drivers/driver_iphone.m +++ b/src/drivers/driver_iphone.m @@ -20,7 +20,7 @@ #include "common.h" #include "driver.h" #include "eloop.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "MobileApple80211.h" diff --git a/src/drivers/driver_ipw.c b/src/drivers/driver_ipw.c index 3c19cccf4640..77984f9e5c4c 100644 --- a/src/drivers/driver_ipw.c +++ b/src/drivers/driver_ipw.c @@ -93,6 +93,8 @@ struct ipw_param { /* end of ipw2100.c and ipw2200.c code */ +static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg); + static int ipw_ioctl(struct wpa_driver_ipw_data *drv, struct ipw_param *param, int len, int show_err) { @@ -213,10 +215,11 @@ static int wpa_driver_ipw_set_wpa(void *priv, int enabled) } -static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int wpa_driver_ipw_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) { struct wpa_driver_ipw_data *drv = priv; struct ipw_param *param; @@ -318,6 +321,11 @@ wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params) int ret = 0; int unencrypted_eapol; + if (wpa_driver_ipw_set_auth_alg(drv, params->auth_alg) < 0) + ret = -1; + if (wpa_driver_ipw_set_drop_unencrypted(drv, params->drop_unencrypted) + < 0) + ret = -1; if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) ret = -1; if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, @@ -347,11 +355,11 @@ static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg) struct wpa_driver_ipw_data *drv = priv; int algs = 0; - if (auth_alg & AUTH_ALG_OPEN_SYSTEM) + if (auth_alg & WPA_AUTH_ALG_OPEN) algs |= 1; - if (auth_alg & AUTH_ALG_SHARED_KEY) + if (auth_alg & WPA_AUTH_ALG_SHARED) algs |= 2; - if (auth_alg & AUTH_ALG_LEAP) + if (auth_alg & WPA_AUTH_ALG_LEAP) algs |= 4; if (algs == 0) algs = 1; /* at least one algorithm should be set */ @@ -375,10 +383,11 @@ static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid) } -static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_ipw_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_ipw_data *drv = priv; - return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); + return wpa_driver_wext_scan(drv->wext, params); } @@ -428,6 +437,8 @@ static void * wpa_driver_ipw_init(void *ctx, const char *ifname) return NULL; } + wpa_driver_ipw_set_wpa(drv, 1); + return drv; } @@ -435,6 +446,7 @@ static void * wpa_driver_ipw_init(void *ctx, const char *ifname) static void wpa_driver_ipw_deinit(void *priv) { struct wpa_driver_ipw_data *drv = priv; + wpa_driver_ipw_set_wpa(drv, 0); wpa_driver_wext_deinit(drv->wext); close(drv->sock); os_free(drv); @@ -447,16 +459,13 @@ const struct wpa_driver_ops wpa_driver_ipw_ops = { "or newer)", .get_bssid = wpa_driver_ipw_get_bssid, .get_ssid = wpa_driver_ipw_get_ssid, - .set_wpa = wpa_driver_ipw_set_wpa, .set_key = wpa_driver_ipw_set_key, .set_countermeasures = wpa_driver_ipw_set_countermeasures, - .set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted, - .scan = wpa_driver_ipw_scan, + .scan2 = wpa_driver_ipw_scan, .get_scan_results2 = wpa_driver_ipw_get_scan_results, .deauthenticate = wpa_driver_ipw_deauthenticate, .disassociate = wpa_driver_ipw_disassociate, .associate = wpa_driver_ipw_associate, - .set_auth_alg = wpa_driver_ipw_set_auth_alg, .init = wpa_driver_ipw_init, .deinit = wpa_driver_ipw_deinit, .set_operstate = wpa_driver_ipw_set_operstate, diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c index 7521037234ce..8687404db902 100644 --- a/src/drivers/driver_madwifi.c +++ b/src/drivers/driver_madwifi.c @@ -1,7 +1,8 @@ /* * WPA Supplicant - driver interaction with MADWIFI 802.11 driver * Copyright (c) 2004, Sam Leffler - * Copyright (c) 2004-2005, Jouni Malinen + * Copyright (c) 2004, Video54 Technologies + * Copyright (c) 2004-2007, Jouni Malinen * * 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 @@ -12,9 +13,10 @@ * * See README and COPYING for more details. * - * Please note that madwifi supports WPA configuration via Linux wireless - * extensions and if the kernel includes support for this, driver_wext.c should - * be used instead of this driver wrapper. + * While this driver wrapper supports both AP (hostapd) and station + * (wpa_supplicant) operations, the station side is deprecated and + * driver_wext.c should be used instead. This driver wrapper should only be + * used with hostapd for AP mode functionality. */ #include "includes.h" @@ -24,7 +26,7 @@ #include "driver.h" #include "driver_wext.h" #include "eloop.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "wireless_copy.h" /* @@ -42,12 +44,1236 @@ #include #include +#ifdef CONFIG_WPS +#ifdef IEEE80211_IOCTL_FILTERFRAME +#include + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW 0x0019 +#endif +#endif /* IEEE80211_IOCTL_FILTERFRAME */ +#endif /* CONFIG_WPS */ + +/* + * Avoid conflicts with hostapd definitions by undefining couple of defines + * from madwifi header files. + */ +#undef RSN_VERSION +#undef WPA_VERSION +#undef WPA_OUI_TYPE +#undef WME_OUI_TYPE + #ifdef IEEE80211_IOCTL_SETWMMPARAMS /* Assume this is built against madwifi-ng */ #define MADWIFI_NG #endif /* IEEE80211_IOCTL_SETWMMPARAMS */ + +#ifdef HOSTAPD + +#include "priv_netlink.h" +#include "netlink.h" +#include "linux_ioctl.h" +#include "l2_packet/l2_packet.h" + + +struct madwifi_driver_data { + struct hostapd_data *hapd; /* back pointer */ + + char iface[IFNAMSIZ + 1]; + int ifindex; + struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ + struct l2_packet_data *sock_recv; /* raw packet recv socket */ + int ioctl_sock; /* socket for ioctl() use */ + struct netlink_data *netlink; + int we_version; + u8 acct_mac[ETH_ALEN]; + struct hostap_sta_driver_data acct_data; + + struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ +}; + +static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code); + +static int +set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) +{ + struct iwreq iwr; + int do_inline = len < IFNAMSIZ; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); +#ifdef IEEE80211_IOCTL_FILTERFRAME + /* FILTERFRAME must be NOT inline, regardless of size. */ + if (op == IEEE80211_IOCTL_FILTERFRAME) + do_inline = 0; +#endif /* IEEE80211_IOCTL_FILTERFRAME */ + if (op == IEEE80211_IOCTL_SET_APPIEBUF) + do_inline = 0; + if (do_inline) { + /* + * Argument data fits inline; put it there. + */ + memcpy(iwr.u.name, data, len); + } else { + /* + * Argument data too big for inline transfer; setup a + * parameter block instead; the kernel will transfer + * the data for the driver. + */ + iwr.u.data.pointer = data; + iwr.u.data.length = len; + } + + if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { +#ifdef MADWIFI_NG + int first = IEEE80211_IOCTL_SETPARAM; + static const char *opnames[] = { + "ioctl[IEEE80211_IOCTL_SETPARAM]", + "ioctl[IEEE80211_IOCTL_GETPARAM]", + "ioctl[IEEE80211_IOCTL_SETMODE]", + "ioctl[IEEE80211_IOCTL_GETMODE]", + "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]", + "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]", + "ioctl[IEEE80211_IOCTL_SETCHANLIST]", + "ioctl[IEEE80211_IOCTL_GETCHANLIST]", + "ioctl[IEEE80211_IOCTL_CHANSWITCH]", + "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]", + "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", + "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]", + "ioctl[IEEE80211_IOCTL_FILTERFRAME]", + "ioctl[IEEE80211_IOCTL_GETCHANINFO]", + "ioctl[IEEE80211_IOCTL_SETOPTIE]", + "ioctl[IEEE80211_IOCTL_GETOPTIE]", + "ioctl[IEEE80211_IOCTL_SETMLME]", + NULL, + "ioctl[IEEE80211_IOCTL_SETKEY]", + NULL, + "ioctl[IEEE80211_IOCTL_DELKEY]", + NULL, + "ioctl[IEEE80211_IOCTL_ADDMAC]", + NULL, + "ioctl[IEEE80211_IOCTL_DELMAC]", + NULL, + "ioctl[IEEE80211_IOCTL_WDSMAC]", + NULL, + "ioctl[IEEE80211_IOCTL_WDSDELMAC]", + NULL, + "ioctl[IEEE80211_IOCTL_KICKMAC]", + }; +#else /* MADWIFI_NG */ + int first = IEEE80211_IOCTL_SETPARAM; + static const char *opnames[] = { + "ioctl[IEEE80211_IOCTL_SETPARAM]", + "ioctl[IEEE80211_IOCTL_GETPARAM]", + "ioctl[IEEE80211_IOCTL_SETKEY]", + "ioctl[SIOCIWFIRSTPRIV+3]", + "ioctl[IEEE80211_IOCTL_DELKEY]", + "ioctl[SIOCIWFIRSTPRIV+5]", + "ioctl[IEEE80211_IOCTL_SETMLME]", + "ioctl[SIOCIWFIRSTPRIV+7]", + "ioctl[IEEE80211_IOCTL_SETOPTIE]", + "ioctl[IEEE80211_IOCTL_GETOPTIE]", + "ioctl[IEEE80211_IOCTL_ADDMAC]", + "ioctl[SIOCIWFIRSTPRIV+11]", + "ioctl[IEEE80211_IOCTL_DELMAC]", + "ioctl[SIOCIWFIRSTPRIV+13]", + "ioctl[IEEE80211_IOCTL_CHANLIST]", + "ioctl[SIOCIWFIRSTPRIV+15]", + "ioctl[IEEE80211_IOCTL_GETRSN]", + "ioctl[SIOCIWFIRSTPRIV+17]", + "ioctl[IEEE80211_IOCTL_GETKEY]", + }; +#endif /* MADWIFI_NG */ + int idx = op - first; + if (first <= op && + idx < (int) (sizeof(opnames) / sizeof(opnames[0])) && + opnames[idx]) + perror(opnames[idx]); + else + perror("ioctl[unknown???]"); + return -1; + } + return 0; +} + +static int +set80211param(struct madwifi_driver_data *drv, int op, int arg) +{ + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.mode = op; + memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); + + if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { + perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); + wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d " + "arg %d)", __func__, op, arg); + return -1; + } + return 0; +} + +#ifndef CONFIG_NO_STDOUT_DEBUG +static const char * +ether_sprintf(const u8 *addr) +{ + static char buf[sizeof(MACSTR)]; + + if (addr != NULL) + snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + else + snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); + return buf; +} +#endif /* CONFIG_NO_STDOUT_DEBUG */ + +/* + * Configure WPA parameters. + */ +static int +madwifi_configure_wpa(struct madwifi_driver_data *drv, + struct wpa_bss_params *params) +{ + int v; + + switch (params->wpa_group) { + case WPA_CIPHER_CCMP: + v = IEEE80211_CIPHER_AES_CCM; + break; + case WPA_CIPHER_TKIP: + v = IEEE80211_CIPHER_TKIP; + break; + case WPA_CIPHER_WEP104: + v = IEEE80211_CIPHER_WEP; + break; + case WPA_CIPHER_WEP40: + v = IEEE80211_CIPHER_WEP; + break; + case WPA_CIPHER_NONE: + v = IEEE80211_CIPHER_NONE; + break; + default: + wpa_printf(MSG_ERROR, "Unknown group key cipher %u", + params->wpa_group); + return -1; + } + wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); + if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { + printf("Unable to set group key cipher to %u\n", v); + return -1; + } + if (v == IEEE80211_CIPHER_WEP) { + /* key length is done only for specific ciphers */ + v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); + if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { + printf("Unable to set group key length to %u\n", v); + return -1; + } + } + + v = 0; + if (params->wpa_pairwise & WPA_CIPHER_CCMP) + v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) + v |= 1<wpa_pairwise & WPA_CIPHER_NONE) + v |= 1<wpa_key_mgmt); + if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, + params->wpa_key_mgmt)) { + printf("Unable to set key management algorithms to 0x%x\n", + params->wpa_key_mgmt); + return -1; + } + + v = 0; + if (params->rsn_preauth) + v |= BIT(0); + wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", + __func__, params->rsn_preauth); + if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { + printf("Unable to set RSN capabilities to 0x%x\n", v); + return -1; + } + + wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); + if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { + printf("Unable to set WPA to %u\n", params->wpa); + return -1; + } + return 0; +} + +static int +madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) +{ + struct madwifi_driver_data *drv = priv; + + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); + + if (!params->enabled) { + /* XXX restore state */ + return set80211param(priv, IEEE80211_PARAM_AUTHMODE, + IEEE80211_AUTH_AUTO); + } + if (!params->wpa && !params->ieee802_1x) { + hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, + HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); + return -1; + } + if (params->wpa && madwifi_configure_wpa(drv, params) != 0) { + hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, + HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); + return -1; + } + if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, + (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { + hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, + HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); + return -1; + } + + return 0; +} + +static int +madwifi_set_privacy(void *priv, int enabled) +{ + struct madwifi_driver_data *drv = priv; + + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); + + return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); +} + +static int +madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) +{ + struct madwifi_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", + __func__, ether_sprintf(addr), authorized); + + if (authorized) + mlme.im_op = IEEE80211_MLME_AUTHORIZE; + else + mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; + mlme.im_reason = 0; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, + __func__, authorized ? "" : "un", MAC2STR(addr)); + } + + return ret; +} + +static int +madwifi_sta_set_flags(void *priv, const u8 *addr, + int total_flags, int flags_or, int flags_and) +{ + /* For now, only support setting Authorized flag */ + if (flags_or & WPA_STA_AUTHORIZED) + return madwifi_set_sta_authorized(priv, addr, 1); + if (!(flags_and & WPA_STA_AUTHORIZED)) + return madwifi_set_sta_authorized(priv, addr, 0); + return 0; +} + +static int +madwifi_del_key(void *priv, const u8 *addr, int key_idx) +{ + struct madwifi_driver_data *drv = priv; + struct ieee80211req_del_key wk; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", + __func__, ether_sprintf(addr), key_idx); + + memset(&wk, 0, sizeof(wk)); + if (addr != NULL) { + memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); + wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; + } else { + wk.idk_keyix = key_idx; + } + + ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" + " key_idx %d)", __func__, ether_sprintf(addr), + key_idx); + } + + return ret; +} + +static int +wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, + const u8 *addr, int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + struct madwifi_driver_data *drv = priv; + struct ieee80211req_key wk; + u_int8_t cipher; + int ret; + + if (alg == WPA_ALG_NONE) + return madwifi_del_key(drv, addr, key_idx); + + wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", + __func__, alg, ether_sprintf(addr), key_idx); + + if (alg == WPA_ALG_WEP) + cipher = IEEE80211_CIPHER_WEP; + else if (alg == WPA_ALG_TKIP) + cipher = IEEE80211_CIPHER_TKIP; + else if (alg == WPA_ALG_CCMP) + cipher = IEEE80211_CIPHER_AES_CCM; + else { + printf("%s: unknown/unsupported algorithm %d\n", + __func__, alg); + return -1; + } + + if (key_len > sizeof(wk.ik_keydata)) { + printf("%s: key length %lu too big\n", __func__, + (unsigned long) key_len); + return -3; + } + + memset(&wk, 0, sizeof(wk)); + wk.ik_type = cipher; + wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; + if (addr == NULL) { + memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + wk.ik_keyix = key_idx; + wk.ik_flags |= IEEE80211_KEY_DEFAULT; + } else { + memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + wk.ik_keyix = IEEE80211_KEYIX_NONE; + } + wk.ik_keylen = key_len; + memcpy(wk.ik_keydata, key, key_len); + + ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" + " key_idx %d alg %d key_len %lu set_tx %d)", + __func__, ether_sprintf(wk.ik_macaddr), key_idx, + alg, (unsigned long) key_len, set_tx); + } + + return ret; +} + + +static int +madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, + u8 *seq) +{ + struct madwifi_driver_data *drv = priv; + struct ieee80211req_key wk; + + wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", + __func__, ether_sprintf(addr), idx); + + memset(&wk, 0, sizeof(wk)); + if (addr == NULL) + memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + else + memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); + wk.ik_keyix = idx; + + if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { + wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " + "(addr " MACSTR " key_idx %d)", + __func__, MAC2STR(wk.ik_macaddr), idx); + return -1; + } + +#ifdef WORDS_BIGENDIAN + { + /* + * wk.ik_keytsc is in host byte order (big endian), need to + * swap it to match with the byte order used in WPA. + */ + int i; + u8 tmp[WPA_KEY_RSC_LEN]; + memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); + for (i = 0; i < WPA_KEY_RSC_LEN; i++) { + seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; + } + } +#else /* WORDS_BIGENDIAN */ + memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); +#endif /* WORDS_BIGENDIAN */ + return 0; +} + + +static int +madwifi_flush(void *priv) +{ +#ifdef MADWIFI_BSD + u8 allsta[IEEE80211_ADDR_LEN]; + memset(allsta, 0xff, IEEE80211_ADDR_LEN); + return madwifi_sta_deauth(priv, NULL, allsta, + IEEE80211_REASON_AUTH_LEAVE); +#else /* MADWIFI_BSD */ + return 0; /* XXX */ +#endif /* MADWIFI_BSD */ +} + + +static int +madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct madwifi_driver_data *drv = priv; + +#ifdef MADWIFI_BSD + struct ieee80211req_sta_stats stats; + + memset(data, 0, sizeof(*data)); + + /* + * Fetch statistics for station from the system. + */ + memset(&stats, 0, sizeof(stats)); + memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); + if (set80211priv(drv, +#ifdef MADWIFI_NG + IEEE80211_IOCTL_STA_STATS, +#else /* MADWIFI_NG */ + IEEE80211_IOCTL_GETSTASTATS, +#endif /* MADWIFI_NG */ + &stats, sizeof(stats))) { + wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " + MACSTR ")", __func__, MAC2STR(addr)); + if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + memcpy(data, &drv->acct_data, sizeof(*data)); + return 0; + } + + printf("Failed to get station stats information element.\n"); + return -1; + } + + data->rx_packets = stats.is_stats.ns_rx_data; + data->rx_bytes = stats.is_stats.ns_rx_bytes; + data->tx_packets = stats.is_stats.ns_tx_data; + data->tx_bytes = stats.is_stats.ns_tx_bytes; + return 0; + +#else /* MADWIFI_BSD */ + + char buf[1024], line[128], *pos; + FILE *f; + unsigned long val; + + memset(data, 0, sizeof(*data)); + snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR, + drv->iface, MAC2STR(addr)); + + f = fopen(buf, "r"); + if (!f) { + if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0) + return -1; + memcpy(data, &drv->acct_data, sizeof(*data)); + return 0; + } + /* Need to read proc file with in one piece, so use large enough + * buffer. */ + setbuffer(f, buf, sizeof(buf)); + + while (fgets(line, sizeof(line), f)) { + pos = strchr(line, '='); + if (!pos) + continue; + *pos++ = '\0'; + val = strtoul(pos, NULL, 10); + if (strcmp(line, "rx_packets") == 0) + data->rx_packets = val; + else if (strcmp(line, "tx_packets") == 0) + data->tx_packets = val; + else if (strcmp(line, "rx_bytes") == 0) + data->rx_bytes = val; + else if (strcmp(line, "tx_bytes") == 0) + data->tx_bytes = val; + } + + fclose(f); + + return 0; +#endif /* MADWIFI_BSD */ +} + + +static int +madwifi_sta_clear_stats(void *priv, const u8 *addr) +{ +#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS) + struct madwifi_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); + + mlme.im_op = IEEE80211_MLME_CLEAR_STATS; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, + sizeof(mlme)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " + MACSTR ")", __func__, MAC2STR(addr)); + } + + return ret; +#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ + return 0; /* FIX */ +#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ +} + + +static int +madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) +{ + /* + * Do nothing; we setup parameters at startup that define the + * contents of the beacon information element. + */ + return 0; +} + +static int +madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code) +{ + struct madwifi_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", + __func__, ether_sprintf(addr), reason_code); + + mlme.im_op = IEEE80211_MLME_DEAUTH; + mlme.im_reason = reason_code; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR + " reason %d)", + __func__, MAC2STR(addr), reason_code); + } + + return ret; +} + +static int +madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, + int reason_code) +{ + struct madwifi_driver_data *drv = priv; + struct ieee80211req_mlme mlme; + int ret; + + wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", + __func__, ether_sprintf(addr), reason_code); + + mlme.im_op = IEEE80211_MLME_DISASSOC; + mlme.im_reason = reason_code; + memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); + ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " + MACSTR " reason %d)", + __func__, MAC2STR(addr), reason_code); + } + + return ret; +} + +#ifdef CONFIG_WPS +#ifdef IEEE80211_IOCTL_FILTERFRAME +static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) +{ + struct madwifi_driver_data *drv = ctx; + const struct ieee80211_mgmt *mgmt; + u16 fc; + union wpa_event_data event; + + /* Send Probe Request information to WPS processing */ + + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) + return; + mgmt = (const struct ieee80211_mgmt *) buf; + + fc = le_to_host16(mgmt->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) + return; + + os_memset(&event, 0, sizeof(event)); + event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.ie = mgmt->u.probe_req.variable; + event.rx_probe_req.ie_len = + len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); + wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); +} +#endif /* IEEE80211_IOCTL_FILTERFRAME */ +#endif /* CONFIG_WPS */ + +static int madwifi_receive_probe_req(struct madwifi_driver_data *drv) +{ + int ret = 0; +#ifdef CONFIG_WPS +#ifdef IEEE80211_IOCTL_FILTERFRAME + struct ieee80211req_set_filter filt; + + wpa_printf(MSG_DEBUG, "%s Enter", __func__); + filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ; + + ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, + sizeof(struct ieee80211req_set_filter)); + if (ret) + return ret; + + drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, + madwifi_raw_receive, drv, 1); + if (drv->sock_raw == NULL) + return -1; +#endif /* IEEE80211_IOCTL_FILTERFRAME */ +#endif /* CONFIG_WPS */ + return ret; +} + +#ifdef CONFIG_WPS +static int +madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) +{ + struct madwifi_driver_data *drv = priv; + u8 buf[256]; + struct ieee80211req_getset_appiebuf *beac_ie; + + wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, + (unsigned long) len); + + beac_ie = (struct ieee80211req_getset_appiebuf *) buf; + beac_ie->app_frmtype = frametype; + beac_ie->app_buflen = len; + memcpy(&(beac_ie->app_buf[0]), ie, len); + + return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, + sizeof(struct ieee80211req_getset_appiebuf) + len); +} + +static int +madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp) +{ + if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, + beacon ? wpabuf_len(beacon) : 0, + IEEE80211_APPIE_FRAME_BEACON) < 0) + return -1; + return madwifi_set_wps_ie(priv, + proberesp ? wpabuf_head(proberesp) : NULL, + proberesp ? wpabuf_len(proberesp) : 0, + IEEE80211_APPIE_FRAME_PROBE_RESP); +} +#else /* CONFIG_WPS */ +#define madwifi_set_ap_wps_ie NULL +#endif /* CONFIG_WPS */ + +static void +madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) +{ + struct hostapd_data *hapd = drv->hapd; + struct ieee80211req_wpaie ie; + int ielen = 0; + u8 *iebuf = NULL; + + /* + * Fetch negotiated WPA/RSN parameters from the system. + */ + memset(&ie, 0, sizeof(ie)); + memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); + if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { + wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE", + __func__); + goto no_ie; + } + wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE", + ie.wpa_ie, IEEE80211_MAX_OPT_IE); + iebuf = ie.wpa_ie; + /* madwifi seems to return some random data if WPA/RSN IE is not set. + * Assume the IE was not included if the IE type is unknown. */ + if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) + iebuf[1] = 0; +#ifdef MADWIFI_NG + wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE", + ie.rsn_ie, IEEE80211_MAX_OPT_IE); + if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { + /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not + * set. This is needed for WPA2. */ + iebuf = ie.rsn_ie; + if (iebuf[0] != WLAN_EID_RSN) + iebuf[1] = 0; + } +#endif /* MADWIFI_NG */ + + ielen = iebuf[1]; + if (ielen == 0) + iebuf = NULL; + else + ielen += 2; + +no_ie: + drv_event_assoc(hapd, addr, iebuf, ielen); + + if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + /* Cached accounting data is not valid anymore. */ + memset(drv->acct_mac, 0, ETH_ALEN); + memset(&drv->acct_data, 0, sizeof(drv->acct_data)); + } +} + +static void +madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, + char *custom) +{ + wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); + + if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { + char *pos; + u8 addr[ETH_ALEN]; + pos = strstr(custom, "addr="); + if (pos == NULL) { + wpa_printf(MSG_DEBUG, + "MLME-MICHAELMICFAILURE.indication " + "without sender address ignored"); + return; + } + pos += 5; + if (hwaddr_aton(pos, addr) == 0) { + union wpa_event_data data; + os_memset(&data, 0, sizeof(data)); + data.michael_mic_failure.unicast = 1; + data.michael_mic_failure.src = addr; + wpa_supplicant_event(drv->hapd, + EVENT_MICHAEL_MIC_FAILURE, &data); + } else { + wpa_printf(MSG_DEBUG, + "MLME-MICHAELMICFAILURE.indication " + "with invalid MAC address"); + } + } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { + char *key, *value; + u32 val; + key = custom; + while ((key = strchr(key, '\n')) != NULL) { + key++; + value = strchr(key, '='); + if (value == NULL) + continue; + *value++ = '\0'; + val = strtoul(value, NULL, 10); + if (strcmp(key, "mac") == 0) + hwaddr_aton(value, drv->acct_mac); + else if (strcmp(key, "rx_packets") == 0) + drv->acct_data.rx_packets = val; + else if (strcmp(key, "tx_packets") == 0) + drv->acct_data.tx_packets = val; + else if (strcmp(key, "rx_bytes") == 0) + drv->acct_data.rx_bytes = val; + else if (strcmp(key, "tx_bytes") == 0) + drv->acct_data.tx_bytes = val; + key = value; + } + } +} + +static void +madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, + char *data, int len) +{ + struct iw_event iwe_buf, *iwe = &iwe_buf; + char *pos, *end, *custom, *buf; + + pos = data; + end = data + len; + + while (pos + IW_EV_LCP_LEN <= end) { + /* Event data may be unaligned, so make a local, aligned copy + * before processing. */ + memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); + wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", + iwe->cmd, iwe->len); + if (iwe->len <= IW_EV_LCP_LEN) + return; + + custom = pos + IW_EV_POINT_LEN; + if (drv->we_version > 18 && + (iwe->cmd == IWEVMICHAELMICFAILURE || + iwe->cmd == IWEVCUSTOM)) { + /* WE-19 removed the pointer from struct iw_point */ + char *dpos = (char *) &iwe_buf.u.data.length; + int dlen = dpos - (char *) &iwe_buf; + memcpy(dpos, pos + IW_EV_LCP_LEN, + sizeof(struct iw_event) - dlen); + } else { + memcpy(&iwe_buf, pos, sizeof(struct iw_event)); + custom += IW_EV_POINT_OFF; + } + + switch (iwe->cmd) { + case IWEVEXPIRED: + drv_event_disassoc(drv->hapd, + (u8 *) iwe->u.addr.sa_data); + break; + case IWEVREGISTERED: + madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data); + break; + case IWEVCUSTOM: + if (custom + iwe->u.data.length > end) + return; + buf = malloc(iwe->u.data.length + 1); + if (buf == NULL) + return; /* XXX */ + memcpy(buf, custom, iwe->u.data.length); + buf[iwe->u.data.length] = '\0'; + madwifi_wireless_event_wireless_custom(drv, buf); + free(buf); + break; + } + + pos += iwe->len; + } +} + + +static void +madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, + u8 *buf, size_t len) +{ + struct madwifi_driver_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; + + if (ifi->ifi_index != drv->ifindex) + return; + + attrlen = len; + attr = (struct rtattr *) buf; + + rta_len = RTA_ALIGN(sizeof(struct rtattr)); + while (RTA_OK(attr, attrlen)) { + if (attr->rta_type == IFLA_WIRELESS) { + madwifi_wireless_event_wireless( + drv, ((char *) attr) + rta_len, + attr->rta_len - rta_len); + } + attr = RTA_NEXT(attr, attrlen); + } +} + + +static int +madwifi_get_we_version(struct madwifi_driver_data *drv) +{ + struct iw_range *range; + struct iwreq iwr; + int minlen; + size_t buflen; + + drv->we_version = 0; + + /* + * Use larger buffer than struct iw_range in order to allow the + * structure to grow in the future. + */ + buflen = sizeof(struct iw_range) + 500; + range = os_zalloc(buflen); + if (range == NULL) + return -1; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) range; + iwr.u.data.length = buflen; + + minlen = ((char *) &range->enc_capa) - (char *) range + + sizeof(range->enc_capa); + + if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { + perror("ioctl[SIOCGIWRANGE]"); + free(range); + return -1; + } else if (iwr.u.data.length >= minlen && + range->we_version_compiled >= 18) { + wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " + "WE(source)=%d enc_capa=0x%x", + range->we_version_compiled, + range->we_version_source, + range->enc_capa); + drv->we_version = range->we_version_compiled; + } + + free(range); + return 0; +} + + +static int +madwifi_wireless_event_init(struct madwifi_driver_data *drv) +{ + struct netlink_config *cfg; + + madwifi_get_we_version(drv); + + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + return -1; + cfg->ctx = drv; + cfg->newlink_cb = madwifi_wireless_event_rtm_newlink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); + return -1; + } + + return 0; +} + + +static int +madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, + int encrypt, const u8 *own_addr) +{ + struct madwifi_driver_data *drv = priv; + unsigned char buf[3000]; + unsigned char *bp = buf; + struct l2_ethhdr *eth; + size_t len; + int status; + + /* + * Prepend the Ethernet header. If the caller left us + * space at the front we could just insert it but since + * we don't know we copy to a local buffer. Given the frequency + * and size of frames this probably doesn't matter. + */ + len = data_len + sizeof(struct l2_ethhdr); + if (len > sizeof(buf)) { + bp = malloc(len); + if (bp == NULL) { + printf("EAPOL frame discarded, cannot malloc temp " + "buffer of size %lu!\n", (unsigned long) len); + return -1; + } + } + eth = (struct l2_ethhdr *) bp; + memcpy(eth->h_dest, addr, ETH_ALEN); + memcpy(eth->h_source, own_addr, ETH_ALEN); + eth->h_proto = host_to_be16(ETH_P_EAPOL); + memcpy(eth+1, data, data_len); + + wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); + + status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); + + if (bp != buf) + free(bp); + return status; +} + +static void +handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) +{ + struct madwifi_driver_data *drv = ctx; + drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), + len - sizeof(struct l2_ethhdr)); +} + +static void * +madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) +{ + struct madwifi_driver_data *drv; + struct ifreq ifr; + struct iwreq iwr; + char brname[IFNAMSIZ]; + + drv = os_zalloc(sizeof(struct madwifi_driver_data)); + if (drv == NULL) { + printf("Could not allocate memory for madwifi driver data\n"); + return NULL; + } + + drv->hapd = hapd; + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->ioctl_sock < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + goto bad; + } + memcpy(drv->iface, params->ifname, sizeof(drv->iface)); + + memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); + if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { + perror("ioctl(SIOCGIFINDEX)"); + goto bad; + } + drv->ifindex = ifr.ifr_ifindex; + + drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, + handle_read, drv, 1); + if (drv->sock_xmit == NULL) + goto bad; + if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) + goto bad; + if (params->bridge[0]) { + wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", + params->bridge[0]); + drv->sock_recv = l2_packet_init(params->bridge[0], NULL, + ETH_P_EAPOL, handle_read, drv, + 1); + if (drv->sock_recv == NULL) + goto bad; + } else if (linux_br_get(brname, drv->iface) == 0) { + wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " + "EAPOL receive", brname); + drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, + handle_read, drv, 1); + if (drv->sock_recv == NULL) + goto bad; + } else + drv->sock_recv = drv->sock_xmit; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + + iwr.u.mode = IW_MODE_MASTER; + + if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { + perror("ioctl[SIOCSIWMODE]"); + printf("Could not set interface to master mode!\n"); + goto bad; + } + + /* mark down during setup */ + linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); + madwifi_set_privacy(drv, 0); /* default to no privacy */ + + madwifi_receive_probe_req(drv); + + if (madwifi_wireless_event_init(drv)) + goto bad; + + return drv; +bad: + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + if (drv != NULL) + free(drv); + return NULL; +} + + +static void +madwifi_deinit(void *priv) +{ + struct madwifi_driver_data *drv = priv; + + netlink_deinit(drv->netlink); + (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) + l2_packet_deinit(drv->sock_recv); + if (drv->sock_xmit != NULL) + l2_packet_deinit(drv->sock_xmit); + if (drv->sock_raw) + l2_packet_deinit(drv->sock_raw); + free(drv); +} + +static int +madwifi_set_ssid(void *priv, const u8 *buf, int len) +{ + struct madwifi_driver_data *drv = priv; + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.essid.flags = 1; /* SSID active */ + iwr.u.essid.pointer = (caddr_t) buf; + iwr.u.essid.length = len + 1; + + if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { + perror("ioctl[SIOCSIWESSID]"); + printf("len=%d\n", len); + return -1; + } + return 0; +} + +static int +madwifi_get_ssid(void *priv, u8 *buf, int len) +{ + struct madwifi_driver_data *drv = priv; + struct iwreq iwr; + int ret = 0; + + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.essid.pointer = (caddr_t) buf; + iwr.u.essid.length = len; + + if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { + perror("ioctl[SIOCGIWESSID]"); + ret = -1; + } else + ret = iwr.u.essid.length; + + return ret; +} + +static int +madwifi_set_countermeasures(void *priv, int enabled) +{ + struct madwifi_driver_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); + return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); +} + +static int +madwifi_commit(void *priv) +{ + struct madwifi_driver_data *drv = priv; + return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); +} + +#else /* HOSTAPD */ + struct wpa_driver_madwifi_data { void *wext; /* private data for driver_wext */ void *ctx; @@ -55,6 +1281,11 @@ struct wpa_driver_madwifi_data { int sock; }; +static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg); +static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies, + size_t ies_len); + + static int set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len, int show_err) @@ -205,7 +1436,7 @@ wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx, } static int -wpa_driver_madwifi_set_key(void *priv, wpa_alg alg, +wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -227,8 +1458,8 @@ wpa_driver_madwifi_set_key(void *priv, wpa_alg alg, * configuration with IEEE80211_IOCTL_SETKEY, so use * Linux wireless extensions ioctl for this. */ - return wpa_driver_wext_set_key(drv->wext, alg, addr, - key_idx, set_tx, + return wpa_driver_wext_set_key(ifname, drv->wext, alg, + addr, key_idx, set_tx, seq, seq_len, key, key_len); } @@ -303,15 +1534,6 @@ wpa_driver_madwifi_set_countermeasures(void *priv, int enabled) return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1); } - -static int -wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled) -{ - struct wpa_driver_madwifi_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); - return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1); -} - static int wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code) { @@ -348,6 +1570,12 @@ wpa_driver_madwifi_associate(void *priv, wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, + params->drop_unencrypted, 1) < 0) + ret = -1; + if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0) + ret = -1; + /* * NB: Don't need to set the freq or cipher-related state as * this is implied by the bssid which is used to locate @@ -411,10 +1639,10 @@ wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg) struct wpa_driver_madwifi_data *drv = priv; int authmode; - if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) && - (auth_alg & AUTH_ALG_SHARED_KEY)) + if ((auth_alg & WPA_AUTH_ALG_OPEN) && + (auth_alg & WPA_AUTH_ALG_SHARED)) authmode = IEEE80211_AUTH_AUTO; - else if (auth_alg & AUTH_ALG_SHARED_KEY) + else if (auth_alg & WPA_AUTH_ALG_SHARED) authmode = IEEE80211_AUTH_SHARED; else authmode = IEEE80211_AUTH_OPEN; @@ -423,11 +1651,16 @@ wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg) } static int -wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len) +wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params) { struct wpa_driver_madwifi_data *drv = priv; struct iwreq iwr; int ret = 0; + const u8 *ssid = params->ssids[0].ssid; + size_t ssid_len = params->ssids[0].ssid_len; + + wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies, + params->extra_ies_len); os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); @@ -579,23 +1812,43 @@ static void wpa_driver_madwifi_deinit(void *priv) os_free(drv); } +#endif /* HOSTAPD */ + const struct wpa_driver_ops wpa_driver_madwifi_ops = { .name = "madwifi", .desc = "MADWIFI 802.11 support (Atheros, etc.)", + .set_key = wpa_driver_madwifi_set_key, +#ifdef HOSTAPD + .hapd_init = madwifi_init, + .hapd_deinit = madwifi_deinit, + .set_ieee8021x = madwifi_set_ieee8021x, + .set_privacy = madwifi_set_privacy, + .get_seqnum = madwifi_get_seqnum, + .flush = madwifi_flush, + .set_generic_elem = madwifi_set_opt_ie, + .sta_set_flags = madwifi_sta_set_flags, + .read_sta_data = madwifi_read_sta_driver_data, + .hapd_send_eapol = madwifi_send_eapol, + .sta_disassoc = madwifi_sta_disassoc, + .sta_deauth = madwifi_sta_deauth, + .hapd_set_ssid = madwifi_set_ssid, + .hapd_get_ssid = madwifi_get_ssid, + .hapd_set_countermeasures = madwifi_set_countermeasures, + .sta_clear_stats = madwifi_sta_clear_stats, + .commit = madwifi_commit, + .set_ap_wps_ie = madwifi_set_ap_wps_ie, +#else /* HOSTAPD */ .get_bssid = wpa_driver_madwifi_get_bssid, .get_ssid = wpa_driver_madwifi_get_ssid, - .set_key = wpa_driver_madwifi_set_key, .init = wpa_driver_madwifi_init, .deinit = wpa_driver_madwifi_deinit, .set_countermeasures = wpa_driver_madwifi_set_countermeasures, - .set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted, - .scan = wpa_driver_madwifi_scan, + .scan2 = wpa_driver_madwifi_scan, .get_scan_results2 = wpa_driver_madwifi_get_scan_results, .deauthenticate = wpa_driver_madwifi_deauthenticate, .disassociate = wpa_driver_madwifi_disassociate, .associate = wpa_driver_madwifi_associate, - .set_auth_alg = wpa_driver_madwifi_set_auth_alg, .set_operstate = wpa_driver_madwifi_set_operstate, - .set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie, +#endif /* HOSTAPD */ }; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index a90e277ca04d..462dd81f58af 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -40,7 +40,7 @@ int close(int fd); #include "common.h" #include "driver.h" #include "eloop.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "driver_ndis.h" int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv); @@ -353,6 +353,47 @@ typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST { #endif /* OID_802_11_CAPABILITY */ +#ifndef OID_DOT11_CURRENT_OPERATION_MODE +/* Native 802.11 OIDs */ +#define OID_DOT11_NDIS_START 0x0D010300 +#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8) +#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11) + +typedef enum _DOT11_BSS_TYPE { + dot11_BSS_type_infrastructure = 1, + dot11_BSS_type_independent = 2, + dot11_BSS_type_any = 3 +} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE; + +typedef UCHAR DOT11_MAC_ADDRESS[6]; +typedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS; + +typedef enum _DOT11_SCAN_TYPE { + dot11_scan_type_active = 1, + dot11_scan_type_passive = 2, + dot11_scan_type_auto = 3, + dot11_scan_type_forced = 0x80000000 +} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE; + +typedef struct _DOT11_SCAN_REQUEST_V2 { + DOT11_BSS_TYPE dot11BSSType; + DOT11_MAC_ADDRESS dot11BSSID; + DOT11_SCAN_TYPE dot11ScanType; + BOOLEAN bRestrictedScan; + ULONG udot11SSIDsOffset; + ULONG uNumOfdot11SSIDs; + BOOLEAN bUseRequestIE; + ULONG uRequestIDsOffset; + ULONG uNumOfRequestIDs; + ULONG uPhyTypeInfosOffset; + ULONG uNumOfPhyTypeInfos; + ULONG uIEsOffset; + ULONG uIEsLength; + UCHAR ucBuffer[1]; +} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2; + +#endif /* OID_DOT11_CURRENT_OPERATION_MODE */ + #ifdef CONFIG_USE_NDISUIO #ifndef _WIN32_WCE #ifdef __MINGW32_VERSION @@ -698,13 +739,6 @@ static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr, } -static int wpa_driver_ndis_set_wpa(void *priv, int enabled) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return 0; -} - - static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx) { wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); @@ -712,11 +746,35 @@ static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx) } -static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_ndis_scan_native80211( + struct wpa_driver_ndis_data *drv, + struct wpa_driver_scan_params *params) +{ + DOT11_SCAN_REQUEST_V2 req; + int res; + + os_memset(&req, 0, sizeof(req)); + req.dot11BSSType = dot11_BSS_type_any; + os_memset(req.dot11BSSID, 0xff, ETH_ALEN); + req.dot11ScanType = dot11_scan_type_auto; + res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req, + sizeof(req)); + eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); + eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv, + drv->ctx); + return res; +} + + +static int wpa_driver_ndis_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_ndis_data *drv = priv; int res; + if (drv->native80211) + return wpa_driver_ndis_scan_native80211(drv, params); + if (!drv->radio_enabled) { wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first" " scan"); @@ -734,6 +792,25 @@ static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len) } +static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) +{ + const u8 *end, *pos; + + pos = (const u8 *) (res + 1); + end = pos + res->ie_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} + + static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid( struct wpa_scan_res *r, NDIS_802_11_SSID *ssid) { @@ -912,7 +989,8 @@ static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv, } -static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr, +static int wpa_driver_ndis_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -1020,7 +1098,8 @@ wpa_driver_ndis_associate(void *priv, continue; wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP " "key %d", i); - wpa_driver_ndis_set_key(drv, WPA_ALG_WEP, bcast, i, + wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP, + bcast, i, i == params->wep_tx_keyidx, NULL, 0, params->wep_key[i], params->wep_key_len[i]); @@ -1028,8 +1107,8 @@ wpa_driver_ndis_associate(void *priv, } if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { - if (params->auth_alg & AUTH_ALG_SHARED_KEY) { - if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM) + if (params->auth_alg & WPA_AUTH_ALG_SHARED) { + if (params->auth_alg & WPA_AUTH_ALG_OPEN) auth_mode = Ndis802_11AuthModeAutoSwitch; else auth_mode = Ndis802_11AuthModeShared; @@ -2801,16 +2880,31 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname) mode = Ndis802_11Infrastructure; if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, (char *) &mode, sizeof(mode)) < 0) { + char buf[8]; + int res; wpa_printf(MSG_DEBUG, "NDIS: Failed to set " "OID_802_11_INFRASTRUCTURE_MODE (%d)", (int) mode); /* Try to continue anyway */ - if (!drv->has_capability && drv->capa.enc == 0) { + res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf, + sizeof(buf)); + if (res > 0) { + wpa_printf(MSG_INFO, "NDIS: The driver seems to use " + "Native 802.11 OIDs. These are not yet " + "fully supported."); + drv->native80211 = 1; + } else if (!drv->has_capability || drv->capa.enc == 0) { + /* + * Note: This will also happen with NDIS 6 drivers with + * Vista. + */ wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide " "any wireless capabilities - assume it is " "a wired interface"); drv->wired = 1; + drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED; + drv->has_capability = 1; ndis_add_multicast(drv); } } @@ -3096,19 +3190,14 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = { "Windows NDIS driver", wpa_driver_ndis_get_bssid, wpa_driver_ndis_get_ssid, - wpa_driver_ndis_set_wpa, wpa_driver_ndis_set_key, wpa_driver_ndis_init, wpa_driver_ndis_deinit, NULL /* set_param */, NULL /* set_countermeasures */, - NULL /* set_drop_unencrypted */, - wpa_driver_ndis_scan, - NULL /* get_scan_results */, wpa_driver_ndis_deauthenticate, wpa_driver_ndis_disassociate, wpa_driver_ndis_associate, - NULL /* set_auth_alg */, wpa_driver_ndis_add_pmkid, wpa_driver_ndis_remove_pmkid, wpa_driver_ndis_flush_pmkid, @@ -3129,11 +3218,61 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = { NULL /* update_ft_ies */, NULL /* send_ft_action */, wpa_driver_ndis_get_scan_results, - NULL /* set_probe_req_ie */, - NULL /* set_mode */, NULL /* set_country */, NULL /* global_init */, NULL /* global_deinit */, NULL /* init2 */, - wpa_driver_ndis_get_interfaces + wpa_driver_ndis_get_interfaces, + wpa_driver_ndis_scan, + NULL /* authenticate */, + NULL /* set_beacon */, + NULL /* hapd_init */, + NULL /* hapd_deinit */, + NULL /* set_ieee8021x */, + NULL /* set_privacy */, + NULL /* get_seqnum */, + NULL /* flush */, + NULL /* set_generic_elem */, + NULL /* read_sta_data */, + NULL /* hapd_send_eapol */, + NULL /* sta_deauth */, + NULL /* sta_disassoc */, + NULL /* sta_remove */, + NULL /* hapd_get_ssid */, + NULL /* hapd_set_ssid */, + NULL /* hapd_set_countermeasures */, + NULL /* sta_add */, + NULL /* get_inact_sec */, + NULL /* sta_clear_stats */, + NULL /* set_freq */, + NULL /* set_rts */, + NULL /* set_frag */, + NULL /* sta_set_flags */, + NULL /* set_rate_sets */, + NULL /* set_cts_protect */, + NULL /* set_preamble */, + NULL /* set_short_slot_time */, + NULL /* set_tx_queue_params */, + NULL /* valid_bss_mask */, + NULL /* if_add */, + NULL /* if_remove */, + NULL /* set_sta_vlan */, + NULL /* commit */, + NULL /* send_ether */, + NULL /* set_radius_acl_auth */, + NULL /* set_radius_acl_expire */, + NULL /* set_ht_params */, + NULL /* set_ap_wps_ie */, + NULL /* set_supp_port */, + NULL /* set_wds_sta */, + NULL /* send_action */, + NULL /* remain_on_channel */, + NULL /* cancel_remain_on_channel */, + NULL /* probe_req_report */, + NULL /* disable_11b_rates */, + NULL /* deinit_ap */, + NULL /* suspend */, + NULL /* resume */, + NULL /* signal_monitor */, + NULL /* send_frame */ }; diff --git a/src/drivers/driver_ndis.h b/src/drivers/driver_ndis.h index cdce4bac85ab..f263f0e43585 100644 --- a/src/drivers/driver_ndis.h +++ b/src/drivers/driver_ndis.h @@ -52,6 +52,7 @@ struct wpa_driver_ndis_data { struct ndis_pmkid_entry *pmkid; char *adapter_desc; int wired; + int native80211; int mode; int wzc_disabled; int oid_bssid_set; diff --git a/src/drivers/driver_ndiswrapper.c b/src/drivers/driver_ndiswrapper.c index b5c534a74d08..cd2f61e468a0 100644 --- a/src/drivers/driver_ndiswrapper.c +++ b/src/drivers/driver_ndiswrapper.c @@ -33,9 +33,8 @@ struct wpa_driver_ndiswrapper_data { }; -struct wpa_key -{ - wpa_alg alg; +struct wpa_key { + enum wpa_alg alg; const u8 *addr; int key_index; int set_tx; @@ -45,17 +44,16 @@ struct wpa_key size_t key_len; }; -struct wpa_assoc_info -{ +struct wpa_assoc_info { const u8 *bssid; const u8 *ssid; size_t ssid_len; int freq; const u8 *wpa_ie; size_t wpa_ie_len; - wpa_cipher pairwise_suite; - wpa_cipher group_suite; - wpa_key_mgmt key_mgmt_suite; + enum wpa_cipher pairwise_suite; + enum wpa_cipher group_suite; + enum wpa_key_mgmt key_mgmt_suite; int auth_alg; int mode; }; @@ -73,6 +71,8 @@ struct wpa_assoc_info #define WPA_DEINIT SIOCIWFIRSTPRIV+10 #define WPA_GET_CAPA SIOCIWFIRSTPRIV+11 +static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg); + static int get_socket(void) { static const int families[] = { @@ -111,7 +111,8 @@ static int wpa_ndiswrapper_set_wpa(void *priv, int enabled) return ret; } -static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr, +static int wpa_ndiswrapper_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -146,8 +147,8 @@ static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr, * did not associate. Try to make sure the keys are cleared so * that plaintext APs can be used in all cases. */ - wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx, - seq, seq_len, key, key_len); + wpa_driver_wext_set_key(ifname, drv->wext, alg, addr, key_idx, + set_tx, seq, seq_len, key, key_len); } return ret; @@ -223,6 +224,12 @@ wpa_ndiswrapper_associate(void *priv, struct wpa_assoc_info wpa_assoc_info; struct iwreq priv_req; + if (wpa_ndiswrapper_set_drop_unencrypted(drv, + params->drop_unencrypted) < 0) + ret = -1; + if (wpa_ndiswrapper_set_auth_alg(drv, params->auth_alg) < 0) + ret = -1; + os_memset(&priv_req, 0, sizeof(priv_req)); os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info)); @@ -274,10 +281,11 @@ static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid) } -static int wpa_ndiswrapper_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_ndiswrapper_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_ndiswrapper_data *drv = priv; - return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); + return wpa_driver_wext_scan(drv->wext, params); } @@ -334,6 +342,8 @@ static void * wpa_ndiswrapper_init(void *ctx, const char *ifname) return NULL; } + wpa_ndiswrapper_set_wpa(drv, 1); + return drv; } @@ -341,6 +351,7 @@ static void * wpa_ndiswrapper_init(void *ctx, const char *ifname) static void wpa_ndiswrapper_deinit(void *priv) { struct wpa_driver_ndiswrapper_data *drv = priv; + wpa_ndiswrapper_set_wpa(drv, 0); wpa_driver_wext_deinit(drv->wext); close(drv->sock); os_free(drv); @@ -350,18 +361,15 @@ static void wpa_ndiswrapper_deinit(void *priv) const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = { .name = "ndiswrapper", .desc = "Linux ndiswrapper (deprecated; use wext)", - .set_wpa = wpa_ndiswrapper_set_wpa, .set_key = wpa_ndiswrapper_set_key, .set_countermeasures = wpa_ndiswrapper_set_countermeasures, - .set_drop_unencrypted = wpa_ndiswrapper_set_drop_unencrypted, .deauthenticate = wpa_ndiswrapper_deauthenticate, .disassociate = wpa_ndiswrapper_disassociate, .associate = wpa_ndiswrapper_associate, - .set_auth_alg = wpa_ndiswrapper_set_auth_alg, .get_bssid = wpa_ndiswrapper_get_bssid, .get_ssid = wpa_ndiswrapper_get_ssid, - .scan = wpa_ndiswrapper_scan, + .scan2 = wpa_ndiswrapper_scan, .get_scan_results2 = wpa_ndiswrapper_get_scan_results, .init = wpa_ndiswrapper_init, .deinit = wpa_ndiswrapper_deinit, diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 9ab6d17279a9..364158c7d8e2 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1,6 +1,10 @@ /* - * WPA Supplicant - driver interaction with Linux nl80211/cfg80211 - * Copyright (c) 2003-2008, Jouni Malinen + * Driver interaction with Linux nl80211/cfg80211 + * Copyright (c) 2002-2010, Jouni Malinen + * Copyright (c) 2003-2004, Instant802 Networks, Inc. + * Copyright (c) 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2007, Johannes Berg + * Copyright (c) 2009-2010, Atheros Communications * * 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 @@ -14,23 +18,30 @@ #include "includes.h" #include -#include +#include #include #include #include -#include "nl80211_copy.h" -#ifdef CONFIG_CLIENT_MLME #include -#include +#include +#include "nl80211_copy.h" + +#include "common.h" +#include "eloop.h" +#include "common/ieee802_11_defs.h" +#include "netlink.h" +#include "linux_ioctl.h" #include "radiotap.h" #include "radiotap_iter.h" -#endif /* CONFIG_CLIENT_MLME */ - -#include "wireless_copy.h" -#include "common.h" #include "driver.h" -#include "eloop.h" -#include "ieee802_11_defs.h" + +#ifdef CONFIG_LIBNL20 +/* libnl 2.0 compatibility code */ +#define nl_handle nl_sock +#define nl_handle_alloc_cb nl_socket_alloc_cb +#define nl_handle_destroy nl_socket_free +#endif /* CONFIG_LIBNL20 */ + #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ @@ -46,51 +57,104 @@ #define IF_OPER_UP 6 #endif +struct i802_bss { + struct wpa_driver_nl80211_data *drv; + struct i802_bss *next; + int ifindex; + char ifname[IFNAMSIZ + 1]; + unsigned int beacon_set:1; +}; struct wpa_driver_nl80211_data { void *ctx; - int wext_event_sock; - int ioctl_sock; - char ifname[IFNAMSIZ + 1]; + struct netlink_data *netlink; + int ioctl_sock; /* socket for ioctl() use */ + char brname[IFNAMSIZ]; int ifindex; int if_removed; - u8 *assoc_req_ies; - size_t assoc_req_ies_len; - u8 *assoc_resp_ies; - size_t assoc_resp_ies_len; struct wpa_driver_capa capa; int has_capability; - int we_version_compiled; - - /* for set_auth_alg fallback */ - int use_crypt; - int auth_alg_fallback; int operstate; - char mlmedev[IFNAMSIZ + 1]; - int scan_complete_events; struct nl_handle *nl_handle; + struct nl_handle *nl_handle_event; struct nl_cache *nl_cache; + struct nl_cache *nl_cache_event; struct nl_cb *nl_cb; struct genl_family *nl80211; -#ifdef CONFIG_CLIENT_MLME - int monitor_sock; /* socket for monitor */ + u8 auth_bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + int associated; + u8 ssid[32]; + size_t ssid_len; + int nlmode; + int ap_scan_as_station; + unsigned int assoc_freq; + + int monitor_sock; int monitor_ifidx; -#endif /* CONFIG_CLIENT_MLME */ + int probe_req_report; + int disable_11b_rates; + + unsigned int pending_remain_on_chan:1; + unsigned int added_bridge:1; + unsigned int added_if_into_bridge:1; + + u64 remain_on_chan_cookie; + u64 send_action_cookie; + + struct wpa_driver_scan_filter *filter_ssids; + size_t num_filter_ssids; + + struct i802_bss first_bss; + +#ifdef HOSTAPD + int eapol_sock; /* socket for EAPOL frames */ + + int default_if_indices[16]; + int *if_indices; + int num_if_indices; + + int last_freq; + int last_freq_ht; +#endif /* HOSTAPD */ }; static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); static int wpa_driver_nl80211_set_mode(void *priv, int mode); -static int wpa_driver_nl80211_flush_pmkid(void *priv); -static int wpa_driver_nl80211_get_range(void *priv); -static void +static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); +static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, + const u8 *addr, int cmd, u16 reason_code, + int local_state_change); +static void nl80211_remove_monitor_interface( + struct wpa_driver_nl80211_data *drv); + +#ifdef HOSTAPD +static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); +static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); +static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); +static int wpa_driver_nl80211_if_remove(void *priv, + enum wpa_driver_if_type type, + const char *ifname); +#else /* HOSTAPD */ +static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ + return 0; +} +#endif /* HOSTAPD */ + +static int i802_set_freq(void *priv, struct hostapd_freq_params *freq); +static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx, + void *timeout_ctx); +static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, + int ifindex, int disabled); /* nl80211 code */ @@ -116,10 +180,17 @@ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, return NL_SKIP; } -static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, - struct nl_msg *msg, - int (*valid_handler)(struct nl_msg *, void *), - void *valid_data) + +static int no_seq_check(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + + +static int send_and_recv(struct wpa_driver_nl80211_data *drv, + struct nl_handle *nl_handle, struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) { struct nl_cb *cb; int err = -ENOMEM; @@ -128,7 +199,7 @@ static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, if (!cb) goto out; - err = nl_send_auto_complete(drv->nl_handle, msg); + err = nl_send_auto_complete(nl_handle, msg); if (err < 0) goto out; @@ -143,7 +214,7 @@ static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, valid_handler, valid_data); while (err > 0) - nl_recvmsgs(drv->nl_handle, cb); + nl_recvmsgs(nl_handle, cb); out: nl_cb_put(cb); nlmsg_free(msg); @@ -151,6 +222,16 @@ static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, } +static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + return send_and_recv(drv, drv->nl_handle, msg, valid_handler, + valid_data); +} + + struct family_data { const char *group; int id; @@ -213,509 +294,30 @@ nla_put_failure: } -static int wpa_driver_nl80211_send_oper_ifla( - struct wpa_driver_nl80211_data *drv, - int linkmode, int operstate) -{ - struct { - struct nlmsghdr hdr; - struct ifinfomsg ifinfo; - char opts[16]; - } req; - struct rtattr *rta; - static int nl_seq; - ssize_t ret; - - os_memset(&req, 0, sizeof(req)); - - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.hdr.nlmsg_type = RTM_SETLINK; - req.hdr.nlmsg_flags = NLM_F_REQUEST; - req.hdr.nlmsg_seq = ++nl_seq; - req.hdr.nlmsg_pid = 0; - - req.ifinfo.ifi_family = AF_UNSPEC; - req.ifinfo.ifi_type = 0; - req.ifinfo.ifi_index = drv->ifindex; - req.ifinfo.ifi_flags = 0; - req.ifinfo.ifi_change = 0; - - if (linkmode != -1) { - rta = aliasing_hide_typecast( - ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), - struct rtattr); - rta->rta_type = IFLA_LINKMODE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - *((char *) RTA_DATA(rta)) = linkmode; - req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + - RTA_LENGTH(sizeof(char)); - } - if (operstate != -1) { - rta = (struct rtattr *) - ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)); - rta->rta_type = IFLA_OPERSTATE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - *((char *) RTA_DATA(rta)) = operstate; - req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + - RTA_LENGTH(sizeof(char)); - } - - wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d", - linkmode, operstate); - - ret = send(drv->wext_event_sock, &req, req.hdr.nlmsg_len, 0); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: " - "%s (assume operstate is not supported)", - strerror(errno)); - } - - return ret < 0 ? -1 : 0; -} - - -static int wpa_driver_nl80211_set_auth_param( - struct wpa_driver_nl80211_data *drv, int idx, u32 value) -{ - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.param.flags = idx & IW_AUTH_INDEX; - iwr.u.param.value = value; - - if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { - if (errno != EOPNOTSUPP) { - wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d " - "value 0x%x) failed: %s)", - idx, value, strerror(errno)); - } - ret = errno == EOPNOTSUPP ? -2 : -1; - } - - return ret; -} - - static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) { - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { - perror("ioctl[SIOCGIWAP]"); - ret = -1; - } - os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); - - return ret; -} - - -static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid) - os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); - else - os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); - - if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { - perror("ioctl[SIOCSIWAP]"); - ret = -1; - } - - return ret; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (!drv->associated) + return -1; + os_memcpy(bssid, drv->bssid, ETH_ALEN); + return 0; } static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) { - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.essid.pointer = (caddr_t) ssid; - iwr.u.essid.length = 32; - - if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); - ret = -1; - } else { - ret = iwr.u.essid.length; - if (ret > 32) - ret = 32; - /* Some drivers include nul termination in the SSID, so let's - * remove it here before further processing. WE-21 changes this - * to explicitly require the length _not_ to include nul - * termination. */ - if (ret > 0 && ssid[ret - 1] == '\0' && - drv->we_version_compiled < 21) - ret--; - } - - return ret; -} - - -static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid, - size_t ssid_len) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - char buf[33]; - - if (ssid_len > 32) + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (!drv->associated) return -1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ - iwr.u.essid.flags = (ssid_len != 0); - os_memset(buf, 0, sizeof(buf)); - os_memcpy(buf, ssid, ssid_len); - iwr.u.essid.pointer = (caddr_t) buf; - if (drv->we_version_compiled < 21) { - /* For historic reasons, set SSID length to include one extra - * character, C string nul termination, even though SSID is - * really an octet string that should not be presented as a C - * string. Some Linux drivers decrement the length by one and - * can thus end up missing the last octet of the SSID if the - * length is not incremented here. WE-21 changes this to - * explicitly require the length _not_ to include nul - * termination. */ - if (ssid_len) - ssid_len++; - } - iwr.u.essid.length = ssid_len; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_set_freq(void *priv, int freq) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.freq.m = freq * 100000; - iwr.u.freq.e = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { - perror("ioctl[SIOCSIWFREQ]"); - ret = -1; - } - - return ret; -} - - -static void -wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom) -{ - union wpa_event_data data; - - wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", - custom); - - os_memset(&data, 0, sizeof(data)); - /* Host AP driver */ - if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - data.michael_mic_failure.unicast = - os_strstr(custom, " unicast ") != NULL; - /* TODO: parse parameters(?) */ - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { - char *spos; - int bytes; - - spos = custom + 17; - - bytes = strspn(spos, "0123456789abcdefABCDEF"); - if (!bytes || (bytes & 1)) - return; - bytes /= 2; - - data.assoc_info.req_ies = os_malloc(bytes); - if (data.assoc_info.req_ies == NULL) - return; - - data.assoc_info.req_ies_len = bytes; - hexstr2bin(spos, data.assoc_info.req_ies, bytes); - - spos += bytes * 2; - - data.assoc_info.resp_ies = NULL; - data.assoc_info.resp_ies_len = 0; - - if (os_strncmp(spos, " RespIEs=", 9) == 0) { - spos += 9; - - bytes = strspn(spos, "0123456789abcdefABCDEF"); - if (!bytes || (bytes & 1)) - goto done; - bytes /= 2; - - data.assoc_info.resp_ies = os_malloc(bytes); - if (data.assoc_info.resp_ies == NULL) - goto done; - - data.assoc_info.resp_ies_len = bytes; - hexstr2bin(spos, data.assoc_info.resp_ies, bytes); - } - - wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - - done: - os_free(data.assoc_info.resp_ies); - os_free(data.assoc_info.req_ies); -#ifdef CONFIG_PEERKEY - } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { - if (hwaddr_aton(custom + 17, data.stkstart.peer)) { - wpa_printf(MSG_DEBUG, "WEXT: unrecognized " - "STKSTART.request '%s'", custom + 17); - return; - } - wpa_supplicant_event(ctx, EVENT_STKSTART, &data); -#endif /* CONFIG_PEERKEY */ - } -} - - -static int wpa_driver_nl80211_event_wireless_michaelmicfailure( - void *ctx, const char *ev, size_t len) -{ - const struct iw_michaelmicfailure *mic; - union wpa_event_data data; - - if (len < sizeof(*mic)) - return -1; - - mic = (const struct iw_michaelmicfailure *) ev; - - wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " - "flags=0x%x src_addr=" MACSTR, mic->flags, - MAC2STR(mic->src_addr.sa_data)); - - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - - return 0; -} - - -static int wpa_driver_nl80211_event_wireless_pmkidcand( - struct wpa_driver_nl80211_data *drv, const char *ev, size_t len) -{ - const struct iw_pmkid_cand *cand; - union wpa_event_data data; - const u8 *addr; - - if (len < sizeof(*cand)) - return -1; - - cand = (const struct iw_pmkid_cand *) ev; - addr = (const u8 *) cand->bssid.sa_data; - - wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " - "flags=0x%x index=%d bssid=" MACSTR, cand->flags, - cand->index, MAC2STR(addr)); - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); - data.pmkid_candidate.index = cand->index; - data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; - wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); - - return 0; -} - - -static int wpa_driver_nl80211_event_wireless_assocreqie( - struct wpa_driver_nl80211_data *drv, const char *ev, int len) -{ - if (len < 0) - return -1; - - wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, - len); - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = os_malloc(len); - if (drv->assoc_req_ies == NULL) { - drv->assoc_req_ies_len = 0; - return -1; - } - os_memcpy(drv->assoc_req_ies, ev, len); - drv->assoc_req_ies_len = len; - - return 0; -} - - -static int wpa_driver_nl80211_event_wireless_assocrespie( - struct wpa_driver_nl80211_data *drv, const char *ev, int len) -{ - if (len < 0) - return -1; - - wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, - len); - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = os_malloc(len); - if (drv->assoc_resp_ies == NULL) { - drv->assoc_resp_ies_len = 0; - return -1; - } - os_memcpy(drv->assoc_resp_ies, ev, len); - drv->assoc_resp_ies_len = len; - - return 0; -} - - -static void wpa_driver_nl80211_event_assoc_ies(struct wpa_driver_nl80211_data *drv) -{ - union wpa_event_data data; - - if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) - return; - - os_memset(&data, 0, sizeof(data)); - if (drv->assoc_req_ies) { - data.assoc_info.req_ies = drv->assoc_req_ies; - drv->assoc_req_ies = NULL; - data.assoc_info.req_ies_len = drv->assoc_req_ies_len; - } - if (drv->assoc_resp_ies) { - data.assoc_info.resp_ies = drv->assoc_resp_ies; - drv->assoc_resp_ies = NULL; - data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; - } - - wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); - - os_free(data.assoc_info.req_ies); - os_free(data.assoc_info.resp_ies); -} - - -static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv, - void *ctx, char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - if (drv->we_version_compiled > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM || - iwe->cmd == IWEVASSOCREQIE || - iwe->cmd == IWEVASSOCRESPIE || - iwe->cmd == IWEVPMKIDCAND)) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - os_memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case SIOCGIWAP: - wpa_printf(MSG_DEBUG, "Wireless event: new AP: " - MACSTR, - MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); - if (is_zero_ether_addr( - (const u8 *) iwe->u.ap_addr.sa_data) || - os_memcmp(iwe->u.ap_addr.sa_data, - "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == - 0) { - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = NULL; - wpa_supplicant_event(ctx, EVENT_DISASSOC, - NULL); - - } else { - wpa_driver_nl80211_event_assoc_ies(drv); - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); - } - break; - case IWEVMICHAELMICFAILURE: - wpa_driver_nl80211_event_wireless_michaelmicfailure( - ctx, custom, iwe->u.data.length); - break; - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = os_malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - os_memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - wpa_driver_nl80211_event_wireless_custom(ctx, buf); - os_free(buf); - break; - case IWEVASSOCREQIE: - wpa_driver_nl80211_event_wireless_assocreqie( - drv, custom, iwe->u.data.length); - break; - case IWEVASSOCRESPIE: - wpa_driver_nl80211_event_wireless_assocrespie( - drv, custom, iwe->u.data.length); - break; - case IWEVPMKIDCAND: - wpa_driver_nl80211_event_wireless_pmkidcand( - drv, custom, iwe->u.data.length); - break; - } - - pos += iwe->len; - } + os_memcpy(ssid, drv->ssid, drv->ssid_len); + return drv->ssid_len; } static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, - void *ctx, char *buf, size_t len, - int del) + char *buf, size_t len, int del) { union wpa_event_data event; @@ -731,38 +333,30 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, event.interface_status.ifname, del ? "removed" : "added"); - if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) { + if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) { if (del) drv->if_removed = 1; else drv->if_removed = 0; } - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv, - struct nlmsghdr *h) + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, _nlmsg_len, rta_len; + int attrlen, rta_len; struct rtattr *attr; - ifi = NLMSG_DATA(h); - - _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - _nlmsg_len; - if (attrlen < 0) - return 0; - - attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { - if (os_strcmp(((char *) attr) + rta_len, drv->ifname) + if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname) == 0) return 1; else @@ -776,13 +370,13 @@ static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv, static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, - int ifindex, struct nlmsghdr *h) + int ifindex, u8 *buf, size_t len) { if (drv->ifindex == ifindex) return 1; - if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) { - drv->ifindex = if_nametoindex(drv->ifname); + if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) { + drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname); wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed " "interface"); wpa_driver_nl80211_finish_drv_init(drv); @@ -793,22 +387,19 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, } -static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv, - void *ctx, struct nlmsghdr *h, - size_t len) +static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, + struct ifinfomsg *ifi, + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, _nlmsg_len, rta_len; - struct rtattr * attr; + struct wpa_driver_nl80211_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; + u32 brid = 0; - if (len < sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) { - wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", - ifi->ifi_index); + if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) && + !have_ifidx(drv, ifi->ifi_index)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign " + "ifindex %d", ifi->ifi_index); return; } @@ -828,137 +419,553 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) - wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP); - - _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - _nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len); + netlink_send_oper_ifla(drv->netlink, drv->ifindex, + -1, IF_OPER_UP); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - wpa_driver_nl80211_event_wireless( - drv, ctx, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } else if (attr->rta_type == IFLA_IFNAME) { + if (attr->rta_type == IFLA_IFNAME) { wpa_driver_nl80211_event_link( - drv, ctx, + drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 0); - } + } else if (attr->rta_type == IFLA_MASTER) + brid = nla_get_u32((struct nlattr *) attr); attr = RTA_NEXT(attr, attrlen); } + +#ifdef HOSTAPD + if (ifi->ifi_family == AF_BRIDGE && brid) { + /* device has been added to bridge */ + char namebuf[IFNAMSIZ]; + if_indextoname(brid, namebuf); + wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s", + brid, namebuf); + add_ifidx(drv, brid); + } +#endif /* HOSTAPD */ } -static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv, - void *ctx, struct nlmsghdr *h, - size_t len) +static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, + struct ifinfomsg *ifi, + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, _nlmsg_len, rta_len; - struct rtattr * attr; + struct wpa_driver_nl80211_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; + u32 brid = 0; - 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); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { wpa_driver_nl80211_event_link( - drv, ctx, + drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 1); - } + } else if (attr->rta_type == IFLA_MASTER) + brid = nla_get_u32((struct nlattr *) attr); attr = RTA_NEXT(attr, attrlen); } + +#ifdef HOSTAPD + if (ifi->ifi_family == AF_BRIDGE && brid) { + /* device has been removed from bridge */ + char namebuf[IFNAMSIZ]; + if_indextoname(brid, namebuf); + wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge " + "%s", brid, namebuf); + del_ifidx(drv, brid); + } +#endif /* HOSTAPD */ } -static void wpa_driver_nl80211_event_receive_wext(int sock, void *eloop_ctx, - void *sock_ctx) +static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, + const u8 *frame, size_t len) { - char buf[8192]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - int max_events = 10; + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; -try_again: - 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)"); + mgmt = (const struct ieee80211_mgmt *) frame; + if (len < 24 + sizeof(mgmt->u.auth)) { + wpa_printf(MSG_DEBUG, "nl80211: Too short association event " + "frame"); 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) { - wpa_printf(MSG_DEBUG, "Malformed netlink message: " - "len=%d left=%d plen=%d", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx, - h, plen); - break; - case RTM_DELLINK: - wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx, - h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); + os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); + event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); + event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); + if (len > 24 + sizeof(mgmt->u.auth)) { + event.auth.ies = mgmt->u.auth.variable; + event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); } - if (left > 0) { - wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink " - "message", left); + wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); +} + + +static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + u16 status; + + mgmt = (const struct ieee80211_mgmt *) frame; + if (len < 24 + sizeof(mgmt->u.assoc_resp)) { + wpa_printf(MSG_DEBUG, "nl80211: Too short association event " + "frame"); + return; } - if (--max_events > 0) { + status = le_to_host16(mgmt->u.assoc_resp.status_code); + if (status != WLAN_STATUS_SUCCESS) { + os_memset(&event, 0, sizeof(event)); + if (len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_reject.resp_ies = + (u8 *) mgmt->u.assoc_resp.variable; + event.assoc_reject.resp_ies_len = + len - 24 - sizeof(mgmt->u.assoc_resp); + } + event.assoc_reject.status_code = status; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); + return; + } + + drv->associated = 1; + os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); + + os_memset(&event, 0, sizeof(event)); + if (len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; + event.assoc_info.resp_ies_len = + len - 24 - sizeof(mgmt->u.assoc_resp); + } + + event.assoc_info.freq = drv->assoc_freq; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); +} + + +static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, + enum nl80211_commands cmd, struct nlattr *status, + struct nlattr *addr, struct nlattr *req_ie, + struct nlattr *resp_ie) +{ + union wpa_event_data event; + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* - * Try to receive all events in one eloop call in order to - * limit race condition on cases where AssocInfo event, Assoc - * event, and EAPOL frames are received more or less at the - * same time. We want to process the event messages first - * before starting EAPOL processing. + * Avoid reporting two association events that would confuse + * the core code. */ - goto try_again; + wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) " + "when using userspace SME", cmd); + return; + } + + os_memset(&event, 0, sizeof(event)); + if (cmd == NL80211_CMD_CONNECT && + nla_get_u16(status) != WLAN_STATUS_SUCCESS) { + if (resp_ie) { + event.assoc_reject.resp_ies = nla_data(resp_ie); + event.assoc_reject.resp_ies_len = nla_len(resp_ie); + } + event.assoc_reject.status_code = nla_get_u16(status); + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); + return; + } + + drv->associated = 1; + if (addr) + os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); + + if (req_ie) { + event.assoc_info.req_ies = nla_data(req_ie); + event.assoc_info.req_ies_len = nla_len(req_ie); + } + if (resp_ie) { + event.assoc_info.resp_ies = nla_data(resp_ie); + event.assoc_info.resp_ies_len = nla_len(resp_ie); + } + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); +} + + +static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, + enum nl80211_commands cmd, struct nlattr *addr) +{ + union wpa_event_data event; + enum wpa_event_type ev; + + if (nla_len(addr) != ETH_ALEN) + return; + + wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR, + cmd, MAC2STR((u8 *) nla_data(addr))); + + if (cmd == NL80211_CMD_AUTHENTICATE) + ev = EVENT_AUTH_TIMED_OUT; + else if (cmd == NL80211_CMD_ASSOCIATE) + ev = EVENT_ASSOC_TIMED_OUT; + else + return; + + os_memset(&event, 0, sizeof(event)); + os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); + wpa_supplicant_event(drv->ctx, ev, &event); +} + + +static void mlme_event_action(struct wpa_driver_nl80211_data *drv, + struct nlattr *freq, const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + u16 fc, stype; + + mgmt = (const struct ieee80211_mgmt *) frame; + if (len < 24) { + wpa_printf(MSG_DEBUG, "nl80211: Too short action frame"); + return; + } + + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + + os_memset(&event, 0, sizeof(event)); + event.rx_action.da = mgmt->da; + event.rx_action.sa = mgmt->sa; + event.rx_action.bssid = mgmt->bssid; + event.rx_action.category = mgmt->u.action.category; + event.rx_action.data = &mgmt->u.action.category + 1; + event.rx_action.len = frame + len - event.rx_action.data; + if (freq) + event.rx_action.freq = nla_get_u32(freq); + wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); +} + + +static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv, + struct nlattr *cookie, const u8 *frame, + size_t len, struct nlattr *ack) +{ + union wpa_event_data event; + const struct ieee80211_hdr *hdr; + u16 fc; + u64 cookie_val; + + if (!cookie) + return; + + cookie_val = nla_get_u64(cookie); + wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s", + (long long unsigned int) cookie_val, + cookie_val == drv->send_action_cookie ? + " (match)" : " (unknown)"); + if (cookie_val != drv->send_action_cookie) + return; + + hdr = (const struct ieee80211_hdr *) frame; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = frame; + event.tx_status.data_len = len; + event.tx_status.ack = ack != NULL; + wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); +} + + +static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, + enum wpa_event_type type, + const u8 *frame, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + union wpa_event_data event; + const u8 *bssid = NULL; + u16 reason_code = 0; + + mgmt = (const struct ieee80211_mgmt *) frame; + if (len >= 24) { + bssid = mgmt->bssid; + + if (drv->associated != 0 && + os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && + os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { + /* + * We have presumably received this deauth as a + * response to a clear_state_mismatch() outgoing + * deauth. Don't let it take us offline! + */ + wpa_printf(MSG_DEBUG, "nl80211: Deauth received " + "from Unknown BSSID " MACSTR " -- ignoring", + MAC2STR(bssid)); + return; + } + } + + drv->associated = 0; + os_memset(&event, 0, sizeof(event)); + + /* Note: Same offset for Reason Code in both frame subtypes */ + if (len >= 24 + sizeof(mgmt->u.deauth)) + reason_code = le_to_host16(mgmt->u.deauth.reason_code); + + if (type == EVENT_DISASSOC) { + event.disassoc_info.addr = bssid; + event.disassoc_info.reason_code = reason_code; + } else { + event.deauth_info.addr = bssid; + event.deauth_info.reason_code = reason_code; + } + + wpa_supplicant_event(drv->ctx, type, &event); +} + + +static void mlme_event(struct wpa_driver_nl80211_data *drv, + enum nl80211_commands cmd, struct nlattr *frame, + struct nlattr *addr, struct nlattr *timed_out, + struct nlattr *freq, struct nlattr *ack, + struct nlattr *cookie) +{ + if (timed_out && addr) { + mlme_timeout_event(drv, cmd, addr); + return; + } + + if (frame == NULL) { + wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame " + "data", cmd); + return; + } + + wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd); + wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame", + nla_data(frame), nla_len(frame)); + + switch (cmd) { + case NL80211_CMD_AUTHENTICATE: + mlme_event_auth(drv, nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_ASSOCIATE: + mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_DEAUTHENTICATE: + mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, + nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_DISASSOCIATE: + mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, + nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_ACTION: + mlme_event_action(drv, freq, nla_data(frame), nla_len(frame)); + break; + case NL80211_CMD_ACTION_TX_STATUS: + mlme_event_action_tx_status(drv, cookie, nla_data(frame), + nla_len(frame), ack); + break; + default: + break; } } -static int no_seq_check(struct nl_msg *msg, void *arg) +static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) { - return NL_OK; + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); + os_memset(&data, 0, sizeof(data)); + if (tb[NL80211_ATTR_MAC]) { + wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", + nla_data(tb[NL80211_ATTR_MAC]), + nla_len(tb[NL80211_ATTR_MAC])); + data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); + } + if (tb[NL80211_ATTR_KEY_SEQ]) { + wpa_hexdump(MSG_DEBUG, "nl80211: TSC", + nla_data(tb[NL80211_ATTR_KEY_SEQ]), + nla_len(tb[NL80211_ATTR_KEY_SEQ])); + } + if (tb[NL80211_ATTR_KEY_TYPE]) { + enum nl80211_key_type key_type = + nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); + wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type); + if (key_type == NL80211_KEYTYPE_PAIRWISE) + data.michael_mic_failure.unicast = 1; + } else + data.michael_mic_failure.unicast = 1; + + if (tb[NL80211_ATTR_KEY_IDX]) { + u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); + wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id); + } + + wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); +} + + +static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + if (tb[NL80211_ATTR_MAC] == NULL) { + wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " + "event"); + return; + } + os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + drv->associated = 1; + wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", + MAC2STR(drv->bssid)); + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); +} + + +static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, + int cancel_event, struct nlattr *tb[]) +{ + unsigned int freq, chan_type, duration; + union wpa_event_data data; + u64 cookie; + + if (tb[NL80211_ATTR_WIPHY_FREQ]) + freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + else + freq = 0; + + if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) + chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + else + chan_type = 0; + + if (tb[NL80211_ATTR_DURATION]) + duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); + else + duration = 0; + + if (tb[NL80211_ATTR_COOKIE]) + cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + else + cookie = 0; + + wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d " + "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", + cancel_event, freq, chan_type, duration, + (long long unsigned int) cookie, + cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); + + if (cookie != drv->remain_on_chan_cookie) + return; /* not for us */ + + drv->pending_remain_on_chan = !cancel_event; + + os_memset(&data, 0, sizeof(data)); + data.remain_on_channel.freq = freq; + data.remain_on_channel.duration = duration; + wpa_supplicant_event(drv->ctx, cancel_event ? + EVENT_CANCEL_REMAIN_ON_CHANNEL : + EVENT_REMAIN_ON_CHANNEL, &data); +} + + +static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, + struct nlattr *tb[]) +{ + union wpa_event_data event; + struct nlattr *nl; + int rem; + struct scan_info *info; +#define MAX_REPORT_FREQS 50 + int freqs[MAX_REPORT_FREQS]; + int num_freqs = 0; + + os_memset(&event, 0, sizeof(event)); + info = &event.scan_info; + info->aborted = aborted; + + if (tb[NL80211_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { + struct wpa_driver_scan_ssid *s = + &info->ssids[info->num_ssids]; + s->ssid = nla_data(nl); + s->ssid_len = nla_len(nl); + info->num_ssids++; + if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) + break; + } + } + if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) + { + freqs[num_freqs] = nla_get_u32(nl); + num_freqs++; + if (num_freqs == MAX_REPORT_FREQS - 1) + break; + } + info->freqs = freqs; + info->num_freqs = num_freqs; + } + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); +} + + +static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { + [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, + [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, + }; + struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; + enum nl80211_cqm_rssi_threshold_event event; + union wpa_event_data ed; + + if (tb[NL80211_ATTR_CQM] == NULL || + nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], + cqm_policy)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event"); + return; + } + + if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) + return; + event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); + + os_memset(&ed, 0, sizeof(ed)); + + if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { + wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " + "event: RSSI high"); + ed.signal_change.above_threshold = 1; + } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { + wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " + "event: RSSI low"); + ed.signal_change.above_threshold = 0; + } else + return; + + wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); } @@ -967,13 +974,14 @@ static int process_event(struct nl_msg *msg, void *arg) struct wpa_driver_nl80211_data *drv = arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; + union wpa_event_data data; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_IFINDEX]) { int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - if (ifindex != drv->ifindex) { + if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)" " for foreign interface (ifindex %d)", gnlh->cmd, ifindex); @@ -981,6 +989,14 @@ static int process_event(struct nl_msg *msg, void *arg) } } + if (drv->ap_scan_as_station && + (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || + gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { + wpa_driver_nl80211_set_mode(&drv->first_bss, + IEEE80211_MODE_AP); + drv->ap_scan_as_station = 0; + } + switch (gnlh->cmd) { case NL80211_CMD_TRIGGER_SCAN: wpa_printf(MSG_DEBUG, "nl80211: Scan trigger"); @@ -990,7 +1006,7 @@ static int process_event(struct nl_msg *msg, void *arg) drv->scan_complete_events = 1; eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); + send_scan_event(drv, 0, tb); break; case NL80211_CMD_SCAN_ABORTED: wpa_printf(MSG_DEBUG, "nl80211: Scan aborted"); @@ -1000,11 +1016,62 @@ static int process_event(struct nl_msg *msg, void *arg) */ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); + send_scan_event(drv, 1, tb); + break; + case NL80211_CMD_AUTHENTICATE: + case NL80211_CMD_ASSOCIATE: + case NL80211_CMD_DEAUTHENTICATE: + case NL80211_CMD_DISASSOCIATE: + case NL80211_CMD_ACTION: + case NL80211_CMD_ACTION_TX_STATUS: + mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE]); + break; + case NL80211_CMD_CONNECT: + case NL80211_CMD_ROAM: + mlme_event_connect(drv, gnlh->cmd, + tb[NL80211_ATTR_STATUS_CODE], + tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_REQ_IE], + tb[NL80211_ATTR_RESP_IE]); + break; + case NL80211_CMD_DISCONNECT: + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + /* + * Avoid reporting two disassociation events that could + * confuse the core code. + */ + wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " + "event when using userspace SME"); + break; + } + drv->associated = 0; + os_memset(&data, 0, sizeof(data)); + if (tb[NL80211_ATTR_REASON_CODE]) + data.disassoc_info.reason_code = + nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); + break; + case NL80211_CMD_MICHAEL_MIC_FAILURE: + mlme_event_michael_mic_failure(drv, tb); + break; + case NL80211_CMD_JOIN_IBSS: + mlme_event_join_ibss(drv, tb); + break; + case NL80211_CMD_REMAIN_ON_CHANNEL: + mlme_event_remain_on_channel(drv, 0, tb); + break; + case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: + mlme_event_remain_on_channel(drv, 1, tb); + break; + case NL80211_CMD_NOTIFY_CQM: + nl80211_cqm_event(drv, tb); break; default: - wpa_printf(MSG_DEBUG, "nl0211: Ignored unknown event (cmd=%d)", - gnlh->cmd); + wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " + "(cmd=%d)", gnlh->cmd); break; } @@ -1025,70 +1092,11 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx, return; nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv); - nl_recvmsgs(drv->nl_handle, cb); + nl_recvmsgs(drv->nl_handle_event, cb); nl_cb_put(cb); } -static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv, - const char *ifname, int *flags) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - *flags = ifr.ifr_flags & 0xffff; - return 0; -} - - -/** - * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS) - * @drv: driver_nl80211 private data - * @flags: Pointer to returned flags value - * Returns: 0 on success, -1 on failure - */ -static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv, - int *flags) -{ - return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags); -} - - -static int wpa_driver_nl80211_set_ifflags_ifname( - struct wpa_driver_nl80211_data *drv, - const char *ifname, int flags) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_flags = flags & 0xffff; - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { - perror("SIOCSIFFLAGS"); - return -1; - } - return 0; -} - - -/** - * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS) - * @drv: driver_nl80211 private data - * @flags: New value for flags - * Returns: 0 on success, -1 on failure - */ -static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv, - int flags) -{ - return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags); -} - - /** * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain * @priv: driver_nl80211 private data @@ -1100,13 +1108,14 @@ static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv, */ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg) { - struct wpa_driver_nl80211_data *drv = priv; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; char alpha2[3]; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) - goto nla_put_failure; + return -ENOMEM; alpha2[0] = alpha2_arg[0]; alpha2[1] = alpha2_arg[1]; @@ -1124,306 +1133,127 @@ nla_put_failure: } -static int wpa_driver_nl80211_set_probe_req_ie(void *priv, const u8 *ies, - size_t ies_len) +#ifndef HOSTAPD +struct wiphy_info_data { + int max_scan_ssids; + int ap_supported; + int auth_supported; + int connect_supported; +}; + + +static int wiphy_info_handler(struct nl_msg *msg, void *arg) { - struct wpa_driver_nl80211_data *drv = priv; - struct nl_msg *msg; - int ret = -1; + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wiphy_info_data *info = arg; - msg = nlmsg_alloc(); - if (!msg) - return -ENOMEM; + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_MGMT_EXTRA_IE, 0); + if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) + info->max_scan_ssids = + nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); - NLA_PUT_U8(msg, NL80211_ATTR_MGMT_SUBTYPE, 4 /* ProbeReq */); - if (ies) - NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies); + if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { + struct nlattr *nl_mode; + int i; + nla_for_each_nested(nl_mode, + tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { + if (nl_mode->nla_type == NL80211_IFTYPE_AP) { + info->ap_supported = 1; + break; + } + } + } - ret = 0; + if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { + struct nlattr *nl_cmd; + int i; - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + nla_for_each_nested(nl_cmd, + tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { + u32 cmd = nla_get_u32(nl_cmd); + if (cmd == NL80211_CMD_AUTHENTICATE) + info->auth_supported = 1; + else if (cmd == NL80211_CMD_CONNECT) + info->connect_supported = 1; + } + } - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - return ret; - -nla_put_failure: - return -ENOBUFS; + return NL_SKIP; } -#ifdef CONFIG_CLIENT_MLME - -static int nl80211_set_vif(struct wpa_driver_nl80211_data *drv, - int drop_unencrypted, int userspace_mlme) +static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, + struct wiphy_info_data *info) { -#ifdef NL80211_CMD_SET_VIF struct nl_msg *msg; - int ret = -1; + os_memset(info, 0, sizeof(*info)); msg = nlmsg_alloc(); if (!msg) - return -ENOMEM; + return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_SET_VIF, 0); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_GET_WIPHY, 0); - if (drop_unencrypted >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_VIF_DROP_UNENCRYPTED, - drop_unencrypted); - if (userspace_mlme >= 0) - NLA_PUT_U8(msg, NL80211_ATTR_VIF_USERSPACE_MLME, - userspace_mlme); - - ret = 0; - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - return ret; + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex); + if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0) + return 0; + msg = NULL; nla_put_failure: - return -ENOBUFS; -#else /* NL80211_CMD_SET_VIF */ + nlmsg_free(msg); return -1; -#endif /* NL80211_CMD_SET_VIF */ } -static int wpa_driver_nl80211_set_userspace_mlme( - struct wpa_driver_nl80211_data *drv, int enabled) +static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) { - return nl80211_set_vif(drv, -1, enabled); -} - - -static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, - int ifidx) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); - if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) - return; -nla_put_failure: - wpa_printf(MSG_ERROR, "nl80211: Failed to remove interface."); -} - - -static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, - const char *ifname, enum nl80211_iftype iftype) -{ - struct nl_msg *msg, *flags = NULL; - int ifidx, err; - int ret = -ENOBUFS; - - msg = nlmsg_alloc(); - if (!msg) + struct wiphy_info_data info; + if (wpa_driver_nl80211_get_info(drv, &info)) return -1; + drv->has_capability = 1; + /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ + drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; + drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | + WPA_DRIVER_CAPA_ENC_WEP104 | + WPA_DRIVER_CAPA_ENC_TKIP | + WPA_DRIVER_CAPA_ENC_CCMP; + drv->capa.auth = WPA_DRIVER_AUTH_OPEN | + WPA_DRIVER_AUTH_SHARED | + WPA_DRIVER_AUTH_LEAP; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname)); - NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); + drv->capa.max_scan_ssids = info.max_scan_ssids; + if (info.ap_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_AP; - if (iftype == NL80211_IFTYPE_MONITOR) { - flags = nlmsg_alloc(); - if (!flags) - goto nla_put_failure; - - NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); - - err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); - - nlmsg_free(flags); - - if (err) - goto nla_put_failure; - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - nla_put_failure: - wpa_printf(MSG_ERROR, "nl80211: Failed to create interface %d", - ret); - return ret; - } - - ifidx = if_nametoindex(ifname); - if (ifidx <= 0) + if (info.auth_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_SME; + else if (!info.connect_supported) { + wpa_printf(MSG_INFO, "nl80211: Driver does not support " + "authentication/association or connect commands"); return -1; - - return ifidx; -} - - -static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct wpa_driver_nl80211_data *drv = eloop_ctx; - int len; - unsigned char buf[3000]; - struct ieee80211_radiotap_iterator iter; - int ret; - int injected = 0, failed = 0, rxflags = 0; - struct ieee80211_rx_status rx_status; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; } - if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len)) { - wpa_printf(MSG_DEBUG, "nl80211: received invalid radiotap " - "frame"); - return; - } - - os_memset(&rx_status, 0, sizeof(rx_status)); - - while (1) { - ret = ieee80211_radiotap_iterator_next(&iter); - if (ret == -ENOENT) - break; - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: received invalid " - "radiotap frame (%d)", ret); - return; - } - switch (iter.this_arg_index) { - case IEEE80211_RADIOTAP_FLAGS: - if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) - len -= 4; - break; - case IEEE80211_RADIOTAP_RX_FLAGS: - rxflags = 1; - break; - case IEEE80211_RADIOTAP_TX_FLAGS: - injected = 1; - failed = le_to_host16((*(u16 *) iter.this_arg)) & - IEEE80211_RADIOTAP_F_TX_FAIL; - break; - case IEEE80211_RADIOTAP_DATA_RETRIES: - break; - case IEEE80211_RADIOTAP_CHANNEL: - /* TODO convert from freq/flags to channel number - * rx_status.channel = XXX; - */ - break; - case IEEE80211_RADIOTAP_RATE: - break; - case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - rx_status.ssi = *iter.this_arg; - break; - } - } - - if (rxflags && injected) - return; - - if (!injected) { - wpa_supplicant_sta_rx(drv->ctx, buf + iter.max_length, - len - iter.max_length, &rx_status); - } else if (failed) { - /* TX failure callback */ - } else { - /* TX success (ACK) callback */ - } -} - - -static int wpa_driver_nl80211_create_monitor_interface( - struct wpa_driver_nl80211_data *drv) -{ - char buf[IFNAMSIZ]; - struct sockaddr_ll ll; - int optval, flags; - socklen_t optlen; - - os_snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname); - buf[IFNAMSIZ - 1] = '\0'; - - drv->monitor_ifidx = - nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR); - - if (drv->monitor_ifidx < 0) - return -1; - - if (wpa_driver_nl80211_get_ifflags_ifname(drv, buf, &flags) != 0 || - wpa_driver_nl80211_set_ifflags_ifname(drv, buf, flags | IFF_UP) != - 0) { - wpa_printf(MSG_ERROR, "nl80211: Could not set interface '%s' " - "UP", buf); - goto error; - } - - os_memset(&ll, 0, sizeof(ll)); - ll.sll_family = AF_PACKET; - ll.sll_ifindex = drv->monitor_ifidx; - drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->monitor_sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - goto error; - } - - if (bind(drv->monitor_sock, (struct sockaddr *) &ll, - sizeof(ll)) < 0) { - perror("monitor socket bind"); - goto error; - } - - optlen = sizeof(optval); - optval = 20; - if (setsockopt - (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { - perror("Failed to set socket priority"); - goto error; - } - - if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, - drv, NULL)) { - wpa_printf(MSG_ERROR, "nl80211: Could not register monitor " - "read socket"); - goto error; - } + drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; + drv->capa.max_remain_on_chan = 5000; return 0; - - error: - nl80211_remove_iface(drv, drv->monitor_ifidx); - return -1; } - -#endif /* CONFIG_CLIENT_MLME */ +#endif /* HOSTAPD */ -/** - * wpa_driver_nl80211_init - Initialize nl80211 driver interface - * @ctx: context to be used when calling wpa_supplicant functions, - * e.g., wpa_supplicant_event() - * @ifname: interface name, e.g., wlan0 - * Returns: Pointer to private data, %NULL on failure - */ -static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) +static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv, + void *ctx) { - int s, ret; - struct sockaddr_nl local; - struct wpa_driver_nl80211_data *drv; + int ret; - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); + /* Initialize generic netlink and nl80211 */ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); if (drv->nl_cb == NULL) { @@ -1439,18 +1269,51 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) goto err2; } + drv->nl_handle_event = nl_handle_alloc_cb(drv->nl_cb); + if (drv->nl_handle_event == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " + "callbacks (event)"); + goto err2b; + } + if (genl_connect(drv->nl_handle)) { wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " "netlink"); goto err3; } + if (genl_connect(drv->nl_handle_event)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " + "netlink (event)"); + goto err3; + } + +#ifdef CONFIG_LIBNL20 + if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " + "netlink cache"); + goto err3; + } + if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) < + 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " + "netlink cache (event)"); + goto err3b; + } +#else /* CONFIG_LIBNL20 */ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); if (drv->nl_cache == NULL) { wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " "netlink cache"); goto err3; } + drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event); + if (drv->nl_cache_event == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " + "netlink cache (event)"); + goto err3b; + } +#endif /* CONFIG_LIBNL20 */ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); if (drv->nl80211 == NULL) { @@ -1461,89 +1324,212 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) ret = nl_get_multicast_id(drv, "nl80211", "scan"); if (ret >= 0) - ret = nl_socket_add_membership(drv->nl_handle, ret); + ret = nl_socket_add_membership(drv->nl_handle_event, ret); if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for scan events: %d (%s)", ret, strerror(-ret)); goto err4; } - eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle), + + ret = nl_get_multicast_id(drv, "nl80211", "mlme"); + if (ret >= 0) + ret = nl_socket_add_membership(drv->nl_handle_event, ret); + if (ret < 0) { + wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " + "membership for mlme events: %d (%s)", + ret, strerror(-ret)); + goto err4; + } + + eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event), wpa_driver_nl80211_event_receive, drv, ctx); - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket(PF_INET,SOCK_DGRAM)"); - goto err5; - } + return 0; - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - goto err6; - } - - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - goto err6; - } - - eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_wext, drv, - ctx); - drv->wext_event_sock = s; - - wpa_driver_nl80211_finish_drv_init(drv); - - return drv; - -err6: - close(drv->ioctl_sock); -err5: - genl_family_put(drv->nl80211); err4: + nl_cache_free(drv->nl_cache_event); +err3b: nl_cache_free(drv->nl_cache); err3: + nl_handle_destroy(drv->nl_handle_event); +err2b: nl_handle_destroy(drv->nl_handle); err2: nl_cb_put(drv->nl_cb); err1: + return -1; +} + + +/** + * wpa_driver_nl80211_init - Initialize nl80211 driver interface + * @ctx: context to be used when calling wpa_supplicant functions, + * e.g., wpa_supplicant_event() + * @ifname: interface name, e.g., wlan0 + * Returns: Pointer to private data, %NULL on failure + */ +static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) +{ + struct wpa_driver_nl80211_data *drv; + struct netlink_config *cfg; + struct i802_bss *bss; + + drv = os_zalloc(sizeof(*drv)); + if (drv == NULL) + return NULL; + drv->ctx = ctx; + bss = &drv->first_bss; + bss->drv = drv; + os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); + drv->monitor_ifidx = -1; + drv->monitor_sock = -1; + drv->ioctl_sock = -1; + + if (wpa_driver_nl80211_init_nl(drv, ctx)) { + os_free(drv); + return NULL; + } + + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (drv->ioctl_sock < 0) { + perror("socket(PF_INET,SOCK_DGRAM)"); + goto failed; + } + + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto failed; + cfg->ctx = drv; + cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); + goto failed; + } + if (wpa_driver_nl80211_finish_drv_init(drv)) + goto failed; + + return bss; + +failed: + netlink_deinit(drv->netlink); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + + genl_family_put(drv->nl80211); + nl_cache_free(drv->nl_cache); + nl_handle_destroy(drv->nl_handle); + nl_cb_put(drv->nl_cb); + eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); + os_free(drv); return NULL; } -static void +static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv, + const u8 *match, size_t match_len) +{ + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_REGISTER_ACTION, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); + + ret = send_and_recv(drv, drv->nl_handle_event, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Register Action command " + "failed: ret=%d (%s)", ret, strerror(-ret)); + wpa_hexdump(MSG_DEBUG, "nl80211: Register Action match", + match, match_len); + goto nla_put_failure; + } + ret = 0; +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv) +{ + /* FT Action frames */ + if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0) + return -1; + else + drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | + WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; + + return 0; +} + + +static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) { - int flags; + struct i802_bss *bss = &drv->first_bss; - drv->ifindex = if_nametoindex(drv->ifname); + drv->ifindex = if_nametoindex(bss->ifname); + drv->first_bss.ifindex = drv->ifindex; - if (wpa_driver_nl80211_set_mode(drv, 0) < 0) { - printf("Could not configure driver to use managed mode\n"); +#ifndef HOSTAPD + if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " + "use managed mode"); } - if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0) - printf("Could not get interface '%s' flags\n", drv->ifname); - else if (!(flags & IFF_UP)) { - if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) { - printf("Could not set interface '%s' UP\n", - drv->ifname); - } + if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { + wpa_printf(MSG_ERROR, "Could not set interface '%s' UP", + bss->ifname); + return -1; } - /* - * Make sure that the driver does not have any obsolete PMKID entries. - */ - wpa_driver_nl80211_flush_pmkid(drv); + if (wpa_driver_nl80211_capa(drv)) + return -1; - wpa_driver_nl80211_get_range(drv); + netlink_send_oper_ifla(drv->netlink, drv->ifindex, + 1, IF_OPER_DORMANT); +#endif /* HOSTAPD */ - wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT); + if (nl80211_register_action_frames(drv) < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " + "frame processing - ignore for now"); + /* + * Older kernel versions did not support this, so ignore the + * error for now. Some functionality may not be available + * because of this. + */ + } + + return 0; +} + + +static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_DEL_BEACON, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; } @@ -1556,54 +1542,80 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) */ static void wpa_driver_nl80211_deinit(void *priv) { - struct wpa_driver_nl80211_data *drv = priv; - int flags; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; -#ifdef CONFIG_CLIENT_MLME - if (drv->monitor_sock >= 0) { - eloop_unregister_read_sock(drv->monitor_sock); - close(drv->monitor_sock); + if (drv->added_if_into_bridge) { + if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname) + < 0) + wpa_printf(MSG_INFO, "nl80211: Failed to remove " + "interface %s from bridge %s: %s", + bss->ifname, drv->brname, strerror(errno)); } - if (drv->monitor_ifidx > 0) - nl80211_remove_iface(drv, drv->monitor_ifidx); - if (drv->capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) - wpa_driver_nl80211_set_userspace_mlme(drv, 0); -#endif /* CONFIG_CLIENT_MLME */ + if (drv->added_bridge) { + if (linux_br_del(drv->ioctl_sock, drv->brname) < 0) + wpa_printf(MSG_INFO, "nl80211: Failed to remove " + "bridge %s: %s", + drv->brname, strerror(errno)); + } + + nl80211_remove_monitor_interface(drv); + + if (drv->nlmode == NL80211_IFTYPE_AP) + wpa_driver_nl80211_del_beacon(drv); + +#ifdef HOSTAPD + if (drv->last_freq_ht) { + /* Clear HT flags from the driver */ + struct hostapd_freq_params freq; + os_memset(&freq, 0, sizeof(freq)); + freq.freq = drv->last_freq; + i802_set_freq(priv, &freq); + } + + if (drv->eapol_sock >= 0) { + eloop_unregister_read_sock(drv->eapol_sock); + close(drv->eapol_sock); + } + + if (drv->if_indices != drv->default_if_indices) + os_free(drv->if_indices); +#endif /* HOSTAPD */ + + if (drv->disable_11b_rates) + nl80211_disable_11b_rates(drv, drv->ifindex, 0); + + netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); + netlink_deinit(drv->netlink); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - /* - * Clear possibly configured driver parameters in order to make it - * easier to use the driver after wpa_supplicant has been terminated. - */ - (void) wpa_driver_nl80211_set_bssid(drv, - (u8 *) "\x00\x00\x00\x00\x00\x00"); + (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); + wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA); - wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); - eloop_unregister_read_sock(drv->wext_event_sock); - - if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) - (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP); - - close(drv->wext_event_sock); - close(drv->ioctl_sock); - os_free(drv->assoc_req_ies); - os_free(drv->assoc_resp_ies); - - eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle)); + eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); genl_family_put(drv->nl80211); nl_cache_free(drv->nl_cache); + nl_cache_free(drv->nl_cache_event); nl_handle_destroy(drv->nl_handle); + nl_handle_destroy(drv->nl_handle_event); nl_cb_put(drv->nl_cb); + eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout, + drv, NULL); + + os_free(drv->filter_ssids); + os_free(drv); } /** * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion - * @eloop_ctx: Unused + * @eloop_ctx: Driver private data * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init() * * This function can be used as registered timeout when starting a scan to @@ -1611,6 +1623,12 @@ static void wpa_driver_nl80211_deinit(void *priv) */ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) { + struct wpa_driver_nl80211_data *drv = eloop_ctx; + if (drv->ap_scan_as_station) { + wpa_driver_nl80211_set_mode(&drv->first_bss, + IEEE80211_MODE_AP); + drv->ap_scan_as_station = 0; + } wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } @@ -1618,47 +1636,94 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) /** * wpa_driver_nl80211_scan - Request the driver to initiate scan - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() - * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for - * all SSIDs (either active scan with broadcast SSID or passive - * scan - * @ssid_len: Length of the SSID + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() + * @params: Scan parameters * Returns: 0 on success, -1 on failure */ -static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_nl80211_scan(void *priv, + struct wpa_driver_scan_params *params) { - struct wpa_driver_nl80211_data *drv = priv; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; int ret = 0, timeout; - struct nl_msg *msg, *ssids; + struct nl_msg *msg, *ssids, *freqs; + size_t i; msg = nlmsg_alloc(); ssids = nlmsg_alloc(); - if (!msg || !ssids) { + freqs = nlmsg_alloc(); + if (!msg || !ssids || !freqs) { nlmsg_free(msg); nlmsg_free(ssids); + nlmsg_free(freqs); return -1; } + os_free(drv->filter_ssids); + drv->filter_ssids = params->filter_ssids; + params->filter_ssids = NULL; + drv->num_filter_ssids = params->num_filter_ssids; + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_TRIGGER_SCAN, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - if (ssid && ssid_len) { - /* Request an active scan for a specific SSID */ - NLA_PUT(ssids, 1, ssid_len, ssid); - } else { - /* Request an active scan for wildcard SSID */ - NLA_PUT(ssids, 1, 0, ""); + for (i = 0; i < params->num_ssids; i++) { + wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID", + params->ssids[i].ssid, + params->ssids[i].ssid_len); + NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, + params->ssids[i].ssid); + } + if (params->num_ssids) + nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); + + if (params->extra_ies) { + wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs", + params->extra_ies, params->extra_ies_len); + NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, + params->extra_ies); + } + + if (params->freqs) { + for (i = 0; params->freqs[i]; i++) { + wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " + "MHz", params->freqs[i]); + NLA_PUT_U32(freqs, i + 1, params->freqs[i]); + } + nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); } - nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); +#ifdef HOSTAPD + if (drv->nlmode == NL80211_IFTYPE_AP) { + /* + * mac80211 does not allow scan requests in AP mode, so + * try to do this in station mode. + */ + if (wpa_driver_nl80211_set_mode(bss, + IEEE80211_MODE_INFRA)) + goto nla_put_failure; + + if (wpa_driver_nl80211_scan(drv, params)) { + wpa_driver_nl80211_set_mode(bss, + IEEE80211_MODE_AP); + goto nla_put_failure; + } + + /* Restore AP mode when processing scan results */ + drv->ap_scan_as_station = 1; + ret = 0; + } else + goto nla_put_failure; +#else /* HOSTAPD */ goto nla_put_failure; +#endif /* HOSTAPD */ } /* Not all drivers generate "scan completed" wireless event, so try to @@ -1666,9 +1731,9 @@ static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len) timeout = 10; if (drv->scan_complete_events) { /* - * The driver seems to deliver SIOCGIWSCAN events to notify - * when scan is complete, so use longer timeout to avoid race - * conditions with scanning and following association request. + * The driver seems to deliver events to notify when scan is + * complete, so use longer timeout to avoid race conditions + * with scanning and following association request. */ timeout = 30; } @@ -1681,10 +1746,62 @@ static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len) nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); + nlmsg_free(freqs); return ret; } +static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie) +{ + const u8 *end, *pos; + + if (ies == NULL) + return NULL; + + pos = ies; + end = ies + ies_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} + + +static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, + const u8 *ie, size_t ie_len) +{ + const u8 *ssid; + size_t i; + + if (drv->filter_ssids == NULL) + return 0; + + ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID); + if (ssid == NULL) + return 1; + + for (i = 0; i < drv->num_filter_ssids; i++) { + if (ssid[1] == drv->filter_ssids[i].ssid_len && + os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == + 0) + return 0; + } + + return 1; +} + + +struct nl80211_bss_info_arg { + struct wpa_driver_nl80211_data *drv; + struct wpa_scan_results *res; +}; + static int bss_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -1699,12 +1816,17 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, + [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, }; - struct wpa_scan_results *res = arg; + struct nl80211_bss_info_arg *_arg = arg; + struct wpa_scan_results *res = _arg->res; struct wpa_scan_res **tmp; struct wpa_scan_res *r; - const u8 *ie; - size_t ie_len; + const u8 *ie, *beacon_ie; + size_t ie_len, beacon_ie_len; + u8 *pos; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -1720,8 +1842,19 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) ie = NULL; ie_len = 0; } + if (bss[NL80211_BSS_BEACON_IES]) { + beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); + beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); + } else { + beacon_ie = NULL; + beacon_ie_len = 0; + } - r = os_zalloc(sizeof(*r) + ie_len); + if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie, + ie ? ie_len : beacon_ie_len)) + return NL_SKIP; + + r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); if (r == NULL) return NL_SKIP; if (bss[NL80211_BSS_BSSID]) @@ -1733,15 +1866,44 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); if (bss[NL80211_BSS_CAPABILITY]) r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); - if (bss[NL80211_BSS_SIGNAL_UNSPEC]) - r->qual = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); - if (bss[NL80211_BSS_SIGNAL_MBM]) + r->flags |= WPA_SCAN_NOISE_INVALID; + if (bss[NL80211_BSS_SIGNAL_MBM]) { r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); + r->level /= 100; /* mBm to dBm */ + r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; + } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { + r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); + r->flags |= WPA_SCAN_LEVEL_INVALID; + } else + r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; if (bss[NL80211_BSS_TSF]) r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); + if (bss[NL80211_BSS_SEEN_MS_AGO]) + r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); r->ie_len = ie_len; - if (ie) - os_memcpy(r + 1, ie, ie_len); + pos = (u8 *) (r + 1); + if (ie) { + os_memcpy(pos, ie, ie_len); + pos += ie_len; + } + r->beacon_ie_len = beacon_ie_len; + if (beacon_ie) + os_memcpy(pos, beacon_ie, beacon_ie_len); + + if (bss[NL80211_BSS_STATUS]) { + enum nl80211_bss_status status; + status = nla_get_u32(bss[NL80211_BSS_STATUS]); + switch (status) { + case NL80211_BSS_STATUS_AUTHENTICATED: + r->flags |= WPA_SCAN_AUTHENTICATED; + break; + case NL80211_BSS_STATUS_ASSOCIATED: + r->flags |= WPA_SCAN_ASSOCIATED; + break; + default: + break; + } + } tmp = os_realloc(res->res, (res->num + 1) * sizeof(struct wpa_scan_res *)); @@ -1756,22 +1918,95 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) } -/** - * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() - * Returns: Scan results on success, -1 on failure - */ -static struct wpa_scan_results * -wpa_driver_nl80211_get_scan_results(void *priv) +static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, + const u8 *addr) +{ + if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { + wpa_printf(MSG_DEBUG, "nl80211: Clear possible state " + "mismatch (" MACSTR ")", MAC2STR(addr)); + wpa_driver_nl80211_mlme(drv, addr, + NL80211_CMD_DEAUTHENTICATE, + WLAN_REASON_PREV_AUTH_NOT_VALID, 1); + } +} + + +static void wpa_driver_nl80211_check_bss_status( + struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res) +{ + size_t i; + + for (i = 0; i < res->num; i++) { + struct wpa_scan_res *r = res->res[i]; + if (r->flags & WPA_SCAN_AUTHENTICATED) { + wpa_printf(MSG_DEBUG, "nl80211: Scan results " + "indicates BSS status with " MACSTR + " as authenticated", + MAC2STR(r->bssid)); + if (drv->nlmode == NL80211_IFTYPE_STATION && + os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && + os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID" + " in local state (auth=" MACSTR + " assoc=" MACSTR ")", + MAC2STR(drv->auth_bssid), + MAC2STR(drv->bssid)); + clear_state_mismatch(drv, r->bssid); + } + } + + if (r->flags & WPA_SCAN_ASSOCIATED) { + wpa_printf(MSG_DEBUG, "nl80211: Scan results " + "indicate BSS status with " MACSTR + " as associated", + MAC2STR(r->bssid)); + if (drv->nlmode == NL80211_IFTYPE_STATION && + !drv->associated) { + wpa_printf(MSG_DEBUG, "nl80211: Local state " + "(not associated) does not match " + "with BSS state"); + clear_state_mismatch(drv, r->bssid); + } else if (drv->nlmode == NL80211_IFTYPE_STATION && + os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "nl80211: Local state " + "(associated with " MACSTR ") does " + "not match with BSS state", + MAC2STR(drv->bssid)); + clear_state_mismatch(drv, r->bssid); + clear_state_mismatch(drv, drv->bssid); + } + } + } +} + + +static void wpa_scan_results_free(struct wpa_scan_results *res) +{ + size_t i; + + if (res == NULL) + return; + + for (i = 0; i < res->num; i++) + os_free(res->res[i]); + os_free(res->res); + os_free(res); +} + + +static struct wpa_scan_results * +nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) { - struct wpa_driver_nl80211_data *drv = priv; struct nl_msg *msg; struct wpa_scan_results *res; int ret; + struct nl80211_bss_info_arg arg; res = os_zalloc(sizeof(*res)); if (res == NULL) - return 0; + return NULL; msg = nlmsg_alloc(); if (!msg) goto nla_put_failure; @@ -1780,7 +2015,9 @@ wpa_driver_nl80211_get_scan_results(void *priv) NL80211_CMD_GET_SCAN, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - ret = send_and_recv_msgs(drv, msg, bss_info_handler, res); + arg.drv = drv; + arg.res = res; + ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); msg = NULL; if (ret == 0) { wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)", @@ -1796,167 +2033,264 @@ nla_put_failure: } -static int wpa_driver_nl80211_get_range(void *priv) +/** + * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results + * @priv: Pointer to private wext data from wpa_driver_nl80211_init() + * Returns: Scan results on success, -1 on failure + */ +static struct wpa_scan_results * +wpa_driver_nl80211_get_scan_results(void *priv) { - struct wpa_driver_nl80211_data *drv = priv; - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct wpa_scan_results *res; - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; + res = nl80211_get_scan_results(drv); + if (res) + wpa_driver_nl80211_check_bss_status(drv, res); + return res; +} - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); +static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) +{ + struct wpa_scan_results *res; + size_t i; - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - os_free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->has_capability = 1; - drv->we_version_compiled = range->we_version_compiled; - if (range->enc_capa & IW_ENC_CAPA_WPA) { - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; - } - if (range->enc_capa & IW_ENC_CAPA_WPA2) { - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | - WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - } - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104; - if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; - if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; - drv->capa.auth = WPA_DRIVER_AUTH_OPEN | - WPA_DRIVER_AUTH_SHARED | - WPA_DRIVER_AUTH_LEAP; - wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x", - drv->capa.key_mgmt, drv->capa.enc); - } else { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " - "assuming WPA is not supported"); + res = nl80211_get_scan_results(drv); + if (res == NULL) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results"); + return; } - os_free(range); - return 0; + wpa_printf(MSG_DEBUG, "nl80211: Scan result dump"); + for (i = 0; i < res->num; i++) { + struct wpa_scan_res *r = res->res[i]; + wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s", + (int) i, (int) res->num, MAC2STR(r->bssid), + r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "", + r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); + } + + wpa_scan_results_free(res); } -static int wpa_driver_nl80211_set_wpa(void *priv, int enabled) -{ - struct wpa_driver_nl80211_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED, - enabled); -} - - -static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg, - const u8 *addr, int key_idx, - int set_tx, const u8 *seq, - size_t seq_len, +static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { - struct wpa_driver_nl80211_data *drv = priv; - int err; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ifindex = if_nametoindex(ifname); struct nl_msg *msg; + int ret; - wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " - "seq_len=%lu key_len=%lu", - __func__, alg, addr, key_idx, set_tx, + wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d " + "set_tx=%d seq_len=%lu key_len=%lu", + __func__, ifindex, alg, addr, key_idx, set_tx, (unsigned long) seq_len, (unsigned long) key_len); msg = nlmsg_alloc(); - if (msg == NULL) - return -1; + if (!msg) + return -ENOMEM; if (alg == WPA_ALG_NONE) { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_DEL_KEY, 0); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_DEL_KEY, 0); } else { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, - NL80211_CMD_NEW_KEY, 0); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_NEW_KEY, 0); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); switch (alg) { case WPA_ALG_WEP: if (key_len == 5) NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - 0x000FAC01); + WLAN_CIPHER_SUITE_WEP40); else NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - 0x000FAC05); + WLAN_CIPHER_SUITE_WEP104); break; case WPA_ALG_TKIP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_TKIP); break; case WPA_ALG_CCMP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_CCMP); break; -#ifdef CONFIG_IEEE80211W case WPA_ALG_IGTK: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + WLAN_CIPHER_SUITE_AES_CMAC); break; -#endif /* CONFIG_IEEE80211W */ default: + wpa_printf(MSG_ERROR, "%s: Unsupported encryption " + "algorithm %d", __func__, alg); nlmsg_free(msg); return -1; } } + if (seq && seq_len) + NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq); + if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); } NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - err = send_and_recv_msgs(drv, msg, NULL, NULL); - if (err) { - wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) + ret = 0; + if (ret) + wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)", + ret, strerror(-ret)); + + /* + * If we failed or don't need to set the default TX key (below), + * we're done here. + */ + if (ret || !set_tx || alg == WPA_ALG_NONE) + return ret; +#ifdef HOSTAPD + if (addr) + return ret; +#else /* HOSTAPD */ + if (drv->nlmode == NL80211_IFTYPE_AP && addr) + return ret; +#endif /* HOSTAPD */ + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_KEY, 0); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + if (alg == WPA_ALG_IGTK) + NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); + else + NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + ret = 0; + if (ret) + wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; " + "err=%d %s)", ret, strerror(-ret)); + return ret; + +nla_put_failure: + return -ENOBUFS; +} + + +static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, + int key_idx, int defkey, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); + if (!key_attr) + return -1; + + if (defkey && alg == WPA_ALG_IGTK) + NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT); + else if (defkey) + NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); + + NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); + + switch (alg) { + case WPA_ALG_WEP: + if (key_len == 5) + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP40); + else + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP104); + break; + case WPA_ALG_TKIP: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); + break; + case WPA_ALG_CCMP: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); + break; + case WPA_ALG_IGTK: + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_AES_CMAC); + break; + default: + wpa_printf(MSG_ERROR, "%s: Unsupported encryption " + "algorithm %d", __func__, alg); return -1; } - if (set_tx && alg != WPA_ALG_NONE) { - msg = nlmsg_alloc(); - if (msg == NULL) - return -1; + if (seq && seq_len) + NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_KEY, 0); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); + NLA_PUT(msg, NL80211_KEY_DATA, key_len, key); - err = send_and_recv_msgs(drv, msg, NULL, NULL); - if (err) { - wpa_printf(MSG_DEBUG, "nl80211: set default key " - "failed; err=%d", err); - return -1; - } + nla_nest_end(msg, key_attr); + + return 0; + nla_put_failure: + return -1; +} + + +static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params, + struct nl_msg *msg) +{ + int i, privacy = 0; + struct nlattr *nl_keys, *nl_key; + + for (i = 0; i < 4; i++) { + if (!params->wep_key[i]) + continue; + privacy = 1; + break; } + if (!privacy) + return 0; + + NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); + + nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS); + if (!nl_keys) + goto nla_put_failure; + + for (i = 0; i < 4; i++) { + if (!params->wep_key[i]) + continue; + + nl_key = nla_nest_start(msg, i); + if (!nl_key) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i], + params->wep_key[i]); + if (params->wep_key_len[i] == 5) + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP40); + else + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + WLAN_CIPHER_SUITE_WEP104); + + NLA_PUT_U8(msg, NL80211_KEY_IDX, i); + + if (i == params->wep_tx_keyidx) + NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); + + nla_nest_end(msg, nl_key); + } + nla_nest_end(msg, nl_keys); return 0; @@ -1965,470 +2299,199 @@ nla_put_failure: } -static int wpa_driver_nl80211_set_countermeasures(void *priv, - int enabled) -{ - struct wpa_driver_nl80211_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_TKIP_COUNTERMEASURES, - enabled); -} - - -static int wpa_driver_nl80211_set_drop_unencrypted(void *priv, - int enabled) -{ - struct wpa_driver_nl80211_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - drv->use_crypt = enabled; - return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, - enabled); -} - - static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, - const u8 *addr, int cmd, int reason_code) + const u8 *addr, int cmd, u16 reason_code, + int local_state_change) { - struct iwreq iwr; - struct iw_mlme mlme; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - os_memset(&mlme, 0, sizeof(mlme)); - mlme.cmd = cmd; - mlme.reason_code = reason_code; - mlme.addr.sa_family = ARPHRD_ETHER; - os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); - iwr.u.data.pointer = (caddr_t) &mlme; - iwr.u.data.length = sizeof(mlme); - - if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { - perror("ioctl[SIOCSIWMLME]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_nl80211_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DEAUTH, reason_code); -} - - -static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr, - int reason_code) -{ - struct wpa_driver_nl80211_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DISASSOC, - reason_code); -} - - -static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie, - size_t ie_len) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) ie; - iwr.u.data.length = ie_len; - - if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { - perror("ioctl[SIOCSIWGENIE]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_cipher2wext(int cipher) -{ - switch (cipher) { - case CIPHER_NONE: - return IW_AUTH_CIPHER_NONE; - case CIPHER_WEP40: - return IW_AUTH_CIPHER_WEP40; - case CIPHER_TKIP: - return IW_AUTH_CIPHER_TKIP; - case CIPHER_CCMP: - return IW_AUTH_CIPHER_CCMP; - case CIPHER_WEP104: - return IW_AUTH_CIPHER_WEP104; - default: - return 0; - } -} - - -static int wpa_driver_nl80211_keymgmt2wext(int keymgmt) -{ - switch (keymgmt) { - case KEY_MGMT_802_1X: - case KEY_MGMT_802_1X_NO_WPA: - return IW_AUTH_KEY_MGMT_802_1X; - case KEY_MGMT_PSK: - return IW_AUTH_KEY_MGMT_PSK; - default: - return 0; - } -} - - -static int -wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) -{ - struct iwreq iwr; - int ret = 0; - - wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " - "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* Just changing mode, not actual keys */ - iwr.u.encoding.flags = 0; - iwr.u.encoding.pointer = (caddr_t) NULL; - iwr.u.encoding.length = 0; - - /* - * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two - * different things. Here they are used to indicate Open System vs. - * Shared Key authentication algorithm. However, some drivers may use - * them to select between open/restricted WEP encrypted (open = allow - * both unencrypted and encrypted frames; restricted = only allow - * encrypted frames). - */ - - if (!drv->use_crypt) { - iwr.u.encoding.flags |= IW_ENCODE_DISABLED; - } else { - if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM) - iwr.u.encoding.flags |= IW_ENCODE_OPEN; - if (params->auth_alg & AUTH_ALG_SHARED_KEY) - iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; - } - - if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { - perror("ioctl[SIOCSIWENCODE]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_associate( - void *priv, struct wpa_driver_associate_params *params) -{ - struct wpa_driver_nl80211_data *drv = priv; - int ret = 0; - int allow_unencrypted_eapol; - int value; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - /* - * If the driver did not support SIOCSIWAUTH, fallback to - * SIOCSIWENCODE here. - */ - if (drv->auth_alg_fallback && - wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0) - ret = -1; - - if (!params->bssid && - wpa_driver_nl80211_set_bssid(drv, NULL) < 0) - ret = -1; - - /* TODO: should consider getting wpa version and cipher/key_mgmt suites - * from configuration, not from here, where only the selected suite is - * available */ - if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) - < 0) - ret = -1; - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) - value = IW_AUTH_WPA_VERSION_DISABLED; - else if (params->wpa_ie[0] == WLAN_EID_RSN) - value = IW_AUTH_WPA_VERSION_WPA2; - else - value = IW_AUTH_WPA_VERSION_WPA; - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_WPA_VERSION, value) < 0) - ret = -1; - value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite); - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_CIPHER_PAIRWISE, value) < 0) - ret = -1; - value = wpa_driver_nl80211_cipher2wext(params->group_suite); - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_CIPHER_GROUP, value) < 0) - ret = -1; - value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite); - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_KEY_MGMT, value) < 0) - ret = -1; - value = params->key_mgmt_suite != KEY_MGMT_NONE || - params->pairwise_suite != CIPHER_NONE || - params->group_suite != CIPHER_NONE || - params->wpa_ie_len; - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_PRIVACY_INVOKED, value) < 0) - ret = -1; - - /* Allow unencrypted EAPOL messages even if pairwise keys are set when - * not using WPA. IEEE 802.1X specifies that these frames are not - * encrypted, but WPA encrypts them when pairwise keys are in use. */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK) - allow_unencrypted_eapol = 0; - else - allow_unencrypted_eapol = 1; - - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_RX_UNENCRYPTED_EAPOL, - allow_unencrypted_eapol) < 0) - ret = -1; - if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0) - ret = -1; - if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0) - ret = -1; - if (params->bssid && - wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0) - ret = -1; - - return ret; -} - - -static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg) -{ - struct wpa_driver_nl80211_data *drv = priv; - int algs = 0, res; - - if (auth_alg & AUTH_ALG_OPEN_SYSTEM) - algs |= IW_AUTH_ALG_OPEN_SYSTEM; - if (auth_alg & AUTH_ALG_SHARED_KEY) - algs |= IW_AUTH_ALG_SHARED_KEY; - if (auth_alg & AUTH_ALG_LEAP) - algs |= IW_AUTH_ALG_LEAP; - if (algs == 0) { - /* at least one algorithm should be set */ - algs = IW_AUTH_ALG_OPEN_SYSTEM; - } - - res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, - algs); - drv->auth_alg_fallback = res == -2; - return res; -} - - -/** - * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() - * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS - * Returns: 0 on success, -1 on failure - */ -static int wpa_driver_nl80211_set_mode(void *priv, int mode) -{ - struct wpa_driver_nl80211_data *drv = priv; - int ret = -1, flags; + int ret = -1; struct nl_msg *msg; msg = nlmsg_alloc(); if (!msg) return -1; - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, - mode ? NL80211_IFTYPE_ADHOC : NL80211_IFTYPE_STATION); + NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + if (local_state_change) + NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (!ret) - return 0; - else - goto try_again; + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " + "(%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; nla_put_failure: - wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)", - ret, strerror(-ret)); - return -1; + nlmsg_free(msg); + return ret; +} -try_again: - /* mac80211 doesn't allow mode changes while the device is up, so - * take the device down, try to set the mode again, and bring the - * device back up. - */ - if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) { - (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP); - /* Try to set the mode again while the interface is down */ - msg = nlmsg_alloc(); - if (!msg) +static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, + const u8 *addr, int reason_code) +{ + wpa_printf(MSG_DEBUG, "%s", __func__); + drv->associated = 0; + return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT, + reason_code, 0); +} + + +static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr, + int reason_code) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) + return wpa_driver_nl80211_disconnect(drv, addr, reason_code); + wpa_printf(MSG_DEBUG, "%s", __func__); + drv->associated = 0; + return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, + reason_code, 0); +} + + +static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr, + int reason_code) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) + return wpa_driver_nl80211_disconnect(drv, addr, reason_code); + wpa_printf(MSG_DEBUG, "%s", __func__); + drv->associated = 0; + return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE, + reason_code, 0); +} + + +static int wpa_driver_nl80211_authenticate( + void *priv, struct wpa_driver_auth_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = -1, i; + struct nl_msg *msg; + enum nl80211_auth_type type; + int count = 0; + + drv->associated = 0; + os_memset(drv->auth_bssid, 0, ETH_ALEN); + /* FIX: IBSS mode */ + if (drv->nlmode != NL80211_IFTYPE_STATION) + wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA); + + if (wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0) + return -1; + +retry: + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)", + drv->ifindex); + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_AUTHENTICATE, 0); + + for (i = 0; i < 4; i++) { + if (!params->wep_key[i]) + continue; + wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP, + NULL, i, + i == params->wep_tx_keyidx, NULL, 0, + params->wep_key[i], + params->wep_key_len[i]); + if (params->wep_tx_keyidx != i) + continue; + if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, + params->wep_key[i], params->wep_key_len[i])) { + nlmsg_free(msg); return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, - mode ? NL80211_IFTYPE_ADHOC : - NL80211_IFTYPE_STATION); - ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret) { - wpa_printf(MSG_ERROR, "Failed to set interface %s " - "mode(try_again): %d (%s)", - drv->ifname, ret, strerror(-ret)); } - - /* Ignore return value of get_ifflags to ensure that the device - * is always up like it was before this function was called. - */ - (void) wpa_driver_nl80211_get_ifflags(drv, &flags); - (void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP); } + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { + wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + } + if (params->ssid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + } + wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len); + if (params->ie) + NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie); + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (params->auth_alg & WPA_AUTH_ALG_SHARED) + type = NL80211_AUTHTYPE_SHARED_KEY; + else if (params->auth_alg & WPA_AUTH_ALG_LEAP) + type = NL80211_AUTHTYPE_NETWORK_EAP; + else if (params->auth_alg & WPA_AUTH_ALG_FT) + type = NL80211_AUTHTYPE_FT; + else + goto nla_put_failure; + wpa_printf(MSG_DEBUG, " * Auth Type %d", type); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); + if (params->local_state_change) { + wpa_printf(MSG_DEBUG, " * Local state change only"); + NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " + "(%s)", ret, strerror(-ret)); + count++; + if (ret == -EALREADY && count == 1 && params->bssid && + !params->local_state_change) { + /* + * mac80211 does not currently accept new + * authentication if we are already authenticated. As a + * workaround, force deauthentication and try again. + */ + wpa_printf(MSG_DEBUG, "nl80211: Retry authentication " + "after forced deauthentication"); + wpa_driver_nl80211_deauthenticate( + bss, params->bssid, + WLAN_REASON_PREV_AUTH_NOT_VALID); + nlmsg_free(msg); + goto retry; + } + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "nl80211: Authentication request send " + "successfully"); + +nla_put_failure: + nlmsg_free(msg); return ret; } -static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv, - u32 cmd, const u8 *bssid, const u8 *pmkid) -{ - struct iwreq iwr; - struct iw_pmksa pmksa; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - os_memset(&pmksa, 0, sizeof(pmksa)); - pmksa.cmd = cmd; - pmksa.bssid.sa_family = ARPHRD_ETHER; - if (bssid) - os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); - if (pmkid) - os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); - iwr.u.data.pointer = (caddr_t) &pmksa; - iwr.u.data.length = sizeof(pmksa); - - if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { - if (errno != EOPNOTSUPP) - perror("ioctl[SIOCSIWPMKSA]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_nl80211_data *drv = priv; - return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid); -} - - -static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_nl80211_data *drv = priv; - return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid); -} - - -static int wpa_driver_nl80211_flush_pmkid(void *priv) -{ - struct wpa_driver_nl80211_data *drv = priv; - return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); -} - - -static int wpa_driver_nl80211_get_capa(void *priv, - struct wpa_driver_capa *capa) -{ - struct wpa_driver_nl80211_data *drv = priv; - if (!drv->has_capability) - return -1; - os_memcpy(capa, &drv->capa, sizeof(*capa)); - return 0; -} - - -static int wpa_driver_nl80211_set_operstate(void *priv, int state) -{ - struct wpa_driver_nl80211_data *drv = priv; - - wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", - __func__, drv->operstate, state, state ? "UP" : "DORMANT"); - drv->operstate = state; - return wpa_driver_nl80211_send_oper_ifla( - drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); -} - - -#ifdef CONFIG_CLIENT_MLME -static int wpa_driver_nl80211_open_mlme(struct wpa_driver_nl80211_data *drv) -{ - if (wpa_driver_nl80211_set_userspace_mlme(drv, 1) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to enable userspace " - "MLME"); - return -1; - } - if (wpa_driver_nl80211_create_monitor_interface(drv)) { - wpa_printf(MSG_ERROR, "nl80211: Failed to create monitor " - "interface"); - return -1; - } - return 0; -} -#endif /* CONFIG_CLIENT_MLME */ - - -static int wpa_driver_nl80211_set_param(void *priv, const char *param) -{ -#ifdef CONFIG_CLIENT_MLME - struct wpa_driver_nl80211_data *drv = priv; - - if (param == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); - - if (os_strstr(param, "use_mlme=1")) { - wpa_printf(MSG_DEBUG, "nl80211: Using user space MLME"); - drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; - - if (wpa_driver_nl80211_open_mlme(drv)) - return -1; - } -#endif /* CONFIG_CLIENT_MLME */ - - return 0; -} - - -#ifdef CONFIG_CLIENT_MLME - struct phy_info_arg { u16 *num_modes; - struct wpa_hw_modes *modes; + struct hostapd_hw_modes *modes; }; - static int phy_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; @@ -2438,27 +2501,26 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] - = { + static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, }; struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, - [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = - { .type = NLA_FLAG }, + [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, }; struct nlattr *nl_band; struct nlattr *nl_freq; struct nlattr *nl_rate; int rem_band, rem_freq, rem_rate; - struct wpa_hw_modes *mode; + struct hostapd_hw_modes *mode; int idx, mode_is_set; nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), @@ -2467,10 +2529,8 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) return NL_SKIP; - nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], - rem_band) { - mode = os_realloc(phy_info->modes, - (*phy_info->num_modes + 1) * sizeof(*mode)); + nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { + mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); if (!mode) return NL_SKIP; phy_info->modes = mode; @@ -2478,108 +2538,123 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) mode_is_set = 0; mode = &phy_info->modes[*(phy_info->num_modes)]; - os_memset(mode, 0, sizeof(*mode)); + memset(mode, 0, sizeof(*mode)); *(phy_info->num_modes) += 1; nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], - rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_freq), nla_len(nl_freq), - freq_policy); + if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { + mode->ht_capab = nla_get_u16( + tb_band[NL80211_BAND_ATTR_HT_CAPA]); + } + + if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { + mode->a_mpdu_params |= nla_get_u8( + tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) & + 0x03; + } + + if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { + mode->a_mpdu_params |= nla_get_u8( + tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) << + 2; + } + + if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && + nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) { + u8 *mcs; + mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); + os_memcpy(mode->mcs_set, mcs, 16); + } + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), + nla_len(nl_freq), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; mode->num_channels++; } - mode->channels = os_zalloc(mode->num_channels * - sizeof(struct wpa_channel_data)); + mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data)); if (!mode->channels) return NL_SKIP; idx = 0; - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], - rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nla_data(nl_freq), nla_len(nl_freq), - freq_policy); + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), + nla_len(nl_freq), freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; - mode->channels[idx].freq = nla_get_u32( - tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - mode->channels[idx].flag |= WPA_CHAN_W_SCAN | - WPA_CHAN_W_ACTIVE_SCAN | - WPA_CHAN_W_IBSS; + mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + mode->channels[idx].flag = 0; if (!mode_is_set) { /* crude heuristic */ if (mode->channels[idx].freq < 4000) - mode->mode = WPA_MODE_IEEE80211B; + mode->mode = HOSTAPD_MODE_IEEE80211B; else - mode->mode = WPA_MODE_IEEE80211A; + mode->mode = HOSTAPD_MODE_IEEE80211A; mode_is_set = 1; } /* crude heuristic */ - if (mode->channels[idx].freq < 4000) { + if (mode->channels[idx].freq < 4000) if (mode->channels[idx].freq == 2484) mode->channels[idx].chan = 14; else - mode->channels[idx].chan = - (mode->channels[idx].freq - - 2407) / 5; - } else - mode->channels[idx].chan = - mode->channels[idx].freq / 5 - 1000; + mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; + else + mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - mode->channels[idx].flag &= ~WPA_CHAN_W_SCAN; + mode->channels[idx].flag |= + HOSTAPD_CHAN_DISABLED; if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) - mode->channels[idx].flag &= - ~WPA_CHAN_W_ACTIVE_SCAN; + mode->channels[idx].flag |= + HOSTAPD_CHAN_PASSIVE_SCAN; if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) - mode->channels[idx].flag &= ~WPA_CHAN_W_IBSS; + mode->channels[idx].flag |= + HOSTAPD_CHAN_NO_IBSS; + if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) + mode->channels[idx].flag |= + HOSTAPD_CHAN_RADAR; + + if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && + !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) + mode->channels[idx].max_tx_power = + nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100; + idx++; } - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], - rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, - nla_data(nl_rate), nla_len(nl_rate), - rate_policy); + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), + nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; mode->num_rates++; } - mode->rates = os_zalloc(mode->num_rates * - sizeof(struct wpa_rate_data)); + mode->rates = os_zalloc(mode->num_rates * sizeof(int)); if (!mode->rates) return NL_SKIP; idx = 0; - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], - rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, - nla_data(nl_rate), nla_len(nl_rate), - rate_policy); + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), + nla_len(nl_rate), rate_policy); if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) continue; - mode->rates[idx].rate = nla_get_u32( - tb_rate[NL80211_BITRATE_ATTR_RATE]); + mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); /* crude heuristic */ - if (mode->mode == WPA_MODE_IEEE80211B && - mode->rates[idx].rate > 200) - mode->mode = WPA_MODE_IEEE80211G; - - if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) - mode->rates[idx].flags |= WPA_RATE_PREAMBLE2; + if (mode->mode == HOSTAPD_MODE_IEEE80211B && + mode->rates[idx] > 200) + mode->mode = HOSTAPD_MODE_IEEE80211G; idx++; } @@ -2588,11 +2663,85 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) return NL_SKIP; } +static struct hostapd_hw_modes * +wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes) +{ + u16 m; + struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; + int i, mode11g_idx = -1; -static struct wpa_hw_modes * + /* If only 802.11g mode is included, use it to construct matching + * 802.11b mode data. */ + + for (m = 0; m < *num_modes; m++) { + if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) + return modes; /* 802.11b already included */ + if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) + mode11g_idx = m; + } + + if (mode11g_idx < 0) + return modes; /* 2.4 GHz band not supported at all */ + + nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes)); + if (nmodes == NULL) + return modes; /* Could not add 802.11b mode */ + + mode = &nmodes[*num_modes]; + os_memset(mode, 0, sizeof(*mode)); + (*num_modes)++; + modes = nmodes; + + mode->mode = HOSTAPD_MODE_IEEE80211B; + + mode11g = &modes[mode11g_idx]; + mode->num_channels = mode11g->num_channels; + mode->channels = os_malloc(mode11g->num_channels * + sizeof(struct hostapd_channel_data)); + if (mode->channels == NULL) { + (*num_modes)--; + return modes; /* Could not add 802.11b mode */ + } + os_memcpy(mode->channels, mode11g->channels, + mode11g->num_channels * sizeof(struct hostapd_channel_data)); + + mode->num_rates = 0; + mode->rates = os_malloc(4 * sizeof(int)); + if (mode->rates == NULL) { + os_free(mode->channels); + (*num_modes)--; + return modes; /* Could not add 802.11b mode */ + } + + for (i = 0; i < mode11g->num_rates; i++) { + if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && + mode11g->rates[i] != 55 && mode11g->rates[i] != 110) + continue; + mode->rates[mode->num_rates] = mode11g->rates[i]; + mode->num_rates++; + if (mode->num_rates == 4) + break; + } + + if (mode->num_rates == 0) { + os_free(mode->channels); + os_free(mode->rates); + (*num_modes)--; + return modes; /* No 802.11b rates */ + } + + wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g " + "information"); + + return modes; +} + + +static struct hostapd_hw_modes * wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) { - struct wpa_driver_nl80211_data *drv = priv; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; struct phy_info_arg result = { .num_modes = num_modes, @@ -2612,28 +2761,21 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) - return result.modes; -nla_put_failure: + return wpa_driver_nl80211_add_11b(result.modes, num_modes); + nla_put_failure: return NULL; } -static int wpa_driver_nl80211_set_channel(void *priv, wpa_hw_mode phymode, - int chan, int freq) +static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, + const void *data, size_t len, + int encrypt) { - return wpa_driver_nl80211_set_freq(priv, freq); -} - - -static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, - size_t data_len) -{ - struct wpa_driver_nl80211_data *drv = priv; __u8 rtap_hdr[] = { 0x00, 0x00, /* radiotap version */ 0x0e, 0x00, /* radiotap length */ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ - 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */ + IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ 0x00, /* padding */ 0x00, 0x00, /* RX and TX flags to indicate that */ 0x00, 0x00, /* this is the injected frame directly */ @@ -2645,7 +2787,7 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, }, { .iov_base = (void *) data, - .iov_len = data_len, + .iov_len = len, } }; struct msghdr msg = { @@ -2658,22 +2800,138 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, .msg_flags = 0, }; - if (sendmsg(drv->monitor_sock, &msg, 0) < 0) { - perror("send[MLME]"); - return -1; - } + if (encrypt) + rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; - return 0; + return sendmsg(drv->monitor_sock, &msg, 0); } -static int wpa_driver_nl80211_mlme_add_sta(void *priv, const u8 *addr, - const u8 *supp_rates, - size_t supp_rates_len) +static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, + size_t data_len) { - struct wpa_driver_nl80211_data *drv = priv; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ieee80211_mgmt *mgmt; + int encrypt = 1; + u16 fc; + + mgmt = (struct ieee80211_mgmt *) data; + fc = le_to_host16(mgmt->frame_control); + + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { + /* + * Only one of the authentication frame types is encrypted. + * In order for static WEP encryption to work properly (i.e., + * to not encrypt the frame), we need to tell mac80211 about + * the frames that must not be encrypted. + */ + u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); + u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); + if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) + encrypt = 0; + } + + return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); +} + + +static int wpa_driver_nl80211_set_beacon(void *priv, + const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, + int dtim_period, int beacon_int) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; - int ret = -1; + u8 cmd = NL80211_CMD_NEW_BEACON; + int ret; + int beacon_set; + int ifindex = if_nametoindex(bss->ifname); + + beacon_set = bss->beacon_set; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)", + beacon_set); + if (beacon_set) + cmd = NL80211_CMD_SET_BEACON; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, cmd, 0); + NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); + NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int); + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", + ret, strerror(-ret)); + } else { + bss->beacon_set = 1; + } + return ret; + nla_put_failure: + return -ENOBUFS; +} + + +static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, + int freq, int ht_enabled, + int sec_channel_offset) +{ + struct nl_msg *msg; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_SET_WIPHY, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (ht_enabled) { + switch (sec_channel_offset) { + case -1: + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_HT40MINUS); + break; + case 1: + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_HT40PLUS); + break; + default: + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_HT20); + break; + } + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == 0) + return 0; + wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): " + "%d (%s)", freq, ret, strerror(-ret)); +nla_put_failure: + return -1; +} + + +static int wpa_driver_nl80211_sta_add(void *priv, + struct hostapd_sta_add_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; msg = nlmsg_alloc(); if (!msg) @@ -2682,29 +2940,36 @@ static int wpa_driver_nl80211_mlme_add_sta(void *priv, const u8 *addr, genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_NEW_STATION, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - /* TODO: Get proper Association ID and listen interval */ - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len, - supp_rates); - NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 1); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); + NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); + NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, + params->supp_rates); + NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, + params->listen_interval); + if (params->ht_capabilities) { + NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, + sizeof(*params->ht_capabilities), + params->ht_capabilities); + } ret = send_and_recv_msgs(drv, msg, NULL, NULL); - /* ignore EEXIST, this happens if a STA associates while associated */ - if (ret == -EEXIST || ret >= 0) + if (ret) + wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION " + "result: %d (%s)", ret, strerror(-ret)); + if (ret == -EEXIST) ret = 0; - -nla_put_failure: + nla_put_failure: return ret; } -static int wpa_driver_nl80211_mlme_remove_sta(void *priv, const u8 *addr) +static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr) { - struct wpa_driver_nl80211_data *drv = priv; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; - int ret = -1; + int ret; msg = nlmsg_alloc(); if (!msg) @@ -2713,19 +2978,2354 @@ static int wpa_driver_nl80211_mlme_remove_sta(void *priv, const u8 *addr) genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_DEL_STATION, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - ret = 0; - ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == -ENOENT) + return 0; return ret; - -nla_put_failure: + nla_put_failure: return -ENOBUFS; } -#endif /* CONFIG_CLIENT_MLME */ + +static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, + int ifidx) +{ + struct nl_msg *msg; + + wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx); + +#ifdef HOSTAPD + /* stop listening for EAPOL on this interface */ + del_ifidx(drv, ifidx); +#endif /* HOSTAPD */ + + msg = nlmsg_alloc(); + if (!msg) + goto nla_put_failure; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_DEL_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); + + if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + return; + nla_put_failure: + wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); +} + + +static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, + const char *ifname, + enum nl80211_iftype iftype, + const u8 *addr, int wds) +{ + struct nl_msg *msg, *flags = NULL; + int ifidx; + int ret = -ENOBUFS; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_NEW_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); + + if (iftype == NL80211_IFTYPE_MONITOR) { + int err; + + flags = nlmsg_alloc(); + if (!flags) + goto nla_put_failure; + + NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); + + err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); + + nlmsg_free(flags); + + if (err) + goto nla_put_failure; + } else if (wds) { + NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + nla_put_failure: + wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", + ifname, ret, strerror(-ret)); + return ret; + } + + ifidx = if_nametoindex(ifname); + wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d", + ifname, ifidx); + + if (ifidx <= 0) + return -1; + +#ifdef HOSTAPD + /* start listening for EAPOL on this interface */ + add_ifidx(drv, ifidx); +#endif /* HOSTAPD */ + + if (addr && iftype != NL80211_IFTYPE_MONITOR && + linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) { + nl80211_remove_iface(drv, ifidx); + return -1; + } + + return ifidx; +} + + +static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, + const char *ifname, enum nl80211_iftype iftype, + const u8 *addr, int wds) +{ + int ret; + + ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds); + + /* if error occured and interface exists already */ + if (ret == -ENFILE && if_nametoindex(ifname)) { + wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); + + /* Try to remove the interface that was already there. */ + nl80211_remove_iface(drv, if_nametoindex(ifname)); + + /* Try to create the interface again */ + ret = nl80211_create_iface_once(drv, ifname, iftype, addr, + wds); + } + + if (ret >= 0 && drv->disable_11b_rates) + nl80211_disable_11b_rates(drv, ret, 1); + + return ret; +} + + +static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) +{ + struct ieee80211_hdr *hdr; + u16 fc; + union wpa_event_data event; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = buf; + event.tx_status.data_len = len; + event.tx_status.ack = ok; + wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); +} + + +static void from_unknown_sta(struct wpa_driver_nl80211_data *drv, + u8 *buf, size_t len) +{ + union wpa_event_data event; + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.frame = buf; + event.rx_from_unknown.len = len; + wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); +} + + +static void handle_frame(struct wpa_driver_nl80211_data *drv, + u8 *buf, size_t len, int datarate, int ssi_signal) +{ + struct ieee80211_hdr *hdr; + u16 fc; + union wpa_event_data event; + + hdr = (struct ieee80211_hdr *) buf; + fc = le_to_host16(hdr->frame_control); + + switch (WLAN_FC_GET_TYPE(fc)) { + case WLAN_FC_TYPE_MGMT: + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.datarate = datarate; + event.rx_mgmt.ssi_signal = ssi_signal; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + break; + case WLAN_FC_TYPE_CTRL: + /* can only get here with PS-Poll frames */ + wpa_printf(MSG_DEBUG, "CTRL"); + from_unknown_sta(drv, buf, len); + break; + case WLAN_FC_TYPE_DATA: + from_unknown_sta(drv, buf, len); + break; + } +} + + +static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_driver_nl80211_data *drv = eloop_ctx; + int len; + unsigned char buf[3000]; + struct ieee80211_radiotap_iterator iter; + int ret; + int datarate = 0, ssi_signal = 0; + int injected = 0, failed = 0, rxflags = 0; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + if (drv->nlmode == NL80211_IFTYPE_STATION && !drv->probe_req_report) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore monitor interface " + "frame since Probe Request reporting is disabled"); + return; + } + + if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { + printf("received invalid radiotap frame\n"); + return; + } + + while (1) { + ret = ieee80211_radiotap_iterator_next(&iter); + if (ret == -ENOENT) + break; + if (ret) { + printf("received invalid radiotap frame (%d)\n", ret); + return; + } + switch (iter.this_arg_index) { + case IEEE80211_RADIOTAP_FLAGS: + if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) + len -= 4; + break; + case IEEE80211_RADIOTAP_RX_FLAGS: + rxflags = 1; + break; + case IEEE80211_RADIOTAP_TX_FLAGS: + injected = 1; + failed = le_to_host16((*(uint16_t *) iter.this_arg)) & + IEEE80211_RADIOTAP_F_TX_FAIL; + break; + case IEEE80211_RADIOTAP_DATA_RETRIES: + break; + case IEEE80211_RADIOTAP_CHANNEL: + /* TODO: convert from freq/flags to channel number */ + break; + case IEEE80211_RADIOTAP_RATE: + datarate = *iter.this_arg * 5; + break; + case IEEE80211_RADIOTAP_DB_ANTSIGNAL: + ssi_signal = *iter.this_arg; + break; + } + } + + if (rxflags && injected) + return; + + if (!injected) + handle_frame(drv, buf + iter.max_length, + len - iter.max_length, datarate, ssi_signal); + else + handle_tx_callback(drv->ctx, buf + iter.max_length, + len - iter.max_length, !failed); +} + + +/* + * we post-process the filter code later and rewrite + * this to the offset to the last instruction + */ +#define PASS 0xFF +#define FAIL 0xFE + +static struct sock_filter msock_filter_insns[] = { + /* + * do a little-endian load of the radiotap length field + */ + /* load lower byte into A */ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), + /* put it into X (== index register) */ + BPF_STMT(BPF_MISC| BPF_TAX, 0), + /* load upper byte into A */ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), + /* left-shift it by 8 */ + BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), + /* or with X */ + BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), + /* put result into X */ + BPF_STMT(BPF_MISC| BPF_TAX, 0), + + /* + * Allow management frames through, this also gives us those + * management frames that we sent ourselves with status + */ + /* load the lower byte of the IEEE 802.11 frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), + /* mask off frame type and version */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), + /* accept frame if it's both 0, fall through otherwise */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), + + /* + * TODO: add a bit to radiotap RX flags that indicates + * that the sending station is not associated, then + * add a filter here that filters on our DA and that flag + * to allow us to deauth frames to that bad station. + * + * Not a regression -- we didn't do it before either. + */ + +#if 0 + /* + * drop non-data frames + */ + /* load the lower byte of the frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), + /* mask off QoS bit */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), + /* drop non-data frames */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), +#endif + /* load the upper byte of the frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), + /* mask off toDS/fromDS */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), + /* accept WDS frames */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), + + /* + * add header length to index + */ + /* load the lower byte of the frame control field */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), + /* mask off QoS bit */ + BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), + /* right shift it by 6 to give 0 or 2 */ + BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), + /* add data frame header length */ + BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), + /* add index, was start of 802.11 header */ + BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), + /* move to index, now start of LL header */ + BPF_STMT(BPF_MISC | BPF_TAX, 0), + + /* + * Accept empty data frames, we use those for + * polling activity. + */ + BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), + + /* + * Accept EAPOL frames + */ + BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), + BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), + + /* keep these last two statements or change the code below */ + /* return 0 == "DROP" */ + BPF_STMT(BPF_RET | BPF_K, 0), + /* return ~0 == "keep all" */ + BPF_STMT(BPF_RET | BPF_K, ~0), +}; + +static struct sock_fprog msock_filter = { + .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]), + .filter = msock_filter_insns, +}; + + +static int add_monitor_filter(int s) +{ + int idx; + + /* rewrite all PASS/FAIL jump offsets */ + for (idx = 0; idx < msock_filter.len; idx++) { + struct sock_filter *insn = &msock_filter_insns[idx]; + + if (BPF_CLASS(insn->code) == BPF_JMP) { + if (insn->code == (BPF_JMP|BPF_JA)) { + if (insn->k == PASS) + insn->k = msock_filter.len - idx - 2; + else if (insn->k == FAIL) + insn->k = msock_filter.len - idx - 3; + } + + if (insn->jt == PASS) + insn->jt = msock_filter.len - idx - 2; + else if (insn->jt == FAIL) + insn->jt = msock_filter.len - idx - 3; + + if (insn->jf == PASS) + insn->jf = msock_filter.len - idx - 2; + else if (insn->jf == FAIL) + insn->jf = msock_filter.len - idx - 3; + } + } + + if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, + &msock_filter, sizeof(msock_filter))) { + perror("SO_ATTACH_FILTER"); + return -1; + } + + return 0; +} + + +static void nl80211_remove_monitor_interface( + struct wpa_driver_nl80211_data *drv) +{ + if (drv->monitor_ifidx >= 0) { + nl80211_remove_iface(drv, drv->monitor_ifidx); + drv->monitor_ifidx = -1; + } + if (drv->monitor_sock >= 0) { + eloop_unregister_read_sock(drv->monitor_sock); + close(drv->monitor_sock); + drv->monitor_sock = -1; + } +} + + +static int +nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) +{ + char buf[IFNAMSIZ]; + struct sockaddr_ll ll; + int optval; + socklen_t optlen; + + snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); + buf[IFNAMSIZ - 1] = '\0'; + + drv->monitor_ifidx = + nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, + 0); + + if (drv->monitor_ifidx < 0) + return -1; + + if (linux_set_iface_flags(drv->ioctl_sock, buf, 1)) + goto error; + + memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + ll.sll_ifindex = drv->monitor_ifidx; + drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (drv->monitor_sock < 0) { + perror("socket[PF_PACKET,SOCK_RAW]"); + goto error; + } + + if (add_monitor_filter(drv->monitor_sock)) { + wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " + "interface; do filtering in user space"); + /* This works, but will cost in performance. */ + } + + if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { + perror("monitor socket bind"); + goto error; + } + + optlen = sizeof(optval); + optval = 20; + if (setsockopt + (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { + perror("Failed to set socket priority"); + goto error; + } + + if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, + drv, NULL)) { + printf("Could not register monitor read socket\n"); + goto error; + } + + return 0; + error: + nl80211_remove_monitor_interface(drv); + return -1; +} + + +static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +static int wpa_driver_nl80211_hapd_send_eapol( + void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, const u8 *own_addr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ieee80211_hdr *hdr; + size_t len; + u8 *pos; + int res; +#if 0 /* FIX */ + int qos = sta->flags & WPA_STA_WMM; +#else + int qos = 0; +#endif + + len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + printf("malloc() failed for i802_send_data(len=%lu)\n", + (unsigned long) len); + return -1; + } + + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); + hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); + if (encrypt) + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); +#if 0 /* To be enabled if qos determination is added above */ + if (qos) { + hdr->frame_control |= + host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); + } +#endif + + memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); + memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + pos = (u8 *) (hdr + 1); + +#if 0 /* To be enabled if qos determination is added above */ + if (qos) { + /* add an empty QoS header if needed */ + pos[0] = 0; + pos[1] = 0; + pos += 2; + } +#endif + + memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); + pos += sizeof(rfc1042_header); + WPA_PUT_BE16(pos, ETH_P_PAE); + pos += 2; + memcpy(pos, data, data_len); + + res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt); + if (res < 0) { + wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " + "failed: %d (%s)", + (unsigned long) len, errno, strerror(errno)); + } + os_free(hdr); + + return res; +} + + +static u32 sta_flags_nl80211(int flags) +{ + u32 f = 0; + + if (flags & WPA_STA_AUTHORIZED) + f |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (flags & WPA_STA_WMM) + f |= BIT(NL80211_STA_FLAG_WME); + if (flags & WPA_STA_SHORT_PREAMBLE) + f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (flags & WPA_STA_MFP) + f |= BIT(NL80211_STA_FLAG_MFP); + + return f; +} + + +static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, + int total_flags, + int flags_or, int flags_and) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg, *flags = NULL; + struct nl80211_sta_flag_update upd; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + flags = nlmsg_alloc(); + if (!flags) { + nlmsg_free(msg); + return -ENOMEM; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_STATION, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + /* + * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This + * can be removed eventually. + */ + if (total_flags & WPA_STA_AUTHORIZED) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); + + if (total_flags & WPA_STA_WMM) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); + + if (total_flags & WPA_STA_SHORT_PREAMBLE) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); + + if (total_flags & WPA_STA_MFP) + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); + + if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) + goto nla_put_failure; + + os_memset(&upd, 0, sizeof(upd)); + upd.mask = sta_flags_nl80211(flags_or | ~flags_and); + upd.set = sta_flags_nl80211(flags_or); + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + nlmsg_free(flags); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + nlmsg_free(flags); + return -ENOBUFS; +} + + +static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) || + wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) { + nl80211_remove_monitor_interface(drv); + return -1; + } + + /* TODO: setup monitor interface (and add code somewhere to remove this + * when AP mode is stopped; associate with mode != 2 or drv_deinit) */ + + return 0; +} + + +static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv) +{ + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_LEAVE_IBSS, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d " + "(%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + + ret = 0; + wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + int ret = -1; + int count = 0; + + wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); + + if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) { + wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " + "IBSS mode"); + return -1; + } + +retry: + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_JOIN_IBSS, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; + + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + + ret = nl80211_set_conn_keys(params, msg); + if (ret) + goto nla_put_failure; + + if (params->wpa_ie) { + wpa_hexdump(MSG_DEBUG, + " * Extra IEs for Beacon/Probe Response frames", + params->wpa_ie, params->wpa_ie_len); + NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, + params->wpa_ie); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)", + ret, strerror(-ret)); + count++; + if (ret == -EALREADY && count == 1) { + wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after " + "forced leave"); + nl80211_leave_ibss(drv); + nlmsg_free(msg); + goto retry; + } + + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_nl80211_connect( + struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + enum nl80211_auth_type type; + int ret = 0; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_CONNECT, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { + wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + } + if (params->ssid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; + } + wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); + if (params->wpa_ie) + NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, + params->wpa_ie); + + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (params->auth_alg & WPA_AUTH_ALG_SHARED) + type = NL80211_AUTHTYPE_SHARED_KEY; + else if (params->auth_alg & WPA_AUTH_ALG_LEAP) + type = NL80211_AUTHTYPE_NETWORK_EAP; + else if (params->auth_alg & WPA_AUTH_ALG_FT) + type = NL80211_AUTHTYPE_FT; + else + goto nla_put_failure; + + wpa_printf(MSG_DEBUG, " * Auth Type %d", type); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); + + if (params->wpa_ie && params->wpa_ie_len) { + enum nl80211_wpa_versions ver; + + if (params->wpa_ie[0] == WLAN_EID_RSN) + ver = NL80211_WPA_VERSION_2; + else + ver = NL80211_WPA_VERSION_1; + + wpa_printf(MSG_DEBUG, " * WPA Version %d", ver); + NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); + } + + if (params->pairwise_suite != CIPHER_NONE) { + int cipher; + + switch (params->pairwise_suite) { + case CIPHER_WEP40: + cipher = WLAN_CIPHER_SUITE_WEP40; + break; + case CIPHER_WEP104: + cipher = WLAN_CIPHER_SUITE_WEP104; + break; + case CIPHER_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case CIPHER_TKIP: + default: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); + } + + if (params->group_suite != CIPHER_NONE) { + int cipher; + + switch (params->group_suite) { + case CIPHER_WEP40: + cipher = WLAN_CIPHER_SUITE_WEP40; + break; + case CIPHER_WEP104: + cipher = WLAN_CIPHER_SUITE_WEP104; + break; + case CIPHER_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case CIPHER_TKIP: + default: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); + } + + if (params->key_mgmt_suite == KEY_MGMT_802_1X || + params->key_mgmt_suite == KEY_MGMT_PSK) { + int mgmt = WLAN_AKM_SUITE_PSK; + + switch (params->key_mgmt_suite) { + case KEY_MGMT_802_1X: + mgmt = WLAN_AKM_SUITE_8021X; + break; + case KEY_MGMT_PSK: + default: + mgmt = WLAN_AKM_SUITE_PSK; + break; + } + NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); + } + + ret = nl80211_set_conn_keys(params, msg); + if (ret) + goto nla_put_failure; + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " + "(%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; + +} + + +static int wpa_driver_nl80211_associate( + void *priv, struct wpa_driver_associate_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = -1; + struct nl_msg *msg; + + if (params->mode == IEEE80211_MODE_AP) + return wpa_driver_nl80211_ap(drv, params); + + if (params->mode == IEEE80211_MODE_IBSS) + return wpa_driver_nl80211_ibss(drv, params); + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { + if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0) + return -1; + return wpa_driver_nl80211_connect(drv, params); + } + + drv->associated = 0; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)", + drv->ifindex); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_ASSOCIATE, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { + wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, + MAC2STR(params->bssid)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); + } + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + drv->assoc_freq = params->freq; + } else + drv->assoc_freq = 0; + if (params->ssid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->ssid, params->ssid_len); + NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid); + if (params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; + } + wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); + if (params->wpa_ie) + NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, + params->wpa_ie); + +#ifdef CONFIG_IEEE80211W + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) + NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); +#endif /* CONFIG_IEEE80211W */ + + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + + if (params->prev_bssid) { + wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, + MAC2STR(params->prev_bssid)); + NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, + params->prev_bssid); + } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " + "(%s)", ret, strerror(-ret)); + nl80211_dump_scan(drv); + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "nl80211: Association request send " + "successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, + int ifindex, int mode) +{ + struct nl_msg *msg; + int ret = -ENOBUFS; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (!ret) + return 0; +nla_put_failure: + wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:" + " %d (%s)", ifindex, mode, ret, strerror(-ret)); + return ret; +} + + +static int wpa_driver_nl80211_set_mode(void *priv, int mode) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = -1; + int nlmode; + + switch (mode) { + case 0: + nlmode = NL80211_IFTYPE_STATION; + break; + case 1: + nlmode = NL80211_IFTYPE_ADHOC; + break; + case 2: + nlmode = NL80211_IFTYPE_AP; + break; + default: + return -1; + } + + if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) { + drv->nlmode = nlmode; + ret = 0; + goto done; + } + + if (nlmode == drv->nlmode) { + wpa_printf(MSG_DEBUG, "nl80211: Interface already in " + "requested mode - ignore error"); + ret = 0; + goto done; /* Already in the requested mode */ + } + + /* mac80211 doesn't allow mode changes while the device is up, so + * take the device down, try to set the mode again, and bring the + * device back up. + */ + if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == 0) { + /* Try to set the mode again while the interface is down */ + ret = nl80211_set_mode(drv, drv->ifindex, nlmode); + if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) + ret = -1; + } + + if (!ret) { + wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while " + "interface is down"); + drv->nlmode = nlmode; + } + +done: + if (!ret && nlmode == NL80211_IFTYPE_AP) { + /* Setup additional AP mode functionality if needed */ + if (drv->monitor_ifidx < 0 && + nl80211_create_monitor_interface(drv)) + return -1; + } else if (!ret && nlmode != NL80211_IFTYPE_AP) { + /* Remove additional AP mode functionality */ + nl80211_remove_monitor_interface(drv); + bss->beacon_set = 0; + } + + if (ret) + wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " + "from %d failed", nlmode, drv->nlmode); + + return ret; +} + + +static int wpa_driver_nl80211_get_capa(void *priv, + struct wpa_driver_capa *capa) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (!drv->has_capability) + return -1; + os_memcpy(capa, &drv->capa, sizeof(*capa)); + return 0; +} + + +static int wpa_driver_nl80211_set_operstate(void *priv, int state) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", + __func__, drv->operstate, state, state ? "UP" : "DORMANT"); + drv->operstate = state; + return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, + state ? IF_OPER_UP : IF_OPER_DORMANT); +} + + +static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nl80211_sta_flag_update upd; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_STATION, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); + + os_memset(&upd, 0, sizeof(upd)); + upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); + if (authorized) + upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); + NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; +} + + +#ifdef HOSTAPD + +static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ + int i; + int *old; + + wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d", + ifidx); + for (i = 0; i < drv->num_if_indices; i++) { + if (drv->if_indices[i] == 0) { + drv->if_indices[i] = ifidx; + return; + } + } + + if (drv->if_indices != drv->default_if_indices) + old = drv->if_indices; + else + old = NULL; + + drv->if_indices = os_realloc(old, + sizeof(int) * (drv->num_if_indices + 1)); + if (!drv->if_indices) { + if (!old) + drv->if_indices = drv->default_if_indices; + else + drv->if_indices = old; + wpa_printf(MSG_ERROR, "Failed to reallocate memory for " + "interfaces"); + wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); + return; + } else if (!old) + os_memcpy(drv->if_indices, drv->default_if_indices, + sizeof(drv->default_if_indices)); + drv->if_indices[drv->num_if_indices] = ifidx; + drv->num_if_indices++; +} + + +static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ + int i; + + for (i = 0; i < drv->num_if_indices; i++) { + if (drv->if_indices[i] == ifidx) { + drv->if_indices[i] = 0; + break; + } + } +} + + +static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) +{ + int i; + + for (i = 0; i < drv->num_if_indices; i++) + if (drv->if_indices[i] == ifidx) + return 1; + + return 0; +} + + +static inline int min_int(int a, int b) +{ + if (a < b) + return a; + return b; +} + + +static int get_key_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + /* + * TODO: validate the key index and mac address! + * Otherwise, there's a race condition as soon as + * the kernel starts sending key notifications. + */ + + if (tb[NL80211_ATTR_KEY_SEQ]) + memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), + min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); + return NL_SKIP; +} + + +static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, + int idx, u8 *seq) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_GET_KEY, 0); + + if (addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); + + memset(seq, 0, 6); + + return send_and_recv_msgs(drv, msg, get_key_handler, seq); + nla_put_failure: + return -ENOBUFS; +} + + +static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, + int mode) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + u8 rates[NL80211_MAX_SUPP_RATES]; + u8 rates_len = 0; + int i; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_SET_BSS, 0); + + for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) + rates[rates_len++] = basic_rates[i] / 5; + + NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; +} + +#endif /* HOSTAPD */ + + +/* Set kernel driver on given frequency (MHz) */ +static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled, + freq->sec_channel_offset); +} + + +#ifdef HOSTAPD + +static int i802_set_rts(void *priv, int rts) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; + u32 val; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + if (rts >= 2347) + val = (u32) -1; + else + val = rts; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_WIPHY, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (!ret) + return 0; +nla_put_failure: + wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: " + "%d (%s)", rts, ret, strerror(-ret)); + return ret; +} + + +static int i802_set_frag(void *priv, int frag) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; + u32 val; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + if (frag >= 2346) + val = (u32) -1; + else + val = frag; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_WIPHY, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (!ret) + return 0; +nla_put_failure: + wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold " + "%d: %d (%s)", frag, ret, strerror(-ret)); + return ret; +} + + +static int i802_flush(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_DEL_STATION, 0); + + /* + * XXX: FIX! this needs to flush all VLANs too + */ + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; +} + + +static int get_sta_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct hostap_sta_driver_data *data = arg; + struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; + static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + }; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + /* + * TODO: validate the interface and mac address! + * Otherwise, there's a race condition as soon as + * the kernel starts sending station notifications. + */ + + if (!tb[NL80211_ATTR_STA_INFO]) { + wpa_printf(MSG_DEBUG, "sta stats missing!"); + return NL_SKIP; + } + if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, + tb[NL80211_ATTR_STA_INFO], + stats_policy)) { + wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); + return NL_SKIP; + } + + if (stats[NL80211_STA_INFO_INACTIVE_TIME]) + data->inactive_msec = + nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); + if (stats[NL80211_STA_INFO_RX_BYTES]) + data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); + if (stats[NL80211_STA_INFO_TX_BYTES]) + data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); + if (stats[NL80211_STA_INFO_RX_PACKETS]) + data->rx_packets = + nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); + if (stats[NL80211_STA_INFO_TX_PACKETS]) + data->tx_packets = + nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); + + return NL_SKIP; +} + +static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, + const u8 *addr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + os_memset(data, 0, sizeof(*data)); + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_GET_STATION, 0); + + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, get_sta_handler, data); + nla_put_failure: + return -ENOBUFS; +} + + +static int i802_set_tx_queue_params(void *priv, int queue, int aifs, + int cw_min, int cw_max, int burst_time) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *txq, *params; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_WIPHY, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); + if (!txq) + goto nla_put_failure; + + /* We are only sending parameters for a single TXQ at a time */ + params = nla_nest_start(msg, 1); + if (!params) + goto nla_put_failure; + + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, queue); + /* Burst time is configured in units of 0.1 msec and TXOP parameter in + * 32 usec, so need to convert the value here. */ + NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); + NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); + NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); + NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); + + nla_nest_end(msg, params); + + nla_nest_end(msg, txq); + + if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + return 0; + nla_put_failure: + return -1; +} + + +static int i802_set_bss(void *priv, int cts, int preamble, int slot) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_SET_BSS, 0); + + if (cts >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); + if (preamble >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); + if (slot >= 0) + NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; +} + + +static int i802_set_cts_protect(void *priv, int value) +{ + return i802_set_bss(priv, value, -1, -1); +} + + +static int i802_set_preamble(void *priv, int value) +{ + return i802_set_bss(priv, -1, value, -1); +} + + +static int i802_set_short_slot_time(void *priv, int value) +{ + return i802_set_bss(priv, -1, -1, value); +} + + +static int i802_set_sta_vlan(void *priv, const u8 *addr, + const char *ifname, int vlan_id) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -ENOBUFS; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_STATION, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, + if_nametoindex(bss->ifname)); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, + if_nametoindex(ifname)); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret < 0) { + wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr=" + MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", + MAC2STR(addr), ifname, vlan_id, ret, + strerror(-ret)); + } + nla_put_failure: + return ret; +} + + +static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + char name[IFNAMSIZ + 1]; + + os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); + wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR + " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); + if (val) { + if (nl80211_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN, + NULL, 1) < 0) + return -1; + linux_set_iface_flags(drv->ioctl_sock, name, 1); + return i802_set_sta_vlan(priv, addr, name, 0); + } else { + i802_set_sta_vlan(priv, addr, bss->ifname, 0); + return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN, + name); + } +} + + +static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_driver_nl80211_data *drv = eloop_ctx; + struct sockaddr_ll lladdr; + unsigned char buf[3000]; + int len; + socklen_t fromlen = sizeof(lladdr); + + len = recvfrom(sock, buf, sizeof(buf), 0, + (struct sockaddr *)&lladdr, &fromlen); + if (len < 0) { + perror("recv"); + return; + } + + if (have_ifidx(drv, lladdr.sll_ifindex)) + drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len); +} + + +static int i802_get_inact_sec(void *priv, const u8 *addr) +{ + struct hostap_sta_driver_data data; + int ret; + + data.inactive_msec = (unsigned long) -1; + ret = i802_read_sta_data(priv, &data, addr); + if (ret || data.inactive_msec == (unsigned long) -1) + return -1; + return data.inactive_msec / 1000; +} + + +static int i802_sta_clear_stats(void *priv, const u8 *addr) +{ +#if 0 + /* TODO */ +#endif + return 0; +} + + +static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, + int reason) +{ + struct i802_bss *bss = priv; + struct ieee80211_mgmt mgmt; + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DEAUTH); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); + mgmt.u.deauth.reason_code = host_to_le16(reason); + return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, + IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth)); +} + + +static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, + int reason) +{ + struct i802_bss *bss = priv; + struct ieee80211_mgmt mgmt; + + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DISASSOC); + memcpy(mgmt.da, addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); + mgmt.u.disassoc.reason_code = host_to_le16(reason); + return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, + IEEE80211_HDRLEN + + sizeof(mgmt.u.disassoc)); +} + + +static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, + const char *brname, const char *ifname) +{ + int ifindex; + char in_br[IFNAMSIZ]; + + os_strlcpy(drv->brname, brname, IFNAMSIZ); + ifindex = if_nametoindex(brname); + if (ifindex == 0) { + /* + * Bridge was configured, but the bridge device does + * not exist. Try to add it now. + */ + if (linux_br_add(drv->ioctl_sock, brname) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to add the " + "bridge interface %s: %s", + brname, strerror(errno)); + return -1; + } + drv->added_bridge = 1; + add_ifidx(drv, if_nametoindex(brname)); + } + + if (linux_br_get(in_br, ifname) == 0) { + if (os_strcmp(in_br, brname) == 0) + return 0; /* already in the bridge */ + + wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from " + "bridge %s", ifname, in_br); + if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to " + "remove interface %s from bridge " + "%s: %s", + ifname, brname, strerror(errno)); + return -1; + } + } + + wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s", + ifname, brname); + if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s " + "into bridge %s: %s", + ifname, brname, strerror(errno)); + return -1; + } + drv->added_if_into_bridge = 1; + + return 0; +} + + +static void *i802_init(struct hostapd_data *hapd, + struct wpa_init_params *params) +{ + struct wpa_driver_nl80211_data *drv; + struct i802_bss *bss; + size_t i; + char brname[IFNAMSIZ]; + int ifindex, br_ifindex; + int br_added = 0; + + bss = wpa_driver_nl80211_init(hapd, params->ifname); + if (bss == NULL) + return NULL; + + drv = bss->drv; + if (linux_br_get(brname, params->ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s", + params->ifname, brname); + br_ifindex = if_nametoindex(brname); + } else { + brname[0] = '\0'; + br_ifindex = 0; + } + + drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); + drv->if_indices = drv->default_if_indices; + for (i = 0; i < params->num_bridge; i++) { + if (params->bridge[i]) { + ifindex = if_nametoindex(params->bridge[i]); + if (ifindex) + add_ifidx(drv, ifindex); + if (ifindex == br_ifindex) + br_added = 1; + } + } + if (!br_added && br_ifindex && + (params->num_bridge == 0 || !params->bridge[0])) + add_ifidx(drv, br_ifindex); + + /* start listening for EAPOL on the default AP interface */ + add_ifidx(drv, drv->ifindex); + + if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0)) + goto failed; + + if (params->bssid) { + if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname, + params->bssid)) + goto failed; + } + + if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s " + "into AP mode", bss->ifname); + goto failed; + } + + if (params->num_bridge && params->bridge[0] && + i802_check_bridge(drv, params->bridge[0], params->ifname) < 0) + goto failed; + + if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) + goto failed; + + drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); + if (drv->eapol_sock < 0) { + perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); + goto failed; + } + + if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) + { + printf("Could not register read socket for eapol\n"); + goto failed; + } + + if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr)) + goto failed; + + return bss; + +failed: + nl80211_remove_monitor_interface(drv); + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + + genl_family_put(drv->nl80211); + nl_cache_free(drv->nl_cache); + nl_handle_destroy(drv->nl_handle); + nl_cb_put(drv->nl_cb); + + os_free(drv); + return NULL; +} + + +static void i802_deinit(void *priv) +{ + wpa_driver_nl80211_deinit(priv); +} + +#endif /* HOSTAPD */ + + +static enum nl80211_iftype wpa_driver_nl80211_if_type( + enum wpa_driver_if_type type) +{ + switch (type) { + case WPA_IF_STATION: + return NL80211_IFTYPE_STATION; + case WPA_IF_AP_VLAN: + return NL80211_IFTYPE_AP_VLAN; + case WPA_IF_AP_BSS: + return NL80211_IFTYPE_AP; + } + return -1; +} + + +static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, + const char *ifname, const u8 *addr, + void *bss_ctx, void **drv_priv, + char *force_ifname, u8 *if_addr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ifidx; +#ifdef HOSTAPD + struct i802_bss *new_bss = NULL; + + if (type == WPA_IF_AP_BSS) { + new_bss = os_zalloc(sizeof(*new_bss)); + if (new_bss == NULL) + return -1; + } +#endif /* HOSTAPD */ + + if (addr) + os_memcpy(if_addr, addr, ETH_ALEN); + ifidx = nl80211_create_iface(drv, ifname, + wpa_driver_nl80211_if_type(type), addr, + 0); + if (ifidx < 0) { +#ifdef HOSTAPD + os_free(new_bss); +#endif /* HOSTAPD */ + return -1; + } + + if (!addr && + linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) + return -1; + +#ifdef HOSTAPD + if (type == WPA_IF_AP_BSS) { + if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) { + nl80211_remove_iface(drv, ifidx); + os_free(new_bss); + return -1; + } + os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); + new_bss->ifindex = ifidx; + new_bss->drv = drv; + new_bss->next = drv->first_bss.next; + drv->first_bss.next = new_bss; + if (drv_priv) + *drv_priv = new_bss; + } +#endif /* HOSTAPD */ + + return 0; +} + + +static int wpa_driver_nl80211_if_remove(void *priv, + enum wpa_driver_if_type type, + const char *ifname) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ifindex = if_nametoindex(ifname); + + wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d", + __func__, type, ifname, ifindex); + if (ifindex <= 0) + return -1; + nl80211_remove_iface(drv, ifindex); + +#ifdef HOSTAPD + if (type != WPA_IF_AP_BSS) + return 0; + + if (bss != &drv->first_bss) { + struct i802_bss *tbss = &drv->first_bss; + + while (tbss) { + if (tbss->next != bss) + continue; + + tbss->next = bss->next; + os_free(bss); + break; + } + } +#endif /* HOSTAPD */ + + return 0; +} + + +static int cookie_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + u64 *cookie = arg; + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (tb[NL80211_ATTR_COOKIE]) + *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + return NL_SKIP; +} + + +static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, + const u8 *dst, const u8 *src, + const u8 *bssid, + const u8 *data, size_t data_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = -1; + struct nl_msg *msg; + u8 *buf; + struct ieee80211_hdr *hdr; + u64 cookie; + + wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d)", + drv->ifindex); + + buf = os_zalloc(24 + data_len); + if (buf == NULL) + return ret; + os_memcpy(buf + 24, data, data_len); + hdr = (struct ieee80211_hdr *) buf; + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); + os_memcpy(hdr->addr1, dst, ETH_ALEN); + os_memcpy(hdr->addr2, src, ETH_ALEN); + os_memcpy(hdr->addr3, bssid, ETH_ALEN); + + if (drv->nlmode == NL80211_IFTYPE_AP) { + ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len); + os_free(buf); + return ret; + } + + msg = nlmsg_alloc(); + if (!msg) { + os_free(buf); + return -1; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_ACTION, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT(msg, NL80211_ATTR_FRAME, 24 + data_len, buf); + os_free(buf); + buf = NULL; + + cookie = 0; + ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Action command failed: ret=%d " + "(%s)", ret, strerror(-ret)); + goto nla_put_failure; + } + wpa_printf(MSG_DEBUG, "nl80211: Action TX command accepted; " + "cookie 0x%llx", (long long unsigned int) cookie); + drv->send_action_cookie = cookie; + ret = 0; + +nla_put_failure: + os_free(buf); + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, + unsigned int duration) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + u64 cookie; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_REMAIN_ON_CHANNEL, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); + + cookie = 0; + ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); + if (ret == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie " + "0x%llx for freq=%u MHz duration=%u", + (long long unsigned int) cookie, freq, duration); + drv->remain_on_chan_cookie = cookie; + return 0; + } + wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel " + "(freq=%d): %d (%s)", freq, ret, strerror(-ret)); +nla_put_failure: + return -1; +} + + +static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + if (!drv->pending_remain_on_chan) { + wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel " + "to cancel"); + return -1; + } + + wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie " + "0x%llx", + (long long unsigned int) drv->remain_on_chan_cookie); + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == 0) + return 0; + wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: " + "%d (%s)", ret, strerror(-ret)); +nla_put_failure: + return -1; +} + + +static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_driver_nl80211_data *drv = eloop_ctx; + if (drv->monitor_ifidx < 0) + return; /* monitor interface already removed */ + + if (drv->nlmode != NL80211_IFTYPE_STATION) + return; /* not in station mode anymore */ + + if (drv->probe_req_report) + return; /* reporting enabled */ + + wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface due to no " + "Probe Request reporting needed anymore"); + nl80211_remove_monitor_interface(drv); +} + + +static int wpa_driver_nl80211_probe_req_report(void *priv, int report) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (drv->nlmode != NL80211_IFTYPE_STATION) { + wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only " + "allowed in station mode (iftype=%d)", + drv->nlmode); + return -1; + } + drv->probe_req_report = report; + + if (report) { + eloop_cancel_timeout( + wpa_driver_nl80211_probe_req_report_timeout, + drv, NULL); + if (drv->monitor_ifidx < 0 && + nl80211_create_monitor_interface(drv)) + return -1; + } else { + /* + * It takes a while to remove the monitor interface, so try to + * avoid doing this if it is needed again shortly. Instead, + * schedule the interface to be removed later if no need for it + * is seen. + */ + wpa_printf(MSG_DEBUG, "nl80211: Scheduling monitor interface " + "to be removed after 10 seconds of no use"); + eloop_register_timeout( + 10, 0, wpa_driver_nl80211_probe_req_report_timeout, + drv, NULL); + } + + return 0; +} + + +static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, + int ifindex, int disabled) +{ + struct nl_msg *msg; + struct nlattr *bands, *band; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_SET_TX_BITRATE_MASK, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + + bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); + if (!bands) + goto nla_put_failure; + + /* + * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything + * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS + * rates. All 5 GHz rates are left enabled. + */ + band = nla_nest_start(msg, NL80211_BAND_2GHZ); + if (!band) + goto nla_put_failure; + NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, + "\x0c\x12\x18\x24\x30\x48\x60\x6c"); + nla_nest_end(msg, band); + + nla_nest_end(msg, bands); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d " + "(%s)", ret, strerror(-ret)); + } + + return ret; + +nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + drv->disable_11b_rates = disabled; + return nl80211_disable_11b_rates(drv, drv->ifindex, disabled); +} + + +static int wpa_driver_nl80211_deinit_ap(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (drv->nlmode != NL80211_IFTYPE_AP) + return -1; + wpa_driver_nl80211_del_beacon(drv); + return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA); +} + + +static void wpa_driver_nl80211_resume(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on " + "resume event"); + } +} + + +static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret; + u8 *data, *pos; + size_t data_len; + u8 own_addr[ETH_ALEN]; + + if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0) + return -1; + + if (action != 1) { + wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action " + "action %d", action); + return -1; + } + + /* + * Action frame payload: + * Category[1] = 6 (Fast BSS Transition) + * Action[1] = 1 (Fast BSS Transition Request) + * STA Address + * Target AP Address + * FT IEs + */ + + data_len = 2 + 2 * ETH_ALEN + ies_len; + data = os_malloc(data_len); + if (data == NULL) + return -1; + pos = data; + *pos++ = 0x06; /* FT Action category */ + *pos++ = action; + os_memcpy(pos, own_addr, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, target_ap, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, ies, ies_len); + + ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid, + own_addr, drv->bssid, + data, data_len); + os_free(data); + + return ret; +} + + +static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg, *cqm = NULL; + + wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d " + "hysteresis=%d", threshold, hysteresis); + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_CQM, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); + + cqm = nlmsg_alloc(); + if (cqm == NULL) + return -1; + + NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold); + NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis); + nla_put_nested(msg, NL80211_ATTR_CQM, cqm); + + if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) + return 0; + msg = NULL; + +nla_put_failure: + if (cqm) + nlmsg_free(cqm); + nlmsg_free(msg); + return -1; +} + + +static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, + int encrypt) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); +} const struct wpa_driver_ops wpa_driver_nl80211_ops = { @@ -2733,34 +5333,58 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .desc = "Linux nl80211/cfg80211", .get_bssid = wpa_driver_nl80211_get_bssid, .get_ssid = wpa_driver_nl80211_get_ssid, - .set_wpa = wpa_driver_nl80211_set_wpa, .set_key = wpa_driver_nl80211_set_key, - .set_countermeasures = wpa_driver_nl80211_set_countermeasures, - .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted, - .scan = wpa_driver_nl80211_scan, + .scan2 = wpa_driver_nl80211_scan, .get_scan_results2 = wpa_driver_nl80211_get_scan_results, .deauthenticate = wpa_driver_nl80211_deauthenticate, .disassociate = wpa_driver_nl80211_disassociate, - .set_mode = wpa_driver_nl80211_set_mode, + .authenticate = wpa_driver_nl80211_authenticate, .associate = wpa_driver_nl80211_associate, - .set_auth_alg = wpa_driver_nl80211_set_auth_alg, .init = wpa_driver_nl80211_init, .deinit = wpa_driver_nl80211_deinit, - .set_param = wpa_driver_nl80211_set_param, - .add_pmkid = wpa_driver_nl80211_add_pmkid, - .remove_pmkid = wpa_driver_nl80211_remove_pmkid, - .flush_pmkid = wpa_driver_nl80211_flush_pmkid, .get_capa = wpa_driver_nl80211_get_capa, .set_operstate = wpa_driver_nl80211_set_operstate, + .set_supp_port = wpa_driver_nl80211_set_supp_port, .set_country = wpa_driver_nl80211_set_country, - .set_probe_req_ie = wpa_driver_nl80211_set_probe_req_ie, -#ifdef CONFIG_CLIENT_MLME - .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data, - .set_channel = wpa_driver_nl80211_set_channel, - .set_ssid = wpa_driver_nl80211_set_ssid, - .set_bssid = wpa_driver_nl80211_set_bssid, + .set_beacon = wpa_driver_nl80211_set_beacon, + .if_add = wpa_driver_nl80211_if_add, + .if_remove = wpa_driver_nl80211_if_remove, .send_mlme = wpa_driver_nl80211_send_mlme, - .mlme_add_sta = wpa_driver_nl80211_mlme_add_sta, - .mlme_remove_sta = wpa_driver_nl80211_mlme_remove_sta, -#endif /* CONFIG_CLIENT_MLME */ + .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data, + .sta_add = wpa_driver_nl80211_sta_add, + .sta_remove = wpa_driver_nl80211_sta_remove, + .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol, + .sta_set_flags = wpa_driver_nl80211_sta_set_flags, +#ifdef HOSTAPD + .hapd_init = i802_init, + .hapd_deinit = i802_deinit, + .get_seqnum = i802_get_seqnum, + .flush = i802_flush, + .read_sta_data = i802_read_sta_data, + .sta_deauth = i802_sta_deauth, + .sta_disassoc = i802_sta_disassoc, + .get_inact_sec = i802_get_inact_sec, + .sta_clear_stats = i802_sta_clear_stats, + .set_rts = i802_set_rts, + .set_frag = i802_set_frag, + .set_rate_sets = i802_set_rate_sets, + .set_cts_protect = i802_set_cts_protect, + .set_preamble = i802_set_preamble, + .set_short_slot_time = i802_set_short_slot_time, + .set_tx_queue_params = i802_set_tx_queue_params, + .set_sta_vlan = i802_set_sta_vlan, + .set_wds_sta = i802_set_wds_sta, +#endif /* HOSTAPD */ + .set_freq = i802_set_freq, + .send_action = wpa_driver_nl80211_send_action, + .remain_on_channel = wpa_driver_nl80211_remain_on_channel, + .cancel_remain_on_channel = + wpa_driver_nl80211_cancel_remain_on_channel, + .probe_req_report = wpa_driver_nl80211_probe_req_report, + .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates, + .deinit_ap = wpa_driver_nl80211_deinit_ap, + .resume = wpa_driver_nl80211_resume, + .send_ft_action = nl80211_send_ft_action, + .signal_monitor = nl80211_signal_monitor, + .send_frame = nl80211_send_frame, }; diff --git a/hostapd/driver_none.c b/src/drivers/driver_none.c similarity index 55% rename from hostapd/driver_none.c rename to src/drivers/driver_none.c index 96e7e644e526..aaeacd66435d 100644 --- a/hostapd/driver_none.c +++ b/src/drivers/driver_none.c @@ -1,5 +1,5 @@ /* - * hostapd / Driver interface for RADIUS server only (no driver) + * Driver interface for RADIUS server or WPS ER only (no driver) * Copyright (c) 2008, Atheros Communications * * This program is free software; you can redistribute it and/or modify @@ -14,16 +14,18 @@ #include "includes.h" -#include "hostapd.h" +#include "common.h" #include "driver.h" struct none_driver_data { struct hostapd_data *hapd; + void *ctx; }; -static void * none_driver_init(struct hostapd_data *hapd) +static void * none_driver_hapd_init(struct hostapd_data *hapd, + struct wpa_init_params *params) { struct none_driver_data *drv; @@ -39,7 +41,7 @@ static void * none_driver_init(struct hostapd_data *hapd) } -static void none_driver_deinit(void *priv) +static void none_driver_hapd_deinit(void *priv) { struct none_driver_data *drv = priv; @@ -54,9 +56,44 @@ static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src, } +static void * none_driver_init(void *ctx, const char *ifname) +{ + struct none_driver_data *drv; + + drv = os_zalloc(sizeof(struct none_driver_data)); + if (drv == NULL) { + wpa_printf(MSG_ERROR, "Could not allocate memory for none " + "driver data"); + return NULL; + } + drv->ctx = ctx; + + return drv; +} + + +static void none_driver_deinit(void *priv) +{ + struct none_driver_data *drv = priv; + + os_free(drv); +} + + +static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto, + const u8 *data, size_t data_len) +{ + return -1; +} + + const struct wpa_driver_ops wpa_driver_none_ops = { .name = "none", + .desc = "no driver (RADIUS server/WPS ER)", + .hapd_init = none_driver_hapd_init, + .hapd_deinit = none_driver_hapd_deinit, + .send_ether = none_driver_send_ether, .init = none_driver_init, .deinit = none_driver_deinit, - .send_ether = none_driver_send_ether, + .send_eapol = none_driver_send_eapol, }; diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m index 93d7df01adfe..69ca4b576c3c 100644 --- a/src/drivers/driver_osx.m +++ b/src/drivers/driver_osx.m @@ -20,6 +20,7 @@ #include "common.h" #include "driver.h" #include "eloop.h" +#include "common/ieee802_11_defs.h" #include "Apple80211.h" @@ -111,10 +112,12 @@ static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx) } -static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params) { struct wpa_driver_osx_data *drv = priv; WirelessError err; + const u8 *ssid = params->ssids[0].ssid; + size_t ssid_len = params->ssids[0].ssid_len; if (drv->scan_results) { CFRelease(drv->scan_results); @@ -156,43 +159,66 @@ static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len) } -static int wpa_driver_osx_get_scan_results(void *priv, - struct wpa_scan_result *results, - size_t max_size) +static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res, + WirelessNetworkInfo *info) +{ + struct wpa_scan_res *result, **tmp; + size_t extra_len; + u8 *pos; + + extra_len = 2 + info->ssid_len; + + result = os_zalloc(sizeof(*result) + extra_len); + if (result == NULL) + return; + os_memcpy(result->bssid, info->bssid, ETH_ALEN); + result->freq = 2407 + info->channel * 5; + //result->beacon_int =; + result->caps = info->capability; + //result->qual = info->signal; + result->noise = info->noise; + + pos = (u8 *)(result + 1); + + *pos++ = WLAN_EID_SSID; + *pos++ = info->ssid_len; + os_memcpy(pos, info->ssid, info->ssid_len); + pos += info->ssid_len; + + result->ie_len = pos - (u8 *)(result + 1); + + tmp = os_realloc(res->res, + (res->num + 1) * sizeof(struct wpa_scan_res *)); + if (tmp == NULL) { + os_free(result); + return; + } + tmp[res->num++] = result; + res->res = tmp; +} + + +static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv) { struct wpa_driver_osx_data *drv = priv; + struct wpa_scan_results *res; size_t i, num; if (drv->scan_results == NULL) return 0; num = CFArrayGetCount(drv->scan_results); - if (num > max_size) - num = max_size; - os_memset(results, 0, num * sizeof(struct wpa_scan_result)); - for (i = 0; i < num; i++) { - struct wpa_scan_result *res = &results[i]; - WirelessNetworkInfo *info; - info = (WirelessNetworkInfo *) + res = os_zalloc(sizeof(*res)); + if (res == NULL) + return NULL; + + for (i = 0; i < num; i++) + wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *) CFDataGetBytePtr(CFArrayGetValueAtIndex( - drv->scan_results, i)); + drv->scan_results, i))); - os_memcpy(res->bssid, info->bssid, ETH_ALEN); - if (info->ssid_len > 32) { - wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in " - "scan results", (int) info->ssid_len); - continue; - } - os_memcpy(res->ssid, info->ssid, info->ssid_len); - res->ssid_len = info->ssid_len; - res->caps = info->capability; - res->freq = 2407 + info->channel * 5; - res->level = info->signal; - res->noise = info->noise; - } - - return num; + return res; } @@ -277,7 +303,8 @@ static int wpa_driver_osx_associate(void *priv, } -static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr, +static int wpa_driver_osx_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -424,8 +451,8 @@ const struct wpa_driver_ops wpa_driver_osx_ops = { .get_bssid = wpa_driver_osx_get_bssid, .init = wpa_driver_osx_init, .deinit = wpa_driver_osx_deinit, - .scan = wpa_driver_osx_scan, - .get_scan_results = wpa_driver_osx_get_scan_results, + .scan2 = wpa_driver_osx_scan, + .get_scan_results2 = wpa_driver_osx_get_scan_results, .associate = wpa_driver_osx_associate, .set_key = wpa_driver_osx_set_key, .get_capa = wpa_driver_osx_get_capa, diff --git a/src/drivers/driver_prism54.c b/src/drivers/driver_prism54.c deleted file mode 100644 index e64e762eddb5..000000000000 --- a/src/drivers/driver_prism54.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * WPA Supplicant - driver interaction with Linux Prism54.org driver - * Copyright (c) 2003-2005, Jouni Malinen - * Copyright (c) 2004, Luis R. Rodriguez - * - * 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 - -#include "wireless_copy.h" -#include "common.h" -#include "driver.h" -#include "driver_wext.h" -#include "driver_hostap.h" - -struct wpa_driver_prism54_data { - void *wext; /* private data for driver_wext */ - void *ctx; - char ifname[IFNAMSIZ + 1]; - int sock; -}; - -#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 -#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25 -#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26 - -static void show_set_key_error(struct prism2_hostapd_param *); - -static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv, - struct prism2_hostapd_param *param, - int len, int show_err) -{ - struct iwreq iwr; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) param; - iwr.u.data.length = len; - - if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) { - int ret = errno; - if (show_err) - perror("ioctl[PRISM54_HOSTAPD]"); - return ret; - } - - return 0; -} - - -static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv, - const u8 *wpa_ie, - size_t wpa_ie_len) -{ - struct prism2_hostapd_param *param; - int res; - size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len; - if (blen < sizeof(*param)) - blen = sizeof(*param); - - param = os_zalloc(blen); - if (param == NULL) - return -1; - - param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; - param->u.generic_elem.len = wpa_ie_len; - os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len); - res = hostapd_ioctl_prism54(drv, param, blen, 1); - - os_free(param); - - return res; -} - - -/* This is called at wpa_supplicant daemon init time */ -static int wpa_driver_prism54_set_wpa(void *priv, int enabled) -{ - struct wpa_driver_prism54_data *drv = priv; - struct prism2_hostapd_param *param; - int res; - size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; - if (blen < sizeof(*param)) - blen = sizeof(*param); - - param = os_zalloc(blen); - if (param == NULL) - return -1; - - param->cmd = PRISM54_SET_WPA; - param->u.generic_elem.len = 0; - res = hostapd_ioctl_prism54(drv, param, blen, 1); - - os_free(param); - - return res; -} - - -static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ - struct wpa_driver_prism54_data *drv = priv; - struct prism2_hostapd_param *param; - u8 *buf; - size_t blen; - int ret = 0; - char *alg_name; - - switch (alg) { - case WPA_ALG_NONE: - alg_name = "none"; - return -1; - break; - case WPA_ALG_WEP: - alg_name = "WEP"; - return -1; - break; - case WPA_ALG_TKIP: - alg_name = "TKIP"; - break; - case WPA_ALG_CCMP: - alg_name = "CCMP"; - return -1; - break; - default: - return -1; - } - - wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " - "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len); - - if (seq_len > 8) - return -2; - - blen = sizeof(*param) + key_len; - buf = os_zalloc(blen); - if (buf == NULL) - return -1; - - param = (struct prism2_hostapd_param *) buf; - param->cmd = PRISM2_SET_ENCRYPTION; - /* TODO: In theory, STA in client mode can use five keys; four default - * keys for receiving (with keyidx 0..3) and one individual key for - * both transmitting and receiving (keyidx 0) _unicast_ packets. Now, - * keyidx 0 is reserved for this unicast use and default keys can only - * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported). - * This should be fine for more or less all cases, but for completeness - * sake, the driver could be enhanced to support the missing key. */ -#if 0 - if (addr == NULL) - os_memset(param->sta_addr, 0xff, ETH_ALEN); - else - os_memcpy(param->sta_addr, addr, ETH_ALEN); -#else - os_memset(param->sta_addr, 0xff, ETH_ALEN); -#endif - os_strlcpy((char *) param->u.crypt.alg, alg_name, - HOSTAP_CRYPT_ALG_NAME_LEN); - param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; - param->u.crypt.idx = key_idx; - os_memcpy(param->u.crypt.seq, seq, seq_len); - param->u.crypt.key_len = key_len; - os_memcpy((u8 *) (param + 1), key, key_len); - - if (hostapd_ioctl_prism54(drv, param, blen, 1)) { - wpa_printf(MSG_WARNING, "Failed to set encryption."); - show_set_key_error(param); - ret = -1; - } - os_free(buf); - - return ret; -} - - -static int wpa_driver_prism54_set_countermeasures(void *priv, - int enabled) -{ - /* FIX */ - printf("wpa_driver_prism54_set_countermeasures - not yet " - "implemented\n"); - return 0; -} - - -static int wpa_driver_prism54_set_drop_unencrypted(void *priv, - int enabled) -{ - struct wpa_driver_prism54_data *drv = priv; - struct prism2_hostapd_param *param; - int res; - size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; - if (blen < sizeof(*param)) - blen = sizeof(*param); - - param = os_zalloc(blen); - if (param == NULL) - return -1; - - param->cmd = PRISM54_DROP_UNENCRYPTED; - param->u.generic_elem.len = 0; - res = hostapd_ioctl_prism54(drv, param, blen, 1); - - os_free(param); - - return res; -} - - -static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr, - int reason_code) -{ - /* FIX */ - printf("wpa_driver_prism54_deauthenticate - not yet implemented\n"); - return 0; -} - - -static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr, - int reason_code) -{ - /* FIX */ - printf("wpa_driver_prism54_disassociate - not yet implemented\n"); - return 0; -} - - -static int -wpa_driver_prism54_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_prism54_data *drv = priv; - int ret = 0; - - if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie, - params->wpa_ie_len) < 0) - ret = -1; - if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) - ret = -1; - if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, - params->ssid_len) < 0) - ret = -1; - if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) - ret = -1; - - return ret; -} - -static void show_set_key_error(struct prism2_hostapd_param *param) -{ - switch (param->u.crypt.err) { - case HOSTAP_CRYPT_ERR_UNKNOWN_ALG: - wpa_printf(MSG_INFO, "Unknown algorithm '%s'.", - param->u.crypt.alg); - wpa_printf(MSG_INFO, "You may need to load kernel module to " - "register that algorithm."); - wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for " - "WEP."); - break; - case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR: - wpa_printf(MSG_INFO, "Unknown address " MACSTR ".", - MAC2STR(param->sta_addr)); - break; - case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED: - wpa_printf(MSG_INFO, "Crypt algorithm initialization failed."); - break; - case HOSTAP_CRYPT_ERR_KEY_SET_FAILED: - wpa_printf(MSG_INFO, "Key setting failed."); - break; - case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED: - wpa_printf(MSG_INFO, "TX key index setting failed."); - break; - case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED: - wpa_printf(MSG_INFO, "Card configuration failed."); - break; - } -} - - -static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid) -{ - struct wpa_driver_prism54_data *drv = priv; - return wpa_driver_wext_get_bssid(drv->wext, bssid); -} - - -static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid) -{ - struct wpa_driver_prism54_data *drv = priv; - return wpa_driver_wext_get_ssid(drv->wext, ssid); -} - - -static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len) -{ - struct wpa_driver_prism54_data *drv = priv; - return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); -} - - -static struct wpa_scan_results * -wpa_driver_prism54_get_scan_results(void *priv) -{ - struct wpa_driver_prism54_data *drv = priv; - return wpa_driver_wext_get_scan_results(drv->wext); -} - - -static int wpa_driver_prism54_set_operstate(void *priv, int state) -{ - struct wpa_driver_prism54_data *drv = priv; - return wpa_driver_wext_set_operstate(drv->wext, state); -} - - -static void * wpa_driver_prism54_init(void *ctx, const char *ifname) -{ - struct wpa_driver_prism54_data *drv; - - drv = os_zalloc(sizeof(*drv)); - if (drv == NULL) - return NULL; - drv->wext = wpa_driver_wext_init(ctx, ifname); - if (drv->wext == NULL) { - os_free(drv); - return NULL; - } - - drv->ctx = ctx; - os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); - drv->sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->sock < 0) { - wpa_driver_wext_deinit(drv->wext); - os_free(drv); - return NULL; - } - - return drv; -} - - -static void wpa_driver_prism54_deinit(void *priv) -{ - struct wpa_driver_prism54_data *drv = priv; - wpa_driver_wext_deinit(drv->wext); - close(drv->sock); - os_free(drv); -} - - -const struct wpa_driver_ops wpa_driver_prism54_ops = { - .name = "prism54", - .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)", - .get_bssid = wpa_driver_prism54_get_bssid, - .get_ssid = wpa_driver_prism54_get_ssid, - .set_wpa = wpa_driver_prism54_set_wpa, - .set_key = wpa_driver_prism54_set_key, - .set_countermeasures = wpa_driver_prism54_set_countermeasures, - .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted, - .scan = wpa_driver_prism54_scan, - .get_scan_results2 = wpa_driver_prism54_get_scan_results, - .deauthenticate = wpa_driver_prism54_deauthenticate, - .disassociate = wpa_driver_prism54_disassociate, - .associate = wpa_driver_prism54_associate, - .init = wpa_driver_prism54_init, - .deinit = wpa_driver_prism54_deinit, - .set_operstate = wpa_driver_prism54_set_operstate, -}; diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c index fdf299dc84e4..28485215e2b2 100644 --- a/src/drivers/driver_privsep.c +++ b/src/drivers/driver_privsep.c @@ -18,7 +18,7 @@ #include "common.h" #include "driver.h" #include "eloop.h" -#include "privsep_commands.h" +#include "common/privsep_commands.h" struct wpa_driver_privsep_data { @@ -102,18 +102,12 @@ static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd, } -static int wpa_driver_privsep_set_wpa(void *priv, int enabled) -{ - struct wpa_driver_privsep_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled, - sizeof(enabled), NULL, NULL); -} - - -static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_privsep_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_privsep_data *drv = priv; + const u8 *ssid = params->ssids[0].ssid; + size_t ssid_len = params->ssids[0].ssid_len; wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len, NULL, NULL); @@ -196,10 +190,11 @@ wpa_driver_privsep_get_scan_results2(void *priv) } -static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int wpa_driver_privsep_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, + int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) { struct wpa_driver_privsep_data *drv = priv; struct privsep_cmd_set_key cmd; @@ -326,7 +321,8 @@ static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr, } -static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event, +static void wpa_driver_privsep_event_assoc(void *ctx, + enum wpa_event_type event, u8 *buf, size_t len) { union wpa_event_data data; @@ -438,24 +434,7 @@ static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len) { if (len < ETH_ALEN) return; - - wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN); -} - - -static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len) -{ -#ifdef CONFIG_CLIENT_MLME - struct ieee80211_rx_status *rx_status; - - if (len < sizeof(*rx_status)) - return; - rx_status = (struct ieee80211_rx_status *) buf; - buf += sizeof(*rx_status); - len -= sizeof(*rx_status); - - wpa_supplicant_sta_rx(ctx, buf, len, rx_status); -#endif /* CONFIG_CLIENT_MLME */ + drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN); } @@ -535,10 +514,6 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf, event_len); break; - case PRIVSEP_EVENT_STA_RX: - wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf, - event_len); - break; } os_free(buf); @@ -747,15 +722,6 @@ static const u8 * wpa_driver_privsep_get_mac_addr(void *priv) } -static int wpa_driver_privsep_set_mode(void *priv, int mode) -{ - struct wpa_driver_privsep_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode); - return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode), - NULL, NULL); -} - - static int wpa_driver_privsep_set_country(void *priv, const char *alpha2) { struct wpa_driver_privsep_data *drv = priv; @@ -768,52 +734,24 @@ static int wpa_driver_privsep_set_country(void *priv, const char *alpha2) struct wpa_driver_ops wpa_driver_privsep_ops = { "privsep", "wpa_supplicant privilege separated driver", - wpa_driver_privsep_get_bssid, - wpa_driver_privsep_get_ssid, - wpa_driver_privsep_set_wpa, - wpa_driver_privsep_set_key, - wpa_driver_privsep_init, - wpa_driver_privsep_deinit, - wpa_driver_privsep_set_param, - NULL /* set_countermeasures */, - NULL /* set_drop_unencrypted */, - wpa_driver_privsep_scan, - NULL /* get_scan_results */, - wpa_driver_privsep_deauthenticate, - wpa_driver_privsep_disassociate, - wpa_driver_privsep_associate, - NULL /* set_auth_alg */, - NULL /* add_pmkid */, - NULL /* remove_pmkid */, - NULL /* flush_pmkid */, - wpa_driver_privsep_get_capa, - NULL /* poll */, - NULL /* get_ifname */, - wpa_driver_privsep_get_mac_addr, - NULL /* send_eapol */, - NULL /* set_operstate */, - NULL /* mlme_setprotection */, - NULL /* get_hw_feature_data */, - NULL /* set_channel */, - NULL /* set_ssid */, - NULL /* set_bssid */, - NULL /* send_mlme */, - NULL /* mlme_add_sta */, - NULL /* mlme_remove_sta */, - NULL /* update_ft_ies */, - NULL /* send_ft_action */, - wpa_driver_privsep_get_scan_results2, - NULL /* set_probe_req_ie */, - wpa_driver_privsep_set_mode, - wpa_driver_privsep_set_country, - NULL /* global_init */, - NULL /* global_deinit */, - NULL /* init2 */, - NULL /* get_interfaces */ + .get_bssid = wpa_driver_privsep_get_bssid, + .get_ssid = wpa_driver_privsep_get_ssid, + .set_key = wpa_driver_privsep_set_key, + .init = wpa_driver_privsep_init, + .deinit = wpa_driver_privsep_deinit, + .set_param = wpa_driver_privsep_set_param, + .scan2 = wpa_driver_privsep_scan, + .deauthenticate = wpa_driver_privsep_deauthenticate, + .disassociate = wpa_driver_privsep_disassociate, + .associate = wpa_driver_privsep_associate, + .get_capa = wpa_driver_privsep_get_capa, + .get_mac_addr = wpa_driver_privsep_get_mac_addr, + .get_scan_results2 = wpa_driver_privsep_get_scan_results2, + .set_country = wpa_driver_privsep_set_country, }; -struct wpa_driver_ops *wpa_supplicant_drivers[] = +struct wpa_driver_ops *wpa_drivers[] = { &wpa_driver_privsep_ops, NULL diff --git a/src/drivers/driver_ps3.c b/src/drivers/driver_ps3.c deleted file mode 100644 index fde3425e281f..000000000000 --- a/src/drivers/driver_ps3.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * WPA Supplicant - PS3 Linux wireless extension driver interface - * Copyright 2007, 2008 Sony Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" -#include -#include "wireless_copy.h" -#include "common.h" -#include "wpa_common.h" -#include "driver.h" -#include "eloop.h" -#include "driver_wext.h" -#include "ieee802_11_defs.h" - -static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv, - struct wpa_driver_associate_params *params) -{ - int ret, i; - struct iwreq iwr; - char *buf, *str; - - if (!params->psk && !params->passphrase) { - wpa_printf(MSG_INFO, "%s:no PSK error", __func__); - return -EINVAL; - } - - os_memset(&iwr, 0, sizeof(iwr)); - if (params->psk) { - /* includes null */ - iwr.u.data.length = PMK_LEN * 2 + 1; - buf = os_malloc(iwr.u.data.length); - if (!buf) - return -ENOMEM; - str = buf; - for (i = 0; i < PMK_LEN; i++) { - str += snprintf(str, iwr.u.data.length - (str - buf), - "%02x", params->psk[i]); - } - } else if (params->passphrase) { - /* including quotations and null */ - iwr.u.data.length = strlen(params->passphrase) + 3; - buf = os_malloc(iwr.u.data.length); - if (!buf) - return -ENOMEM; - buf[0] = '"'; - os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3); - buf[iwr.u.data.length - 2] = '"'; - buf[iwr.u.data.length - 1] = '\0'; - } else - return -EINVAL; - iwr.u.data.pointer = (caddr_t) buf; - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr); - os_free(buf); - - return ret; -} - -static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv, - struct wpa_driver_associate_params *params) -{ - int ret, i; - struct iwreq iwr; - - for (i = 0; i < 4; i++) { - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.encoding.flags = i + 1; - if (params->wep_key_len[i]) { - iwr.u.encoding.pointer = (caddr_t) params->wep_key[i]; - iwr.u.encoding.length = params->wep_key_len[i]; - } else - iwr.u.encoding.flags = IW_ENCODE_NOKEY | - IW_ENCODE_DISABLED; - - if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { - perror("ioctl[SIOCSIWENCODE]"); - ret = -1; - } - } - return ret; -} - -static int wpa_driver_ps3_associate(void *priv, - struct wpa_driver_associate_params *params) -{ - struct wpa_driver_wext_data *drv = priv; - int ret, value; - - wpa_printf(MSG_DEBUG, "%s: <-", __func__); - - /* clear BSSID */ - if (!params->bssid && - wpa_driver_wext_set_bssid(drv, NULL) < 0) - ret = -1; - - if (wpa_driver_wext_set_mode(drv, params->mode) < 0) - ret = -1; - - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) - value = IW_AUTH_WPA_VERSION_DISABLED; - else if (params->wpa_ie[0] == WLAN_EID_RSN) - value = IW_AUTH_WPA_VERSION_WPA2; - else - value = IW_AUTH_WPA_VERSION_WPA; - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_WPA_VERSION, value) < 0) - ret = -1; - value = wpa_driver_wext_cipher2wext(params->pairwise_suite); - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_CIPHER_PAIRWISE, value) < 0) - ret = -1; - value = wpa_driver_wext_cipher2wext(params->group_suite); - if (wpa_driver_wext_set_auth_param(drv, - IW_AUTH_CIPHER_GROUP, value) < 0) - ret = -1; - value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite); - if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0) - ret = -1; - - /* set selected BSSID */ - if (params->bssid && - wpa_driver_wext_set_bssid(drv, params->bssid) < 0) - ret = -1; - - switch (params->group_suite) { - case CIPHER_NONE: - ret = 0; - break; - case CIPHER_WEP40: - case CIPHER_WEP104: - ret = wpa_driver_ps3_set_wep_keys(drv, params); - break; - case CIPHER_TKIP: - case CIPHER_CCMP: - ret = wpa_driver_ps3_set_wpa_key(drv, params); - break; - } - - /* start to associate */ - ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len); - - wpa_printf(MSG_DEBUG, "%s: ->", __func__); - - return ret; -} - -static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa) -{ - int ret; - wpa_printf(MSG_DEBUG, "%s:<-", __func__); - - ret = wpa_driver_wext_get_capa(priv, capa); - if (ret) { - wpa_printf(MSG_INFO, "%s: base wext returns error %d", - __func__, ret); - return ret; - } - /* PS3 hypervisor does association and 4way handshake by itself */ - capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; - wpa_printf(MSG_DEBUG, "%s:->", __func__); - return 0; -} - -const struct wpa_driver_ops wpa_driver_ps3_ops = { - .name = "ps3", - .desc = "PLAYSTATION3 Linux wireless extension driver", - .get_bssid = wpa_driver_wext_get_bssid, - .get_ssid = wpa_driver_wext_get_ssid, - .scan = wpa_driver_wext_scan, - .get_scan_results2 = wpa_driver_wext_get_scan_results, - .associate = wpa_driver_ps3_associate, /* PS3 */ - .init = wpa_driver_wext_init, - .deinit = wpa_driver_wext_deinit, - .get_capa = wpa_driver_ps3_get_capa, /* PS3 */ -}; diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c index e9313cb33ef0..09d1ef540509 100644 --- a/src/drivers/driver_ralink.c +++ b/src/drivers/driver_ralink.c @@ -22,8 +22,10 @@ #include "driver.h" #include "l2_packet/l2_packet.h" #include "eloop.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "priv_netlink.h" +#include "netlink.h" +#include "linux_ioctl.h" #include "driver_ralink.h" static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx); @@ -33,7 +35,7 @@ static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx); struct wpa_driver_ralink_data { void *ctx; int ioctl_sock; - int event_sock; + struct netlink_data *netlink; char ifname[IFNAMSIZ + 1]; u8 *assoc_req_ies; size_t assoc_req_ies_len; @@ -45,6 +47,7 @@ struct wpa_driver_ralink_data { int ap_scan; int scanning_done; u8 g_driver_down; + BOOLEAN bAddWepKey; }; static int ralink_set_oid(struct wpa_driver_ralink_data *drv, @@ -450,6 +453,7 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv, void *ctx, char *custom) { union wpa_event_data data; + u8 *req_ies = NULL, *resp_ies = NULL; wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); @@ -478,12 +482,12 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv, */ bytes = drv->assoc_req_ies_len; - data.assoc_info.req_ies = os_malloc(bytes); - if (data.assoc_info.req_ies == NULL) + req_ies = os_malloc(bytes); + if (req_ies == NULL) return; - + os_memcpy(req_ies, spos, bytes); + data.assoc_info.req_ies = req_ies; data.assoc_info.req_ies_len = bytes; - os_memcpy(data.assoc_info.req_ies, spos, bytes); /* skip the '\0' byte */ spos += bytes + 1; @@ -499,21 +503,48 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv, if (!bytes) goto done; - - data.assoc_info.resp_ies = os_malloc(bytes); - if (data.assoc_info.resp_ies == NULL) + resp_ies = os_malloc(bytes); + if (resp_ies == NULL) goto done; - + os_memcpy(resp_ies, spos, bytes); + data.assoc_info.resp_ies = resp_ies; data.assoc_info.resp_ies_len = bytes; - os_memcpy(data.assoc_info.resp_ies, spos, bytes); } wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - /* free allocated memory */ done: - os_free(data.assoc_info.resp_ies); - os_free(data.assoc_info.req_ies); + /* free allocated memory */ + os_free(resp_ies); + os_free(req_ies); + } +} + +static void ralink_interface_up(struct wpa_driver_ralink_data *drv) +{ + union wpa_event_data event; + int enable_wpa_supplicant = 0; + drv->g_driver_down = 0; + os_memset(&event, 0, sizeof(event)); + os_snprintf(event.interface_status.ifname, + sizeof(event.interface_status.ifname), "%s", drv->ifname); + + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); + + if (drv->ap_scan == 1) + enable_wpa_supplicant = 1; + else + enable_wpa_supplicant = 2; + /* trigger driver support wpa_supplicant */ + if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, + (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0) + { + wpa_printf(MSG_INFO, "RALINK: Failed to set " + "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", + (int) enable_wpa_supplicant); + wpa_printf(MSG_ERROR, "ralink. Driver does not support " + "wpa_supplicant"); } } @@ -580,33 +611,9 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv, } if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) { + wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); wpa_printf(MSG_DEBUG, "Custom wireless event: " "receive ASSOCIATED_EVENT !!!"); - /* determine whether the dynamic-WEP is used or - * not */ -#if 0 - if (wpa_s && wpa_s->current_ssid && - wpa_s->current_ssid->key_mgmt == - WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - if ((wpa_s->current_ssid->eapol_flags & - (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) { - //wpa_printf(MSG_DEBUG, "The current ssid - (%s), eapol_flag = %d.\n", - // wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len),wpa_s->current_ssid->eapol_flags); - ieee8021x_required_key = TRUE; - } - - if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0) - { - wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", - (int) ieee8021x_required_key); - } - - wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d).\n", ieee8021x_required_key ? "TRUE" : "FALSE", - wpa_s->current_ssid->eapol_flags); - } -#endif - - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) { wpa_printf(MSG_DEBUG, "Custom wireless event: " "receive ReqIEs !!!"); @@ -689,51 +696,8 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv, } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) { drv->g_driver_down = 1; eloop_terminate(); - } else if (iwe->u.data.flags == RT_REPORT_AP_INFO) { - if (drv->ap_scan != 1) { - typedef struct PACKED { - UCHAR bssid[MAC_ADDR_LEN]; - UCHAR ssid[MAX_LEN_OF_SSID]; - INT ssid_len; - UCHAR wpa_ie[40]; - INT wpa_ie_len; - UCHAR rsn_ie[40]; - INT rsn_ie_len; - INT freq; - USHORT caps; - } *PAPINFO; - - wpa_printf(MSG_DEBUG, "Custom wireless" - " event: receive " - "RT_REPORT_AP_INFO !!!"); - //printf("iwe->u.data.length = %d\n", iwe->u.data.length); - //wpa_hexdump(MSG_DEBUG, "AP_Info: ", buf, iwe->u.data.length); -#if 0 - wpa_s->num_scan_results = 1; - if (wpa_s->scan_results) - os_free(wpa_s->scan_results); - wpa_s->scan_results = os_malloc(sizeof(struct wpa_scan_result) + 1); - if (wpa_s->scan_results) { - PAPINFO pApInfo = (PAPINFO)buf; - os_memcpy(wpa_s->scan_results[0].bssid, pApInfo->bssid, ETH_ALEN); - os_memcpy(wpa_s->scan_results[0].ssid, pApInfo->ssid, pApInfo->ssid_len); - wpa_s->scan_results[0].ssid_len = pApInfo->ssid_len; - if (pApInfo->wpa_ie_len > 0) { - os_memcpy(wpa_s->scan_results[0].wpa_ie, pApInfo->wpa_ie, pApInfo->wpa_ie_len); - wpa_s->scan_results[0].wpa_ie_len = pApInfo->wpa_ie_len; - } else if (pApInfo->rsn_ie_len > 0) { - os_memcpy(wpa_s->scan_results[0].rsn_ie, pApInfo->rsn_ie, pApInfo->rsn_ie_len); - wpa_s->scan_results[0].rsn_ie_len = pApInfo->rsn_ie_len; - } - wpa_s->scan_results[0].caps = pApInfo->caps; - wpa_s->scan_results[0].freq = pApInfo->freq; - } else { - wpa_printf("wpa_s->scan_" - "results fail to " - "os_malloc!!\n"); - } -#endif - } + } else if (iwe->u.data.flags == RT_INTERFACE_UP) { + ralink_interface_up(drv); } else { wpa_driver_ralink_event_wireless_custom( drv, ctx, buf); @@ -747,29 +711,20 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv, } static void -wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv, - void *ctx, struct nlmsghdr *h, int len) +wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; + struct wpa_driver_ralink_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - if (len < (int) sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg)); - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; + attrlen = len; wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen); - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + attr = (struct rtattr *) buf; wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr)); rta_len = RTA_ALIGN(sizeof(struct rtattr)); wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len); @@ -787,60 +742,6 @@ wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv, } } -static void wpa_driver_ralink_event_receive(int sock, void *ctx, - void *sock_ctx) -{ - char buf[8192]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - 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; - wpa_hexdump(MSG_DEBUG, "h: ", (u8 *)h, h->nlmsg_len); - - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - wpa_printf(MSG_DEBUG, "Malformed netlink message: " - "len=%d left=%d plen=%d", len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - wpa_driver_ralink_event_rtm_newlink(ctx, sock_ctx, h, - plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink " - "message", left); - } - -} - static int ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv) { @@ -862,45 +763,13 @@ ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv) return 0; } -static int -ralink_set_iface_flags(void *priv, int dev_up) -{ - struct wpa_driver_ralink_data *drv = priv; - struct ifreq ifr; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - if (drv->ioctl_sock < 0) - return -1; - - os_memset(&ifr, 0, sizeof(ifr)); - os_snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->ifname); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - return 0; -} - static void * wpa_driver_ralink_init(void *ctx, const char *ifname) { int s; struct wpa_driver_ralink_data *drv; struct ifreq ifr; - struct sockaddr_nl local; UCHAR enable_wpa_supplicant = 0; + struct netlink_config *cfg; wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); @@ -928,31 +797,25 @@ static void * wpa_driver_ralink_init(void *ctx, const char *ifname) drv->ioctl_sock = s; drv->g_driver_down = 0; - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) { + close(drv->ioctl_sock); + os_free(drv); + return NULL; + } + cfg->ctx = drv; + cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); close(drv->ioctl_sock); os_free(drv); return NULL; } - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - eloop_register_read_sock(s, wpa_driver_ralink_event_receive, drv, ctx); - drv->event_sock = s; drv->no_of_pmkid = 4; /* Number of PMKID saved supported */ - ralink_set_iface_flags(drv, 1); /* mark up during setup */ + linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); ralink_get_we_version_compiled(drv); wpa_driver_ralink_flush_pmkid(drv); @@ -1003,12 +866,11 @@ static void wpa_driver_ralink_deinit(void *priv) wpa_driver_ralink_flush_pmkid(drv); sleep(1); - ralink_set_iface_flags(drv, 0); + /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */ } eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx); - eloop_unregister_read_sock(drv->event_sock); - close(drv->event_sock); + netlink_deinit(drv->netlink); close(drv->ioctl_sock); os_free(drv); } @@ -1026,7 +888,8 @@ static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx) } -static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_ralink_scan(void *priv, + struct wpa_driver_scan_params *params) { struct wpa_driver_ralink_data *drv = priv; struct iwreq iwr; @@ -1037,6 +900,7 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len) wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); +#if 0 if (ssid_len > IW_ESSID_MAX_SIZE) { wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", __FUNCTION__, (unsigned long) ssid_len); @@ -1044,6 +908,14 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len) } /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */ +#endif + + if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE, + (char *) params->extra_ies, params->extra_ies_len) < + 0) { + wpa_printf(MSG_DEBUG, "RALINK: Failed to set " + "RT_OID_WPS_PROBE_REQ_IE"); + } os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); @@ -1064,96 +936,124 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len) return ret; } -static int -wpa_driver_ralink_get_scan_results(void *priv, - struct wpa_scan_result *results, - size_t max_size) +static struct wpa_scan_results * +wpa_driver_ralink_get_scan_results(void *priv) { struct wpa_driver_ralink_data *drv = priv; UCHAR *buf = NULL; + size_t buf_len; NDIS_802_11_BSSID_LIST_EX *wsr; NDIS_WLAN_BSSID_EX *wbi; struct iwreq iwr; - int rv = 0; size_t ap_num; - u8 *pos, *end; + u8 *pos; + struct wpa_scan_results *res; if (drv->g_driver_down == 1) - return -1; + return NULL; wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - if (drv->we_version_compiled >= 17) { - buf = os_zalloc(8192); - iwr.u.data.length = 8192; - } else { - buf = os_zalloc(4096); - iwr.u.data.length = 4096; + if (drv->we_version_compiled >= 17) + buf_len = 8192; + else + buf_len = 4096; + + for (;;) { + buf = os_zalloc(buf_len); + iwr.u.data.length = buf_len; + if (buf == NULL) + return NULL; + + wsr = (NDIS_802_11_BSSID_LIST_EX *) buf; + + wsr->NumberOfItems = 0; + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = (void *) buf; + iwr.u.data.flags = OID_802_11_BSSID_LIST; + + if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0) + break; + + if (errno == E2BIG && buf_len < 65535) { + os_free(buf); + buf = NULL; + buf_len *= 2; + if (buf_len > 65535) + buf_len = 65535; /* 16-bit length field */ + wpa_printf(MSG_DEBUG, "Scan results did not fit - " + "trying larger buffer (%lu bytes)", + (unsigned long) buf_len); + } else { + perror("ioctl[RT_PRIV_IOCTL]"); + os_free(buf); + return NULL; + } } - if (buf == NULL) - return -1; - wsr = (NDIS_802_11_BSSID_LIST_EX *) buf; - - wsr->NumberOfItems = 0; - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (void *) buf; - iwr.u.data.flags = OID_802_11_BSSID_LIST; - - if ((rv = ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr)) < 0) { - wpa_printf(MSG_DEBUG, "ioctl fail: rv = %d", rv); + res = os_zalloc(sizeof(*res)); + if (res == NULL) { os_free(buf); - return -1; + return NULL; } - os_memset(results, 0, max_size * sizeof(struct wpa_scan_result)); + res->res = os_zalloc(wsr->NumberOfItems * + sizeof(struct wpa_scan_res *)); + if (res->res == NULL) { + os_free(res); + os_free(buf); + return NULL; + } for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems; ++ap_num) { - os_memcpy(results[ap_num].bssid, &wbi->MacAddress, ETH_ALEN); - os_memcpy(results[ap_num].ssid, wbi->Ssid.Ssid, - wbi->Ssid.SsidLength); - results[ap_num].ssid_len = wbi->Ssid.SsidLength; - results[ap_num].freq = (wbi->Configuration.DSConfig / 1000); + struct wpa_scan_res *r = NULL; + size_t extra_len = 0, var_ie_len = 0; + u8 *pos2; + /* SSID data element */ + extra_len += 2 + wbi->Ssid.SsidLength; + var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs); + r = os_zalloc(sizeof(*r) + extra_len + var_ie_len); + if (r == NULL) + break; + res->res[res->num++] = r; + + wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid); /* get ie's */ wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs", - (u8 *) wbi + sizeof(*wbi) - 1, wbi->IELength); + (u8 *) &wbi->IEs[0], wbi->IELength); + + os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN); + + extra_len += (2 + wbi->Ssid.SsidLength); + r->ie_len = extra_len + var_ie_len; + pos2 = (u8 *) (r + 1); + + /* + * Generate a fake SSID IE since the driver did not report + * a full IE list. + */ + *pos2++ = WLAN_EID_SSID; + *pos2++ = wbi->Ssid.SsidLength; + os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength); + pos2 += wbi->Ssid.SsidLength; + + r->freq = (wbi->Configuration.DSConfig / 1000); pos = (u8 *) wbi + sizeof(*wbi) - 1; - end = (u8 *) wbi + sizeof(*wbi) + wbi->IELength; - - if (wbi->IELength < sizeof(NDIS_802_11_FIXED_IEs)) - break; pos += sizeof(NDIS_802_11_FIXED_IEs) - 2; - os_memcpy(&results[ap_num].caps, pos, 2); + os_memcpy(&(r->caps), pos, 2); pos += 2; - while (pos + 1 < end && pos + 2 + pos[1] <= end) { - u8 ielen = 2 + pos[1]; - - if (ielen > SSID_MAX_WPA_IE_LEN) { - pos += ielen; - continue; - } - - if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && - pos[1] >= 4 && - os_memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) { - os_memcpy(results[ap_num].wpa_ie, pos, ielen); - results[ap_num].wpa_ie_len = ielen; - } else if (pos[0] == WLAN_EID_RSN) { - os_memcpy(results[ap_num].rsn_ie, pos, ielen); - results[ap_num].rsn_ie_len = ielen; - } - pos += ielen; - } + if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs)) + os_memcpy(pos2, pos, var_ie_len); wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length); } os_free(buf); - return ap_num; + return res; } static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv, @@ -1173,6 +1073,24 @@ static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv, return 0; } +static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv, + NDIS_802_11_WEP_STATUS encr_type) +{ + NDIS_802_11_WEP_STATUS wep_status = encr_type; + + wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + + if (ralink_set_oid(drv, OID_802_11_WEP_STATUS, + (char *) &wep_status, sizeof(wep_status)) < 0) { + wpa_printf(MSG_DEBUG, "RALINK: Failed to set " + "OID_802_11_WEP_STATUS (%d)", + (int) wep_status); + return -1; + } + return 0; +} + + static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv, int key_idx, const u8 *addr, const u8 *bssid, int pairwise) @@ -1241,7 +1159,8 @@ static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv, return res; } -static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr, +static int wpa_driver_ralink_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -1257,6 +1176,8 @@ static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr, wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + drv->bAddWepKey = FALSE; + if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) { /* Group Key */ @@ -1274,6 +1195,7 @@ static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr, } if (alg == WPA_ALG_WEP) { + drv->bAddWepKey = TRUE; return wpa_driver_ralink_add_wep(drv, pairwise, key_idx, set_tx, key, key_len); } @@ -1363,6 +1285,29 @@ static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr, } } +static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie, + size_t ie_len) +{ + struct wpa_driver_ralink_data *drv = priv; + struct iwreq iwr; + int ret = 0; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) ie; + iwr.u.data.length = ie_len; + + wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ", + (u8 *) ie, ie_len); + + if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { + perror("ioctl[SIOCSIWGENIE]"); + ret = -1; + } + + return ret; +} + static int wpa_driver_ralink_associate(void *priv, struct wpa_driver_associate_params *params) @@ -1373,6 +1318,7 @@ wpa_driver_ralink_associate(void *priv, NDIS_802_11_AUTHENTICATION_MODE auth_mode; NDIS_802_11_WEP_STATUS encr; BOOLEAN ieee8021xMode; + BOOLEAN ieee8021x_required_key = TRUE; if (drv->g_driver_down == 1) return -1; @@ -1391,83 +1337,131 @@ wpa_driver_ralink_associate(void *priv, /* Try to continue anyway */ } - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { - if (params->auth_alg & AUTH_ALG_SHARED_KEY) { - if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM) - auth_mode = Ndis802_11AuthModeAutoSwitch; - else - auth_mode = Ndis802_11AuthModeShared; - } else - auth_mode = Ndis802_11AuthModeOpen; - } else if (params->wpa_ie[0] == WLAN_EID_RSN) { - if (params->key_mgmt_suite == KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPA2PSK; - else - auth_mode = Ndis802_11AuthModeWPA2; + if (params->key_mgmt_suite == KEY_MGMT_WPS) { + UCHAR enable_wps = 0x80; + /* trigger driver support wpa_supplicant */ + if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, + (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) { + wpa_printf(MSG_INFO, "RALINK: Failed to set " + "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", + (int) enable_wps); + } + + wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie, + params->wpa_ie_len); + + ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen); + + ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled); } else { - if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) - auth_mode = Ndis802_11AuthModeWPANone; - else if (params->key_mgmt_suite == KEY_MGMT_PSK) - auth_mode = Ndis802_11AuthModeWPAPSK; +#ifdef CONFIG_WPS + UCHAR enable_wpa_supplicant; + + if (drv->ap_scan == 1) + enable_wpa_supplicant = 0x01; else - auth_mode = Ndis802_11AuthModeWPA; - } + enable_wpa_supplicant = 0x02; - switch (params->pairwise_suite) { - case CIPHER_CCMP: - encr = Ndis802_11Encryption3Enabled; - break; - case CIPHER_TKIP: - encr = Ndis802_11Encryption2Enabled; - break; - case CIPHER_WEP40: - case CIPHER_WEP104: - encr = Ndis802_11Encryption1Enabled; - break; - case CIPHER_NONE: - if (params->group_suite == CIPHER_CCMP) - encr = Ndis802_11Encryption3Enabled; - else if (params->group_suite == CIPHER_TKIP) - encr = Ndis802_11Encryption2Enabled; - else - encr = Ndis802_11EncryptionDisabled; - break; - default: - encr = Ndis802_11EncryptionDisabled; - break; - } - - ralink_set_auth_mode(drv, auth_mode); - - /* notify driver that IEEE8021x mode is enabled */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) - ieee8021xMode = TRUE; - else - ieee8021xMode = FALSE; - - if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, - (char *) &ieee8021xMode, sizeof(BOOLEAN)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_SET_IEEE8021X(%d)", - (int) ieee8021xMode); - } - - if (ralink_set_oid(drv, OID_802_11_WEP_STATUS, - (char *) &encr, sizeof(encr)) < 0) { - wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_WEP_STATUS(%d)", - (int) encr); - } - - if ((ieee8021xMode == FALSE) && - (encr == Ndis802_11Encryption1Enabled)) { - /* static WEP */ - int enabled = 0; - if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED, - (char *) &enabled, sizeof(enabled)) < 0) { + /* trigger driver support wpa_supplicant */ + if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, + (PCHAR) &enable_wpa_supplicant, + sizeof(UCHAR)) < 0) { wpa_printf(MSG_DEBUG, "RALINK: Failed to set " - "OID_802_11_DROP_UNENCRYPTED(%d)", - (int) encr); + "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", + (int) enable_wpa_supplicant); + } + + wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0); +#endif /* CONFIG_WPS */ + + if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { + if (params->auth_alg & WPA_AUTH_ALG_SHARED) { + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + auth_mode = Ndis802_11AuthModeAutoSwitch; + else + auth_mode = Ndis802_11AuthModeShared; + } else + auth_mode = Ndis802_11AuthModeOpen; + } else if (params->wpa_ie[0] == WLAN_EID_RSN) { + if (params->key_mgmt_suite == KEY_MGMT_PSK) + auth_mode = Ndis802_11AuthModeWPA2PSK; + else + auth_mode = Ndis802_11AuthModeWPA2; + } else { + if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) + auth_mode = Ndis802_11AuthModeWPANone; + else if (params->key_mgmt_suite == KEY_MGMT_PSK) + auth_mode = Ndis802_11AuthModeWPAPSK; + else + auth_mode = Ndis802_11AuthModeWPA; + } + + switch (params->pairwise_suite) { + case CIPHER_CCMP: + encr = Ndis802_11Encryption3Enabled; + break; + case CIPHER_TKIP: + encr = Ndis802_11Encryption2Enabled; + break; + case CIPHER_WEP40: + case CIPHER_WEP104: + encr = Ndis802_11Encryption1Enabled; + break; + case CIPHER_NONE: + if (params->group_suite == CIPHER_CCMP) + encr = Ndis802_11Encryption3Enabled; + else if (params->group_suite == CIPHER_TKIP) + encr = Ndis802_11Encryption2Enabled; + else + encr = Ndis802_11EncryptionDisabled; + break; + default: + encr = Ndis802_11EncryptionDisabled; + break; + } + + ralink_set_auth_mode(drv, auth_mode); + + /* notify driver that IEEE8021x mode is enabled */ + if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { + ieee8021xMode = TRUE; + if (drv->bAddWepKey) + ieee8021x_required_key = FALSE; + } else + ieee8021xMode = FALSE; + + if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, + (char *) &ieee8021x_required_key, + sizeof(BOOLEAN)) < 0) { + wpa_printf(MSG_DEBUG, "ERROR: Failed to set " + "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", + (int) ieee8021x_required_key); + } else { + wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s", + ieee8021x_required_key ? "TRUE" : "FALSE"); + } + + if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, + (char *) &ieee8021xMode, sizeof(BOOLEAN)) < + 0) { + wpa_printf(MSG_DEBUG, "RALINK: Failed to set " + "OID_802_11_SET_IEEE8021X(%d)", + (int) ieee8021xMode); + } + + ralink_set_encr_type(drv, encr); + + if ((ieee8021xMode == FALSE) && + (encr == Ndis802_11Encryption1Enabled)) { + /* static WEP */ + int enabled = 0; + if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED, + (char *) &enabled, sizeof(enabled)) + < 0) { + wpa_printf(MSG_DEBUG, "RALINK: Failed to set " + "OID_802_11_DROP_UNENCRYPTED(%d)", + (int) encr); + } } } @@ -1494,8 +1488,8 @@ const struct wpa_driver_ops wpa_driver_ralink_ops = { .init = wpa_driver_ralink_init, .deinit = wpa_driver_ralink_deinit, .set_countermeasures = wpa_driver_ralink_set_countermeasures, - .scan = wpa_driver_ralink_scan, - .get_scan_results = wpa_driver_ralink_get_scan_results, + .scan2 = wpa_driver_ralink_scan, + .get_scan_results2 = wpa_driver_ralink_get_scan_results, .deauthenticate = wpa_driver_ralink_deauthenticate, .disassociate = wpa_driver_ralink_disassociate, .associate = wpa_driver_ralink_associate, diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h index ddf44de232a3..d13df28de456 100644 --- a/src/drivers/driver_ralink.h +++ b/src/drivers/driver_ralink.h @@ -54,6 +54,7 @@ #define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support #define RT_OID_WE_VERSION_COMPILED 0x0622 #define RT_OID_NEW_DRIVER 0x0623 +#define RT_OID_WPS_PROBE_REQ_IE 0x0625 #define PACKED __attribute__ ((packed)) @@ -65,7 +66,7 @@ #define RT_ASSOCINFO_EVENT_FLAG 0x0105 #define RT_PMKIDCAND_FLAG 0x0106 #define RT_INTERFACE_DOWN 0x0107 -#define RT_REPORT_AP_INFO 0x0108 +#define RT_INTERFACE_UP 0x0108 // // IEEE 802.11 Structures and definitions diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c index bc11a4848432..6877eda3ed22 100644 --- a/src/drivers/driver_roboswitch.c +++ b/src/drivers/driver_roboswitch.c @@ -23,10 +23,6 @@ #include "driver.h" #include "l2_packet/l2_packet.h" -#ifndef ETH_P_EAPOL -#define ETH_P_EAPOL 0x888e -#endif - #define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */ /* MII access registers */ @@ -183,10 +179,8 @@ static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr, struct wpa_driver_roboswitch_data *drv = priv; if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL && - os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) { - wpa_supplicant_rx_eapol(drv->ctx, src_addr, buf + 14, - len - 14); - } + os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) + drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14); } @@ -205,6 +199,15 @@ static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid) } +static int wpa_driver_roboswitch_get_capa(void *priv, + struct wpa_driver_capa *capa) +{ + os_memset(capa, 0, sizeof(*capa)); + capa->flags = WPA_DRIVER_FLAGS_WIRED; + return 0; +} + + static int wpa_driver_roboswitch_set_param(void *priv, const char *param) { struct wpa_driver_roboswitch_data *drv = priv; @@ -469,6 +472,7 @@ const struct wpa_driver_ops wpa_driver_roboswitch_ops = { .desc = "wpa_supplicant roboswitch driver", .get_ssid = wpa_driver_roboswitch_get_ssid, .get_bssid = wpa_driver_roboswitch_get_bssid, + .get_capa = wpa_driver_roboswitch_get_capa, .init = wpa_driver_roboswitch_init, .deinit = wpa_driver_roboswitch_deinit, .set_param = wpa_driver_roboswitch_set_param, diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 2a41cf260a5a..fb2467350f1e 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant - testing driver interface - * Copyright (c) 2004-2008, Jouni Malinen + * Testing driver interface for a simulated network driver + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -12,13 +12,13 @@ * See README and COPYING for more details. */ -/* Make dure we get winsock2.h for Windows build to get sockaddr_storage */ +/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */ #include "build_config.h" #ifdef CONFIG_NATIVE_WINDOWS #include #endif /* CONFIG_NATIVE_WINDOWS */ -#include "includes.h" +#include "utils/includes.h" #ifndef CONFIG_NATIVE_WINDOWS #include @@ -27,21 +27,50 @@ #define DRIVER_TEST_UNIX #endif /* CONFIG_NATIVE_WINDOWS */ -#include "common.h" -#include "driver.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/list.h" +#include "utils/trace.h" +#include "common/ieee802_11_defs.h" +#include "crypto/sha1.h" #include "l2_packet/l2_packet.h" -#include "eloop.h" -#include "sha1.h" -#include "ieee802_11_defs.h" +#include "driver.h" +struct test_client_socket { + struct test_client_socket *next; + u8 addr[ETH_ALEN]; + struct sockaddr_un un; + socklen_t unlen; + struct test_driver_bss *bss; +}; + +struct test_driver_bss { + struct wpa_driver_test_data *drv; + struct dl_list list; + void *bss_ctx; + char ifname[IFNAMSIZ]; + u8 bssid[ETH_ALEN]; + u8 *ie; + size_t ielen; + u8 *wps_beacon_ie; + size_t wps_beacon_ie_len; + u8 *wps_probe_resp_ie; + size_t wps_probe_resp_ie_len; + u8 ssid[32]; + size_t ssid_len; + int privacy; +}; + struct wpa_driver_test_global { - int dummy; + int bss_add_used; + u8 req_addr[ETH_ALEN]; }; struct wpa_driver_test_data { struct wpa_driver_test_global *global; void *ctx; + WPA_TRACE_REF(ctx); u8 own_addr[ETH_ALEN]; int test_socket; #ifdef DRIVER_TEST_UNIX @@ -52,9 +81,6 @@ struct wpa_driver_test_data { int hostapd_addr_udp_set; char *own_socket_path; char *test_dir; - u8 bssid[ETH_ALEN]; - u8 ssid[32]; - size_t ssid_len; #define MAX_SCAN_RESULTS 30 struct wpa_scan_res *scanres[MAX_SCAN_RESULTS]; size_t num_scanres; @@ -65,9 +91,1164 @@ struct wpa_driver_test_data { int associated; u8 *probe_req_ie; size_t probe_req_ie_len; + u8 probe_req_ssid[32]; + size_t probe_req_ssid_len; + int ibss; + int ap; + + struct test_client_socket *cli; + struct dl_list bss; + int udp_port; + + int alloc_iface_idx; + + int probe_req_report; + unsigned int remain_on_channel_freq; + unsigned int remain_on_channel_duration; + + int current_freq; }; +static void wpa_driver_test_deinit(void *priv); +static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, + const char *dir, int ap); +static void wpa_driver_test_close_test_socket( + struct wpa_driver_test_data *drv); +static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx); + + +static void test_driver_free_bss(struct test_driver_bss *bss) +{ + os_free(bss->ie); + os_free(bss->wps_beacon_ie); + os_free(bss->wps_probe_resp_ie); + os_free(bss); +} + + +static void test_driver_free_bsses(struct wpa_driver_test_data *drv) +{ + struct test_driver_bss *bss, *tmp; + + dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss, + list) { + dl_list_del(&bss->list); + test_driver_free_bss(bss); + } +} + + +static struct test_client_socket * +test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from, + socklen_t fromlen) +{ + struct test_client_socket *cli = drv->cli; + + while (cli) { + if (cli->unlen == fromlen && + strncmp(cli->un.sun_path, from->sun_path, + fromlen - sizeof(cli->un.sun_family)) == 0) + return cli; + cli = cli->next; + } + + return NULL; +} + + +static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, + const u8 *own_addr) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct test_client_socket *cli; + struct msghdr msg; + struct iovec io[3]; + struct l2_ethhdr eth; + + if (drv->test_socket < 0) + return -1; + + cli = drv->cli; + while (cli) { + if (memcmp(cli->addr, addr, ETH_ALEN) == 0) + break; + cli = cli->next; + } + + if (!cli) { + wpa_printf(MSG_DEBUG, "%s: no destination client entry", + __func__); + return -1; + } + + memcpy(eth.h_dest, addr, ETH_ALEN); + memcpy(eth.h_source, own_addr, ETH_ALEN); + eth.h_proto = host_to_be16(ETH_P_EAPOL); + + io[0].iov_base = "EAPOL "; + io[0].iov_len = 6; + io[1].iov_base = ð + io[1].iov_len = sizeof(eth); + io[2].iov_base = (u8 *) data; + io[2].iov_len = data_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 3; + msg.msg_name = &cli->un; + msg.msg_namelen = cli->unlen; + return sendmsg(drv->test_socket, &msg, 0); +} + + +static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src, + u16 proto, const u8 *data, size_t data_len) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct msghdr msg; + struct iovec io[3]; + struct l2_ethhdr eth; + char desttxt[30]; + struct sockaddr_un addr; + struct dirent *dent; + DIR *dir; + int ret = 0, broadcast = 0, count = 0; + + if (drv->test_socket < 0 || drv->test_dir == NULL) { + wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d " + "test_dir=%p)", + __func__, drv->test_socket, drv->test_dir); + return -1; + } + + broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; + snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst)); + + memcpy(eth.h_dest, dst, ETH_ALEN); + memcpy(eth.h_source, src, ETH_ALEN); + eth.h_proto = host_to_be16(proto); + + io[0].iov_base = "ETHER "; + io[0].iov_len = 6; + io[1].iov_base = ð + io[1].iov_len = sizeof(eth); + io[2].iov_base = (u8 *) data; + io[2].iov_len = data_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 3; + + dir = opendir(drv->test_dir); + if (dir == NULL) { + perror("test_driver: opendir"); + return -1; + } + while ((dent = readdir(dir))) { +#ifdef _DIRENT_HAVE_D_TYPE + /* Skip the file if it is not a socket. Also accept + * DT_UNKNOWN (0) in case the C library or underlying file + * system does not support d_type. */ + if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) + continue; +#endif /* _DIRENT_HAVE_D_TYPE */ + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", + drv->test_dir, dent->d_name); + + if (strcmp(addr.sun_path, drv->own_socket_path) == 0) + continue; + if (!broadcast && strstr(dent->d_name, desttxt) == NULL) + continue; + + wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s", + __func__, dent->d_name); + + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + ret = sendmsg(drv->test_socket, &msg, 0); + if (ret < 0) + perror("driver_test: sendmsg"); + count++; + } + closedir(dir); + + if (!broadcast && count == 0) { + wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found", + __func__, MAC2STR(dst)); + return -1; + } + + return ret; +} + + +static int wpa_driver_test_send_mlme(void *priv, const u8 *data, + size_t data_len) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct msghdr msg; + struct iovec io[2]; + const u8 *dest; + struct sockaddr_un addr; + struct dirent *dent; + DIR *dir; + int broadcast; + int ret = 0; + struct ieee80211_hdr *hdr; + u16 fc; + char cmd[50]; + int freq; +#ifdef HOSTAPD + char desttxt[30]; +#endif /* HOSTAPD */ + union wpa_event_data event; + + wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len); + if (drv->test_socket < 0 || data_len < 10) { + wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu" + " test_dir=%p)", + __func__, drv->test_socket, + (unsigned long) data_len, + drv->test_dir); + return -1; + } + + dest = data + 4; + broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; + +#ifdef HOSTAPD + snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest)); +#endif /* HOSTAPD */ + + if (drv->remain_on_channel_freq) + freq = drv->remain_on_channel_freq; + else + freq = drv->current_freq; + wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz", + dbss->ifname, freq); + os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq); + io[0].iov_base = cmd; + io[0].iov_len = os_strlen(cmd); + io[1].iov_base = (void *) data; + io[1].iov_len = data_len; + + os_memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 2; + +#ifdef HOSTAPD + if (drv->test_dir == NULL) { + wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__); + return -1; + } + + dir = opendir(drv->test_dir); + if (dir == NULL) { + perror("test_driver: opendir"); + return -1; + } + while ((dent = readdir(dir))) { +#ifdef _DIRENT_HAVE_D_TYPE + /* Skip the file if it is not a socket. Also accept + * DT_UNKNOWN (0) in case the C library or underlying file + * system does not support d_type. */ + if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) + continue; +#endif /* _DIRENT_HAVE_D_TYPE */ + if (os_strcmp(dent->d_name, ".") == 0 || + os_strcmp(dent->d_name, "..") == 0) + continue; + + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", + drv->test_dir, dent->d_name); + + if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0) + continue; + if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL) + continue; + + wpa_printf(MSG_DEBUG, "%s: Send management frame to %s", + __func__, dent->d_name); + + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + ret = sendmsg(drv->test_socket, &msg, 0); + if (ret < 0) + perror("driver_test: sendmsg(test_socket)"); + } + closedir(dir); +#else /* HOSTAPD */ + + if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 || + drv->test_dir == NULL) { + if (drv->hostapd_addr_udp_set) { + msg.msg_name = &drv->hostapd_addr_udp; + msg.msg_namelen = sizeof(drv->hostapd_addr_udp); + } else { +#ifdef DRIVER_TEST_UNIX + msg.msg_name = &drv->hostapd_addr; + msg.msg_namelen = sizeof(drv->hostapd_addr); +#endif /* DRIVER_TEST_UNIX */ + } + } else if (broadcast) { + dir = opendir(drv->test_dir); + if (dir == NULL) + return -1; + while ((dent = readdir(dir))) { +#ifdef _DIRENT_HAVE_D_TYPE + /* Skip the file if it is not a socket. + * Also accept DT_UNKNOWN (0) in case + * the C library or underlying file + * system does not support d_type. */ + if (dent->d_type != DT_SOCK && + dent->d_type != DT_UNKNOWN) + continue; +#endif /* _DIRENT_HAVE_D_TYPE */ + if (os_strcmp(dent->d_name, ".") == 0 || + os_strcmp(dent->d_name, "..") == 0) + continue; + wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s", + __func__, dent->d_name); + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + os_snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/%s", drv->test_dir, dent->d_name); + + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + + ret = sendmsg(drv->test_socket, &msg, 0); + if (ret < 0) + perror("driver_test: sendmsg(test_socket)"); + } + closedir(dir); + return ret; + } else { + struct stat st; + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + os_snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); + if (stat(addr.sun_path, &st) < 0) { + os_snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/STA-" MACSTR, + drv->test_dir, MAC2STR(dest)); + } + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + } + + if (sendmsg(drv->test_socket, &msg, 0) < 0) { + perror("sendmsg(test_socket)"); + return -1; + } +#endif /* HOSTAPD */ + + hdr = (struct ieee80211_hdr *) data; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = data; + event.tx_status.data_len = data_len; + event.tx_status.ack = ret >= 0; + wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); + + return ret; +} + + +static void test_driver_scan(struct wpa_driver_test_data *drv, + struct sockaddr_un *from, socklen_t fromlen, + char *data) +{ + char buf[512], *pos, *end; + int ret; + struct test_driver_bss *bss; + u8 sa[ETH_ALEN]; + u8 ie[512]; + size_t ielen; + union wpa_event_data event; + + /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */ + + wpa_printf(MSG_DEBUG, "test_driver: SCAN"); + + if (*data) { + if (*data != ' ' || + hwaddr_aton(data + 1, sa)) { + wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN " + "command format"); + return; + } + + data += 18; + while (*data == ' ') + data++; + ielen = os_strlen(data) / 2; + if (ielen > sizeof(ie)) + ielen = sizeof(ie); + if (hexstr2bin(data, ie, ielen) < 0) + ielen = 0; + + wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR, + MAC2STR(sa)); + wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen); + + os_memset(&event, 0, sizeof(event)); + event.rx_probe_req.sa = sa; + event.rx_probe_req.ie = ie; + event.rx_probe_req.ie_len = ielen; + wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); + } + + dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { + pos = buf; + end = buf + sizeof(buf); + + /* reply: SCANRESP BSSID SSID IEs */ + ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", + MAC2STR(bss->bssid)); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, + bss->ssid, bss->ssid_len); + ret = snprintf(pos, end - pos, " "); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen); + pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie, + bss->wps_probe_resp_ie_len); + + if (bss->privacy) { + ret = snprintf(pos, end - pos, " PRIVACY"); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + } + + sendto(drv->test_socket, buf, pos - buf, 0, + (struct sockaddr *) from, fromlen); + } +} + + +static void test_driver_assoc(struct wpa_driver_test_data *drv, + struct sockaddr_un *from, socklen_t fromlen, + char *data) +{ + struct test_client_socket *cli; + u8 ie[256], ssid[32]; + size_t ielen, ssid_len = 0; + char *pos, *pos2, cmd[50]; + struct test_driver_bss *bss, *tmp; + + /* data: STA-addr SSID(hex) IEs(hex) */ + + cli = os_zalloc(sizeof(*cli)); + if (cli == NULL) + return; + + if (hwaddr_aton(data, cli->addr)) { + printf("test_socket: Invalid MAC address '%s' in ASSOC\n", + data); + os_free(cli); + return; + } + pos = data + 17; + while (*pos == ' ') + pos++; + pos2 = strchr(pos, ' '); + ielen = 0; + if (pos2) { + ssid_len = (pos2 - pos) / 2; + if (hexstr2bin(pos, ssid, ssid_len) < 0) { + wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__); + os_free(cli); + return; + } + wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID", + ssid, ssid_len); + + pos = pos2 + 1; + ielen = strlen(pos) / 2; + if (ielen > sizeof(ie)) + ielen = sizeof(ie); + if (hexstr2bin(pos, ie, ielen) < 0) + ielen = 0; + } + + bss = NULL; + dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) { + if (tmp->ssid_len == ssid_len && + os_memcmp(tmp->ssid, ssid, ssid_len) == 0) { + bss = tmp; + break; + } + } + if (bss == NULL) { + wpa_printf(MSG_DEBUG, "%s: No matching SSID found from " + "configured BSSes", __func__); + os_free(cli); + return; + } + + cli->bss = bss; + memcpy(&cli->un, from, sizeof(cli->un)); + cli->unlen = fromlen; + cli->next = drv->cli; + drv->cli = cli; + wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path", + (const u8 *) cli->un.sun_path, + cli->unlen - sizeof(cli->un.sun_family)); + + snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0", + MAC2STR(bss->bssid)); + sendto(drv->test_socket, cmd, strlen(cmd), 0, + (struct sockaddr *) from, fromlen); + + drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen); +} + + +static void test_driver_disassoc(struct wpa_driver_test_data *drv, + struct sockaddr_un *from, socklen_t fromlen) +{ + struct test_client_socket *cli; + + cli = test_driver_get_cli(drv, from, fromlen); + if (!cli) + return; + + drv_event_disassoc(drv->ctx, cli->addr); +} + + +static void test_driver_eapol(struct wpa_driver_test_data *drv, + struct sockaddr_un *from, socklen_t fromlen, + u8 *data, size_t datalen) +{ +#ifdef HOSTAPD + struct test_client_socket *cli; +#endif /* HOSTAPD */ + const u8 *src = NULL; + + if (datalen > 14) { + /* Skip Ethernet header */ + src = data + ETH_ALEN; + wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src=" + MACSTR " proto=%04x", + MAC2STR(data), MAC2STR(src), + WPA_GET_BE16(data + 2 * ETH_ALEN)); + data += 14; + datalen -= 14; + } + +#ifdef HOSTAPD + cli = test_driver_get_cli(drv, from, fromlen); + if (cli) { + drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data, + datalen); + } else { + wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown " + "client"); + } +#else /* HOSTAPD */ + if (src) + drv_event_eapol_rx(drv->ctx, src, data, datalen); +#endif /* HOSTAPD */ +} + + +static void test_driver_ether(struct wpa_driver_test_data *drv, + struct sockaddr_un *from, socklen_t fromlen, + u8 *data, size_t datalen) +{ + struct l2_ethhdr *eth; + + if (datalen < sizeof(*eth)) + return; + + eth = (struct l2_ethhdr *) data; + wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src=" + MACSTR " proto=%04x", + MAC2STR(eth->h_dest), MAC2STR(eth->h_source), + be_to_host16(eth->h_proto)); + +#ifdef CONFIG_IEEE80211R + if (be_to_host16(eth->h_proto) == ETH_P_RRB) { + union wpa_event_data ev; + os_memset(&ev, 0, sizeof(ev)); + ev.ft_rrb_rx.src = eth->h_source; + ev.ft_rrb_rx.data = data + sizeof(*eth); + ev.ft_rrb_rx.data_len = datalen - sizeof(*eth); + } +#endif /* CONFIG_IEEE80211R */ +} + + +static void test_driver_mlme(struct wpa_driver_test_data *drv, + struct sockaddr_un *from, socklen_t fromlen, + u8 *data, size_t datalen) +{ + struct ieee80211_hdr *hdr; + u16 fc; + union wpa_event_data event; + int freq = 0, own_freq; + struct test_driver_bss *bss; + + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + + if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) { + size_t pos; + for (pos = 5; pos < datalen; pos++) { + if (data[pos] == ' ') + break; + } + if (pos < datalen) { + freq = atoi((const char *) &data[5]); + wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on " + "freq %d MHz", bss->ifname, freq); + pos++; + data += pos; + datalen -= pos; + } + } + + if (drv->remain_on_channel_freq) + own_freq = drv->remain_on_channel_freq; + else + own_freq = drv->current_freq; + + if (freq && own_freq && freq != own_freq) { + wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on " + "another frequency %d MHz (own %d MHz)", + bss->ifname, freq, own_freq); + return; + } + + hdr = (struct ieee80211_hdr *) data; + + if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) { + struct test_client_socket *cli; + cli = os_zalloc(sizeof(*cli)); + if (cli == NULL) + return; + wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR, + MAC2STR(hdr->addr2)); + memcpy(cli->addr, hdr->addr2, ETH_ALEN); + memcpy(&cli->un, from, sizeof(cli->un)); + cli->unlen = fromlen; + cli->next = drv->cli; + drv->cli = cli; + } + + wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame", + data, datalen); + fc = le_to_host16(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) { + wpa_printf(MSG_ERROR, "%s: received non-mgmt frame", + __func__); + return; + } + + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.frame = data; + event.rx_mgmt.frame_len = datalen; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); +} + + +static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_driver_test_data *drv = eloop_ctx; + char buf[2000]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(test_socket)"); + return; + } + buf[res] = '\0'; + + wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); + + if (strncmp(buf, "SCAN", 4) == 0) { + test_driver_scan(drv, &from, fromlen, buf + 4); + } else if (strncmp(buf, "ASSOC ", 6) == 0) { + test_driver_assoc(drv, &from, fromlen, buf + 6); + } else if (strcmp(buf, "DISASSOC") == 0) { + test_driver_disassoc(drv, &from, fromlen); + } else if (strncmp(buf, "EAPOL ", 6) == 0) { + test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6, + res - 6); + } else if (strncmp(buf, "ETHER ", 6) == 0) { + test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6, + res - 6); + } else if (strncmp(buf, "MLME ", 5) == 0) { + test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5); + } else { + wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", + (u8 *) buf, res); + } +} + + +static int test_driver_set_generic_elem(void *priv, + const u8 *elem, size_t elem_len) +{ + struct test_driver_bss *bss = priv; + + os_free(bss->ie); + + if (elem == NULL) { + bss->ie = NULL; + bss->ielen = 0; + return 0; + } + + bss->ie = os_malloc(elem_len); + if (bss->ie == NULL) { + bss->ielen = 0; + return -1; + } + + memcpy(bss->ie, elem, elem_len); + bss->ielen = elem_len; + return 0; +} + + +static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp) +{ + struct test_driver_bss *bss = priv; + + if (beacon == NULL) + wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE"); + else + wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE", + beacon); + + os_free(bss->wps_beacon_ie); + + if (beacon == NULL) { + bss->wps_beacon_ie = NULL; + bss->wps_beacon_ie_len = 0; + } else { + bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon)); + if (bss->wps_beacon_ie == NULL) { + bss->wps_beacon_ie_len = 0; + return -1; + } + + os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon), + wpabuf_len(beacon)); + bss->wps_beacon_ie_len = wpabuf_len(beacon); + } + + if (proberesp == NULL) + wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS " + "IE"); + else + wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS " + "IE", proberesp); + + os_free(bss->wps_probe_resp_ie); + + if (proberesp == NULL) { + bss->wps_probe_resp_ie = NULL; + bss->wps_probe_resp_ie_len = 0; + } else { + bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp)); + if (bss->wps_probe_resp_ie == NULL) { + bss->wps_probe_resp_ie_len = 0; + return -1; + } + + os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp), + wpabuf_len(proberesp)); + bss->wps_probe_resp_ie_len = wpabuf_len(proberesp); + } + + return 0; +} + + +static int test_driver_sta_deauth(void *priv, const u8 *own_addr, + const u8 *addr, int reason) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct test_client_socket *cli; + + if (drv->test_socket < 0) + return -1; + + cli = drv->cli; + while (cli) { + if (memcmp(cli->addr, addr, ETH_ALEN) == 0) + break; + cli = cli->next; + } + + if (!cli) + return -1; + + return sendto(drv->test_socket, "DEAUTH", 6, 0, + (struct sockaddr *) &cli->un, cli->unlen); +} + + +static int test_driver_sta_disassoc(void *priv, const u8 *own_addr, + const u8 *addr, int reason) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct test_client_socket *cli; + + if (drv->test_socket < 0) + return -1; + + cli = drv->cli; + while (cli) { + if (memcmp(cli->addr, addr, ETH_ALEN) == 0) + break; + cli = cli->next; + } + + if (!cli) + return -1; + + return sendto(drv->test_socket, "DISASSOC", 8, 0, + (struct sockaddr *) &cli->un, cli->unlen); +} + + +static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid, + void *bss_ctx, void **drv_priv) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct test_driver_bss *bss; + + wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")", + __func__, ifname, MAC2STR(bssid)); + + bss = os_zalloc(sizeof(*bss)); + if (bss == NULL) + return -1; + + bss->bss_ctx = bss_ctx; + bss->drv = drv; + os_strlcpy(bss->ifname, ifname, IFNAMSIZ); + os_memcpy(bss->bssid, bssid, ETH_ALEN); + + dl_list_add(&drv->bss, &bss->list); + if (drv->global) { + drv->global->bss_add_used = 1; + os_memcpy(drv->global->req_addr, bssid, ETH_ALEN); + } + + if (drv_priv) + *drv_priv = bss; + + return 0; +} + + +static int test_driver_bss_remove(void *priv, const char *ifname) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct test_driver_bss *bss; + struct test_client_socket *cli, *prev_c; + + wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname); + + dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { + if (strcmp(bss->ifname, ifname) != 0) + continue; + + for (prev_c = NULL, cli = drv->cli; cli; + prev_c = cli, cli = cli->next) { + if (cli->bss != bss) + continue; + if (prev_c) + prev_c->next = cli->next; + else + drv->cli = cli->next; + os_free(cli); + break; + } + + dl_list_del(&bss->list); + test_driver_free_bss(bss); + return 0; + } + + return -1; +} + + +static int test_driver_if_add(void *priv, enum wpa_driver_if_type type, + const char *ifname, const u8 *addr, + void *bss_ctx, void **drv_priv, + char *force_ifname, u8 *if_addr) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + + wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)", + __func__, type, ifname, bss_ctx); + if (addr) + os_memcpy(if_addr, addr, ETH_ALEN); + else { + drv->alloc_iface_idx++; + if_addr[0] = 0x02; /* locally administered */ + sha1_prf(drv->own_addr, ETH_ALEN, + "hostapd test addr generation", + (const u8 *) &drv->alloc_iface_idx, + sizeof(drv->alloc_iface_idx), + if_addr + 1, ETH_ALEN - 1); + } + if (type == WPA_IF_AP_BSS) + return test_driver_bss_add(priv, ifname, if_addr, bss_ctx, + drv_priv); + return 0; +} + + +static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type, + const char *ifname) +{ + wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname); + if (type == WPA_IF_AP_BSS) + return test_driver_bss_remove(priv, ifname); + return 0; +} + + +static int test_driver_valid_bss_mask(void *priv, const u8 *addr, + const u8 *mask) +{ + return 0; +} + + +static int test_driver_set_ssid(void *priv, const u8 *buf, int len) +{ + struct test_driver_bss *bss = priv; + + wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname); + wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len); + + if (len < 0 || (size_t) len > sizeof(bss->ssid)) + return -1; + + os_memcpy(bss->ssid, buf, len); + bss->ssid_len = len; + + return 0; +} + + +static int test_driver_set_privacy(void *priv, int enabled) +{ + struct test_driver_bss *dbss = priv; + + wpa_printf(MSG_DEBUG, "%s(enabled=%d)", __func__, enabled); + dbss->privacy = enabled; + + return 0; +} + + +static int test_driver_set_sta_vlan(void *priv, const u8 *addr, + const char *ifname, int vlan_id) +{ + wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)", + __func__, MAC2STR(addr), ifname, vlan_id); + return 0; +} + + +static int test_driver_sta_add(void *priv, + struct hostapd_sta_add_params *params) +{ + struct test_driver_bss *bss = priv; + struct wpa_driver_test_data *drv = bss->drv; + struct test_client_socket *cli; + + wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d " + "capability=0x%x listen_interval=%d)", + __func__, bss->ifname, MAC2STR(params->addr), params->aid, + params->capability, params->listen_interval); + wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates", + params->supp_rates, params->supp_rates_len); + + cli = drv->cli; + while (cli) { + if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0) + break; + cli = cli->next; + } + if (!cli) { + wpa_printf(MSG_DEBUG, "%s: no matching client entry", + __func__); + return -1; + } + + cli->bss = bss; + + return 0; +} + + +static struct wpa_driver_test_data * test_alloc_data(void *ctx, + const char *ifname) +{ + struct wpa_driver_test_data *drv; + struct test_driver_bss *bss; + + drv = os_zalloc(sizeof(struct wpa_driver_test_data)); + if (drv == NULL) { + wpa_printf(MSG_ERROR, "Could not allocate memory for test " + "driver data"); + return NULL; + } + + bss = os_zalloc(sizeof(struct test_driver_bss)); + if (bss == NULL) { + os_free(drv); + return NULL; + } + + drv->ctx = ctx; + wpa_trace_add_ref(drv, ctx, ctx); + dl_list_init(&drv->bss); + dl_list_add(&drv->bss, &bss->list); + os_strlcpy(bss->ifname, ifname, IFNAMSIZ); + bss->bss_ctx = ctx; + bss->drv = drv; + + /* Generate a MAC address to help testing with multiple STAs */ + drv->own_addr[0] = 0x02; /* locally administered */ + sha1_prf((const u8 *) ifname, os_strlen(ifname), + "test mac addr generation", + NULL, 0, drv->own_addr + 1, ETH_ALEN - 1); + + return drv; +} + + +static void * test_driver_init(struct hostapd_data *hapd, + struct wpa_init_params *params) +{ + struct wpa_driver_test_data *drv; + struct sockaddr_un addr_un; + struct sockaddr_in addr_in; + struct sockaddr *addr; + socklen_t alen; + struct test_driver_bss *bss; + + drv = test_alloc_data(hapd, params->ifname); + if (drv == NULL) + return NULL; + drv->ap = 1; + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + + bss->bss_ctx = hapd; + os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN); + os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN); + + if (params->test_socket) { + if (os_strlen(params->test_socket) >= + sizeof(addr_un.sun_path)) { + printf("Too long test_socket path\n"); + wpa_driver_test_deinit(bss); + return NULL; + } + if (strncmp(params->test_socket, "DIR:", 4) == 0) { + size_t len = strlen(params->test_socket) + 30; + drv->test_dir = os_strdup(params->test_socket + 4); + drv->own_socket_path = os_malloc(len); + if (drv->own_socket_path) { + snprintf(drv->own_socket_path, len, + "%s/AP-" MACSTR, + params->test_socket + 4, + MAC2STR(params->own_addr)); + } + } else if (strncmp(params->test_socket, "UDP:", 4) == 0) { + drv->udp_port = atoi(params->test_socket + 4); + } else { + drv->own_socket_path = os_strdup(params->test_socket); + } + if (drv->own_socket_path == NULL && drv->udp_port == 0) { + wpa_driver_test_deinit(bss); + return NULL; + } + + drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX, + SOCK_DGRAM, 0); + if (drv->test_socket < 0) { + perror("socket"); + wpa_driver_test_deinit(bss); + return NULL; + } + + if (drv->udp_port) { + os_memset(&addr_in, 0, sizeof(addr_in)); + addr_in.sin_family = AF_INET; + addr_in.sin_port = htons(drv->udp_port); + addr = (struct sockaddr *) &addr_in; + alen = sizeof(addr_in); + } else { + os_memset(&addr_un, 0, sizeof(addr_un)); + addr_un.sun_family = AF_UNIX; + os_strlcpy(addr_un.sun_path, drv->own_socket_path, + sizeof(addr_un.sun_path)); + addr = (struct sockaddr *) &addr_un; + alen = sizeof(addr_un); + } + if (bind(drv->test_socket, addr, alen) < 0) { + perror("bind(PF_UNIX)"); + close(drv->test_socket); + if (drv->own_socket_path) + unlink(drv->own_socket_path); + wpa_driver_test_deinit(bss); + return NULL; + } + eloop_register_read_sock(drv->test_socket, + test_driver_receive_unix, drv, NULL); + } else + drv->test_socket = -1; + + return bss; +} + + static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_test_data *drv = eloop_ctx; @@ -88,13 +1269,6 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) } -static int wpa_driver_test_set_wpa(void *priv, int enabled) -{ - wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); - return 0; -} - - static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) { wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); @@ -129,11 +1303,31 @@ static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv, pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie, drv->probe_req_ie_len); } + if (drv->probe_req_ssid_len) { + /* Add SSID IE */ + ret = os_snprintf(pos, end - pos, "%02x%02x", + WLAN_EID_SSID, + (unsigned int) drv->probe_req_ssid_len); + if (ret >= 0 && ret < end - pos) + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid, + drv->probe_req_ssid_len); + } end[-1] = '\0'; while ((dent = readdir(dir))) { - if (os_strncmp(dent->d_name, "AP-", 3) != 0) + if (os_strncmp(dent->d_name, "AP-", 3) != 0 && + os_strncmp(dent->d_name, "STA-", 4) != 0) continue; + if (drv->own_socket_path) { + size_t olen, dlen; + olen = os_strlen(drv->own_socket_path); + dlen = os_strlen(dent->d_name); + if (olen >= dlen && + os_strcmp(dent->d_name, + drv->own_socket_path + olen - dlen) == 0) + continue; + } wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name); os_memset(&addr, 0, sizeof(addr)); @@ -151,11 +1345,42 @@ static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv, #endif /* DRIVER_TEST_UNIX */ -static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len) +static int wpa_driver_test_scan(void *priv, + struct wpa_driver_scan_params *params) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + size_t i; + wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); + os_free(drv->probe_req_ie); + if (params->extra_ies) { + drv->probe_req_ie = os_malloc(params->extra_ies_len); + if (drv->probe_req_ie == NULL) { + drv->probe_req_ie_len = 0; + return -1; + } + os_memcpy(drv->probe_req_ie, params->extra_ies, + params->extra_ies_len); + drv->probe_req_ie_len = params->extra_ies_len; + } else { + drv->probe_req_ie = NULL; + drv->probe_req_ie_len = 0; + } + + for (i = 0; i < params->num_ssids; i++) + wpa_hexdump(MSG_DEBUG, "Scan SSID", + params->ssids[i].ssid, params->ssids[i].ssid_len); + drv->probe_req_ssid_len = 0; + if (params->num_ssids) { + os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid, + params->ssids[0].ssid_len); + drv->probe_req_ssid_len = params->ssids[0].ssid_len; + } + wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)", + params->extra_ies, params->extra_ies_len); + drv->num_scanres = 0; #ifdef DRIVER_TEST_UNIX @@ -186,7 +1411,8 @@ static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len) static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; struct wpa_scan_results *res; size_t i; @@ -216,22 +1442,37 @@ static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv) } -static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr, +static int wpa_driver_test_set_key(const char *ifname, void *priv, + enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { - wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", - __func__, priv, alg, key_idx, set_tx); - if (addr) { + wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d " + "set_tx=%d", + __func__, ifname, priv, alg, key_idx, set_tx); + if (addr) wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); - } - if (seq) { + if (seq) wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len); + if (key) + wpa_hexdump_key(MSG_DEBUG, " key", key, key_len); + return 0; +} + + +static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap) +{ + if (ap && !drv->ap) { + wpa_driver_test_close_test_socket(drv); + wpa_driver_test_attach(drv, drv->test_dir, 1); + drv->ap = 1; + } else if (!ap && drv->ap) { + wpa_driver_test_close_test_socket(drv); + wpa_driver_test_attach(drv, drv->test_dir, 0); + drv->ap = 0; } - if (key) { - wpa_hexdump(MSG_DEBUG, " key", key, key_len); - } + return 0; } @@ -239,7 +1480,8 @@ static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr, static int wpa_driver_test_associate( void *priv, struct wpa_driver_associate_params *params) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", __func__, priv, params->freq, params->pairwise_suite, @@ -264,8 +1506,23 @@ static int wpa_driver_test_associate( } else drv->assoc_wpa_ie_len = 0; + wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP); + + drv->ibss = params->mode == IEEE80211_MODE_IBSS; + dbss->privacy = params->key_mgmt_suite & + (WPA_KEY_MGMT_IEEE8021X | + WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_WPA_NONE | + WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_PSK_SHA256); + if (params->wep_key_len[params->wep_tx_keyidx]) + dbss->privacy = 1; + #ifdef DRIVER_TEST_UNIX - if (drv->test_dir && params->bssid) { + if (drv->test_dir && params->bssid && + params->mode != IEEE80211_MODE_IBSS) { os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); drv->hostapd_addr.sun_family = AF_UNIX; os_snprintf(drv->hostapd_addr.sun_path, @@ -276,8 +1533,20 @@ static int wpa_driver_test_associate( } #endif /* DRIVER_TEST_UNIX */ - if (drv->test_socket >= 0 && - (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) { + if (params->mode == IEEE80211_MODE_AP) { + os_memcpy(dbss->ssid, params->ssid, params->ssid_len); + dbss->ssid_len = params->ssid_len; + os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN); + if (params->wpa_ie && params->wpa_ie_len) { + dbss->ie = os_malloc(params->wpa_ie_len); + if (dbss->ie) { + os_memcpy(dbss->ie, params->wpa_ie, + params->wpa_ie_len); + dbss->ielen = params->wpa_ie_len; + } + } + } else if (drv->test_socket >= 0 && + (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) { char cmd[200], *pos, *end; int ret; end = cmd + sizeof(cmd); @@ -311,10 +1580,22 @@ static int wpa_driver_test_associate( return -1; } - os_memcpy(drv->ssid, params->ssid, params->ssid_len); - drv->ssid_len = params->ssid_len; + os_memcpy(dbss->ssid, params->ssid, params->ssid_len); + dbss->ssid_len = params->ssid_len; } else { drv->associated = 1; + if (params->mode == IEEE80211_MODE_IBSS) { + os_memcpy(dbss->ssid, params->ssid, params->ssid_len); + dbss->ssid_len = params->ssid_len; + if (params->bssid) + os_memcpy(dbss->bssid, params->bssid, + ETH_ALEN); + else { + os_get_random(dbss->bssid, ETH_ALEN); + dbss->bssid[0] &= ~0x01; + dbss->bssid[0] |= 0x02; + } + } wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); } @@ -324,17 +1605,17 @@ static int wpa_driver_test_associate( static int wpa_driver_test_get_bssid(void *priv, u8 *bssid) { - struct wpa_driver_test_data *drv = priv; - os_memcpy(bssid, drv->bssid, ETH_ALEN); + struct test_driver_bss *dbss = priv; + os_memcpy(bssid, dbss->bssid, ETH_ALEN); return 0; } static int wpa_driver_test_get_ssid(void *priv, u8 *ssid) { - struct wpa_driver_test_data *drv = priv; - os_memcpy(ssid, drv->ssid, 32); - return drv->ssid_len; + struct test_driver_bss *dbss = priv; + os_memcpy(ssid, dbss->ssid, 32); + return dbss->ssid_len; } @@ -363,10 +1644,11 @@ static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv) static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr, int reason_code) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", __func__, MAC2STR(addr), reason_code); - os_memset(drv->bssid, 0, ETH_ALEN); + os_memset(dbss->bssid, 0, ETH_ALEN); drv->associated = 0; wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); return wpa_driver_test_send_disassoc(drv); @@ -376,16 +1658,36 @@ static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr, static int wpa_driver_test_disassociate(void *priv, const u8 *addr, int reason_code) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", __func__, MAC2STR(addr), reason_code); - os_memset(drv->bssid, 0, ETH_ALEN); + os_memset(dbss->bssid, 0, ETH_ALEN); drv->associated = 0; wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); return wpa_driver_test_send_disassoc(drv); } +static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) +{ + const u8 *end, *pos; + + pos = (const u8 *) (res + 1); + end = pos + res->ie_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} + + static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, struct sockaddr *from, socklen_t fromlen, @@ -396,6 +1698,7 @@ static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, size_t len; u8 *ie_pos, *ie_start, *ie_end; #define MAX_IE_LEN 1000 + const u8 *ds_params; wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data); if (drv->num_scanres >= MAX_SCAN_RESULTS) { @@ -464,8 +1767,16 @@ static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, pos = pos2 + 1; while (*pos == ' ') pos++; - if (os_strncmp(pos, "PRIVACY", 7) == 0) + if (os_strstr(pos, "PRIVACY")) res->caps |= IEEE80211_CAP_PRIVACY; + if (os_strstr(pos, "IBSS")) + res->caps |= IEEE80211_CAP_IBSS; + } + + ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS); + if (ds_params && ds_params[1] > 0) { + if (ds_params[2] >= 1 && ds_params[2] <= 13) + res->freq = 2407 + ds_params[2] * 5; } os_free(drv->scanres[drv->num_scanres]); @@ -478,8 +1789,12 @@ static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv, socklen_t fromlen, const char *data) { + struct test_driver_bss *bss; + + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + /* ASSOCRESP BSSID */ - if (hwaddr_aton(data, drv->bssid)) { + if (hwaddr_aton(data, bss->bssid)) { wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in " "assocresp"); } @@ -509,15 +1824,20 @@ static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv, socklen_t fromlen, const u8 *data, size_t data_len) { - const u8 *src = drv->bssid; + const u8 *src; + struct test_driver_bss *bss; + + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); if (data_len > 14) { /* Skip Ethernet header */ src = data + ETH_ALEN; data += 14; data_len -= 14; - } - wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len); + } else + src = bss->bssid; + + drv_event_eapol_rx(drv->ctx, src, data, data_len); } @@ -526,11 +1846,113 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, socklen_t fromlen, const u8 *data, size_t data_len) { -#ifdef CONFIG_CLIENT_MLME - struct ieee80211_rx_status rx_status; - os_memset(&rx_status, 0, sizeof(rx_status)); - wpa_supplicant_sta_rx(drv->ctx, data, data_len, &rx_status); -#endif /* CONFIG_CLIENT_MLME */ + int freq = 0, own_freq; + union wpa_event_data event; + struct test_driver_bss *bss; + + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) { + size_t pos; + for (pos = 5; pos < data_len; pos++) { + if (data[pos] == ' ') + break; + } + if (pos < data_len) { + freq = atoi((const char *) &data[5]); + wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on " + "freq %d MHz", bss->ifname, freq); + pos++; + data += pos; + data_len -= pos; + } + } + + if (drv->remain_on_channel_freq) + own_freq = drv->remain_on_channel_freq; + else + own_freq = drv->current_freq; + + if (freq && own_freq && freq != own_freq) { + wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on " + "another frequency %d MHz (own %d MHz)", + bss->ifname, freq, own_freq); + return; + } + + os_memset(&event, 0, sizeof(event)); + event.mlme_rx.buf = data; + event.mlme_rx.len = data_len; + event.mlme_rx.freq = freq; + wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event); + + if (drv->probe_req_report && data_len >= 24) { + const struct ieee80211_mgmt *mgmt; + u16 fc; + + mgmt = (const struct ieee80211_mgmt *) data; + fc = le_to_host16(mgmt->frame_control); + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) { + os_memset(&event, 0, sizeof(event)); + event.rx_probe_req.sa = mgmt->sa; + event.rx_probe_req.ie = mgmt->u.probe_req.variable; + event.rx_probe_req.ie_len = + data_len - (mgmt->u.probe_req.variable - data); + wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, + &event); + } + } +} + + +static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, + struct sockaddr *from, + socklen_t fromlen, + const u8 *data, size_t data_len) +{ + char buf[512], *pos, *end; + int ret; + struct test_driver_bss *bss; + + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); + + /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ + + if (!drv->ibss) + return; + + pos = buf; + end = buf + sizeof(buf); + + /* reply: SCANRESP BSSID SSID IEs */ + ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", + MAC2STR(bss->bssid)); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, + bss->ssid, bss->ssid_len); + ret = snprintf(pos, end - pos, " "); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie, + drv->assoc_wpa_ie_len); + + if (bss->privacy) { + ret = snprintf(pos, end - pos, " PRIVACY"); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + } + + ret = snprintf(pos, end - pos, " IBSS"); + if (ret < 0 || ret >= end - pos) + return; + pos += ret; + + sendto(drv->test_socket, buf, pos - buf, 0, + (struct sockaddr *) from, fromlen); } @@ -544,6 +1966,11 @@ static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx, socklen_t fromlen = sizeof(from); const size_t buflen = 2000; + if (drv->ap) { + test_driver_receive_unix(sock, eloop_ctx, sock_ctx); + return; + } + buf = os_malloc(buflen); if (buf == NULL) return; @@ -576,6 +2003,10 @@ static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "MLME ", 5) == 0) { wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen, (const u8 *) buf + 5, res - 5); + } else if (os_strncmp(buf, "SCAN ", 5) == 0) { + wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from, + fromlen, + (const u8 *) buf + 5, res - 5); } else { wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", (u8 *) buf, res); @@ -588,32 +2019,34 @@ static void * wpa_driver_test_init2(void *ctx, const char *ifname, void *global_priv) { struct wpa_driver_test_data *drv; + struct wpa_driver_test_global *global = global_priv; + struct test_driver_bss *bss; - drv = os_zalloc(sizeof(*drv)); + drv = test_alloc_data(ctx, ifname); if (drv == NULL) return NULL; + bss = dl_list_first(&drv->bss, struct test_driver_bss, list); drv->global = global_priv; - drv->ctx = ctx; drv->test_socket = -1; /* Set dummy BSSID and SSID for testing. */ - drv->bssid[0] = 0x02; - drv->bssid[1] = 0x00; - drv->bssid[2] = 0x00; - drv->bssid[3] = 0x00; - drv->bssid[4] = 0x00; - drv->bssid[5] = 0x01; - os_memcpy(drv->ssid, "test", 5); - drv->ssid_len = 4; + bss->bssid[0] = 0x02; + bss->bssid[1] = 0x00; + bss->bssid[2] = 0x00; + bss->bssid[3] = 0x00; + bss->bssid[4] = 0x00; + bss->bssid[5] = 0x01; + os_memcpy(bss->ssid, "test", 5); + bss->ssid_len = 4; + + if (global->bss_add_used) { + os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN); + global->bss_add_used = 0; + } - /* Generate a MAC address to help testing with multiple STAs */ - drv->own_addr[0] = 0x02; /* locally administered */ - sha1_prf((const u8 *) ifname, os_strlen(ifname), - "wpa_supplicant test mac addr generation", - NULL, 0, drv->own_addr + 1, ETH_ALEN - 1); eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); - return drv; + return bss; } @@ -635,21 +2068,42 @@ static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv) static void wpa_driver_test_deinit(void *priv) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + struct test_client_socket *cli, *prev; int i; + + cli = drv->cli; + while (cli) { + prev = cli; + cli = cli->next; + os_free(prev); + } + +#ifdef HOSTAPD + /* There should be only one BSS remaining at this point. */ + if (dl_list_len(&drv->bss) != 1) + wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries", + __func__, dl_list_len(&drv->bss)); +#endif /* HOSTAPD */ + + test_driver_free_bsses(drv); + wpa_driver_test_close_test_socket(drv); eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL); + eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); os_free(drv->test_dir); for (i = 0; i < MAX_SCAN_RESULTS; i++) os_free(drv->scanres[i]); os_free(drv->probe_req_ie); + wpa_trace_remove_ref(drv, ctx, drv->ctx); os_free(drv); } static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, - const char *dir) + const char *dir, int ap) { #ifdef DRIVER_TEST_UNIX static unsigned int counter = 0; @@ -662,8 +2116,8 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, drv->own_socket_path = os_malloc(len); if (drv->own_socket_path == NULL) return -1; - os_snprintf(drv->own_socket_path, len, "%s/STA-" MACSTR, - dir, MAC2STR(drv->own_addr)); + os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR, + dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr)); } else { drv->own_socket_path = os_malloc(100); if (drv->own_socket_path == NULL) @@ -750,7 +2204,8 @@ static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv, static int wpa_driver_test_set_param(void *priv, const char *param) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; const char *pos; wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); @@ -790,7 +2245,7 @@ static int wpa_driver_test_set_param(void *priv, const char *param) end = os_strchr(drv->test_dir, ' '); if (end) *end = '\0'; - if (wpa_driver_test_attach(drv, drv->test_dir)) + if (wpa_driver_test_attach(drv, drv->test_dir, 0)) return -1; } else { pos = os_strstr(param, "test_udp="); @@ -805,7 +2260,7 @@ static int wpa_driver_test_set_param(void *priv, const char *param) if (wpa_driver_test_attach_udp(drv, dst)) return -1; os_free(dst); - } else if (wpa_driver_test_attach(drv, NULL)) + } else if (wpa_driver_test_attach(drv, NULL, 0)) return -1; } @@ -827,7 +2282,8 @@ static int wpa_driver_test_set_param(void *priv, const char *param) static const u8 * wpa_driver_test_get_mac_addr(void *priv) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; wpa_printf(MSG_DEBUG, "%s", __func__); return drv->own_addr; } @@ -836,7 +2292,8 @@ static const u8 * wpa_driver_test_get_mac_addr(void *priv) static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, const u8 *data, size_t data_len) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; char *msg; size_t msg_len; struct l2_ethhdr eth; @@ -861,7 +2318,7 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, os_memcpy(msg + 6, ð, sizeof(eth)); os_memcpy(msg + 6 + sizeof(eth), data, data_len); - if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 || + if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 || drv->test_dir == NULL) { if (drv->hostapd_addr_udp_set) { addr = (struct sockaddr *) &drv->hostapd_addr_udp; @@ -908,7 +2365,8 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) { - struct wpa_driver_test_data *drv = priv; + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; os_memset(capa, 0, sizeof(*capa)); capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | @@ -926,6 +2384,9 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) WPA_DRIVER_AUTH_LEAP; if (drv->use_mlme) capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; + capa->flags |= WPA_DRIVER_FLAGS_AP; + capa->max_scan_ssids = 2; + capa->max_remain_on_chan = 60000; return 0; } @@ -947,134 +2408,15 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, } -#ifdef CONFIG_CLIENT_MLME -static struct wpa_hw_modes * -wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) -{ - struct wpa_hw_modes *modes; - - *num_modes = 1; - *flags = 0; - modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes)); - if (modes == NULL) - return NULL; - modes[0].mode = WPA_MODE_IEEE80211G; - modes[0].num_channels = 1; - modes[0].num_rates = 1; - modes[0].channels = os_zalloc(sizeof(struct wpa_channel_data)); - modes[0].rates = os_zalloc(sizeof(struct wpa_rate_data)); - if (modes[0].channels == NULL || modes[0].rates == NULL) { - wpa_supplicant_sta_free_hw_features(modes, *num_modes); - return NULL; - } - modes[0].channels[0].chan = 1; - modes[0].channels[0].freq = 2412; - modes[0].channels[0].flag = WPA_CHAN_W_SCAN | WPA_CHAN_W_ACTIVE_SCAN; - modes[0].rates[0].rate = 10; - modes[0].rates[0].flags = WPA_RATE_BASIC | WPA_RATE_SUPPORTED | - WPA_RATE_CCK | WPA_RATE_MANDATORY; - - return modes; -} - - -static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode, +static int wpa_driver_test_set_channel(void *priv, + enum hostapd_hw_mode phymode, int chan, int freq) { + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d", __func__, phymode, chan, freq); - return 0; -} - - -static int wpa_driver_test_send_mlme(void *priv, const u8 *data, - size_t data_len) -{ - struct wpa_driver_test_data *drv = priv; - struct msghdr msg; - struct iovec io[2]; - struct sockaddr_un addr; - const u8 *dest; - struct dirent *dent; - DIR *dir; - - wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len); - if (data_len < 10) - return -1; - dest = data + 4; - - io[0].iov_base = "MLME "; - io[0].iov_len = 5; - io[1].iov_base = (u8 *) data; - io[1].iov_len = data_len; - - os_memset(&msg, 0, sizeof(msg)); - msg.msg_iov = io; - msg.msg_iovlen = 2; - if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 || - drv->test_dir == NULL) { - if (drv->hostapd_addr_udp_set) { - msg.msg_name = &drv->hostapd_addr_udp; - msg.msg_namelen = sizeof(drv->hostapd_addr_udp); - } else { -#ifdef DRIVER_TEST_UNIX - msg.msg_name = &drv->hostapd_addr; - msg.msg_namelen = sizeof(drv->hostapd_addr); -#endif /* DRIVER_TEST_UNIX */ - } - } else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) - { - dir = opendir(drv->test_dir); - if (dir == NULL) - return -1; - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. - * Also accept DT_UNKNOWN (0) in case - * the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && - dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - if (os_strcmp(dent->d_name, ".") == 0 || - os_strcmp(dent->d_name, "..") == 0) - continue; - wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s", - __func__, dent->d_name); - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "%s/%s", drv->test_dir, dent->d_name); - - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - - if (sendmsg(drv->test_socket, &msg, 0) < 0) - perror("sendmsg(test_socket)"); - } - closedir(dir); - return 0; - } else { - struct stat st; - os_memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); - if (stat(addr.sun_path, &st) < 0) { - os_snprintf(addr.sun_path, sizeof(addr.sun_path), - "%s/STA-" MACSTR, - drv->test_dir, MAC2STR(dest)); - } - msg.msg_name = &addr; - msg.msg_namelen = sizeof(addr); - } - - if (sendmsg(drv->test_socket, &msg, 0) < 0) { - perror("sendmsg(test_socket)"); - return -1; - } - + drv->current_freq = freq; return 0; } @@ -1108,29 +2450,6 @@ static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid) wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid)); return 0; } -#endif /* CONFIG_CLIENT_MLME */ - - -static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies, - size_t ies_len) -{ - struct wpa_driver_test_data *drv = priv; - - os_free(drv->probe_req_ie); - if (ies) { - drv->probe_req_ie = os_malloc(ies_len); - if (drv->probe_req_ie == NULL) { - drv->probe_req_ie_len = 0; - return -1; - } - os_memcpy(drv->probe_req_ie, ies, ies_len); - drv->probe_req_ie_len = ies_len; - } else { - drv->probe_req_ie = NULL; - drv->probe_req_ie_len = 0; - } - return 0; -} static void * wpa_driver_test_global_init(void) @@ -1172,59 +2491,263 @@ wpa_driver_test_get_interfaces(void *global_priv) } +static struct hostapd_hw_modes * +wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) +{ + struct hostapd_hw_modes *modes; + size_t i; + + *num_modes = 3; + *flags = 0; + modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); + if (modes == NULL) + return NULL; + modes[0].mode = HOSTAPD_MODE_IEEE80211G; + modes[0].num_channels = 11; + modes[0].num_rates = 12; + modes[0].channels = + os_zalloc(11 * sizeof(struct hostapd_channel_data)); + modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int)); + if (modes[0].channels == NULL || modes[0].rates == NULL) + goto fail; + for (i = 0; i < 11; i++) { + modes[0].channels[i].chan = i + 1; + modes[0].channels[i].freq = 2412 + 5 * i; + modes[0].channels[i].flag = 0; + } + modes[0].rates[0] = 10; + modes[0].rates[1] = 20; + modes[0].rates[2] = 55; + modes[0].rates[3] = 110; + modes[0].rates[4] = 60; + modes[0].rates[5] = 90; + modes[0].rates[6] = 120; + modes[0].rates[7] = 180; + modes[0].rates[8] = 240; + modes[0].rates[9] = 360; + modes[0].rates[10] = 480; + modes[0].rates[11] = 540; + + modes[1].mode = HOSTAPD_MODE_IEEE80211B; + modes[1].num_channels = 11; + modes[1].num_rates = 4; + modes[1].channels = + os_zalloc(11 * sizeof(struct hostapd_channel_data)); + modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int)); + if (modes[1].channels == NULL || modes[1].rates == NULL) + goto fail; + for (i = 0; i < 11; i++) { + modes[1].channels[i].chan = i + 1; + modes[1].channels[i].freq = 2412 + 5 * i; + modes[1].channels[i].flag = 0; + } + modes[1].rates[0] = 10; + modes[1].rates[1] = 20; + modes[1].rates[2] = 55; + modes[1].rates[3] = 110; + + modes[2].mode = HOSTAPD_MODE_IEEE80211A; + modes[2].num_channels = 1; + modes[2].num_rates = 8; + modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data)); + modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); + if (modes[2].channels == NULL || modes[2].rates == NULL) + goto fail; + modes[2].channels[0].chan = 60; + modes[2].channels[0].freq = 5300; + modes[2].channels[0].flag = 0; + modes[2].rates[0] = 60; + modes[2].rates[1] = 90; + modes[2].rates[2] = 120; + modes[2].rates[3] = 180; + modes[2].rates[4] = 240; + modes[2].rates[5] = 360; + modes[2].rates[6] = 480; + modes[2].rates[7] = 540; + + return modes; + +fail: + if (modes) { + for (i = 0; i < *num_modes; i++) { + os_free(modes[i].channels); + os_free(modes[i].rates); + } + os_free(modes); + } + return NULL; +} + + +static int wpa_driver_test_set_freq(void *priv, + struct hostapd_freq_params *freq) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq); + drv->current_freq = freq->freq; + return 0; +} + + +static int wpa_driver_test_send_action(void *priv, unsigned int freq, + const u8 *dst, const u8 *src, + const u8 *bssid, + const u8 *data, size_t data_len) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + int ret = -1; + u8 *buf; + struct ieee80211_hdr *hdr; + + wpa_printf(MSG_DEBUG, "test: Send Action frame"); + + if ((drv->remain_on_channel_freq && + freq != drv->remain_on_channel_freq) || + (drv->remain_on_channel_freq == 0 && + freq != (unsigned int) drv->current_freq)) { + wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on " + "unexpected channel: freq=%u MHz (current_freq=%u " + "MHz, remain-on-channel freq=%u MHz)", + freq, drv->current_freq, + drv->remain_on_channel_freq); + return -1; + } + + buf = os_zalloc(24 + data_len); + if (buf == NULL) + return ret; + os_memcpy(buf + 24, data, data_len); + hdr = (struct ieee80211_hdr *) buf; + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); + os_memcpy(hdr->addr1, dst, ETH_ALEN); + os_memcpy(hdr->addr2, src, ETH_ALEN); + os_memcpy(hdr->addr3, bssid, ETH_ALEN); + + ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len); + os_free(buf); + return ret; +} + + +static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_driver_test_data *drv = eloop_ctx; + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout"); + + os_memset(&data, 0, sizeof(data)); + data.remain_on_channel.freq = drv->remain_on_channel_freq; + data.remain_on_channel.duration = drv->remain_on_channel_duration; + wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); + + drv->remain_on_channel_freq = 0; +} + + +static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq, + unsigned int duration) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)", + __func__, freq, duration); + if (drv->remain_on_channel_freq && + drv->remain_on_channel_freq != freq) { + wpa_printf(MSG_DEBUG, "test: Refuse concurrent " + "remain_on_channel request"); + return -1; + } + + drv->remain_on_channel_freq = freq; + drv->remain_on_channel_duration = duration; + eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); + eloop_register_timeout(duration / 1000, (duration % 1000) * 1000, + test_remain_on_channel_timeout, drv, NULL); + + os_memset(&data, 0, sizeof(data)); + data.remain_on_channel.freq = freq; + data.remain_on_channel.duration = duration; + wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data); + + return 0; +} + + +static int wpa_driver_test_cancel_remain_on_channel(void *priv) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + wpa_printf(MSG_DEBUG, "%s", __func__); + if (!drv->remain_on_channel_freq) + return -1; + drv->remain_on_channel_freq = 0; + eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); + return 0; +} + + +static int wpa_driver_test_probe_req_report(void *priv, int report) +{ + struct test_driver_bss *dbss = priv; + struct wpa_driver_test_data *drv = dbss->drv; + wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report); + drv->probe_req_report = report; + return 0; +} + + const struct wpa_driver_ops wpa_driver_test_ops = { "test", "wpa_supplicant test driver", - wpa_driver_test_get_bssid, - wpa_driver_test_get_ssid, - wpa_driver_test_set_wpa, - wpa_driver_test_set_key, - NULL /* init */, - wpa_driver_test_deinit, - wpa_driver_test_set_param, - NULL /* set_countermeasures */, - NULL /* set_drop_unencrypted */, - wpa_driver_test_scan, - NULL /* get_scan_results */, - wpa_driver_test_deauthenticate, - wpa_driver_test_disassociate, - wpa_driver_test_associate, - NULL /* set_auth_alg */, - NULL /* add_pmkid */, - NULL /* remove_pmkid */, - NULL /* flush_pmkid */, - wpa_driver_test_get_capa, - NULL /* poll */, - NULL /* get_ifname */, - wpa_driver_test_get_mac_addr, - wpa_driver_test_send_eapol, - NULL /* set_operstate */, - wpa_driver_test_mlme_setprotection, -#ifdef CONFIG_CLIENT_MLME - wpa_driver_test_get_hw_feature_data, - wpa_driver_test_set_channel, - wpa_driver_test_set_ssid, - wpa_driver_test_set_bssid, - wpa_driver_test_send_mlme, - wpa_driver_test_mlme_add_sta, - wpa_driver_test_mlme_remove_sta, -#else /* CONFIG_CLIENT_MLME */ - NULL /* get_hw_feature_data */, - NULL /* set_channel */, - NULL /* set_ssid */, - NULL /* set_bssid */, - NULL /* send_mlme */, - NULL /* mlme_add_sta */, - NULL /* mlme_remove_sta */, -#endif /* CONFIG_CLIENT_MLME */ - NULL /* update_ft_ies */, - NULL /* send_ft_action */, - wpa_driver_test_get_scan_results2, - wpa_driver_test_set_probe_req_ie, - NULL /* set_mode */, - NULL /* set_country */, - wpa_driver_test_global_init, - wpa_driver_test_global_deinit, - wpa_driver_test_init2, - wpa_driver_test_get_interfaces + .hapd_init = test_driver_init, + .hapd_deinit = wpa_driver_test_deinit, + .hapd_send_eapol = test_driver_send_eapol, + .send_mlme = wpa_driver_test_send_mlme, + .set_generic_elem = test_driver_set_generic_elem, + .sta_deauth = test_driver_sta_deauth, + .sta_disassoc = test_driver_sta_disassoc, + .get_hw_feature_data = wpa_driver_test_get_hw_feature_data, + .if_add = test_driver_if_add, + .if_remove = test_driver_if_remove, + .valid_bss_mask = test_driver_valid_bss_mask, + .hapd_set_ssid = test_driver_set_ssid, + .set_privacy = test_driver_set_privacy, + .set_sta_vlan = test_driver_set_sta_vlan, + .sta_add = test_driver_sta_add, + .send_ether = test_driver_send_ether, + .set_ap_wps_ie = test_driver_set_ap_wps_ie, + .get_bssid = wpa_driver_test_get_bssid, + .get_ssid = wpa_driver_test_get_ssid, + .set_key = wpa_driver_test_set_key, + .deinit = wpa_driver_test_deinit, + .set_param = wpa_driver_test_set_param, + .deauthenticate = wpa_driver_test_deauthenticate, + .disassociate = wpa_driver_test_disassociate, + .associate = wpa_driver_test_associate, + .get_capa = wpa_driver_test_get_capa, + .get_mac_addr = wpa_driver_test_get_mac_addr, + .send_eapol = wpa_driver_test_send_eapol, + .mlme_setprotection = wpa_driver_test_mlme_setprotection, + .set_channel = wpa_driver_test_set_channel, + .set_ssid = wpa_driver_test_set_ssid, + .set_bssid = wpa_driver_test_set_bssid, + .mlme_add_sta = wpa_driver_test_mlme_add_sta, + .mlme_remove_sta = wpa_driver_test_mlme_remove_sta, + .get_scan_results2 = wpa_driver_test_get_scan_results2, + .global_init = wpa_driver_test_global_init, + .global_deinit = wpa_driver_test_global_deinit, + .init2 = wpa_driver_test_init2, + .get_interfaces = wpa_driver_test_get_interfaces, + .scan2 = wpa_driver_test_scan, + .set_freq = wpa_driver_test_set_freq, + .send_action = wpa_driver_test_send_action, + .remain_on_channel = wpa_driver_test_remain_on_channel, + .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel, + .probe_req_report = wpa_driver_test_probe_req_report, }; diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index e771d37dedb7..2614f23093fa 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant - driver interaction with generic Linux Wireless Extensions - * Copyright (c) 2003-2007, Jouni Malinen + * Driver interaction with generic Linux Wireless Extensions + * Copyright (c) 2003-2010, Jouni Malinen * * 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 @@ -20,82 +20,26 @@ #include "includes.h" #include +#include #include #include "wireless_copy.h" #include "common.h" -#include "driver.h" #include "eloop.h" +#include "common/ieee802_11_defs.h" +#include "common/wpa_common.h" #include "priv_netlink.h" +#include "netlink.h" +#include "linux_ioctl.h" +#include "driver.h" #include "driver_wext.h" -#include "ieee802_11_defs.h" -#include "wpa_common.h" static int wpa_driver_wext_flush_pmkid(void *priv); static int wpa_driver_wext_get_range(void *priv); -static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); +static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv); - - -static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv, - int linkmode, int operstate) -{ - struct { - struct nlmsghdr hdr; - struct ifinfomsg ifinfo; - char opts[16]; - } req; - struct rtattr *rta; - static int nl_seq; - ssize_t ret; - - os_memset(&req, 0, sizeof(req)); - - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.hdr.nlmsg_type = RTM_SETLINK; - req.hdr.nlmsg_flags = NLM_F_REQUEST; - req.hdr.nlmsg_seq = ++nl_seq; - req.hdr.nlmsg_pid = 0; - - req.ifinfo.ifi_family = AF_UNSPEC; - req.ifinfo.ifi_type = 0; - req.ifinfo.ifi_index = drv->ifindex; - req.ifinfo.ifi_flags = 0; - req.ifinfo.ifi_change = 0; - - if (linkmode != -1) { - rta = aliasing_hide_typecast( - ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), - struct rtattr); - rta->rta_type = IFLA_LINKMODE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - *((char *) RTA_DATA(rta)) = linkmode; - req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + - RTA_LENGTH(sizeof(char)); - } - if (operstate != -1) { - rta = (struct rtattr *) - ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)); - rta->rta_type = IFLA_OPERSTATE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - *((char *) RTA_DATA(rta)) = operstate; - req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + - RTA_LENGTH(sizeof(char)); - } - - wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d", - linkmode, operstate); - - ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: " - "%s (assume operstate is not supported)", - strerror(errno)); - } - - return ret < 0 ? -1 : 0; -} +static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg); int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, @@ -304,6 +248,7 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { char *spos; int bytes; + u8 *req_ies = NULL, *resp_ies = NULL; spos = custom + 17; @@ -312,12 +257,12 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) return; bytes /= 2; - data.assoc_info.req_ies = os_malloc(bytes); - if (data.assoc_info.req_ies == NULL) - return; - + req_ies = os_malloc(bytes); + if (req_ies == NULL || + hexstr2bin(spos, req_ies, bytes) < 0) + goto done; + data.assoc_info.req_ies = req_ies; data.assoc_info.req_ies_len = bytes; - hexstr2bin(spos, data.assoc_info.req_ies, bytes); spos += bytes * 2; @@ -332,19 +277,19 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) goto done; bytes /= 2; - data.assoc_info.resp_ies = os_malloc(bytes); - if (data.assoc_info.resp_ies == NULL) + resp_ies = os_malloc(bytes); + if (resp_ies == NULL || + hexstr2bin(spos, resp_ies, bytes) < 0) goto done; - + data.assoc_info.resp_ies = resp_ies; data.assoc_info.resp_ies_len = bytes; - hexstr2bin(spos, data.assoc_info.resp_ies, bytes); } wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); done: - os_free(data.assoc_info.resp_ies); - os_free(data.assoc_info.req_ies); + os_free(resp_ies); + os_free(req_ies); #ifdef CONFIG_PEERKEY } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { if (hwaddr_aton(custom + 17, data.stkstart.peer)) { @@ -460,24 +405,24 @@ static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) os_memset(&data, 0, sizeof(data)); if (drv->assoc_req_ies) { data.assoc_info.req_ies = drv->assoc_req_ies; - drv->assoc_req_ies = NULL; data.assoc_info.req_ies_len = drv->assoc_req_ies_len; } if (drv->assoc_resp_ies) { data.assoc_info.resp_ies = drv->assoc_resp_ies; - drv->assoc_resp_ies = NULL; data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; } wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); - os_free(data.assoc_info.req_ies); - os_free(data.assoc_info.resp_ies); + os_free(drv->assoc_req_ies); + drv->assoc_req_ies = NULL; + os_free(drv->assoc_resp_ies); + drv->assoc_resp_ies = NULL; } static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, - void *ctx, char *data, int len) + char *data, int len) { struct iw_event iwe_buf, *iwe = &iwe_buf; char *pos, *end, *custom, *buf; @@ -525,12 +470,13 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, drv->assoc_req_ies = NULL; os_free(drv->assoc_resp_ies); drv->assoc_resp_ies = NULL; - wpa_supplicant_event(ctx, EVENT_DISASSOC, + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); } else { wpa_driver_wext_event_assoc_ies(drv); - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, + NULL); } break; case IWEVMICHAELMICFAILURE: @@ -540,7 +486,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, return; } wpa_driver_wext_event_wireless_michaelmicfailure( - ctx, custom, iwe->u.data.length); + drv->ctx, custom, iwe->u.data.length); break; case IWEVCUSTOM: if (custom + iwe->u.data.length > end) { @@ -553,14 +499,15 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, return; os_memcpy(buf, custom, iwe->u.data.length); buf[iwe->u.data.length] = '\0'; - wpa_driver_wext_event_wireless_custom(ctx, buf); + wpa_driver_wext_event_wireless_custom(drv->ctx, buf); os_free(buf); break; case SIOCGIWSCAN: drv->scan_complete_events = 1; eloop_cancel_timeout(wpa_driver_wext_scan_timeout, - drv, ctx); - wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); + drv, drv->ctx); + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, + NULL); break; case IWEVASSOCREQIE: if (custom + iwe->u.data.length > end) { @@ -597,8 +544,7 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, - void *ctx, char *buf, size_t len, - int del) + char *buf, size_t len, int del) { union wpa_event_data event; @@ -621,26 +567,18 @@ static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, drv->if_removed = 0; } - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, - struct nlmsghdr *h) + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; + int attrlen, rta_len; struct rtattr *attr; - ifi = NLMSG_DATA(h); - - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return 0; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { @@ -659,12 +597,12 @@ static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, - int ifindex, struct nlmsghdr *h) + int ifindex, u8 *buf, size_t len) { if (drv->ifindex == ifindex || drv->ifindex2 == ifindex) return 1; - if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) { + if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) { drv->ifindex = if_nametoindex(drv->ifname); wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed " "interface"); @@ -676,20 +614,14 @@ static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, } -static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, - void *ctx, struct nlmsghdr *h, - size_t len) +static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; + struct wpa_driver_wext_data *drv = ctx; + int attrlen, rta_len; + struct rtattr *attr; - if (len < sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) { + if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) { wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", ifi->ifi_index); return; @@ -711,24 +643,20 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && !(ifi->ifi_flags & IFF_RUNNING)) - wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP); + netlink_send_oper_ifla(drv->netlink, drv->ifindex, + -1, IF_OPER_UP); - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_WIRELESS) { wpa_driver_wext_event_wireless( - drv, ctx, ((char *) attr) + rta_len, + drv, ((char *) attr) + rta_len, attr->rta_len - rta_len); } else if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_wext_event_link(drv, ctx, + wpa_driver_wext_event_link(drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 0); } @@ -737,31 +665,20 @@ static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv, } -static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv, - void *ctx, struct nlmsghdr *h, - size_t len) +static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, + u8 *buf, size_t len) { - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr * attr; + struct wpa_driver_wext_data *drv = ctx; + int attrlen, 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); + attrlen = len; + attr = (struct rtattr *) buf; rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_wext_event_link(drv, ctx, + wpa_driver_wext_event_link(drv, ((char *) attr) + rta_len, attr->rta_len - rta_len, 1); } @@ -770,129 +687,6 @@ static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv, } -static void wpa_driver_wext_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; - int max_events = 10; - -try_again: - 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) { - wpa_printf(MSG_DEBUG, "Malformed netlink message: " - "len=%d left=%d plen=%d", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx, - h, plen); - break; - case RTM_DELLINK: - wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx, - h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink " - "message", left); - } - - if (--max_events > 0) { - /* - * Try to receive all events in one eloop call in order to - * limit race condition on cases where AssocInfo event, Assoc - * event, and EAPOL frames are received more or less at the - * same time. We want to process the event messages first - * before starting EAPOL processing. - */ - goto try_again; - } -} - - -static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv, - const char *ifname, int *flags) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { - perror("ioctl[SIOCGIFFLAGS]"); - return -1; - } - *flags = ifr.ifr_flags & 0xffff; - return 0; -} - - -/** - * wpa_driver_wext_get_ifflags - Get interface flags (SIOCGIFFLAGS) - * @drv: driver_wext private data - * @flags: Pointer to returned flags value - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags) -{ - return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags); -} - - -static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv, - const char *ifname, int flags) -{ - struct ifreq ifr; - - os_memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_flags = flags & 0xffff; - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { - perror("SIOCSIFFLAGS"); - return -1; - } - return 0; -} - - -/** - * wpa_driver_wext_set_ifflags - Set interface flags (SIOCSIFFLAGS) - * @drv: driver_wext private data - * @flags: New value for flags - * Returns: 0 on success, -1 on failure - */ -int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags) -{ - return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags); -} - - /** * wpa_driver_wext_init - Initialize WE driver interface * @ctx: context to be used when calling wpa_supplicant functions, @@ -902,9 +696,10 @@ int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags) */ void * wpa_driver_wext_init(void *ctx, const char *ifname) { - int s; - struct sockaddr_nl local; struct wpa_driver_wext_data *drv; + struct netlink_config *cfg; + char path[128]; + struct stat buf; drv = os_zalloc(sizeof(*drv)); if (drv == NULL) @@ -912,66 +707,53 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) drv->ctx = ctx; os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); + os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); + if (stat(path, &buf) == 0) { + wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected"); + drv->cfg80211 = 1; + } + drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); if (drv->ioctl_sock < 0) { perror("socket(PF_INET,SOCK_DGRAM)"); - os_free(drv); - return NULL; + goto err1; } - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - close(drv->ioctl_sock); - os_free(drv); - return NULL; + cfg = os_zalloc(sizeof(*cfg)); + if (cfg == NULL) + goto err1; + cfg->ctx = drv; + cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; + cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; + drv->netlink = netlink_init(cfg); + if (drv->netlink == NULL) { + os_free(cfg); + goto err2; } - os_memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - close(drv->ioctl_sock); - os_free(drv); - return NULL; - } - - eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx); - drv->event_sock = s; - drv->mlme_sock = -1; - wpa_driver_wext_finish_drv_init(drv); + if (wpa_driver_wext_finish_drv_init(drv) < 0) + goto err3; + + wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); return drv; + +err3: + netlink_deinit(drv->netlink); +err2: + close(drv->ioctl_sock); +err1: + os_free(drv); + return NULL; } -static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) +static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) { - int flags; - - if (wpa_driver_wext_get_ifflags(drv, &flags) != 0) - printf("Could not get interface '%s' flags\n", drv->ifname); - else if (!(flags & IFF_UP)) { - if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) { - printf("Could not set interface '%s' UP\n", - drv->ifname); - } else { - /* - * Wait some time to allow driver to initialize before - * starting configuring the driver. This seems to be - * needed at least some drivers that load firmware etc. - * when the interface is set up. - */ - wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting " - "a second for the driver to complete " - "initialization", drv->ifname); - sleep(1); - } - } + if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) + return -1; /* * Make sure that the driver does not have any obsolete PMKID entries. @@ -979,7 +761,9 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) wpa_driver_wext_flush_pmkid(drv); if (wpa_driver_wext_set_mode(drv, 0) < 0) { - printf("Could not configure driver to use managed mode\n"); + wpa_printf(MSG_DEBUG, "Could not configure driver to use " + "managed mode"); + /* Try to use it anyway */ } wpa_driver_wext_get_range(drv); @@ -1008,7 +792,10 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) wpa_driver_wext_alternative_ifindex(drv, ifname2); } - wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT); + netlink_send_oper_ifla(drv->netlink, drv->ifindex, + 1, IF_OPER_DORMANT); + + return 0; } @@ -1022,7 +809,8 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) void wpa_driver_wext_deinit(void *priv) { struct wpa_driver_wext_data *drv = priv; - int flags; + + wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0); eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); @@ -1032,16 +820,14 @@ void wpa_driver_wext_deinit(void *priv) */ wpa_driver_wext_disconnect(drv); - wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP); + netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); + netlink_deinit(drv->netlink); - eloop_unregister_read_sock(drv->event_sock); if (drv->mlme_sock >= 0) eloop_unregister_read_sock(drv->mlme_sock); - if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) - (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP); + (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); - close(drv->event_sock); close(drv->ioctl_sock); if (drv->mlme_sock >= 0) close(drv->mlme_sock); @@ -1069,18 +855,17 @@ void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) /** * wpa_driver_wext_scan - Request the driver to initiate scan * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for - * all SSIDs (either active scan with broadcast SSID or passive - * scan - * @ssid_len: Length of the SSID + * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) * Returns: 0 on success, -1 on failure */ -int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len) +int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) { struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0, timeout; struct iw_scan_req req; + const u8 *ssid = params->ssids[0].ssid; + size_t ssid_len = params->ssids[0].ssid_len; if (ssid_len > IW_ESSID_MAX_SIZE) { wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", @@ -1261,6 +1046,14 @@ static void wext_get_scan_qual(struct iw_event *iwe, res->res.qual = iwe->u.qual.qual; res->res.noise = iwe->u.qual.noise; res->res.level = iwe->u.qual.level; + if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID) + res->res.flags |= WPA_SCAN_QUAL_INVALID; + if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID) + res->res.flags |= WPA_SCAN_LEVEL_INVALID; + if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID) + res->res.flags |= WPA_SCAN_NOISE_INVALID; + if (iwe->u.qual.updated & IW_QUAL_DBM) + res->res.flags |= WPA_SCAN_LEVEL_DBM; } @@ -1349,8 +1142,9 @@ static void wext_get_scan_custom(struct iw_event *iwe, tmp = os_realloc(res->ie, res->ie_len + bytes); if (tmp == NULL) return; - hexstr2bin(spos, tmp + res->ie_len, bytes); res->ie = tmp; + if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) + return; res->ie_len += bytes; } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { char *spos; @@ -1363,8 +1157,9 @@ static void wext_get_scan_custom(struct iw_event *iwe, tmp = os_realloc(res->ie, res->ie_len + bytes); if (tmp == NULL) return; - hexstr2bin(spos, tmp + res->ie_len, bytes); res->ie = tmp; + if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) + return; res->ie_len += bytes; } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { char *spos; @@ -1377,7 +1172,10 @@ static void wext_get_scan_custom(struct iw_event *iwe, return; } bytes /= 2; - hexstr2bin(spos, bin, bytes); + if (hexstr2bin(spos, bin, bytes) < 0) { + wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value"); + return; + } res->res.tsf += WPA_GET_BE64(bin); } } @@ -1619,6 +1417,7 @@ static int wpa_driver_wext_get_range(void *priv) drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; + drv->capa.max_scan_ssids = 1; wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " "flags 0x%x", @@ -1633,16 +1432,6 @@ static int wpa_driver_wext_get_range(void *priv) } -static int wpa_driver_wext_set_wpa(void *priv, int enabled) -{ - struct wpa_driver_wext_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, - enabled); -} - - static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, const u8 *psk) { @@ -1680,7 +1469,7 @@ static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, } -static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg, +static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, @@ -1800,7 +1589,7 @@ static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg, * This function uses SIOCSIWENCODEEXT by default, but tries to use * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. */ -int wpa_driver_wext_set_key(void *priv, wpa_alg alg, +int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -1929,17 +1718,32 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) } if (iwr.u.mode == IW_MODE_INFRA) { + if (drv->cfg80211) { + /* + * cfg80211 supports SIOCSIWMLME commands, so there is + * no need for the random SSID hack, but clear the + * BSSID and SSID. + */ + if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || + wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { + wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " + "to disconnect"); + } + return; + } /* * Clear the BSSID selection and set a random SSID to make sure * the driver will not be trying to associate with something * even if it does not understand SIOCSIWMLME commands (or * tries to associate automatically after deauth/disassoc). */ - wpa_driver_wext_set_bssid(drv, null_bssid); - for (i = 0; i < 32; i++) ssid[i] = rand() & 0xFF; - wpa_driver_wext_set_ssid(drv, ssid, 32); + if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || + wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { + wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " + "BSSID/SSID to disconnect"); + } } } @@ -2051,9 +1855,9 @@ wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv, if (!drv->use_crypt) { iwr.u.encoding.flags |= IW_ENCODE_DISABLED; } else { - if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM) + if (params->auth_alg & WPA_AUTH_ALG_OPEN) iwr.u.encoding.flags |= IW_ENCODE_OPEN; - if (params->auth_alg & AUTH_ALG_SHARED_KEY) + if (params->auth_alg & WPA_AUTH_ALG_SHARED) iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; } @@ -2076,6 +1880,22 @@ int wpa_driver_wext_associate(void *priv, wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); + if (drv->cfg80211) { + /* + * Stop cfg80211 from trying to associate before we are done + * with all parameters. + */ + wpa_driver_wext_set_ssid(drv, (u8 *) "", 0); + } + + if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) + < 0) + ret = -1; + if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0) + ret = -1; + if (wpa_driver_wext_set_mode(drv, params->mode) < 0) + ret = -1; + /* * If the driver did not support SIOCSIWAUTH, fallback to * SIOCSIWENCODE here. @@ -2155,11 +1975,15 @@ int wpa_driver_wext_associate(void *priv, #endif /* CONFIG_IEEE80211W */ if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0) ret = -1; - if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) + if (!drv->cfg80211 && + wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) ret = -1; if (params->bssid && wpa_driver_wext_set_bssid(drv, params->bssid) < 0) ret = -1; + if (drv->cfg80211 && + wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) + ret = -1; return ret; } @@ -2170,11 +1994,11 @@ static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg) struct wpa_driver_wext_data *drv = priv; int algs = 0, res; - if (auth_alg & AUTH_ALG_OPEN_SYSTEM) + if (auth_alg & WPA_AUTH_ALG_OPEN) algs |= IW_AUTH_ALG_OPEN_SYSTEM; - if (auth_alg & AUTH_ALG_SHARED_KEY) + if (auth_alg & WPA_AUTH_ALG_SHARED) algs |= IW_AUTH_ALG_SHARED_KEY; - if (auth_alg & AUTH_ALG_LEAP) + if (auth_alg & WPA_AUTH_ALG_LEAP) algs |= IW_AUTH_ALG_LEAP; if (algs == 0) { /* at least one algorithm should be set */ @@ -2198,7 +2022,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode) { struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; - int ret = -1, flags; + int ret = -1; unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA; os_memset(&iwr, 0, sizeof(iwr)); @@ -2228,9 +2052,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode) goto done; } - if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) { - (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP); - + if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) { /* Try to set the mode again while the interface is down */ iwr.u.mode = new_mode; if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) @@ -2238,11 +2060,7 @@ int wpa_driver_wext_set_mode(void *priv, int mode) else ret = 0; - /* Ignore return value of get_ifflags to ensure that the device - * is always up like it was before this function was called. - */ - (void) wpa_driver_wext_get_ifflags(drv, &flags); - (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP); + (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); } done: @@ -2338,8 +2156,8 @@ int wpa_driver_wext_set_operstate(void *priv, int state) wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", __func__, drv->operstate, state, state ? "UP" : "DORMANT"); drv->operstate = state; - return wpa_driver_wext_send_oper_ifla( - drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); + return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, + state ? IF_OPER_UP : IF_OPER_DORMANT); } @@ -2354,17 +2172,13 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .desc = "Linux wireless extensions (generic)", .get_bssid = wpa_driver_wext_get_bssid, .get_ssid = wpa_driver_wext_get_ssid, - .set_wpa = wpa_driver_wext_set_wpa, .set_key = wpa_driver_wext_set_key, .set_countermeasures = wpa_driver_wext_set_countermeasures, - .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted, - .scan = wpa_driver_wext_scan, + .scan2 = wpa_driver_wext_scan, .get_scan_results2 = wpa_driver_wext_get_scan_results, .deauthenticate = wpa_driver_wext_deauthenticate, .disassociate = wpa_driver_wext_disassociate, - .set_mode = wpa_driver_wext_set_mode, .associate = wpa_driver_wext_associate, - .set_auth_alg = wpa_driver_wext_set_auth_alg, .init = wpa_driver_wext_init, .deinit = wpa_driver_wext_deinit, .add_pmkid = wpa_driver_wext_add_pmkid, diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index b89c2cb2fdfa..602c7e1f689c 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -19,7 +19,7 @@ struct wpa_driver_wext_data { void *ctx; - int event_sock; + struct netlink_data *netlink; int ioctl_sock; int mlme_sock; char ifname[IFNAMSIZ + 1]; @@ -43,21 +43,21 @@ struct wpa_driver_wext_data { char mlmedev[IFNAMSIZ + 1]; int scan_complete_events; + + int cfg80211; /* whether driver is using cfg80211 */ }; -int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags); -int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags); int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid); int wpa_driver_wext_get_ssid(void *priv, u8 *ssid); int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len); int wpa_driver_wext_set_freq(void *priv, int freq); int wpa_driver_wext_set_mode(void *priv, int mode); -int wpa_driver_wext_set_key(void *priv, wpa_alg alg, +int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len); -int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len); +int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params); struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv); void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx); diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c index 098991a1a44d..2b197f0ab6c7 100644 --- a/src/drivers/driver_wired.c +++ b/src/drivers/driver_wired.c @@ -1,6 +1,7 @@ /* - * WPA Supplicant - wired Ethernet driver interface - * Copyright (c) 2005-2007, Jouni Malinen + * Wired Ethernet driver interface + * Copyright (c) 2005-2009, Jouni Malinen + * Copyright (c) 2004, Gunter Burchardt * * 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 @@ -17,27 +18,374 @@ #include #ifdef __linux__ #include +#include +#include #endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) #include -#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */ +#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ #include "common.h" +#include "eloop.h" #include "driver.h" +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct ieee8023_hdr { + u8 dest[6]; + u8 src[6]; + u16 ethertype; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ static const u8 pae_group_addr[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; struct wpa_driver_wired_data { - void *ctx; - int pf_sock; char ifname[IFNAMSIZ + 1]; + void *ctx; + + int sock; /* raw packet socket for driver access */ + int dhcp_sock; /* socket for dhcp packets */ + int use_pae_group_addr; + + int pf_sock; int membership, multi, iff_allmulti, iff_up; }; +/* TODO: detecting new devices should eventually be changed from using DHCP + * snooping to trigger on any packet from a new layer 2 MAC address, e.g., + * based on ebtables, etc. */ + +struct dhcp_message { + u_int8_t op; + u_int8_t htype; + u_int8_t hlen; + u_int8_t hops; + u_int32_t xid; + u_int16_t secs; + u_int16_t flags; + u_int32_t ciaddr; + u_int32_t yiaddr; + u_int32_t siaddr; + u_int32_t giaddr; + u_int8_t chaddr[16]; + u_int8_t sname[64]; + u_int8_t file[128]; + u_int32_t cookie; + u_int8_t options[308]; /* 312 - cookie */ +}; + + +static int wired_multicast_membership(int sock, int ifindex, + const u8 *addr, int add) +{ +#ifdef __linux__ + struct packet_mreq mreq; + + if (sock < 0) + return -1; + + os_memset(&mreq, 0, sizeof(mreq)); + mreq.mr_ifindex = ifindex; + mreq.mr_type = PACKET_MR_MULTICAST; + mreq.mr_alen = ETH_ALEN; + os_memcpy(mreq.mr_address, addr, ETH_ALEN); + + if (setsockopt(sock, SOL_PACKET, + add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + perror("setsockopt"); + return -1; + } + return 0; +#else /* __linux__ */ + return -1; +#endif /* __linux__ */ +} + + +#ifdef __linux__ +static void handle_data(void *ctx, unsigned char *buf, size_t len) +{ +#ifdef HOSTAPD + struct ieee8023_hdr *hdr; + u8 *pos, *sa; + size_t left; + union wpa_event_data event; + + /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, + * 2 byte ethertype */ + if (len < 14) { + wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", + (unsigned long) len); + return; + } + + hdr = (struct ieee8023_hdr *) buf; + + switch (ntohs(hdr->ethertype)) { + case ETH_P_PAE: + wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); + sa = hdr->src; + os_memset(&event, 0, sizeof(event)); + event.new_sta.addr = sa; + wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); + + pos = (u8 *) (hdr + 1); + left = len - sizeof(*hdr); + drv_event_eapol_rx(ctx, sa, pos, left); + break; + + default: + wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", + ntohs(hdr->ethertype)); + break; + } +#endif /* HOSTAPD */ +} + + +static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + int len; + unsigned char buf[3000]; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + handle_data(eloop_ctx, buf, len); +} + + +static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) +{ + int len; + unsigned char buf[3000]; + struct dhcp_message *msg; + u8 *mac_address; + union wpa_event_data event; + + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + perror("recv"); + return; + } + + /* must contain at least dhcp_message->chaddr */ + if (len < 44) { + wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); + return; + } + + msg = (struct dhcp_message *) buf; + mac_address = (u8 *) &(msg->chaddr); + + wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, + MAC2STR(mac_address)); + + os_memset(&event, 0, sizeof(event)); + event.new_sta.addr = mac_address; + wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event); +} +#endif /* __linux__ */ + + +static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) +{ +#ifdef __linux__ + struct ifreq ifr; + struct sockaddr_ll addr; + struct sockaddr_in addr2; + int n = 1; + + drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); + if (drv->sock < 0) { + perror("socket[PF_PACKET,SOCK_RAW]"); + return -1; + } + + if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) { + printf("Could not register read socket\n"); + return -1; + } + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { + perror("ioctl(SIOCGIFINDEX)"); + return -1; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sll_family = AF_PACKET; + addr.sll_ifindex = ifr.ifr_ifindex; + wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", + addr.sll_ifindex); + + if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind"); + return -1; + } + + /* filter multicast address */ + if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex, + pae_group_addr, 1) < 0) { + wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " + "membership"); + return -1; + } + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); + if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { + perror("ioctl(SIOCGIFHWADDR)"); + return -1; + } + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { + printf("Invalid HW-addr family 0x%04x\n", + ifr.ifr_hwaddr.sa_family); + return -1; + } + os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + /* setup dhcp listen socket for sta detection */ + if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + perror("socket call failed for dhcp"); + return -1; + } + + if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx, + NULL)) { + printf("Could not register read socket\n"); + return -1; + } + + os_memset(&addr2, 0, sizeof(addr2)); + addr2.sin_family = AF_INET; + addr2.sin_port = htons(67); + addr2.sin_addr.s_addr = INADDR_ANY; + + if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, + sizeof(n)) == -1) { + perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); + return -1; + } + if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, + sizeof(n)) == -1) { + perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); + return -1; + } + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ); + if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, + (char *) &ifr, sizeof(ifr)) < 0) { + perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); + return -1; + } + + if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, + sizeof(struct sockaddr)) == -1) { + perror("bind"); + return -1; + } + + return 0; +#else /* __linux__ */ + return -1; +#endif /* __linux__ */ +} + + +static int wired_send_eapol(void *priv, const u8 *addr, + const u8 *data, size_t data_len, int encrypt, + const u8 *own_addr) +{ + struct wpa_driver_wired_data *drv = priv; + struct ieee8023_hdr *hdr; + size_t len; + u8 *pos; + int res; + + len = sizeof(*hdr) + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + printf("malloc() failed for wired_send_eapol(len=%lu)\n", + (unsigned long) len); + return -1; + } + + os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, + ETH_ALEN); + os_memcpy(hdr->src, own_addr, ETH_ALEN); + hdr->ethertype = htons(ETH_P_PAE); + + pos = (u8 *) (hdr + 1); + os_memcpy(pos, data, data_len); + + res = send(drv->sock, (u8 *) hdr, len, 0); + os_free(hdr); + + if (res < 0) { + perror("wired_send_eapol: send"); + printf("wired_send_eapol - packet len: %lu - failed\n", + (unsigned long) len); + } + + return res; +} + + +static void * wired_driver_hapd_init(struct hostapd_data *hapd, + struct wpa_init_params *params) +{ + struct wpa_driver_wired_data *drv; + + drv = os_zalloc(sizeof(struct wpa_driver_wired_data)); + if (drv == NULL) { + printf("Could not allocate memory for wired driver data\n"); + return NULL; + } + + drv->ctx = hapd; + os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); + drv->use_pae_group_addr = params->use_pae_group_addr; + + if (wired_init_sockets(drv, params->own_addr)) { + os_free(drv); + return NULL; + } + + return drv; +} + + +static void wired_driver_hapd_deinit(void *priv) +{ + struct wpa_driver_wired_data *drv = priv; + + if (drv->sock >= 0) + close(drv->sock); + + if (drv->dhcp_sock >= 0) + close(drv->dhcp_sock); + + os_free(drv); +} + + static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid) { ssid[0] = 0; @@ -53,6 +401,14 @@ static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid) } +static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa) +{ + os_memset(capa, 0, sizeof(*capa)); + capa->flags = WPA_DRIVER_FLAGS_WIRED; + return 0; +} + + static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags) { struct ifreq ifr; @@ -118,7 +474,7 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) ifr.ifr_hwaddr.sa_family = AF_UNSPEC; os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); #endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) { struct sockaddr_dl *dlp; dlp = (struct sockaddr_dl *) &ifr.ifr_addr; @@ -128,9 +484,9 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) dlp->sdl_nlen = 0; dlp->sdl_alen = ETH_ALEN; dlp->sdl_slen = 0; - os_memcpy(LLADDR(dlp), addr, ETH_ALEN); + os_memcpy(LLADDR(dlp), addr, ETH_ALEN); } -#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */ +#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) { struct sockaddr *sap; @@ -151,34 +507,6 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) } -static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv, - const u8 *addr, int add) -{ -#ifdef __linux__ - struct packet_mreq mreq; - - if (drv->pf_sock == -1) - return -1; - - os_memset(&mreq, 0, sizeof(mreq)); - mreq.mr_ifindex = if_nametoindex(drv->ifname); - mreq.mr_type = PACKET_MR_MULTICAST; - mreq.mr_alen = ETH_ALEN; - os_memcpy(mreq.mr_address, addr, ETH_ALEN); - - if (setsockopt(drv->pf_sock, SOL_PACKET, - add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - perror("setsockopt"); - return -1; - } - return 0; -#else /* __linux__ */ - return -1; -#endif /* __linux__ */ -} - - static void * wpa_driver_wired_init(void *ctx, const char *ifname) { struct wpa_driver_wired_data *drv; @@ -195,16 +523,18 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname) if (drv->pf_sock < 0) perror("socket(PF_PACKET)"); #else /* __linux__ */ - drv->pf_sock = -1; + drv->pf_sock = -1; #endif /* __linux__ */ - + if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 && !(flags & IFF_UP) && wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) { drv->iff_up = 1; } - if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) { + if (wired_multicast_membership(drv->pf_sock, + if_nametoindex(drv->ifname), + pae_group_addr, 1) == 0) { wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " "packet socket", __func__); drv->membership = 1; @@ -242,7 +572,9 @@ static void wpa_driver_wired_deinit(void *priv) int flags; if (drv->membership && - wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) { + wired_multicast_membership(drv->pf_sock, + if_nametoindex(drv->ifname), + pae_group_addr, 0) < 0) { wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " "group (PACKET)", __func__); } @@ -271,16 +603,20 @@ static void wpa_driver_wired_deinit(void *priv) if (drv->pf_sock != -1) close(drv->pf_sock); - + os_free(drv); } const struct wpa_driver_ops wpa_driver_wired_ops = { .name = "wired", - .desc = "wpa_supplicant wired Ethernet driver", + .desc = "Wired Ethernet driver", + .hapd_init = wired_driver_hapd_init, + .hapd_deinit = wired_driver_hapd_deinit, + .hapd_send_eapol = wired_send_eapol, .get_ssid = wpa_driver_wired_get_ssid, .get_bssid = wpa_driver_wired_get_bssid, + .get_capa = wpa_driver_wired_get_capa, .init = wpa_driver_wired_init, .deinit = wpa_driver_wired_deinit, }; diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index d278797d7de2..bffbbde72b77 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -1,5 +1,5 @@ /* - * WPA Supplicant / driver interface list + * Driver interface list * Copyright (c) 2004-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify @@ -24,9 +24,6 @@ extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ #ifdef CONFIG_DRIVER_HOSTAP extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ #endif /* CONFIG_DRIVER_HOSTAP */ -#ifdef CONFIG_DRIVER_PRISM54 -extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */ -#endif /* CONFIG_DRIVER_PRISM54 */ #ifdef CONFIG_DRIVER_HERMES extern struct wpa_driver_ops wpa_driver_hermes_ops; /* driver_hermes.c */ #endif /* CONFIG_DRIVER_HERMES */ @@ -64,9 +61,6 @@ extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */ #ifdef CONFIG_DRIVER_OSX extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */ #endif /* CONFIG_DRIVER_OSX */ -#ifdef CONFIG_DRIVER_PS3 -extern struct wpa_driver_ops wpa_driver_ps3_ops; /* driver_ps3.c */ -#endif /* CONFIG_DRIVER_PS3 */ #ifdef CONFIG_DRIVER_IPHONE extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */ #endif /* CONFIG_DRIVER_IPHONE */ @@ -74,9 +68,15 @@ extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */ /* driver_roboswitch.c */ extern struct wpa_driver_ops wpa_driver_roboswitch_ops; #endif /* CONFIG_DRIVER_ROBOSWITCH */ +#ifdef CONFIG_DRIVER_ATHEROS +extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ +#endif /* CONFIG_DRIVER_ATHEROS */ +#ifdef CONFIG_DRIVER_NONE +extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ +#endif /* CONFIG_DRIVER_NONE */ -struct wpa_driver_ops *wpa_supplicant_drivers[] = +struct wpa_driver_ops *wpa_drivers[] = { #ifdef CONFIG_DRIVER_WEXT &wpa_driver_wext_ops, @@ -87,9 +87,6 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] = #ifdef CONFIG_DRIVER_HOSTAP &wpa_driver_hostap_ops, #endif /* CONFIG_DRIVER_HOSTAP */ -#ifdef CONFIG_DRIVER_PRISM54 - &wpa_driver_prism54_ops, -#endif /* CONFIG_DRIVER_PRISM54 */ #ifdef CONFIG_DRIVER_HERMES &wpa_driver_hermes_ops, #endif /* CONFIG_DRIVER_HERMES */ @@ -126,14 +123,17 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] = #ifdef CONFIG_DRIVER_OSX &wpa_driver_osx_ops, #endif /* CONFIG_DRIVER_OSX */ -#ifdef CONFIG_DRIVER_PS3 - &wpa_driver_ps3_ops, -#endif /* CONFIG_DRIVER_PS3 */ #ifdef CONFIG_DRIVER_IPHONE &wpa_driver_iphone_ops, #endif /* CONFIG_DRIVER_IPHONE */ #ifdef CONFIG_DRIVER_ROBOSWITCH &wpa_driver_roboswitch_ops, #endif /* CONFIG_DRIVER_ROBOSWITCH */ +#ifdef CONFIG_DRIVER_ATHEROS + &wpa_driver_atheros_ops, +#endif /* CONFIG_DRIVER_ATHEROS */ +#ifdef CONFIG_DRIVER_NONE + &wpa_driver_none_ops, +#endif /* CONFIG_DRIVER_NONE */ NULL }; diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak new file mode 100644 index 000000000000..b76b22953a38 --- /dev/null +++ b/src/drivers/drivers.mak @@ -0,0 +1,181 @@ +##### COMMON DRIVERS + +ifdef CONFIG_DRIVER_HOSTAP +DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP +DRV_OBJS += ../src/drivers/driver_hostap.o +CONFIG_WIRELESS_EXTENSION=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_WIRED +DRV_CFLAGS += -DCONFIG_DRIVER_WIRED +DRV_OBJS += ../src/drivers/driver_wired.o +endif + +ifdef CONFIG_DRIVER_MADWIFI +DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI +DRV_OBJS += ../src/drivers/driver_madwifi.o +CONFIG_WIRELESS_EXTENSION=y +CONFIG_L2_PACKET=linux +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_NL80211 +DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 +DRV_OBJS += ../src/drivers/driver_nl80211.o +DRV_OBJS += ../src/utils/radiotap.o +NEED_SME=y +NEED_AP_MLME=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +DRV_LIBS += -lnl + +ifdef CONFIG_LIBNL20 +DRV_LIBS += -lnl-genl +DRV_CFLAGS += -DCONFIG_LIBNL20 +endif +endif + +ifdef CONFIG_DRIVER_BSD +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=freebsd +endif +DRV_CFLAGS += -DCONFIG_DRIVER_BSD +DRV_OBJS += ../src/drivers/driver_bsd.o +CONFIG_L2_FREEBSD=y +CONFIG_DNET_PCAP=y +endif + +ifdef CONFIG_DRIVER_TEST +DRV_CFLAGS += -DCONFIG_DRIVER_TEST +DRV_OBJS += ../src/drivers/driver_test.o +NEED_AP_MLME=y +endif + +ifdef CONFIG_DRIVER_NONE +DRV_CFLAGS += -DCONFIG_DRIVER_NONE +DRV_OBJS += ../src/drivers/driver_none.o +endif + +##### PURE AP DRIVERS + +ifdef CONFIG_DRIVER_ATHEROS +DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS +DRV_AP_OBJS += ../src/drivers/driver_atheros.o +CONFIG_L2_PACKET=linux +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +##### PURE CLIENT DRIVERS + +ifdef CONFIG_DRIVER_WEXT +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT +CONFIG_WIRELESS_EXTENSION=y +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_HERMES +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_HERMES +DRV_WPA_OBJS += ../src/drivers/driver_hermes.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_ATMEL +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ATMEL +DRV_WPA_OBJS += ../src/drivers/driver_atmel.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_NDISWRAPPER +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER +DRV_WPA_OBJS += ../src/drivers/driver_ndiswrapper.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_RALINK +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK +DRV_WPA_OBJS += ../src/drivers/driver_ralink.o +NEED_NETLINK=y +NEED_LINUX_IOCTL=y +endif + +ifdef CONFIG_DRIVER_BROADCOM +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM +DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o +endif + +ifdef CONFIG_DRIVER_IPW +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPW +DRV_WPA_OBJS += ../src/drivers/driver_ipw.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_NDIS +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS +DRV_WPA_OBJS += ../src/drivers/driver_ndis.o +ifdef CONFIG_NDIS_EVENTS_INTEGRATED +DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o +endif +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=pcap +endif +CONFIG_WINPCAP=y +ifdef CONFIG_USE_NDISUIO +DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO +endif +endif + +ifdef CONFIG_DRIVER_OSX +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX +DRV_WPA_OBJS += ../src/drivers/driver_osx.o +DRV_WPA_LDFLAGS += -framework CoreFoundation +DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 +endif + +ifdef CONFIG_DRIVER_IPHONE +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE +DRV_WPA_OBJS += ../src/drivers/driver_iphone.o +DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o +DRV_WPA_LDFLAGS += -framework CoreFoundation +endif + +ifdef CONFIG_DRIVER_ROBOSWITCH +DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH +DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o +endif + +ifdef CONFIG_WIRELESS_EXTENSION +DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION +DRV_WPA_OBJS += ../src/drivers/driver_wext.o +endif + +ifdef NEED_NETLINK +DRV_OBJS += ../src/drivers/netlink.o +endif + +ifdef NEED_LINUX_IOCTL +DRV_OBJS += ../src/drivers/linux_ioctl.o +endif + + +##### COMMON VARS +DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) +DRV_WPA_CFLAGS += $(DRV_CFLAGS) +DRV_AP_CFLAGS += $(DRV_CFLAGS) + +DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS) +DRV_WPA_LIBS += $(DRV_LIBS) +DRV_AP_LIBS += $(DRV_LIBS) + +DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS) +DRV_WPA_OBJS += $(DRV_OBJS) +DRV_AP_OBJS += $(DRV_OBJS) + +DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS) +DRV_WPA_LDFLAGS += $(DRV_LDFLAGS) +DRV_AP_LDFLAGS += $(DRV_LDFLAGS) diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c new file mode 100644 index 000000000000..0d6cf5416bee --- /dev/null +++ b/src/drivers/linux_ioctl.c @@ -0,0 +1,198 @@ +/* + * Linux ioctl helper functions for driver wrappers + * Copyright (c) 2002-2010, Jouni Malinen + * + * 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 "utils/includes.h" +#include +#include +#include + +#include "utils/common.h" +#include "linux_ioctl.h" + + +int linux_set_iface_flags(int sock, const char *ifname, int dev_up) +{ + struct ifreq ifr; + + if (sock < 0) + return -1; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + + if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { + wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", + ifname, strerror(errno)); + return -1; + } + + if (dev_up) { + if (ifr.ifr_flags & IFF_UP) + return 0; + ifr.ifr_flags |= IFF_UP; + } else { + if (!(ifr.ifr_flags & IFF_UP)) + return 0; + ifr.ifr_flags &= ~IFF_UP; + } + + if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { + wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s", + ifname, strerror(errno)); + return -1; + } + + return 0; +} + + +int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr) +{ + struct ifreq ifr; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { + wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s", + ifname, strerror(errno)); + return -1; + } + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { + wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x", + ifname, ifr.ifr_hwaddr.sa_family); + return -1; + } + os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + return 0; +} + + +int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr) +{ + struct ifreq ifr; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + + if (ioctl(sock, SIOCSIFHWADDR, &ifr)) { + wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s", + ifname, strerror(errno)); + return -1; + } + + return 0; +} + + +#ifndef SIOCBRADDBR +#define SIOCBRADDBR 0x89a0 +#endif +#ifndef SIOCBRDELBR +#define SIOCBRDELBR 0x89a1 +#endif +#ifndef SIOCBRADDIF +#define SIOCBRADDIF 0x89a2 +#endif +#ifndef SIOCBRDELIF +#define SIOCBRDELIF 0x89a3 +#endif + + +int linux_br_add(int sock, const char *brname) +{ + if (ioctl(sock, SIOCBRADDBR, brname) < 0) { + wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s", + brname, strerror(errno)); + return -1; + } + + return 0; +} + + +int linux_br_del(int sock, const char *brname) +{ + if (ioctl(sock, SIOCBRDELBR, brname) < 0) { + wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s", + brname, strerror(errno)); + return -1; + } + + return 0; +} + + +int linux_br_add_if(int sock, const char *brname, const char *ifname) +{ + struct ifreq ifr; + int ifindex; + + ifindex = if_nametoindex(ifname); + if (ifindex == 0) + return -1; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_ifindex = ifindex; + if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) { + wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge " + "%s: %s", ifname, brname, strerror(errno)); + return -1; + } + + return 0; +} + + +int linux_br_del_if(int sock, const char *brname, const char *ifname) +{ + struct ifreq ifr; + int ifindex; + + ifindex = if_nametoindex(ifname); + if (ifindex == 0) + return -1; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_ifindex = ifindex; + if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) { + wpa_printf(MSG_DEBUG, "Could not remove interface %s from " + "bridge %s: %s", ifname, brname, strerror(errno)); + return -1; + } + + return 0; +} + + +int linux_br_get(char *brname, const char *ifname) +{ + char path[128], brlink[128], *pos; + os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge", + ifname); + os_memset(brlink, 0, sizeof(brlink)); + if (readlink(path, brlink, sizeof(brlink) - 1) < 0) + return -1; + pos = os_strrchr(brlink, '/'); + if (pos == NULL) + return -1; + pos++; + os_strlcpy(brname, pos, IFNAMSIZ); + return 0; +} diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h new file mode 100644 index 000000000000..a5557383d8fe --- /dev/null +++ b/src/drivers/linux_ioctl.h @@ -0,0 +1,27 @@ +/* + * Linux ioctl helper functions for driver wrappers + * Copyright (c) 2002-2010, Jouni Malinen + * + * 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 LINUX_IOCTL_H +#define LINUX_IOCTL_H + +int linux_set_iface_flags(int sock, const char *ifname, int dev_up); +int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr); +int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr); +int linux_br_add(int sock, const char *brname); +int linux_br_del(int sock, const char *brname); +int linux_br_add_if(int sock, const char *brname, const char *ifname); +int linux_br_del_if(int sock, const char *brname, const char *ifname); +int linux_br_get(char *brname, const char *ifname); + +#endif /* LINUX_IOCTL_H */ diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c new file mode 100644 index 000000000000..ad15b1d62a8d --- /dev/null +++ b/src/drivers/netlink.c @@ -0,0 +1,204 @@ +/* + * Netlink helper functions for driver wrappers + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 "priv_netlink.h" +#include "netlink.h" + + +struct netlink_data { + struct netlink_config *cfg; + int sock; +}; + + +static void netlink_receive_link(struct netlink_data *netlink, + void (*cb)(void *ctx, struct ifinfomsg *ifi, + u8 *buf, size_t len), + struct nlmsghdr *h) +{ + if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg)) + return; + cb(netlink->cfg->ctx, NLMSG_DATA(h), + NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), + NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg))); +} + + +static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct netlink_data *netlink = eloop_ctx; + char buf[8192]; + int left; + struct sockaddr_nl from; + socklen_t fromlen; + struct nlmsghdr *h; + int max_events = 10; + +try_again: + fromlen = sizeof(from); + left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, + (struct sockaddr *) &from, &fromlen); + if (left < 0) { + if (errno != EINTR && errno != EAGAIN) + wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s", + strerror(errno)); + return; + } + + h = (struct nlmsghdr *) buf; + while (NLMSG_OK(h, left)) { + switch (h->nlmsg_type) { + case RTM_NEWLINK: + netlink_receive_link(netlink, netlink->cfg->newlink_cb, + h); + break; + case RTM_DELLINK: + netlink_receive_link(netlink, netlink->cfg->dellink_cb, + h); + break; + } + + h = NLMSG_NEXT(h, left); + } + + if (left > 0) { + wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of " + "netlink message", left); + } + + if (--max_events > 0) { + /* + * Try to receive all events in one eloop call in order to + * limit race condition on cases where AssocInfo event, Assoc + * event, and EAPOL frames are received more or less at the + * same time. We want to process the event messages first + * before starting EAPOL processing. + */ + goto try_again; + } +} + + +struct netlink_data * netlink_init(struct netlink_config *cfg) +{ + struct netlink_data *netlink; + struct sockaddr_nl local; + + netlink = os_zalloc(sizeof(*netlink)); + if (netlink == NULL) + return NULL; + + netlink->cfg = cfg; + + netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (netlink->sock < 0) { + wpa_printf(MSG_ERROR, "netlink: Failed to open netlink " + "socket: %s", strerror(errno)); + netlink_deinit(netlink); + return NULL; + } + + os_memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_groups = RTMGRP_LINK; + if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0) + { + wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink " + "socket: %s", strerror(errno)); + netlink_deinit(netlink); + return NULL; + } + + eloop_register_read_sock(netlink->sock, netlink_receive, netlink, + NULL); + + return netlink; +} + + +void netlink_deinit(struct netlink_data *netlink) +{ + if (netlink == NULL) + return; + if (netlink->sock >= 0) { + eloop_unregister_read_sock(netlink->sock); + close(netlink->sock); + } + os_free(netlink->cfg); + os_free(netlink); +} + +int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, + int linkmode, int operstate) +{ + struct { + struct nlmsghdr hdr; + struct ifinfomsg ifinfo; + char opts[16]; + } req; + struct rtattr *rta; + static int nl_seq; + ssize_t ret; + + os_memset(&req, 0, sizeof(req)); + + req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.hdr.nlmsg_type = RTM_SETLINK; + req.hdr.nlmsg_flags = NLM_F_REQUEST; + req.hdr.nlmsg_seq = ++nl_seq; + req.hdr.nlmsg_pid = 0; + + req.ifinfo.ifi_family = AF_UNSPEC; + req.ifinfo.ifi_type = 0; + req.ifinfo.ifi_index = ifindex; + req.ifinfo.ifi_flags = 0; + req.ifinfo.ifi_change = 0; + + if (linkmode != -1) { + rta = aliasing_hide_typecast( + ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), + struct rtattr); + rta->rta_type = IFLA_LINKMODE; + rta->rta_len = RTA_LENGTH(sizeof(char)); + *((char *) RTA_DATA(rta)) = linkmode; + req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + + RTA_LENGTH(sizeof(char)); + } + if (operstate != -1) { + rta = aliasing_hide_typecast( + ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), + struct rtattr); + rta->rta_type = IFLA_OPERSTATE; + rta->rta_len = RTA_LENGTH(sizeof(char)); + *((char *) RTA_DATA(rta)) = operstate; + req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + + RTA_LENGTH(sizeof(char)); + } + + wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d", + linkmode, operstate); + + ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA " + "failed: %s (assume operstate is not supported)", + strerror(errno)); + } + + return ret < 0 ? -1 : 0; +} diff --git a/src/drivers/netlink.h b/src/drivers/netlink.h new file mode 100644 index 000000000000..bcbfbb51fdd7 --- /dev/null +++ b/src/drivers/netlink.h @@ -0,0 +1,33 @@ +/* + * Netlink helper functions for driver wrappers + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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 NETLINK_H +#define NETLINK_H + +struct netlink_data; + +struct netlink_config { + void *ctx; + void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, + size_t len); + void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, + size_t len); +}; + +struct netlink_data * netlink_init(struct netlink_config *cfg); +void netlink_deinit(struct netlink_data *netlink); +int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, + int linkmode, int operstate); + +#endif /* NETLINK_H */ diff --git a/src/common/nl80211_copy.h b/src/drivers/nl80211_copy.h similarity index 86% rename from src/common/nl80211_copy.h rename to src/drivers/nl80211_copy.h index 45db17f81aa3..2ea3edeee7aa 100644 --- a/src/common/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -3,7 +3,7 @@ /* * 802.11 netlink interface public header * - * Copyright 2006, 2007, 2008 Johannes Berg + * Copyright 2006-2010 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch @@ -270,6 +270,66 @@ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices * associated with this wiphy must be down and will follow. * + * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified + * channel for the specified amount of time. This can be used to do + * off-channel operations like transmit a Public Action frame and wait for + * a response while being associated to an AP on another channel. + * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which + * radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the + * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be + * optionally used to specify additional channel parameters. + * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds + * to remain on the channel. This command is also used as an event to + * notify when the requested duration starts (it may take a while for the + * driver to schedule this time due to other concurrent needs for the + * radio). + * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) + * that will be included with any events pertaining to this request; + * the cookie is also used to cancel the request. + * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a + * pending remain-on-channel duration if the desired operation has been + * completed prior to expiration of the originally requested duration. + * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the + * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to + * uniquely identify the request. + * This command is also used as an event to notify when a requested + * remain-on-channel duration has expired. + * + * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX + * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface + * and @NL80211_ATTR_TX_RATES the set of allowed rates. + * + * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames + * (via @NL80211_CMD_ACTION) for processing in userspace. This command + * requires an interface index and a match attribute containing the first + * few bytes of the frame that should match, e.g. a single byte for only + * a category match or four bytes for vendor frames including the OUI. + * The registration cannot be dropped, but is removed automatically + * when the netlink socket is closed. Multiple registrations can be made. + * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This + * command is used both as a request to transmit an Action frame and as an + * event indicating reception of an Action frame that was not processed in + * kernel code, but is for us (i.e., which may need to be processed in a + * user space application). %NL80211_ATTR_FRAME is used to specify the + * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and + * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on + * which channel the frame is to be transmitted or was received. This + * channel has to be the current channel (remain-on-channel or the + * operational channel). When called, this operation returns a cookie + * (%NL80211_ATTR_COOKIE) that will be included with the TX status event + * pertaining to the TX request. + * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame + * transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies + * the TX command and %NL80211_ATTR_FRAME includes the contents of the + * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged + * the frame. + * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command + * is used to configure connection quality monitoring notification trigger + * levels. + * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This + * command is used as an event to indicate the that a trigger level was + * reached. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -349,6 +409,25 @@ enum nl80211_commands { NL80211_CMD_GET_SURVEY, NL80211_CMD_NEW_SURVEY_RESULTS, + NL80211_CMD_SET_PMKSA, + NL80211_CMD_DEL_PMKSA, + NL80211_CMD_FLUSH_PMKSA, + + NL80211_CMD_REMAIN_ON_CHANNEL, + NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, + + NL80211_CMD_SET_TX_BITRATE_MASK, + + NL80211_CMD_REGISTER_ACTION, + NL80211_CMD_ACTION, + NL80211_CMD_ACTION_TX_STATUS, + + NL80211_CMD_SET_POWER_SAVE, + NL80211_CMD_GET_POWER_SAVE, + + NL80211_CMD_SET_CQM, + NL80211_CMD_NOTIFY_CQM, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -398,6 +477,8 @@ enum nl80211_commands { * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length * larger than or equal to this use RTS/CTS handshake); allowed range: * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 + * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 + * section 7.3.2.9; dot11CoverageClass; u8 * * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFNAME: network interface name @@ -598,6 +679,36 @@ enum nl80211_commands { * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute * containing info as possible, see &enum survey_info. * + * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. + * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can + * cache, a wiphy attribute. + * + * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. + * + * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. + * + * @NL80211_ATTR_TX_RATES: Nested set of attributes + * (enum nl80211_tx_rate_attributes) describing TX rates per band. The + * enum nl80211_band value is used as the index (nla_type() of the nested + * data. If a band is not included, it will be configured to allow all + * rates based on negotiated supported rates information. This attribute + * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. + * + * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain + * at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION. + * + * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was + * acknowledged by the recipient. + * + * @NL80211_ATTR_CQM: connection quality monitor configuration in a + * nested attribute with %NL80211_ATTR_CQM_* sub-attributes. + * + * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command + * is requesting a local authentication/association state change without + * invoking actual management frame exchange. This can be used with + * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE, + * NL80211_CMD_DISASSOCIATE. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -732,6 +843,27 @@ enum nl80211_attrs { NL80211_ATTR_SURVEY_INFO, + NL80211_ATTR_PMKID, + NL80211_ATTR_MAX_NUM_PMKIDS, + + NL80211_ATTR_DURATION, + + NL80211_ATTR_COOKIE, + + NL80211_ATTR_WIPHY_COVERAGE_CLASS, + + NL80211_ATTR_TX_RATES, + + NL80211_ATTR_FRAME_MATCH, + + NL80211_ATTR_ACK, + + NL80211_ATTR_PS_STATE, + + NL80211_ATTR_CQM, + + NL80211_ATTR_LOCAL_STATE_CHANGE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1312,13 +1444,20 @@ enum nl80211_channel_type { * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the - * raw information elements from the probe response/beacon (bin) + * raw information elements from the probe response/beacon (bin); + * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are + * from a Probe Response frame; otherwise they are from a Beacon frame. + * However, if the driver does not indicate the source of the IEs, these + * IEs may be from either frame subtype. * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * in unspecified units, scaled to 0..100 (u8) * @NL80211_BSS_STATUS: status, if this BSS is "used" * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms + * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information + * elements from a Beacon frame (bin); not present if no Beacon frame has + * yet been received * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -1334,6 +1473,7 @@ enum nl80211_bss { NL80211_BSS_SIGNAL_UNSPEC, NL80211_BSS_STATUS, NL80211_BSS_SEEN_MS_AGO, + NL80211_BSS_BEACON_IES, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -1431,4 +1571,74 @@ enum nl80211_key_attributes { NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 }; +/** + * enum nl80211_tx_rate_attributes - TX rate set attributes + * @__NL80211_TXRATE_INVALID: invalid + * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection + * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with + * 1 = 500 kbps) but without the IE length restriction (at most + * %NL80211_MAX_SUPP_RATES in a single array). + * @__NL80211_TXRATE_AFTER_LAST: internal + * @NL80211_TXRATE_MAX: highest TX rate attribute + */ +enum nl80211_tx_rate_attributes { + __NL80211_TXRATE_INVALID, + NL80211_TXRATE_LEGACY, + + /* keep last */ + __NL80211_TXRATE_AFTER_LAST, + NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 +}; + +/** + * enum nl80211_band - Frequency band + * @NL80211_BAND_2GHZ - 2.4 GHz ISM band + * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz) + */ +enum nl80211_band { + NL80211_BAND_2GHZ, + NL80211_BAND_5GHZ, +}; + +enum nl80211_ps_state { + NL80211_PS_DISABLED, + NL80211_PS_ENABLED, +}; + +/** + * enum nl80211_attr_cqm - connection quality monitor attributes + * @__NL80211_ATTR_CQM_INVALID: invalid + * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies + * the threshold for the RSSI level at which an event will be sent. Zero + * to disable. + * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies + * the minimum amount the RSSI level must change after an event before a + * new event may be issued (to reduce effects of RSSI oscillation). + * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event + * @__NL80211_ATTR_CQM_AFTER_LAST: internal + * @NL80211_ATTR_CQM_MAX: highest key attribute + */ +enum nl80211_attr_cqm { + __NL80211_ATTR_CQM_INVALID, + NL80211_ATTR_CQM_RSSI_THOLD, + NL80211_ATTR_CQM_RSSI_HYST, + NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, + + /* keep last */ + __NL80211_ATTR_CQM_AFTER_LAST, + NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1 +}; + +/** + * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event + * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the + * configured threshold + * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the + * configured threshold + */ +enum nl80211_cqm_rssi_threshold_event { + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h index 2a31e251a013..23eff83fadd4 100644 --- a/src/drivers/priv_netlink.h +++ b/src/drivers/priv_netlink.h @@ -53,8 +53,17 @@ #define NLMSG_ALIGNTO 4 #define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)) +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) #define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) #define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0))) +#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ + (struct nlmsghdr *) \ + (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) +#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ + (int) (nlh)->nlmsg_len <= (len)) +#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) #define RTA_ALIGNTO 4 #define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)) diff --git a/src/drivers/radiotap.c b/src/drivers/radiotap.c deleted file mode 100644 index 804473fa4bfb..000000000000 --- a/src/drivers/radiotap.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Radiotap parser - * - * Copyright 2007 Andy Green - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - * - * - * Modified for userspace by Johannes Berg - * I only modified some things on top to ease syncing should bugs be found. - */ - -#include "includes.h" - -#include "common.h" -#include "radiotap_iter.h" - -#define le16_to_cpu le_to_host16 -#define le32_to_cpu le_to_host32 -#define __le32 uint32_t -#define ulong unsigned long -#define unlikely(cond) (cond) -#define get_unaligned(p) \ -({ \ - struct packed_dummy_struct { \ - typeof(*(p)) __val; \ - } __attribute__((packed)) *__ptr = (void *) (p); \ - \ - __ptr->__val; \ -}) - -/* function prototypes and related defs are in radiotap_iter.h */ - -/** - * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization - * @iterator: radiotap_iterator to initialize - * @radiotap_header: radiotap header to parse - * @max_length: total length we can parse into (eg, whole packet length) - * - * Returns: 0 or a negative error code if there is a problem. - * - * This function initializes an opaque iterator struct which can then - * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap - * argument which is present in the header. It knows about extended - * present headers and handles them. - * - * How to use: - * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator - * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) - * checking for a good 0 return code. Then loop calling - * __ieee80211_radiotap_iterator_next()... it returns either 0, - * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. - * The iterator's @this_arg member points to the start of the argument - * associated with the current argument index that is present, which can be - * found in the iterator's @this_arg_index member. This arg index corresponds - * to the IEEE80211_RADIOTAP_... defines. - * - * Radiotap header length: - * You can find the CPU-endian total radiotap header length in - * iterator->max_length after executing ieee80211_radiotap_iterator_init() - * successfully. - * - * Alignment Gotcha: - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - * - * Example code: - * See Documentation/networking/radiotap-headers.txt - */ - -int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length) -{ - /* Linux only supports version 0 radiotap format */ - if (radiotap_header->it_version) - return -EINVAL; - - /* sanity check for allowed length and radiotap length field */ - if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) - return -EINVAL; - - iterator->rtheader = radiotap_header; - iterator->max_length = le16_to_cpu(get_unaligned( - &radiotap_header->it_len)); - iterator->arg_index = 0; - iterator->bitmap_shifter = le32_to_cpu(get_unaligned( - &radiotap_header->it_present)); - iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); - iterator->this_arg = NULL; - - /* find payload start allowing for extended bitmap(s) */ - - if (unlikely(iterator->bitmap_shifter & (1<arg)) & - (1<arg += sizeof(u32); - - /* - * check for insanity where the present bitmaps - * keep claiming to extend up to or even beyond the - * stated radiotap header length - */ - - if (((ulong)iterator->arg - (ulong)iterator->rtheader) - > (ulong)iterator->max_length) - return -EINVAL; - } - - iterator->arg += sizeof(u32); - - /* - * no need to check again for blowing past stated radiotap - * header length, because ieee80211_radiotap_iterator_next - * checks it before it is dereferenced - */ - } - - /* we are all initialized happily */ - - return 0; -} - - -/** - * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg - * @iterator: radiotap_iterator to move to next arg (if any) - * - * Returns: 0 if there is an argument to handle, - * -ENOENT if there are no more args or -EINVAL - * if there is something else wrong. - * - * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) - * in @this_arg_index and sets @this_arg to point to the - * payload for the field. It takes care of alignment handling and extended - * present fields. @this_arg can be changed by the caller (eg, - * incremented to move inside a compound argument like - * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in - * little-endian format whatever the endianess of your CPU. - * - * Alignment Gotcha: - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - */ - -int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator) -{ - - /* - * small length lookup table for all radiotap types we heard of - * starting from b0 in the bitmap, so we can walk the payload - * area of the radiotap header - * - * There is a requirement to pad args, so that args - * of a given length must begin at a boundary of that length - * -- but note that compound args are allowed (eg, 2 x u16 - * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not - * a reliable indicator of alignment requirement. - * - * upper nybble: content alignment for arg - * lower nybble: content length for arg - */ - - static const u8 rt_sizes[] = { - [IEEE80211_RADIOTAP_TSFT] = 0x88, - [IEEE80211_RADIOTAP_FLAGS] = 0x11, - [IEEE80211_RADIOTAP_RATE] = 0x11, - [IEEE80211_RADIOTAP_CHANNEL] = 0x24, - [IEEE80211_RADIOTAP_FHSS] = 0x22, - [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, - [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, - [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, - [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, - [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, - [IEEE80211_RADIOTAP_ANTENNA] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, - [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, - [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, - [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, - [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, - /* - * add more here as they are defined in - * include/net/ieee80211_radiotap.h - */ - }; - - /* - * for every radiotap entry we can at - * least skip (by knowing the length)... - */ - - while (iterator->arg_index < (int) sizeof(rt_sizes)) { - int hit = 0; - int pad; - - if (!(iterator->bitmap_shifter & 1)) - goto next_entry; /* arg not present */ - - /* - * arg is present, account for alignment padding - * 8-bit args can be at any alignment - * 16-bit args must start on 16-bit boundary - * 32-bit args must start on 32-bit boundary - * 64-bit args must start on 64-bit boundary - * - * note that total arg size can differ from alignment of - * elements inside arg, so we use upper nybble of length - * table to base alignment on - * - * also note: these alignments are ** relative to the - * start of the radiotap header **. There is no guarantee - * that the radiotap header itself is aligned on any - * kind of boundary. - * - * the above is why get_unaligned() is used to dereference - * multibyte elements from the radiotap area - */ - - pad = (((ulong)iterator->arg) - - ((ulong)iterator->rtheader)) & - ((rt_sizes[iterator->arg_index] >> 4) - 1); - - if (pad) - iterator->arg += - (rt_sizes[iterator->arg_index] >> 4) - pad; - - /* - * this is what we will return to user, but we need to - * move on first so next call has something fresh to test - */ - iterator->this_arg_index = iterator->arg_index; - iterator->this_arg = iterator->arg; - hit = 1; - - /* internally move on the size of this arg */ - iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; - - /* - * check for insanity where we are given a bitmap that - * claims to have more arg content than the length of the - * radiotap section. We will normally end up equalling this - * max_length on the last arg, never exceeding it. - */ - - if (((ulong)iterator->arg - (ulong)iterator->rtheader) > - (ulong) iterator->max_length) - return -EINVAL; - - next_entry: - iterator->arg_index++; - if (unlikely((iterator->arg_index & 31) == 0)) { - /* completed current u32 bitmap */ - if (iterator->bitmap_shifter & 1) { - /* b31 was set, there is more */ - /* move to next u32 bitmap */ - iterator->bitmap_shifter = le32_to_cpu( - get_unaligned(iterator->next_bitmap)); - iterator->next_bitmap++; - } else - /* no more bitmaps: end */ - iterator->arg_index = sizeof(rt_sizes); - } else /* just try the next bit */ - iterator->bitmap_shifter >>= 1; - - /* if we found a valid arg earlier, return it now */ - if (hit) - return 0; - } - - /* we don't know how to handle any more args, we're done */ - return -ENOENT; -} diff --git a/src/drivers/radiotap_iter.h b/src/drivers/radiotap_iter.h deleted file mode 100644 index 92a798a67023..000000000000 --- a/src/drivers/radiotap_iter.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __RADIOTAP_ITER_H -#define __RADIOTAP_ITER_H - -#include "radiotap.h" - -/* Radiotap header iteration - * implemented in radiotap.c - */ -/** - * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args - * @rtheader: pointer to the radiotap header we are walking through - * @max_length: length of radiotap header in cpu byte ordering - * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg - * @this_arg: pointer to current radiotap arg - * @arg_index: internal next argument index - * @arg: internal next argument pointer - * @next_bitmap: internal pointer to next present u32 - * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present - */ - -struct ieee80211_radiotap_iterator { - struct ieee80211_radiotap_header *rtheader; - int max_length; - int this_arg_index; - unsigned char *this_arg; - - int arg_index; - unsigned char *arg; - uint32_t *next_bitmap; - uint32_t bitmap_shifter; -}; - -extern int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length); - -extern int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator); - -#endif /* __RADIOTAP_ITER_H */ diff --git a/src/drivers/scan_helpers.c b/src/drivers/scan_helpers.c deleted file mode 100644 index 63387701ea9a..000000000000 --- a/src/drivers/scan_helpers.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * WPA Supplicant - Helper functions for scan result processing - * Copyright (c) 2007-2008, Jouni Malinen - * - * 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 "drivers/driver.h" -#include "ieee802_11_defs.h" - - -const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) -{ - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - - -const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, - u32 vendor_type) -{ - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && - vendor_type == WPA_GET_BE32(&pos[2])) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - - -struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, - u32 vendor_type) -{ - struct wpabuf *buf; - const u8 *end, *pos; - - buf = wpabuf_alloc(res->ie_len); - if (buf == NULL) - return NULL; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && - vendor_type == WPA_GET_BE32(&pos[2])) - wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); - pos += 2 + pos[1]; - } - - if (wpabuf_len(buf) == 0) { - wpabuf_free(buf); - buf = NULL; - } - - return buf; -} - - -int wpa_scan_get_max_rate(const struct wpa_scan_res *res) -{ - int rate = 0; - const u8 *ie; - int i; - - ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); - for (i = 0; ie && i < ie[1]; i++) { - if ((ie[i + 2] & 0x7f) > rate) - rate = ie[i + 2] & 0x7f; - } - - ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); - for (i = 0; ie && i < ie[1]; i++) { - if ((ie[i + 2] & 0x7f) > rate) - rate = ie[i + 2] & 0x7f; - } - - return rate; -} - - -void wpa_scan_results_free(struct wpa_scan_results *res) -{ - size_t i; - - if (res == NULL) - return; - - for (i = 0; i < res->num; i++) - os_free(res->res[i]); - os_free(res->res); - os_free(res); -} - - -/* Compare function for sorting scan results. Return >0 if @b is considered - * better. */ -static int wpa_scan_result_compar(const void *a, const void *b) -{ - struct wpa_scan_res **_wa = (void *) a; - struct wpa_scan_res **_wb = (void *) b; - struct wpa_scan_res *wa = *_wa; - struct wpa_scan_res *wb = *_wb; - int wpa_a, wpa_b, maxrate_a, maxrate_b; - - /* WPA/WPA2 support preferred */ - wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || - wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; - wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || - wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; - - if (wpa_b && !wpa_a) - return 1; - if (!wpa_b && wpa_a) - return -1; - - /* privacy support preferred */ - if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && - (wb->caps & IEEE80211_CAP_PRIVACY)) - return 1; - if ((wa->caps & IEEE80211_CAP_PRIVACY) && - (wb->caps & IEEE80211_CAP_PRIVACY) == 0) - return -1; - - /* best/max rate preferred if signal level close enough XXX */ - if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) || - (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { - maxrate_a = wpa_scan_get_max_rate(wa); - maxrate_b = wpa_scan_get_max_rate(wb); - if (maxrate_a != maxrate_b) - return maxrate_b - maxrate_a; - } - - /* use freq for channel preference */ - - /* all things being equal, use signal level; if signal levels are - * identical, use quality values since some drivers may only report - * that value and leave the signal level zero */ - if (wb->level == wa->level) - return wb->qual - wa->qual; - return wb->level - wa->level; -} - - -void wpa_scan_sort_results(struct wpa_scan_results *res) -{ - qsort(res->res, res->num, sizeof(struct wpa_scan_res *), - wpa_scan_result_compar); -} diff --git a/src/common/wireless_copy.h b/src/drivers/wireless_copy.h similarity index 100% rename from src/common/wireless_copy.h rename to src/drivers/wireless_copy.h diff --git a/src/eap_common/Makefile b/src/eap_common/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/eap_common/Makefile +++ b/src/eap_common/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/eap_common/chap.c b/src/eap_common/chap.c index a088aff64e2d..60bfc1c8168f 100644 --- a/src/eap_common/chap.c +++ b/src/eap_common/chap.c @@ -1,6 +1,6 @@ /* * CHAP-MD5 (RFC 1994) - * Copyright (c) 2007, Jouni Malinen + * Copyright (c) 2007-2009, Jouni Malinen * * 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 @@ -15,11 +15,10 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "crypto.h" +#include "crypto/crypto.h" #include "chap.h" -void chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, +int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, size_t challenge_len, u8 *response) { const u8 *addr[3]; @@ -31,5 +30,5 @@ void chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, len[1] = secret_len; addr[2] = challenge; len[2] = challenge_len; - md5_vector(3, addr, len, response); + return md5_vector(3, addr, len, response); } diff --git a/src/eap_common/chap.h b/src/eap_common/chap.h index 209dc8a48f0f..b9c400c7c7f4 100644 --- a/src/eap_common/chap.h +++ b/src/eap_common/chap.h @@ -1,6 +1,6 @@ /* * CHAP-MD5 (RFC 1994) - * Copyright (c) 2007, Jouni Malinen + * Copyright (c) 2007-2009, Jouni Malinen * * 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 @@ -17,7 +17,7 @@ #define CHAP_MD5_LEN 16 -void chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, - size_t challenge_len, u8 *response); +int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, + size_t challenge_len, u8 *response); #endif /* CHAP_H */ diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c index 4d3deafa0cec..4de34a87b611 100644 --- a/src/eap_common/eap_fast_common.c +++ b/src/eap_common/eap_fast_common.c @@ -15,8 +15,8 @@ #include "includes.h" #include "common.h" -#include "sha1.h" -#include "tls.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_defs.h" #include "eap_tlv_common.h" #include "eap_fast_common.h" diff --git a/src/eap_common/eap_gpsk_common.c b/src/eap_common/eap_gpsk_common.c index 414610cf5a4e..407626288061 100644 --- a/src/eap_common/eap_gpsk_common.c +++ b/src/eap_common/eap_gpsk_common.c @@ -15,12 +15,9 @@ #include "includes.h" #include "common.h" +#include "crypto/aes_wrap.h" +#include "crypto/sha256.h" #include "eap_defs.h" -#include "aes_wrap.h" -#include "crypto.h" -#ifdef EAP_GPSK_SHA256 -#include "sha256.h" -#endif /* EAP_GPSK_SHA256 */ #include "eap_gpsk_common.h" diff --git a/src/eap_common/eap_pax_common.c b/src/eap_common/eap_pax_common.c index 80110469dcc3..32dc80c74dc5 100644 --- a/src/eap_common/eap_pax_common.c +++ b/src/eap_common/eap_pax_common.c @@ -15,7 +15,7 @@ #include "includes.h" #include "common.h" -#include "sha1.h" +#include "crypto/sha1.h" #include "eap_pax_common.h" diff --git a/src/eap_common/eap_peap_common.c b/src/eap_common/eap_peap_common.c index 14625f963921..3a64b8ecc44c 100644 --- a/src/eap_common/eap_peap_common.c +++ b/src/eap_common/eap_peap_common.c @@ -15,7 +15,7 @@ #include "includes.h" #include "common.h" -#include "sha1.h" +#include "crypto/sha1.h" #include "eap_peap_common.h" void peap_prfplus(int version, const u8 *key, size_t key_len, diff --git a/src/eap_common/eap_psk_common.c b/src/eap_common/eap_psk_common.c index 0def3e885371..7417d5c73df5 100644 --- a/src/eap_common/eap_psk_common.c +++ b/src/eap_common/eap_psk_common.c @@ -15,7 +15,7 @@ #include "includes.h" #include "common.h" -#include "aes_wrap.h" +#include "crypto/aes_wrap.h" #include "eap_defs.h" #include "eap_psk_common.h" diff --git a/src/eap_common/eap_sake_common.c b/src/eap_common/eap_sake_common.c index eafad1d11723..9002b0ca328a 100644 --- a/src/eap_common/eap_sake_common.c +++ b/src/eap_common/eap_sake_common.c @@ -15,8 +15,8 @@ #include "includes.h" #include "common.h" -#include "sha1.h" #include "wpabuf.h" +#include "crypto/sha1.h" #include "eap_defs.h" #include "eap_sake_common.h" diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c index fccda02417aa..56b4ded45963 100644 --- a/src/eap_common/eap_sim_common.c +++ b/src/eap_common/eap_sim_common.c @@ -15,12 +15,12 @@ #include "includes.h" #include "common.h" -#include "eap_common/eap_defs.h" -#include "sha1.h" -#include "sha256.h" -#include "crypto.h" -#include "aes_wrap.h" #include "wpabuf.h" +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "eap_common/eap_defs.h" #include "eap_common/eap_sim_common.h" @@ -233,7 +233,7 @@ void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, } -#ifdef EAP_AKA_PRIME +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) static void prf_prime(const u8 *k, const char *seed1, const u8 *seed2, size_t seed2_len, const u8 *seed3, size_t seed3_len, @@ -496,7 +496,7 @@ void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN); } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ int eap_sim_parse_attr(const u8 *start, const u8 *end, @@ -858,7 +858,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end, wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND"); attr->result_ind = 1; break; -#ifdef EAP_AKA_PRIME +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) case EAP_SIM_AT_KDF_INPUT: if (aka != 2) { wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " @@ -913,7 +913,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end, } attr->bidding = apos; break; -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ default: if (pos[0] < 128) { wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized " @@ -1023,14 +1023,14 @@ struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, eap = wpabuf_mhead(msg->buf); eap->length = host_to_be16(wpabuf_len(msg->buf)); -#ifdef EAP_AKA_PRIME +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) { eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) wpabuf_mhead(msg->buf) + msg->mac, extra, extra_len); } else -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ if (k_aut && msg->mac) { eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf), wpabuf_len(msg->buf), diff --git a/src/eap_common/eap_sim_common.h b/src/eap_common/eap_sim_common.h index a8080e27a7b3..48c8eaac0a09 100644 --- a/src/eap_common/eap_sim_common.h +++ b/src/eap_common/eap_sim_common.h @@ -94,7 +94,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, const u8 *extra, size_t extra_len); -#ifdef EAP_AKA_PRIME +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, const u8 *ik, const u8 *ck, u8 *k_encr, u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk); @@ -110,7 +110,7 @@ void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, const u8 *network_name, size_t network_name_len); -#else /* EAP_AKA_PRIME */ +#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ static inline void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, const u8 *ik, const u8 *ck, @@ -135,7 +135,7 @@ static inline int eap_sim_verify_mac_sha256(const u8 *k_aut, { return -1; } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ /* EAP-SIM/AKA Attributes (0..127 non-skippable) */ diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c index 818b5bdbaad8..67754d8159d0 100644 --- a/src/eap_common/ikev2_common.c +++ b/src/eap_common/ikev2_common.c @@ -15,9 +15,9 @@ #include "includes.h" #include "common.h" -#include "sha1.h" -#include "md5.h" -#include "crypto.h" +#include "crypto/crypto.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" #include "ikev2_common.h" diff --git a/src/eap_peer/Makefile b/src/eap_peer/Makefile index d9449a28da42..365105611049 100644 --- a/src/eap_peer/Makefile +++ b/src/eap_peer/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.so *.d install: diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index e8e504af5495..b9f186bf17d0 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1,6 +1,6 @@ /* * EAP peer state machines (RFC 4137) - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -24,14 +24,14 @@ #include "includes.h" #include "common.h" +#include "pcsc_funcs.h" +#include "state_machine.h" +#include "crypto/crypto.h" +#include "crypto/tls.h" +#include "common/wpa_ctrl.h" +#include "eap_common/eap_wsc_common.h" #include "eap_i.h" #include "eap_config.h" -#include "tls.h" -#include "crypto.h" -#include "pcsc_funcs.h" -#include "wpa_ctrl.h" -#include "state_machine.h" -#include "eap_common/eap_wsc_common.h" #define STATE_MACHINE_DATA struct eap_sm #define STATE_MACHINE_DEBUG_PREFIX "EAP" @@ -228,9 +228,15 @@ SM_STATE(EAP, GET_METHOD) if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) { wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed", sm->reqVendor, method); + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD + "vendor=%u method=%u -> NAK", + sm->reqVendor, method); goto nak; } + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD + "vendor=%u method=%u", sm->reqVendor, method); + /* * RFC 4137 does not define specific operation for fast * re-authentication (session resumption). The design here is to allow @@ -1154,6 +1160,60 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req) } +static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, + union tls_event_data *data) +{ + struct eap_sm *sm = ctx; + char *hash_hex = NULL; + char *cert_hex = NULL; + + switch (ev) { + case TLS_CERT_CHAIN_FAILURE: + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR + "reason=%d depth=%d subject='%s' err='%s'", + data->cert_fail.reason, + data->cert_fail.depth, + data->cert_fail.subject, + data->cert_fail.reason_txt); + break; + case TLS_PEER_CERTIFICATE: + if (data->peer_cert.hash) { + size_t len = data->peer_cert.hash_len * 2 + 1; + hash_hex = os_malloc(len); + if (hash_hex) { + wpa_snprintf_hex(hash_hex, len, + data->peer_cert.hash, + data->peer_cert.hash_len); + } + } + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT + "depth=%d subject='%s'%s%s", + data->peer_cert.depth, data->peer_cert.subject, + hash_hex ? " hash=" : "", hash_hex ? hash_hex : ""); + + if (data->peer_cert.cert) { + size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1; + cert_hex = os_malloc(len); + if (cert_hex == NULL) + break; + wpa_snprintf_hex(cert_hex, len, + wpabuf_head(data->peer_cert.cert), + wpabuf_len(data->peer_cert.cert)); + wpa_msg_ctrl(sm->msg_ctx, MSG_INFO, + WPA_EVENT_EAP_PEER_CERT + "depth=%d subject='%s' cert=%s", + data->peer_cert.depth, + data->peer_cert.subject, + cert_hex); + } + break; + } + + os_free(hash_hex); + os_free(cert_hex); +} + + /** * eap_peer_sm_init - Allocate and initialize EAP peer state machine * @eapol_ctx: Context data to be used with eapol_cb calls @@ -1188,6 +1248,11 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx, tlsconf.opensc_engine_path = conf->opensc_engine_path; tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path; tlsconf.pkcs11_module_path = conf->pkcs11_module_path; +#ifdef CONFIG_FIPS + tlsconf.fips_mode = 1; +#endif /* CONFIG_FIPS */ + tlsconf.event_cb = eap_peer_sm_tls_event; + tlsconf.cb_ctx = sm; sm->ssl_ctx = tls_init(&tlsconf); if (sm->ssl_ctx == NULL) { wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS " diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index d7a562812bb3..40d0b6929ce9 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -15,7 +15,7 @@ #ifndef EAP_H #define EAP_H -#include "defs.h" +#include "common/defs.h" #include "eap_common/eap_defs.h" #include "eap_peer/eap_methods.h" diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index f23714142586..182f01a5e60a 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -15,16 +15,14 @@ #include "includes.h" #include "common.h" -#include "eap_peer/eap_i.h" #include "pcsc_funcs.h" +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/milenage.h" #include "eap_common/eap_sim_common.h" -#include "sha1.h" -#include "sha256.h" -#include "crypto.h" -#include "eap_peer/eap_config.h" -#ifdef CONFIG_USIM_SIMULATOR -#include "hlr_auc_gw/milenage.h" -#endif /* CONFIG_USIM_SIMULATOR */ +#include "eap_config.h" +#include "eap_i.h" struct eap_aka_data { diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index 94245c3d03dd..b64b68f4b76c 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -85,6 +85,15 @@ struct eap_peer_config { * Alternatively, a named configuration blob can be used by setting * this to blob://blob_name. * + * Alternatively, this can be used to only perform matching of the + * server certificate (SHA-256 hash of the DER encoded X.509 + * certificate). In this case, the possible CA certificates in the + * server certificate chain are ignored and only the server certificate + * is verified. This is configured with the following format: + * hash:://server/sha256/cert_hash_in_hex + * For example: "hash://server/sha256/ + * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" + * * On Windows, trusted CA certificates can be loaded from the system * certificate store by setting this to cert_store://name, e.g., * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c index d00867099aa3..5d3e69d3cdfe 100644 --- a/src/eap_peer/eap_fast.c +++ b/src/eap_peer/eap_fast.c @@ -15,12 +15,12 @@ #include "includes.h" #include "common.h" +#include "crypto/tls.h" +#include "crypto/sha1.h" +#include "eap_common/eap_tlv_common.h" #include "eap_i.h" #include "eap_tls_common.h" #include "eap_config.h" -#include "tls.h" -#include "eap_common/eap_tlv_common.h" -#include "sha1.h" #include "eap_fast_pac.h" #ifdef EAP_FAST_DYNAMIC @@ -1445,9 +1445,9 @@ static int eap_fast_process_start(struct eap_sm *sm, /* EAP-FAST Version negotiation (section 3.1) */ wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)", - flags & EAP_PEAP_VERSION_MASK, data->fast_version); - if ((flags & EAP_PEAP_VERSION_MASK) < data->fast_version) - data->fast_version = flags & EAP_PEAP_VERSION_MASK; + flags & EAP_TLS_VERSION_MASK, data->fast_version); + if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version) + data->fast_version = flags & EAP_TLS_VERSION_MASK; wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d", data->fast_version); diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c index 77893d619597..541cce50dc01 100644 --- a/src/eap_peer/eap_fast_pac.c +++ b/src/eap_peer/eap_fast_pac.c @@ -480,8 +480,10 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len, { size_t i, need; int ret; + char *end; - if (data == NULL || *buf == NULL) + if (data == NULL || buf == NULL || *buf == NULL || + pos == NULL || *pos == NULL || *pos < *buf) return; need = os_strlen(field) + len * 2 + 30; @@ -498,32 +500,31 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len, *buf = nbuf; *buf_len += need; } + end = *buf + *buf_len; - ret = os_snprintf(*pos, *buf + *buf_len - *pos, "%s=", field); - if (ret < 0 || ret >= *buf + *buf_len - *pos) + ret = os_snprintf(*pos, end - *pos, "%s=", field); + if (ret < 0 || ret >= end - *pos) return; *pos += ret; - *pos += wpa_snprintf_hex(*pos, *buf + *buf_len - *pos, data, len); - ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n"); - if (ret < 0 || ret >= *buf + *buf_len - *pos) + *pos += wpa_snprintf_hex(*pos, end - *pos, data, len); + ret = os_snprintf(*pos, end - *pos, "\n"); + if (ret < 0 || ret >= end - *pos) return; *pos += ret; if (txt) { - ret = os_snprintf(*pos, *buf + *buf_len - *pos, - "%s-txt=", field); - if (ret < 0 || ret >= *buf + *buf_len - *pos) + ret = os_snprintf(*pos, end - *pos, "%s-txt=", field); + if (ret < 0 || ret >= end - *pos) return; *pos += ret; for (i = 0; i < len; i++) { - ret = os_snprintf(*pos, *buf + *buf_len - *pos, - "%c", data[i]); - if (ret < 0 || ret >= *buf + *buf_len - *pos) + ret = os_snprintf(*pos, end - *pos, "%c", data[i]); + if (ret < 0 || ret >= end - *pos) return; *pos += ret; } - ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n"); - if (ret < 0 || ret >= *buf + *buf_len - *pos) + ret = os_snprintf(*pos, end - *pos, "\n"); + if (ret < 0 || ret >= end - *pos) return; *pos += ret; } diff --git a/src/eap_peer/eap_leap.c b/src/eap_peer/eap_leap.c index 01c1f160abce..a7c94a4d4480 100644 --- a/src/eap_peer/eap_leap.c +++ b/src/eap_peer/eap_leap.c @@ -15,9 +15,9 @@ #include "includes.h" #include "common.h" +#include "crypto/ms_funcs.h" +#include "crypto/crypto.h" #include "eap_i.h" -#include "ms_funcs.h" -#include "crypto.h" #define LEAP_VERSION 1 #define LEAP_CHALLENGE_LEN 8 @@ -233,10 +233,16 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); if (pwhash) { - hash_nt_password_hash(password, pw_hash_hash); + if (hash_nt_password_hash(password, pw_hash_hash)) { + ret->ignore = TRUE; + return NULL; + } } else { - nt_password_hash(password, password_len, pw_hash); - hash_nt_password_hash(pw_hash, pw_hash_hash); + if (nt_password_hash(password, password_len, pw_hash) || + hash_nt_password_hash(pw_hash, pw_hash_hash)) { + ret->ignore = TRUE; + return NULL; + } } challenge_response(data->ap_challenge, pw_hash_hash, expected); @@ -345,11 +351,17 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) if (key == NULL) return NULL; - if (pwhash) - hash_nt_password_hash(password, pw_hash_hash); - else { - nt_password_hash(password, password_len, pw_hash); - hash_nt_password_hash(pw_hash, pw_hash_hash); + if (pwhash) { + if (hash_nt_password_hash(password, pw_hash_hash)) { + os_free(key); + return NULL; + } + } else { + if (nt_password_hash(password, password_len, pw_hash) || + hash_nt_password_hash(pw_hash, pw_hash_hash)) { + os_free(key); + return NULL; + } } wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", pw_hash_hash, 16); diff --git a/src/eap_peer/eap_md5.c b/src/eap_peer/eap_md5.c index 7961143a00c9..0edbae8f74d3 100644 --- a/src/eap_peer/eap_md5.c +++ b/src/eap_peer/eap_md5.c @@ -76,7 +76,7 @@ static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv, wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response"); ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; + ret->decision = DECISION_COND_SUCC; ret->allowNotifications = TRUE; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN, diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c index 2374e5e4225c..3b0af055b39c 100644 --- a/src/eap_peer/eap_methods.c +++ b/src/eap_peer/eap_methods.c @@ -339,161 +339,6 @@ int eap_peer_method_register(struct eap_method *method) } -/** - * eap_peer_register_methods - Register statically linked EAP peer methods - * Returns: 0 on success, -1 on failure - * - * This function is called at program initialization to register all EAP peer - * methods that were linked in statically. - */ -int eap_peer_register_methods(void) -{ - int ret = 0; - -#ifdef EAP_MD5 - if (ret == 0) { - int eap_peer_md5_register(void); - ret = eap_peer_md5_register(); - } -#endif /* EAP_MD5 */ - -#ifdef EAP_TLS - if (ret == 0) { - int eap_peer_tls_register(void); - ret = eap_peer_tls_register(); - } -#endif /* EAP_TLS */ - -#ifdef EAP_MSCHAPv2 - if (ret == 0) { - int eap_peer_mschapv2_register(void); - ret = eap_peer_mschapv2_register(); - } -#endif /* EAP_MSCHAPv2 */ - -#ifdef EAP_PEAP - if (ret == 0) { - int eap_peer_peap_register(void); - ret = eap_peer_peap_register(); - } -#endif /* EAP_PEAP */ - -#ifdef EAP_TTLS - if (ret == 0) { - int eap_peer_ttls_register(void); - ret = eap_peer_ttls_register(); - } -#endif /* EAP_TTLS */ - -#ifdef EAP_GTC - if (ret == 0) { - int eap_peer_gtc_register(void); - ret = eap_peer_gtc_register(); - } -#endif /* EAP_GTC */ - -#ifdef EAP_OTP - if (ret == 0) { - int eap_peer_otp_register(void); - ret = eap_peer_otp_register(); - } -#endif /* EAP_OTP */ - -#ifdef EAP_SIM - if (ret == 0) { - int eap_peer_sim_register(void); - ret = eap_peer_sim_register(); - } -#endif /* EAP_SIM */ - -#ifdef EAP_LEAP - if (ret == 0) { - int eap_peer_leap_register(void); - ret = eap_peer_leap_register(); - } -#endif /* EAP_LEAP */ - -#ifdef EAP_PSK - if (ret == 0) { - int eap_peer_psk_register(void); - ret = eap_peer_psk_register(); - } -#endif /* EAP_PSK */ - -#ifdef EAP_AKA - if (ret == 0) { - int eap_peer_aka_register(void); - ret = eap_peer_aka_register(); - } -#endif /* EAP_AKA */ - -#ifdef EAP_AKA_PRIME - if (ret == 0) { - int eap_peer_aka_prime_register(void); - ret = eap_peer_aka_prime_register(); - } -#endif /* EAP_AKA_PRIME */ - -#ifdef EAP_FAST - if (ret == 0) { - int eap_peer_fast_register(void); - ret = eap_peer_fast_register(); - } -#endif /* EAP_FAST */ - -#ifdef EAP_PAX - if (ret == 0) { - int eap_peer_pax_register(void); - ret = eap_peer_pax_register(); - } -#endif /* EAP_PAX */ - -#ifdef EAP_SAKE - if (ret == 0) { - int eap_peer_sake_register(void); - ret = eap_peer_sake_register(); - } -#endif /* EAP_SAKE */ - -#ifdef EAP_GPSK - if (ret == 0) { - int eap_peer_gpsk_register(void); - ret = eap_peer_gpsk_register(); - } -#endif /* EAP_GPSK */ - -#ifdef EAP_WSC - if (ret == 0) { - int eap_peer_wsc_register(void); - ret = eap_peer_wsc_register(); - } -#endif /* EAP_WSC */ - -#ifdef EAP_IKEV2 - if (ret == 0) { - int eap_peer_ikev2_register(void); - ret = eap_peer_ikev2_register(); - } -#endif /* EAP_IKEV2 */ - -#ifdef EAP_VENDOR_TEST - if (ret == 0) { - int eap_peer_vendor_test_register(void); - ret = eap_peer_vendor_test_register(); - } -#endif /* EAP_VENDOR_TEST */ - -#ifdef EAP_TNC - if (ret == 0) { - int eap_peer_tnc_register(void); - ret = eap_peer_tnc_register(); - } -#endif /* EAP_TNC */ - - return ret; -} - - /** * eap_peer_unregister_methods - Unregister EAP peer methods * diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h index 9fd9b517c79e..384c61bb70ae 100644 --- a/src/eap_peer/eap_methods.h +++ b/src/eap_peer/eap_methods.h @@ -32,7 +32,6 @@ EapType eap_peer_get_type(const char *name, int *vendor); const char * eap_get_name(int vendor, EapType type); size_t eap_get_names(char *buf, size_t buflen); char ** eap_get_names_as_string_array(size_t *num); -int eap_peer_register_methods(void); void eap_peer_unregister_methods(void); #else /* IEEE8021X_EAPOL */ @@ -89,4 +88,26 @@ static inline int eap_peer_method_unload(struct eap_method *method) #endif /* CONFIG_DYNAMIC_EAP_METHODS */ +/* EAP peer method registration calls for statically linked in methods */ +int eap_peer_md5_register(void); +int eap_peer_tls_register(void); +int eap_peer_mschapv2_register(void); +int eap_peer_peap_register(void); +int eap_peer_ttls_register(void); +int eap_peer_gtc_register(void); +int eap_peer_otp_register(void); +int eap_peer_sim_register(void); +int eap_peer_leap_register(void); +int eap_peer_psk_register(void); +int eap_peer_aka_register(void); +int eap_peer_aka_prime_register(void); +int eap_peer_fast_register(void); +int eap_peer_pax_register(void); +int eap_peer_sake_register(void); +int eap_peer_gpsk_register(void); +int eap_peer_wsc_register(void); +int eap_peer_ikev2_register(void); +int eap_peer_vendor_test_register(void); +int eap_peer_tnc_register(void); + #endif /* EAP_METHODS_H */ diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c index b0c3ab77632b..cd410d91b5df 100644 --- a/src/eap_peer/eap_mschapv2.c +++ b/src/eap_peer/eap_mschapv2.c @@ -22,11 +22,11 @@ #include "includes.h" #include "common.h" +#include "crypto/ms_funcs.h" +#include "common/wpa_ctrl.h" +#include "mschapv2.h" #include "eap_i.h" #include "eap_config.h" -#include "ms_funcs.h" -#include "wpa_ctrl.h" -#include "mschapv2.h" #ifdef _MSC_VER @@ -209,10 +209,15 @@ static struct wpabuf * eap_mschapv2_challenge_reply( "in Phase 1"); auth_challenge = data->auth_challenge; } - mschapv2_derive_response(identity, identity_len, password, - password_len, pwhash, auth_challenge, - peer_challenge, r->nt_response, - data->auth_response, data->master_key); + if (mschapv2_derive_response(identity, identity_len, password, + password_len, pwhash, auth_challenge, + peer_challenge, r->nt_response, + data->auth_response, data->master_key)) { + wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive " + "response"); + wpabuf_free(resp); + return NULL; + } data->auth_response_valid = 1; data->master_key_valid = 1; diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c index afd56dd49b7f..2e04831ae53d 100644 --- a/src/eap_peer/eap_pax.c +++ b/src/eap_peer/eap_pax.c @@ -15,10 +15,8 @@ #include "includes.h" #include "common.h" -#include "eap_peer/eap_i.h" #include "eap_common/eap_pax_common.h" -#include "sha1.h" -#include "crypto.h" +#include "eap_i.h" /* * Note: only PAX_STD subprotocol is currently supported diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 894fc632fda3..2b72084e5433 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -16,12 +16,12 @@ #include "common.h" #include "crypto/sha1.h" +#include "crypto/tls.h" +#include "eap_common/eap_tlv_common.h" +#include "eap_common/eap_peap_common.h" #include "eap_i.h" #include "eap_tls_common.h" #include "eap_config.h" -#include "tls.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_peap_common.h" #include "tncc.h" @@ -1048,10 +1048,10 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, if (flags & EAP_TLS_FLAGS_START) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " - "ver=%d)", flags & EAP_PEAP_VERSION_MASK, + "ver=%d)", flags & EAP_TLS_VERSION_MASK, data->peap_version); - if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version) - data->peap_version = flags & EAP_PEAP_VERSION_MASK; + if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version) + data->peap_version = flags & EAP_TLS_VERSION_MASK; if (data->force_peap_version >= 0 && data->force_peap_version != data->peap_version) { wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c index 1ce635663982..ccf871e13ba0 100644 --- a/src/eap_peer/eap_psk.c +++ b/src/eap_peer/eap_psk.c @@ -18,9 +18,9 @@ #include "includes.h" #include "common.h" -#include "eap_peer/eap_i.h" -#include "aes_wrap.h" +#include "crypto/aes_wrap.h" #include "eap_common/eap_psk_common.h" +#include "eap_i.h" struct eap_psk_data { diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index 5e30d1f7ed41..3d8afb22fb00 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -15,13 +15,11 @@ #include "includes.h" #include "common.h" +#include "pcsc_funcs.h" +#include "crypto/milenage.h" #include "eap_peer/eap_i.h" #include "eap_config.h" -#include "pcsc_funcs.h" #include "eap_common/eap_sim_common.h" -#ifdef CONFIG_SIM_SIMULATOR -#include "hlr_auc_gw/milenage.h" -#endif /* CONFIG_SIM_SIMULATOR */ struct eap_sim_data { diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c index 31344a9136b2..20b2212e1cdc 100644 --- a/src/eap_peer/eap_tls.c +++ b/src/eap_peer/eap_tls.c @@ -15,10 +15,10 @@ #include "includes.h" #include "common.h" +#include "crypto/tls.h" #include "eap_i.h" #include "eap_tls_common.h" #include "eap_config.h" -#include "tls.h" static void eap_tls_deinit(struct eap_sm *sm, void *priv); diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 186feaada442..7bd50f677bc8 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -1,6 +1,6 @@ /* * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -15,11 +15,11 @@ #include "includes.h" #include "common.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_i.h" #include "eap_tls_common.h" #include "eap_config.h" -#include "sha1.h" -#include "tls.h" static int eap_tls_check_blob(struct eap_sm *sm, const char **name, @@ -169,10 +169,14 @@ static int eap_tls_init_connection(struct eap_sm *sm, config->pin = NULL; eap_sm_request_pin(sm); sm->ignore = TRUE; + tls_connection_deinit(sm->ssl_ctx, data->conn); + data->conn = NULL; return -1; } else if (res) { wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " "parameters"); + tls_connection_deinit(sm->ssl_ctx, data->conn); + data->conn = NULL; return -1; } @@ -310,27 +314,29 @@ fail: * eap_peer_tls_reassemble_fragment - Reassemble a received fragment * @data: Data for TLS processing * @in_data: Next incoming TLS segment - * @in_len: Length of in_data * Returns: 0 on success, 1 if more data is needed for the full message, or * -1 on error */ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, - const u8 *in_data, size_t in_len) + const struct wpabuf *in_data) { - u8 *buf; + size_t tls_in_len, in_len; - if (data->tls_in_len + in_len == 0) { + tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; + in_len = in_data ? wpabuf_len(in_data) : 0; + + if (tls_in_len + in_len == 0) { /* No message data received?! */ wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " "tls_in_left=%lu tls_in_len=%lu in_len=%lu", (unsigned long) data->tls_in_left, - (unsigned long) data->tls_in_len, + (unsigned long) tls_in_len, (unsigned long) in_len); eap_peer_tls_reset_input(data); return -1; } - if (data->tls_in_len + in_len > 65536) { + if (tls_in_len + in_len > 65536) { /* * Limit length to avoid rogue servers from causing large * memory allocations. @@ -349,16 +355,13 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, return -1; } - buf = os_realloc(data->tls_in, data->tls_in_len + in_len); - if (buf == NULL) { + if (wpabuf_resize(&data->tls_in, in_len) < 0) { wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " "data"); eap_peer_tls_reset_input(data); return -1; } - os_memcpy(buf + data->tls_in_len, in_data, in_len); - data->tls_in = buf; - data->tls_in_len += in_len; + wpabuf_put_buf(data->tls_in, in_data); data->tls_in_left -= in_len; if (data->tls_in_left > 0) { @@ -375,8 +378,6 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, * eap_peer_tls_data_reassemble - Reassemble TLS data * @data: Data for TLS processing * @in_data: Next incoming TLS segment - * @in_len: Length of in_data - * @out_len: Variable for returning length of the reassembled message * @need_more_input: Variable for returning whether more input data is needed * to reassemble this TLS packet * Returns: Pointer to output data, %NULL on error or when more data is needed @@ -385,16 +386,15 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, * This function reassembles TLS fragments. Caller must not free the returned * data buffer since an internal pointer to it is maintained. */ -const u8 * eap_peer_tls_data_reassemble( - struct eap_ssl_data *data, const u8 *in_data, size_t in_len, - size_t *out_len, int *need_more_input) +static const struct wpabuf * eap_peer_tls_data_reassemble( + struct eap_ssl_data *data, const struct wpabuf *in_data, + int *need_more_input) { *need_more_input = 0; - if (data->tls_in_left > in_len || data->tls_in) { + if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { /* Message has fragments */ - int res = eap_peer_tls_reassemble_fragment(data, in_data, - in_len); + int res = eap_peer_tls_reassemble_fragment(data, in_data); if (res) { if (res == 1) *need_more_input = 1; @@ -405,14 +405,11 @@ const u8 * eap_peer_tls_data_reassemble( } else { /* No fragments in this message, so just make a copy of it. */ data->tls_in_left = 0; - data->tls_in = os_malloc(in_len ? in_len : 1); + data->tls_in = wpabuf_dup(in_data); if (data->tls_in == NULL) return NULL; - os_memcpy(data->tls_in, in_data, in_len); - data->tls_in_len = in_len; } - *out_len = data->tls_in_len; return data->tls_in; } @@ -431,14 +428,13 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data, size_t in_len, struct wpabuf **out_data) { - const u8 *msg; - size_t msg_len; + const struct wpabuf *msg; int need_more_input; - u8 *appl_data; - size_t appl_data_len; + struct wpabuf *appl_data; + struct wpabuf buf; - msg = eap_peer_tls_data_reassemble(data, in_data, in_len, - &msg_len, &need_more_input); + wpabuf_set(&buf, in_data, in_len); + msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; @@ -447,31 +443,25 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " "tls_out data even though tls_out_len = 0"); - os_free(data->tls_out); + wpabuf_free(data->tls_out); WPA_ASSERT(data->tls_out == NULL); } appl_data = NULL; data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, - msg, msg_len, - &data->tls_out_len, - &appl_data, &appl_data_len); + msg, &appl_data); eap_peer_tls_reset_input(data); if (appl_data && tls_connection_established(sm->ssl_ctx, data->conn) && !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { - wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data", - appl_data, appl_data_len); - *out_data = wpabuf_alloc_ext_data(appl_data, appl_data_len); - if (*out_data == NULL) { - os_free(appl_data); - return -1; - } + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", + appl_data); + *out_data = appl_data; return 2; } - os_free(appl_data); + wpabuf_free(appl_data); return 0; } @@ -494,11 +484,14 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, size_t len; u8 *flags; int more_fragments, length_included; - - len = data->tls_out_len - data->tls_out_pos; + + if (data->tls_out == NULL) + return -1; + len = wpabuf_len(data->tls_out) - data->tls_out_pos; wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " "%lu bytes)", - (unsigned long) len, (unsigned long) data->tls_out_len); + (unsigned long) len, + (unsigned long) wpabuf_len(data->tls_out)); /* * Limit outgoing message to the configured maximum size. Fragment @@ -513,7 +506,7 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, more_fragments = 0; length_included = data->tls_out_pos == 0 && - (data->tls_out_len > data->tls_out_limit || + (wpabuf_len(data->tls_out) > data->tls_out_limit || data->include_tls_length); if (!length_included && eap_type == EAP_TYPE_PEAP && peap_version == 0 && @@ -539,10 +532,12 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; if (length_included) { *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; - wpabuf_put_be32(*out_data, data->tls_out_len); + wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); } - wpabuf_put_data(*out_data, &data->tls_out[data->tls_out_pos], len); + wpabuf_put_data(*out_data, + wpabuf_head_u8(data->tls_out) + data->tls_out_pos, + len); data->tls_out_pos += len; if (!more_fragments) @@ -590,13 +585,13 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, *out_data = NULL; - if (data->tls_out_len > 0 && in_len > 0) { + if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) { wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " "fragments are waiting to be sent out"); return -1; } - if (data->tls_out_len == 0) { + if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { /* * No more data to send out - expect to receive more data from * the AS. @@ -635,14 +630,14 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, /* TODO: clean pin if engine used? */ } - if (data->tls_out_len == 0) { + if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { /* * TLS negotiation should now be complete since all other cases * needing more data should have been caught above based on * the TLS Message Length field. */ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); - os_free(data->tls_out); + wpabuf_free(data->tls_out); data->tls_out = NULL; return 1; } @@ -794,9 +789,8 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm, if (data->tls_in_left == 0) { data->tls_in_total = tls_msg_len; data->tls_in_left = tls_msg_len; - os_free(data->tls_in); + wpabuf_free(data->tls_in); data->tls_in = NULL; - data->tls_in_len = 0; } pos += 4; left -= 4; @@ -821,8 +815,8 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm, */ void eap_peer_tls_reset_input(struct eap_ssl_data *data) { - data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; - os_free(data->tls_in); + data->tls_in_left = data->tls_in_total = 0; + wpabuf_free(data->tls_in); data->tls_in = NULL; } @@ -836,9 +830,8 @@ void eap_peer_tls_reset_input(struct eap_ssl_data *data) */ void eap_peer_tls_reset_output(struct eap_ssl_data *data) { - data->tls_out_len = 0; data->tls_out_pos = 0; - os_free(data->tls_out); + wpabuf_free(data->tls_out); data->tls_out = NULL; } @@ -855,44 +848,19 @@ int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, const struct wpabuf *in_data, struct wpabuf **in_decrypted) { - int res; - const u8 *msg; - size_t msg_len, buf_len; + const struct wpabuf *msg; int need_more_input; - msg = eap_peer_tls_data_reassemble(data, wpabuf_head(in_data), - wpabuf_len(in_data), &msg_len, - &need_more_input); + msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; - buf_len = wpabuf_len(in_data); - if (data->tls_in_total > buf_len) - buf_len = data->tls_in_total; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - *in_decrypted = wpabuf_alloc(buf_len ? buf_len : 1); - if (*in_decrypted == NULL) { - eap_peer_tls_reset_input(data); - wpa_printf(MSG_WARNING, "SSL: Failed to allocate memory for " - "decryption"); - return -1; - } - - res = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg, msg_len, - wpabuf_mhead(*in_decrypted), buf_len); + *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg); eap_peer_tls_reset_input(data); - if (res < 0) { + if (*in_decrypted == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); return -1; } - wpabuf_put(*in_decrypted, res); return 0; } @@ -913,29 +881,17 @@ int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, const struct wpabuf *in_data, struct wpabuf **out_data) { - int res; - size_t len; - if (in_data) { eap_peer_tls_reset_output(data); - len = wpabuf_len(in_data) + 300; - data->tls_out = os_malloc(len); - if (data->tls_out == NULL) - return -1; - - res = tls_connection_encrypt(sm->ssl_ctx, data->conn, - wpabuf_head(in_data), - wpabuf_len(in_data), - data->tls_out, len); - if (res < 0) { + data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn, + in_data); + if (data->tls_out == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " "data (in_len=%lu)", (unsigned long) wpabuf_len(in_data)); eap_peer_tls_reset_output(data); return -1; } - - data->tls_out_len = res; } return eap_tls_process_output(data, eap_type, peap_version, id, 0, diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h index 2c87427c28f5..e9e0998098cc 100644 --- a/src/eap_peer/eap_tls_common.h +++ b/src/eap_peer/eap_tls_common.h @@ -1,6 +1,6 @@ /* * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2006, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -27,12 +27,7 @@ struct eap_ssl_data { /** * tls_out - TLS message to be sent out in fragments */ - u8 *tls_out; - - /** - * tls_out_len - Total length of the outgoing TLS message - */ - size_t tls_out_len; + struct wpabuf *tls_out; /** * tls_out_pos - The current position in the outgoing TLS message @@ -47,12 +42,7 @@ struct eap_ssl_data { /** * tls_in - Received TLS message buffer for re-assembly */ - u8 *tls_in; - - /** - * tls_in_len - Number of bytes of the received TLS message in tls_in - */ - size_t tls_in_len; + struct wpabuf *tls_in; /** * tls_in_left - Number of remaining bytes in the incoming TLS message @@ -81,7 +71,7 @@ struct eap_ssl_data { int tls_ia; /** - * eap - Pointer to EAP state machine allocated with eap_peer_sm_init() + * eap - EAP state machine allocated with eap_peer_sm_init() */ struct eap_sm *eap; }; @@ -91,7 +81,7 @@ struct eap_ssl_data { #define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 #define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 #define EAP_TLS_FLAGS_START 0x20 -#define EAP_PEAP_VERSION_MASK 0x07 +#define EAP_TLS_VERSION_MASK 0x07 /* could be up to 128 bytes, but only the first 64 bytes are used */ #define EAP_TLS_KEY_LEN 64 @@ -102,9 +92,6 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, const char *label, size_t len); -const u8 * eap_peer_tls_data_reassemble( - struct eap_ssl_data *data, const u8 *in_data, size_t in_len, - size_t *out_len, int *need_more_input); int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, EapType eap_type, int peap_version, u8 id, const u8 *in_data, size_t in_len, diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c index c56001528113..6c95f72c1507 100644 --- a/src/eap_peer/eap_tnc.c +++ b/src/eap_peer/eap_tnc.c @@ -73,12 +73,13 @@ static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) { struct wpabuf *msg; - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id); + msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); if (msg == NULL) { wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " "for fragment ack"); return NULL; } + wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); @@ -262,7 +263,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { - if (len != 0) { + if (len > 1) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in " "WAIT_FRAG_ACK state"); ret->ignore = TRUE; diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index 0851f8bb4d50..25737803beed 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -15,15 +15,15 @@ #include "includes.h" #include "common.h" -#include "eap_peer/eap_i.h" -#include "eap_peer/eap_tls_common.h" -#include "eap_peer/eap_config.h" -#include "ms_funcs.h" -#include "sha1.h" +#include "crypto/ms_funcs.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_common/chap.h" -#include "tls.h" -#include "mschapv2.h" #include "eap_common/eap_ttls.h" +#include "mschapv2.h" +#include "eap_i.h" +#include "eap_tls_common.h" +#include "eap_config.h" /* Maximum supported TTLS version @@ -691,10 +691,15 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; os_memset(pos, 0, 8); /* Reserved, must be zero */ pos += 8; - mschapv2_derive_response(identity, identity_len, password, - password_len, pwhash, challenge, - peer_challenge, pos, data->auth_response, - data->master_key); + if (mschapv2_derive_response(identity, identity_len, password, + password_len, pwhash, challenge, + peer_challenge, pos, data->auth_response, + data->master_key)) { + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " + "response"); + return -1; + } data->auth_response_valid = 1; eap_ttlsv1_permute_inner(sm, data); @@ -1026,27 +1031,25 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, static struct wpabuf * eap_ttls_build_phase_finished( struct eap_sm *sm, struct eap_ttls_data *data, int id, int final) { - int len; - struct wpabuf *req; - u8 *pos; - const int max_len = 300; + struct wpabuf *req, *buf; - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1 + max_len, - EAP_CODE_RESPONSE, id); - if (req == NULL) + buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx, + data->ssl.conn, + final); + if (buf == NULL) return NULL; - wpabuf_put_u8(req, data->ttls_version); - - pos = wpabuf_put(req, 0); - len = tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, - final, pos, max_len); - if (len < 0) { - wpabuf_free(req); + req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, + 1 + wpabuf_len(buf), + EAP_CODE_RESPONSE, id); + if (req == NULL) { + wpabuf_free(buf); return NULL; } - wpabuf_put(req, len); + + wpabuf_put_u8(req, data->ttls_version); + wpabuf_put_buf(req, buf); + wpabuf_free(buf); eap_update_len(req); return req; @@ -1666,10 +1669,10 @@ static int eap_ttls_process_start(struct eap_sm *sm, struct eap_peer_config *config = eap_get_config(sm); wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)", - flags & EAP_PEAP_VERSION_MASK, data->ttls_version); + flags & EAP_TLS_VERSION_MASK, data->ttls_version); #if EAP_TTLS_VERSION > 0 - if ((flags & EAP_PEAP_VERSION_MASK) < data->ttls_version) - data->ttls_version = flags & EAP_PEAP_VERSION_MASK; + if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version) + data->ttls_version = flags & EAP_TLS_VERSION_MASK; if (data->force_ttls_version >= 0 && data->force_ttls_version != data->ttls_version) { wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select " diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c index 7c8ad2fdad98..8317f728f8ea 100644 --- a/src/eap_peer/eap_wsc.c +++ b/src/eap_peer/eap_wsc.c @@ -1,6 +1,6 @@ /* * EAP-WSC peer for Wi-Fi Protected Setup - * Copyright (c) 2007-2008, Jouni Malinen + * Copyright (c) 2007-2009, Jouni Malinen * * 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 @@ -65,6 +65,72 @@ static void eap_wsc_state(struct eap_wsc_data *data, int state) } +static int eap_wsc_new_ap_settings(struct wps_credential *cred, + const char *params) +{ + const char *pos, *end; + size_t len; + + os_memset(cred, 0, sizeof(*cred)); + + pos = os_strstr(params, "new_ssid="); + if (pos == NULL) + return 0; + pos += 9; + end = os_strchr(pos, ' '); + if (end == NULL) + len = os_strlen(pos); + else + len = end - pos; + if ((len & 1) || len > 2 * sizeof(cred->ssid) || + hexstr2bin(pos, cred->ssid, len / 2)) + return -1; + cred->ssid_len = len / 2; + + pos = os_strstr(params, "new_auth="); + if (pos == NULL) + return -1; + if (os_strncmp(pos + 9, "OPEN", 4) == 0) + cred->auth_type = WPS_AUTH_OPEN; + else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) + cred->auth_type = WPS_AUTH_WPAPSK; + else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) + cred->auth_type = WPS_AUTH_WPA2PSK; + else + return -1; + + pos = os_strstr(params, "new_encr="); + if (pos == NULL) + return -1; + if (os_strncmp(pos + 9, "NONE", 4) == 0) + cred->encr_type = WPS_ENCR_NONE; + else if (os_strncmp(pos + 9, "WEP", 3) == 0) + cred->encr_type = WPS_ENCR_WEP; + else if (os_strncmp(pos + 9, "TKIP", 4) == 0) + cred->encr_type = WPS_ENCR_TKIP; + else if (os_strncmp(pos + 9, "CCMP", 4) == 0) + cred->encr_type = WPS_ENCR_AES; + else + return -1; + + pos = os_strstr(params, "new_key="); + if (pos == NULL) + return 0; + pos += 8; + end = os_strchr(pos, ' '); + if (end == NULL) + len = os_strlen(pos); + else + len = end - pos; + if ((len & 1) || len > 2 * sizeof(cred->key) || + hexstr2bin(pos, cred->key, len / 2)) + return -1; + cred->key_len = len / 2; + + return 1; +} + + static void * eap_wsc_init(struct eap_sm *sm) { struct eap_wsc_data *data; @@ -75,6 +141,8 @@ static void * eap_wsc_init(struct eap_sm *sm) const char *pos; const char *phase1; struct wps_context *wps; + struct wps_credential new_ap_settings; + int res; wps = sm->wps; if (wps == NULL) { @@ -135,6 +203,17 @@ static void * eap_wsc_init(struct eap_sm *sm) return NULL; } + res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); + if (res < 0) { + os_free(data); + return NULL; + } + if (res == 1) { + wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " + "WPS"); + cfg.new_ap_settings = &new_ap_settings; + } + data->wps = wps_init(&cfg); if (data->wps == NULL) { os_free(data); @@ -147,6 +226,10 @@ static void * eap_wsc_init(struct eap_sm *sm) cfg.pin, cfg.pin_len, 0); } + /* Use reduced client timeout for WPS to avoid long wait */ + if (sm->ClientTimeout > 30) + sm->ClientTimeout = 30; + return data; } @@ -302,6 +385,7 @@ static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, u16 message_length = 0; enum wps_process_res res; struct wpabuf tmpbuf; + struct wpabuf *r; pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, &len); @@ -427,7 +511,13 @@ send_msg: } eap_wsc_state(data, MESG); - return eap_wsc_build_msg(data, ret, id); + r = eap_wsc_build_msg(data, ret, id); + if (data->state == FAIL && ret->methodState == METHOD_DONE) { + /* Use reduced client timeout for WPS to avoid long wait */ + if (sm->ClientTimeout > 2) + sm->ClientTimeout = 2; + } + return r; } diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c index 9172e1f3481d..309a331124eb 100644 --- a/src/eap_peer/ikev2.c +++ b/src/eap_peer/ikev2.c @@ -15,7 +15,7 @@ #include "includes.h" #include "common.h" -#include "dh_groups.h" +#include "crypto/dh_groups.h" #include "ikev2.h" diff --git a/src/eap_peer/mschapv2.c b/src/eap_peer/mschapv2.c index 01c22d89753f..b8fb07502fd7 100644 --- a/src/eap_peer/mschapv2.c +++ b/src/eap_peer/mschapv2.c @@ -15,7 +15,7 @@ #include "includes.h" #include "common.h" -#include "ms_funcs.h" +#include "crypto/ms_funcs.h" #include "mschapv2.h" const u8 * mschapv2_remove_domain(const u8 *username, size_t *len) @@ -39,13 +39,13 @@ const u8 * mschapv2_remove_domain(const u8 *username, size_t *len) } -void mschapv2_derive_response(const u8 *identity, size_t identity_len, - const u8 *password, size_t password_len, - int pwhash, - const u8 *auth_challenge, - const u8 *peer_challenge, - u8 *nt_response, u8 *auth_response, - u8 *master_key) +int mschapv2_derive_response(const u8 *identity, size_t identity_len, + const u8 *password, size_t password_len, + int pwhash, + const u8 *auth_challenge, + const u8 *peer_challenge, + u8 *nt_response, u8 *auth_response, + u8 *master_key) { const u8 *username; size_t username_len; @@ -93,14 +93,18 @@ void mschapv2_derive_response(const u8 *identity, size_t identity_len, /* Generate master_key here since we have the needed data available. */ if (pwhash) { - hash_nt_password_hash(password, password_hash_hash); + if (hash_nt_password_hash(password, password_hash_hash)) + return -1; } else { - nt_password_hash(password, password_len, password_hash); - hash_nt_password_hash(password_hash, password_hash_hash); + if (nt_password_hash(password, password_len, password_hash) || + hash_nt_password_hash(password_hash, password_hash_hash)) + return -1; } get_master_key(password_hash_hash, nt_response, master_key); wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", master_key, MSCHAPV2_MASTER_KEY_LEN); + + return 0; } diff --git a/src/eap_peer/mschapv2.h b/src/eap_peer/mschapv2.h index c7c36f772178..90dad31ef72a 100644 --- a/src/eap_peer/mschapv2.h +++ b/src/eap_peer/mschapv2.h @@ -21,13 +21,13 @@ #define MSCHAPV2_MASTER_KEY_LEN 16 const u8 * mschapv2_remove_domain(const u8 *username, size_t *len); -void mschapv2_derive_response(const u8 *username, size_t username_len, - const u8 *password, size_t password_len, - int pwhash, - const u8 *auth_challenge, - const u8 *peer_challenge, - u8 *nt_response, u8 *auth_response, - u8 *master_key); +int mschapv2_derive_response(const u8 *username, size_t username_len, + const u8 *password, size_t password_len, + int pwhash, + const u8 *auth_challenge, + const u8 *peer_challenge, + u8 *nt_response, u8 *auth_response, + u8 *master_key); int mschapv2_verify_auth_response(const u8 *auth_response, const u8 *buf, size_t buf_len); diff --git a/src/eap_server/Makefile b/src/eap_server/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/eap_server/Makefile +++ b/src/eap_server/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 6a20da4f46b0..92400a5680c4 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -15,7 +15,7 @@ #ifndef EAP_H #define EAP_H -#include "defs.h" +#include "common/defs.h" #include "eap_common/eap_defs.h" #include "eap_server/eap_methods.h" #include "wpabuf.h" @@ -91,6 +91,7 @@ struct eapol_callbacks { struct eap_config { void *ssl_ctx; + void *msg_ctx; void *eap_sim_db_priv; Boolean backend_auth; int eap_server; @@ -105,6 +106,7 @@ struct eap_config { int tnc; struct wps_context *wps; const struct wpabuf *assoc_wps_ie; + const u8 *peer_addr; }; diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index d52b86f9558f..4269a8cfd6a0 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -185,6 +185,8 @@ struct eap_sm { struct wpabuf *assoc_wps_ie; Boolean start_reauth; + + u8 peer_addr[ETH_ALEN]; }; int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h index 0fd53909ff4b..5d4d92cbf215 100644 --- a/src/eap_server/eap_methods.h +++ b/src/eap_server/eap_methods.h @@ -1,6 +1,6 @@ /* - * hostapd / EAP method registration - * Copyright (c) 2004-2006, Jouni Malinen + * EAP server method registration + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -12,8 +12,10 @@ * See README and COPYING for more details. */ -#ifndef EAP_METHODS_H -#define EAP_METHODS_H +#ifndef EAP_SERVER_METHODS_H +#define EAP_SERVER_METHODS_H + +#include "eap_common/eap_defs.h" const struct eap_method * eap_server_get_eap_method(int vendor, EapType method); @@ -23,7 +25,29 @@ void eap_server_method_free(struct eap_method *method); int eap_server_method_register(struct eap_method *method); EapType eap_server_get_type(const char *name, int *vendor); -int eap_server_register_methods(void); void eap_server_unregister_methods(void); +const char * eap_server_get_name(int vendor, EapType type); -#endif /* EAP_METHODS_H */ +/* EAP server method registration calls for statically linked in methods */ +int eap_server_identity_register(void); +int eap_server_md5_register(void); +int eap_server_tls_register(void); +int eap_server_mschapv2_register(void); +int eap_server_peap_register(void); +int eap_server_tlv_register(void); +int eap_server_gtc_register(void); +int eap_server_ttls_register(void); +int eap_server_sim_register(void); +int eap_server_aka_register(void); +int eap_server_aka_prime_register(void); +int eap_server_pax_register(void); +int eap_server_psk_register(void); +int eap_server_sake_register(void); +int eap_server_gpsk_register(void); +int eap_server_vendor_test_register(void); +int eap_server_fast_register(void); +int eap_server_wsc_register(void); +int eap_server_ikev2_register(void); +int eap_server_tnc_register(void); + +#endif /* EAP_SERVER_METHODS_H */ diff --git a/src/eap_server/eap.c b/src/eap_server/eap_server.c similarity index 98% rename from src/eap_server/eap.c rename to src/eap_server/eap_server.c index 897adc3b1a2a..fdc26f9343fb 100644 --- a/src/eap_server/eap.c +++ b/src/eap_server/eap_server.c @@ -23,6 +23,7 @@ #include "common.h" #include "eap_i.h" #include "state_machine.h" +#include "common/wpa_ctrl.h" #define STATE_MACHINE_DATA struct eap_sm #define STATE_MACHINE_DEBUG_PREFIX "EAP" @@ -167,6 +168,9 @@ SM_STATE(EAP, INITIALIZE) } sm->num_rounds = 0; sm->method_pending = METHOD_PENDING_NONE; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED + MACSTR, MAC2STR(sm->peer_addr)); } @@ -196,6 +200,9 @@ SM_STATE(EAP, PICK_UP_METHOD) sm->currentMethod = EAP_TYPE_NONE; } } + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD + "method=%u", sm->currentMethod); } @@ -350,6 +357,9 @@ SM_STATE(EAP, PROPOSE_METHOD) sm->methodState = METHOD_CONTINUE; else sm->methodState = METHOD_PROPOSED; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD + "vendor=%u method=%u", vendor, sm->currentMethod); } @@ -410,6 +420,9 @@ SM_STATE(EAP, FAILURE) wpabuf_free(sm->lastReqData); sm->lastReqData = NULL; sm->eap_if.eapFail = TRUE; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE + MACSTR, MAC2STR(sm->peer_addr)); } @@ -424,6 +437,9 @@ SM_STATE(EAP, SUCCESS) if (sm->eap_if.eapKeyData) sm->eap_if.eapKeyAvailable = TRUE; sm->eap_if.eapSuccess = TRUE; + + wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS + MACSTR, MAC2STR(sm->peer_addr)); } @@ -1210,6 +1226,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx, sm->eapol_cb = eapol_cb; sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ sm->ssl_ctx = conf->ssl_ctx; + sm->msg_ctx = conf->msg_ctx; sm->eap_sim_db_priv = conf->eap_sim_db_priv; sm->backend_auth = conf->backend_auth; sm->eap_server = conf->eap_server; @@ -1238,6 +1255,8 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx, sm->wps = conf->wps; if (conf->assoc_wps_ie) sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); + if (conf->peer_addr) + os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); diff --git a/src/eap_server/eap_aka.c b/src/eap_server/eap_server_aka.c similarity index 98% rename from src/eap_server/eap_aka.c rename to src/eap_server/eap_server_aka.c index aad52fd649a5..4e7db48d0793 100644 --- a/src/eap_server/eap_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -15,12 +15,11 @@ #include "includes.h" #include "common.h" -#include "eap_server/eap_i.h" +#include "crypto/sha256.h" +#include "crypto/crypto.h" #include "eap_common/eap_sim_common.h" +#include "eap_server/eap_i.h" #include "eap_server/eap_sim_db.h" -#include "sha1.h" -#include "sha256.h" -#include "crypto.h" struct eap_aka_data { @@ -116,7 +115,7 @@ static void * eap_aka_init(struct eap_sm *sm) } -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME static void * eap_aka_prime_init(struct eap_sm *sm) { struct eap_aka_data *data; @@ -148,7 +147,7 @@ static void * eap_aka_prime_init(struct eap_sm *sm) return data; } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ static void eap_aka_reset(struct eap_sm *sm, void *priv) @@ -399,7 +398,7 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); } -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME if (data->eap_method == EAP_TYPE_AKA) { u16 flags = 0; int i; @@ -426,7 +425,7 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, flags |= EAP_AKA_BIDDING_FLAG_D; eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); @@ -701,7 +700,7 @@ static void eap_aka_determine_identity(struct eap_sm *sm, return; } -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME if (data->eap_method == EAP_TYPE_AKA_PRIME) { /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the * needed 6-octet SQN ^AK for CK',IK' derivation */ @@ -710,7 +709,7 @@ static void eap_aka_determine_identity(struct eap_sm *sm, data->network_name, data->network_name_len); } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ data->reauth = NULL; data->counter = 0; /* reset re-auth counter since this is full auth */ @@ -807,7 +806,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME #if 0 /* KDF negotiation; to be enabled only after more than one KDF is * supported */ @@ -830,7 +829,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm, return; } #endif -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ if (attr->checkcode && eap_aka_verify_checkcode(data, attr->checkcode, @@ -892,7 +891,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm, } if (data->next_reauth_id) { if (data->eap_method == EAP_TYPE_AKA_PRIME) { -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, identity, identity_len, @@ -900,7 +899,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm, data->counter + 1, data->k_encr, data->k_aut, data->k_re); -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ } else { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, @@ -1031,7 +1030,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm, } if (data->next_reauth_id) { if (data->eap_method == EAP_TYPE_AKA_PRIME) { -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, identity, identity_len, @@ -1039,7 +1038,7 @@ static void eap_aka_process_reauth(struct eap_sm *sm, data->counter + 1, data->k_encr, data->k_aut, data->k_re); -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ } else { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, @@ -1247,7 +1246,7 @@ int eap_server_aka_register(void) } -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME int eap_server_aka_prime_register(void) { struct eap_method *eap; @@ -1275,4 +1274,4 @@ int eap_server_aka_prime_register(void) return ret; } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ diff --git a/src/eap_server/eap_fast.c b/src/eap_server/eap_server_fast.c similarity index 95% rename from src/eap_server/eap_fast.c rename to src/eap_server/eap_server_fast.c index c06f396ffd67..39beb33056fb 100644 --- a/src/eap_server/eap_fast.c +++ b/src/eap_server/eap_server_fast.c @@ -15,13 +15,13 @@ #include "includes.h" #include "common.h" -#include "aes_wrap.h" -#include "sha1.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "tls.h" +#include "crypto/aes_wrap.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_common/eap_tlv_common.h" #include "eap_common/eap_fast_common.h" +#include "eap_i.h" +#include "eap_tls_common.h" static void eap_fast_reset(struct eap_sm *sm, void *priv); @@ -791,6 +791,11 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, /* Note: headers may be misaligned after A-ID */ + if (sm->identity) { + eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity, + sm->identity_len); + } + /* A-ID-Info (inside PAC-Info) */ eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info, srv_id_info_len); @@ -816,29 +821,28 @@ static int eap_fast_encrypt_phase2(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs", plain); - encr = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_mhead(plain), - wpabuf_len(plain)); + encr = eap_server_tls_encrypt(sm, &data->ssl, plain); wpabuf_free(plain); - if (data->ssl.out_buf && piggyback) { + if (data->ssl.tls_out && piggyback) { wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data " "(len=%d) with last Phase 1 Message (len=%d " "used=%d)", (int) wpabuf_len(encr), - (int) wpabuf_len(data->ssl.out_buf), - (int) data->ssl.out_used); - if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(encr)) < 0) { + (int) wpabuf_len(data->ssl.tls_out), + (int) data->ssl.tls_out_pos); + if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) { wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize " "output buffer"); wpabuf_free(encr); return -1; } - wpabuf_put_buf(data->ssl.out_buf, encr); + wpabuf_put_buf(data->ssl.tls_out, encr); wpabuf_free(encr); } else { - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = encr; + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = encr; } return 0; @@ -987,7 +991,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, left = in_len - sizeof(*hdr); wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; " "allowed types", pos + 1, left - 1); -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (m && m->vendor == EAP_VENDOR_IETF && m->method == EAP_TYPE_TNC) { wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required " @@ -996,7 +1000,7 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, eap_fast_phase2_init(sm, data, next_type); return; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ eap_sm_process_nak(sm, pos + 1, left - 1); if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && sm->user->methods[sm->user_eap_method_index].method != @@ -1064,13 +1068,13 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, eap_fast_state(data, CRYPTO_BINDING); data->eap_seq++; next_type = EAP_TYPE_NONE; -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (sm->tnc && !data->tnc_started) { wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC"); next_type = EAP_TYPE_TNC; data->tnc_started = 1; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ break; case FAILURE: break; @@ -1121,7 +1125,7 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm, } -static int eap_fast_parse_tlvs(u8 *data, size_t data_len, +static int eap_fast_parse_tlvs(struct wpabuf *data, struct eap_fast_tlv_parse *tlv) { int mandatory, tlv_type, len, res; @@ -1129,8 +1133,8 @@ static int eap_fast_parse_tlvs(u8 *data, size_t data_len, os_memset(tlv, 0, sizeof(*tlv)); - pos = data; - end = data + data_len; + pos = wpabuf_mhead(data); + end = pos + wpabuf_len(data); while (pos + 4 < end) { mandatory = pos[0] & 0x80; tlv_type = WPA_GET_BE16(pos) & 0x3fff; @@ -1241,12 +1245,12 @@ static int eap_fast_pac_type(u8 *pac, size_t len, u16 type) static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, struct eap_fast_data *data, - u8 *in_data, size_t in_len) + struct wpabuf *in_data) { struct eap_fast_tlv_parse tlv; int check_crypto_binding = data->state == CRYPTO_BINDING; - if (eap_fast_parse_tlvs(in_data, in_len, &tlv) < 0) { + if (eap_fast_parse_tlvs(in_data, &tlv) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received " "Phase 2 TLVs"); return; @@ -1373,70 +1377,44 @@ static void eap_fast_process_phase2(struct eap_sm *sm, struct eap_fast_data *data, struct wpabuf *in_buf) { - u8 *in_decrypted; - int len_decrypted; - size_t buf_len; - u8 *in_data; - size_t in_len; - - in_data = wpabuf_mhead(in_buf); - in_len = wpabuf_len(in_buf); + struct wpabuf *in_decrypted; wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" - " Phase 2", (unsigned long) in_len); + " Phase 2", (unsigned long) wpabuf_len(in_buf)); if (data->pending_phase2_resp) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " "skip decryption and use old data"); - eap_fast_process_phase2_tlvs( - sm, data, wpabuf_mhead(data->pending_phase2_resp), - wpabuf_len(data->pending_phase2_resp)); + eap_fast_process_phase2_tlvs(sm, data, + data->pending_phase2_resp); wpabuf_free(data->pending_phase2_resp); data->pending_phase2_resp = NULL; return; } - buf_len = in_len; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - in_decrypted = os_malloc(buf_len); + in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, + in_buf); if (in_decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory " - "for decryption"); - return; - } - - len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_data, in_len, - in_decrypted, buf_len); - if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " "data"); - os_free(in_decrypted); eap_fast_state(data, FAILURE); return; } - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", - in_decrypted, len_decrypted); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", + in_decrypted); - eap_fast_process_phase2_tlvs(sm, data, in_decrypted, len_decrypted); + eap_fast_process_phase2_tlvs(sm, data, in_decrypted); if (sm->method_pending == METHOD_PENDING_WAIT) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in " "pending wait state - save decrypted response"); wpabuf_free(data->pending_phase2_resp); - data->pending_phase2_resp = wpabuf_alloc_copy(in_decrypted, - len_decrypted); + data->pending_phase2_resp = in_decrypted; + return; } - os_free(in_decrypted); + wpabuf_free(in_decrypted); } @@ -1475,7 +1453,7 @@ static int eap_fast_process_phase1(struct eap_sm *sm, } if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) || - wpabuf_len(data->ssl.out_buf) > 0) + wpabuf_len(data->ssl.tls_out) > 0) return 1; /* @@ -1541,7 +1519,7 @@ static void eap_fast_process_msg(struct eap_sm *sm, void *priv, case PHASE2_METHOD: case CRYPTO_BINDING: case REQUEST_PAC: - eap_fast_process_phase2(sm, data, data->ssl.in_buf); + eap_fast_process_phase2(sm, data, data->ssl.tls_in); break; default: wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s", diff --git a/src/eap_server/eap_gpsk.c b/src/eap_server/eap_server_gpsk.c similarity index 100% rename from src/eap_server/eap_gpsk.c rename to src/eap_server/eap_server_gpsk.c diff --git a/src/eap_server/eap_gtc.c b/src/eap_server/eap_server_gtc.c similarity index 98% rename from src/eap_server/eap_gtc.c rename to src/eap_server/eap_server_gtc.c index 97e328b83fa6..79b9696b2c95 100644 --- a/src/eap_server/eap_gtc.c +++ b/src/eap_server/eap_server_gtc.c @@ -33,14 +33,14 @@ static void * eap_gtc_init(struct eap_sm *sm) return NULL; data->state = CONTINUE; -#ifdef EAP_FAST +#ifdef EAP_SERVER_FAST if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_FAST) { wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " "with challenge/response"); data->prefix = 1; } -#endif /* EAP_FAST */ +#endif /* EAP_SERVER_FAST */ return data; } @@ -109,7 +109,7 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv, wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen); -#ifdef EAP_FAST +#ifdef EAP_SERVER_FAST if (data->prefix) { const u8 *pos2, *end; /* "RESPONSE=\0" */ @@ -170,7 +170,7 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv, "EAP-GTC: Response password", pos, rlen); } -#endif /* EAP_FAST */ +#endif /* EAP_SERVER_FAST */ if (sm->user == NULL || sm->user->password == NULL || sm->user->password_hash) { diff --git a/src/eap_server/eap_identity.c b/src/eap_server/eap_server_identity.c similarity index 100% rename from src/eap_server/eap_identity.c rename to src/eap_server/eap_server_identity.c diff --git a/src/eap_server/eap_ikev2.c b/src/eap_server/eap_server_ikev2.c similarity index 100% rename from src/eap_server/eap_ikev2.c rename to src/eap_server/eap_server_ikev2.c diff --git a/src/eap_server/eap_md5.c b/src/eap_server/eap_server_md5.c similarity index 100% rename from src/eap_server/eap_md5.c rename to src/eap_server/eap_server_md5.c diff --git a/src/eap_server/eap_methods.c b/src/eap_server/eap_server_methods.c similarity index 55% rename from src/eap_server/eap_methods.c rename to src/eap_server/eap_server_methods.c index 4092d675b34f..900a5dd31810 100644 --- a/src/eap_server/eap_methods.c +++ b/src/eap_server/eap_server_methods.c @@ -1,6 +1,6 @@ /* - * hostapd / EAP method registration - * Copyright (c) 2004-2006, Jouni Malinen + * EAP server method registration + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -133,159 +133,6 @@ int eap_server_method_register(struct eap_method *method) } -/** - * eap_server_register_methods - Register statically linked EAP server methods - * Returns: 0 on success, -1 on failure - * - * This function is called at program initialization to register all EAP server - * methods that were linked in statically. - */ -int eap_server_register_methods(void) -{ - int ret = 0; - - if (ret == 0) { - int eap_server_identity_register(void); - ret = eap_server_identity_register(); - } - -#ifdef EAP_MD5 - if (ret == 0) { - int eap_server_md5_register(void); - ret = eap_server_md5_register(); - } -#endif /* EAP_MD5 */ - -#ifdef EAP_TLS - if (ret == 0) { - int eap_server_tls_register(void); - ret = eap_server_tls_register(); - } -#endif /* EAP_TLS */ - -#ifdef EAP_MSCHAPv2 - if (ret == 0) { - int eap_server_mschapv2_register(void); - ret = eap_server_mschapv2_register(); - } -#endif /* EAP_MSCHAPv2 */ - -#ifdef EAP_PEAP - if (ret == 0) { - int eap_server_peap_register(void); - ret = eap_server_peap_register(); - } -#endif /* EAP_PEAP */ - -#ifdef EAP_TLV - if (ret == 0) { - int eap_server_tlv_register(void); - ret = eap_server_tlv_register(); - } -#endif /* EAP_TLV */ - -#ifdef EAP_GTC - if (ret == 0) { - int eap_server_gtc_register(void); - ret = eap_server_gtc_register(); - } -#endif /* EAP_GTC */ - -#ifdef EAP_TTLS - if (ret == 0) { - int eap_server_ttls_register(void); - ret = eap_server_ttls_register(); - } -#endif /* EAP_TTLS */ - -#ifdef EAP_SIM - if (ret == 0) { - int eap_server_sim_register(void); - ret = eap_server_sim_register(); - } -#endif /* EAP_SIM */ - -#ifdef EAP_AKA - if (ret == 0) { - int eap_server_aka_register(void); - ret = eap_server_aka_register(); - } -#endif /* EAP_AKA */ - -#ifdef EAP_AKA_PRIME - if (ret == 0) { - int eap_server_aka_prime_register(void); - ret = eap_server_aka_prime_register(); - } -#endif /* EAP_AKA_PRIME */ - -#ifdef EAP_PAX - if (ret == 0) { - int eap_server_pax_register(void); - ret = eap_server_pax_register(); - } -#endif /* EAP_PAX */ - -#ifdef EAP_PSK - if (ret == 0) { - int eap_server_psk_register(void); - ret = eap_server_psk_register(); - } -#endif /* EAP_PSK */ - -#ifdef EAP_SAKE - if (ret == 0) { - int eap_server_sake_register(void); - ret = eap_server_sake_register(); - } -#endif /* EAP_SAKE */ - -#ifdef EAP_GPSK - if (ret == 0) { - int eap_server_gpsk_register(void); - ret = eap_server_gpsk_register(); - } -#endif /* EAP_GPSK */ - -#ifdef EAP_VENDOR_TEST - if (ret == 0) { - int eap_server_vendor_test_register(void); - ret = eap_server_vendor_test_register(); - } -#endif /* EAP_VENDOR_TEST */ - -#ifdef EAP_FAST - if (ret == 0) { - int eap_server_fast_register(void); - ret = eap_server_fast_register(); - } -#endif /* EAP_FAST */ - -#ifdef EAP_WSC - if (ret == 0) { - int eap_server_wsc_register(void); - ret = eap_server_wsc_register(); - } -#endif /* EAP_WSC */ - -#ifdef EAP_IKEV2 - if (ret == 0) { - int eap_server_ikev2_register(void); - ret = eap_server_ikev2_register(); - } -#endif /* EAP_IKEV2 */ - -#ifdef EAP_TNC - if (ret == 0) { - int eap_server_tnc_register(void); - ret = eap_server_tnc_register(); - } -#endif /* EAP_TNC */ - - return ret; -} - - /** * eap_server_unregister_methods - Unregister EAP server methods * @@ -306,3 +153,23 @@ void eap_server_unregister_methods(void) eap_server_method_free(m); } } + + +/** + * eap_server_get_name - Get EAP method name for the given EAP type + * @vendor: EAP Vendor-Id (0 = IETF) + * @type: EAP method type + * Returns: EAP method name, e.g., TLS, or %NULL if not found + * + * This function maps EAP type numbers into EAP type names based on the list of + * EAP methods included in the build. + */ +const char * eap_server_get_name(int vendor, EapType type) +{ + struct eap_method *m; + for (m = eap_methods; m; m = m->next) { + if (m->vendor == vendor && m->method == type) + return m->name; + } + return NULL; +} diff --git a/src/eap_server/eap_mschapv2.c b/src/eap_server/eap_server_mschapv2.c similarity index 97% rename from src/eap_server/eap_mschapv2.c rename to src/eap_server/eap_server_mschapv2.c index 20e7adee6f95..39d1c6ef2b36 100644 --- a/src/eap_server/eap_mschapv2.c +++ b/src/eap_server/eap_server_mschapv2.c @@ -15,8 +15,8 @@ #include "includes.h" #include "common.h" +#include "crypto/ms_funcs.h" #include "eap_i.h" -#include "ms_funcs.h" struct eap_mschapv2_hdr { @@ -295,6 +295,7 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, u8 expected[24]; const u8 *username, *user; size_t username_len, user_len; + int res; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, &len); @@ -372,17 +373,22 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, username, username_len); if (sm->user->password_hash) { - generate_nt_response_pwhash(data->auth_challenge, - peer_challenge, - username, username_len, - sm->user->password, - expected); + res = generate_nt_response_pwhash(data->auth_challenge, + peer_challenge, + username, username_len, + sm->user->password, + expected); } else { - generate_nt_response(data->auth_challenge, peer_challenge, - username, username_len, - sm->user->password, - sm->user->password_len, - expected); + res = generate_nt_response(data->auth_challenge, + peer_challenge, + username, username_len, + sm->user->password, + sm->user->password_len, + expected); + } + if (res) { + data->state = FAILURE; + return; } if (os_memcmp(nt_response, expected, 24) == 0) { diff --git a/src/eap_server/eap_pax.c b/src/eap_server/eap_server_pax.c similarity index 100% rename from src/eap_server/eap_pax.c rename to src/eap_server/eap_server_pax.c diff --git a/src/eap_server/eap_peap.c b/src/eap_server/eap_server_peap.c similarity index 92% rename from src/eap_server/eap_peap.c rename to src/eap_server/eap_server_peap.c index 4b2d5a5c83ff..674ecd2231e2 100644 --- a/src/eap_server/eap_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -15,12 +15,12 @@ #include "includes.h" #include "common.h" -#include "sha1.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_i.h" #include "eap_tls_common.h" #include "eap_common/eap_tlv_common.h" #include "eap_common/eap_peap_common.h" -#include "tls.h" #include "tncs.h" @@ -235,7 +235,7 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, struct eap_peap_data *data, u8 id) { - struct wpabuf *buf, *encr_req; + struct wpabuf *buf, *encr_req, msgbuf; const u8 *req; size_t req_len; @@ -260,19 +260,20 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, req_len -= sizeof(struct eap_hdr); } - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + wpabuf_set(&msgbuf, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); wpabuf_free(buf); return encr_req; } -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, struct eap_peap_data *data, u8 id) { - struct wpabuf *buf1, *buf, *encr_req; + struct wpabuf *buf1, *buf, *encr_req, msgbuf; const u8 *req; size_t req_len; @@ -297,13 +298,14 @@ static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, req += sizeof(struct eap_hdr); req_len -= sizeof(struct eap_hdr); + wpabuf_set(&msgbuf, req, req_len); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); wpabuf_free(buf); return encr_req; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ static void eap_peap_get_isk(struct eap_peap_data *data, @@ -370,17 +372,17 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, u8 id) { struct wpabuf *buf, *encr_req; - size_t len; + size_t mlen; - len = 6; /* Result TLV */ + mlen = 6; /* Result TLV */ if (data->crypto_binding != NO_BINDING) - len += 60; /* Cryptobinding TLV */ -#ifdef EAP_TNC + mlen += 60; /* Cryptobinding TLV */ +#ifdef EAP_SERVER_TNC if (data->soh_response) - len += wpabuf_len(data->soh_response); -#endif /* EAP_TNC */ + mlen += wpabuf_len(data->soh_response); +#endif /* EAP_SERVER_TNC */ - buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, + buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen, EAP_CODE_REQUEST, id); if (buf == NULL) return NULL; @@ -401,7 +403,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, size_t len[2]; u16 tlv_type; -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (data->soh_response) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH " "Response TLV"); @@ -409,7 +411,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, wpabuf_free(data->soh_response); data->soh_response = NULL; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ if (eap_peap_derive_cmk(sm, data) < 0 || os_get_random(data->binding_nonce, 32)) { @@ -450,8 +452,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", buf); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf), - wpabuf_len(buf)); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); wpabuf_free(buf); return encr_req; @@ -462,7 +463,7 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, struct eap_peap_data *data, u8 id, int success) { - struct wpabuf *encr_req; + struct wpabuf *encr_req, msgbuf; size_t req_len; struct eap_hdr *hdr; @@ -478,7 +479,8 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", (u8 *) hdr, req_len); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, (u8 *) hdr, req_len); + wpabuf_set(&msgbuf, hdr, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); os_free(hdr); return encr_req; @@ -513,32 +515,32 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) break; case PHASE2_ID: case PHASE2_METHOD: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_peap_build_phase2_req(sm, data, id); + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); break; -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC case PHASE2_SOH: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_peap_build_phase2_soh(sm, data, id); + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id); break; -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ case PHASE2_TLV: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_peap_build_phase2_tlv(sm, data, id); + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id); break; case SUCCESS_REQ: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id, + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, 1); break; case FAILURE_REQ: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id, + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, 0); break; default: @@ -757,7 +759,7 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm, } -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC static void eap_peap_process_phase2_soh(struct eap_sm *sm, struct eap_peap_data *data, struct wpabuf *in_data) @@ -885,7 +887,7 @@ auth_method: wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); eap_peap_phase2_init(sm, data, next_type); } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ static void eap_peap_process_phase2_response(struct eap_sm *sm, @@ -902,12 +904,12 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, return; } -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (data->state == PHASE2_SOH) { eap_peap_process_phase2_soh(sm, data, in_data); return; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ if (data->phase2_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " @@ -991,7 +993,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, break; } -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (data->state != PHASE2_SOH && sm->tnc && data->peap_version == 0) { eap_peap_state(data, PHASE2_SOH); @@ -1000,7 +1002,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, next_type = EAP_TYPE_NONE; break; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ eap_peap_state(data, PHASE2_METHOD); next_type = sm->user->methods[0].method; @@ -1029,17 +1031,11 @@ static void eap_peap_process_phase2(struct eap_sm *sm, struct wpabuf *in_buf) { struct wpabuf *in_decrypted; - int len_decrypted; const struct eap_hdr *hdr; - size_t buf_len, len; - u8 *in_data; - size_t in_len; - - in_data = wpabuf_mhead(in_buf); - in_len = wpabuf_len(in_buf); + size_t len; wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) in_len); + " Phase 2", (unsigned long) wpabuf_len(in_buf)); if (data->pending_phase2_resp) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " @@ -1051,34 +1047,14 @@ static void eap_peap_process_phase2(struct eap_sm *sm, return; } - buf_len = in_len; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - in_decrypted = wpabuf_alloc(buf_len); + in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, + in_buf); if (in_decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory " - "for decryption"); - return; - } - - len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_data, in_len, - wpabuf_mhead(in_decrypted), - buf_len); - if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " "data"); - wpabuf_free(in_decrypted); eap_peap_state(data, FAILURE); return; } - wpabuf_put(in_decrypted, len_decrypted); wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted); @@ -1191,7 +1167,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm, break; } - os_free(in_decrypted); + wpabuf_free(in_decrypted); } @@ -1199,7 +1175,6 @@ static int eap_peapv2_start_phase2(struct eap_sm *sm, struct eap_peap_data *data) { struct wpabuf *buf, *buf2; - int res; wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " "payload in the same message"); @@ -1218,35 +1193,25 @@ static int eap_peapv2_start_phase2(struct eap_sm *sm, wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); - buf = wpabuf_alloc(data->ssl.tls_out_limit); - if (buf == NULL) { - wpabuf_free(buf2); - return -1; - } - - res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, - wpabuf_head(buf2), wpabuf_len(buf2), - wpabuf_put(buf, 0), - data->ssl.tls_out_limit); + buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, + buf2); wpabuf_free(buf2); - if (res < 0) { + if (buf == NULL) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " "data"); - wpabuf_free(buf); return -1; } - wpabuf_put(buf, res); wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", buf); /* Append TLS data into the pending buffer after the Server Finished */ - if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) { + if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) { wpabuf_free(buf); return -1; } - wpabuf_put_buf(data->ssl.out_buf, buf); + wpabuf_put_buf(data->ssl.tls_out, buf); wpabuf_free(buf); return 0; @@ -1305,7 +1270,7 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv, case PHASE2_METHOD: case PHASE2_SOH: case PHASE2_TLV: - eap_peap_process_phase2(sm, data, respData, data->ssl.in_buf); + eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in); break; case SUCCESS_REQ: eap_peap_state(data, SUCCESS); diff --git a/src/eap_server/eap_psk.c b/src/eap_server/eap_server_psk.c similarity index 99% rename from src/eap_server/eap_psk.c rename to src/eap_server/eap_server_psk.c index c68d4c34d451..4c30346e59ce 100644 --- a/src/eap_server/eap_psk.c +++ b/src/eap_server/eap_server_psk.c @@ -18,9 +18,9 @@ #include "includes.h" #include "common.h" -#include "eap_server/eap_i.h" -#include "aes_wrap.h" +#include "crypto/aes_wrap.h" #include "eap_common/eap_psk_common.h" +#include "eap_server/eap_i.h" struct eap_psk_data { diff --git a/src/eap_server/eap_sake.c b/src/eap_server/eap_server_sake.c similarity index 100% rename from src/eap_server/eap_sake.c rename to src/eap_server/eap_server_sake.c diff --git a/src/eap_server/eap_sim.c b/src/eap_server/eap_server_sim.c similarity index 100% rename from src/eap_server/eap_sim.c rename to src/eap_server/eap_server_sim.c diff --git a/src/eap_server/eap_tls.c b/src/eap_server/eap_server_tls.c similarity index 98% rename from src/eap_server/eap_tls.c rename to src/eap_server/eap_server_tls.c index 5747940f7806..c98fa185bb5d 100644 --- a/src/eap_server/eap_tls.c +++ b/src/eap_server/eap_server_tls.c @@ -17,7 +17,7 @@ #include "common.h" #include "eap_i.h" #include "eap_tls_common.h" -#include "tls.h" +#include "crypto/tls.h" static void eap_tls_reset(struct eap_sm *sm, void *priv); @@ -169,7 +169,7 @@ static void eap_tls_process_msg(struct eap_sm *sm, void *priv, const struct wpabuf *respData) { struct eap_tls_data *data = priv; - if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) { + if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " "handshake message"); return; diff --git a/src/eap_server/eap_tls_common.c b/src/eap_server/eap_server_tls_common.c similarity index 79% rename from src/eap_server/eap_tls_common.c rename to src/eap_server/eap_server_tls_common.c index bda1184c02bd..25ae683f0668 100644 --- a/src/eap_server/eap_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -1,6 +1,6 @@ /* - * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2008, Jouni Malinen + * EAP-TLS/PEAP/TTLS/FAST server common functions + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -15,10 +15,13 @@ #include "includes.h" #include "common.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_i.h" #include "eap_tls_common.h" -#include "sha1.h" -#include "tls.h" + + +static void eap_server_tls_free_in_buf(struct eap_ssl_data *data); int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, @@ -58,8 +61,9 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) { tls_connection_deinit(sm->ssl_ctx, data->conn); - os_free(data->in_buf); - os_free(data->out_buf); + eap_server_tls_free_in_buf(data); + wpabuf_free(data->tls_out); + data->tls_out = NULL; } @@ -114,17 +118,17 @@ struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, size_t send_len, plen; wpa_printf(MSG_DEBUG, "SSL: Generating Request"); - if (data->out_buf == NULL) { - wpa_printf(MSG_ERROR, "SSL: out_buf NULL in %s", __func__); + if (data->tls_out == NULL) { + wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); return NULL; } flags = version; - send_len = wpabuf_len(data->out_buf) - data->out_used; + send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; if (1 + send_len > data->tls_out_limit) { send_len = data->tls_out_limit - 1; flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; - if (data->out_used == 0) { + if (data->tls_out_pos == 0) { flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; send_len -= 4; } @@ -141,25 +145,25 @@ struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, wpabuf_put_u8(req, flags); /* Flags */ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) - wpabuf_put_be32(req, wpabuf_len(data->out_buf)); + wpabuf_put_be32(req, wpabuf_len(data->tls_out)); - wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, + wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, send_len); - data->out_used += send_len; + data->tls_out_pos += send_len; - if (data->out_used == wpabuf_len(data->out_buf)) { + if (data->tls_out_pos == wpabuf_len(data->tls_out)) { wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " "(message sent completely)", (unsigned long) send_len); - wpabuf_free(data->out_buf); - data->out_buf = NULL; - data->out_used = 0; + wpabuf_free(data->tls_out); + data->tls_out = NULL; + data->tls_out_pos = 0; data->state = MSG; } else { wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " "(%lu more to send)", (unsigned long) send_len, - (unsigned long) wpabuf_len(data->out_buf) - - data->out_used); + (unsigned long) wpabuf_len(data->tls_out) - + data->tls_out_pos); data->state = WAIT_FRAG_ACK; } @@ -185,15 +189,15 @@ static int eap_server_tls_process_cont(struct eap_ssl_data *data, const u8 *buf, size_t len) { /* Process continuation of a pending message */ - if (len > wpabuf_tailroom(data->in_buf)) { + if (len > wpabuf_tailroom(data->tls_in)) { wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); return -1; } - wpabuf_put_data(data->in_buf, buf, len); + wpabuf_put_data(data->tls_in, buf, len); wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " "bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); + (unsigned long) wpabuf_tailroom(data->tls_in)); return 0; } @@ -204,13 +208,13 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data, const u8 *buf, size_t len) { /* Process a fragment that is not the last one of the message */ - if (data->in_buf == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { + if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " "fragmented packet"); return -1; } - if (data->in_buf == NULL) { + if (data->tls_in == NULL) { /* First fragment of the message */ /* Limit length to avoid rogue peers from causing large @@ -221,16 +225,16 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data, return -1; } - data->in_buf = wpabuf_alloc(message_length); - if (data->in_buf == NULL) { + data->tls_in = wpabuf_alloc(message_length); + if (data->tls_in == NULL) { wpa_printf(MSG_DEBUG, "SSL: No memory for message"); return -1; } - wpabuf_put_data(data->in_buf, buf, len); + wpabuf_put_data(data->tls_in, buf, len); wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " "fragment, waiting for %lu bytes more", (unsigned long) len, - (unsigned long) wpabuf_tailroom(data->in_buf)); + (unsigned long) wpabuf_tailroom(data->tls_in)); } return 0; @@ -239,30 +243,28 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data, int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) { - u8 *next; - size_t next_len; - - next = tls_connection_server_handshake( - sm->ssl_ctx, data->conn, - wpabuf_mhead(data->in_buf), - wpabuf_len(data->in_buf), - &next_len); - if (next == NULL) { - wpa_printf(MSG_INFO, "SSL: TLS processing failed"); - return -1; - } - if (data->out_buf) { + if (data->tls_out) { /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: pending tls_out data when " "processing new message"); - os_free(data->out_buf); - WPA_ASSERT(data->out_buf == NULL); + wpabuf_free(data->tls_out); + WPA_ASSERT(data->tls_out == NULL); } - data->out_buf = wpabuf_alloc_ext_data(next, next_len); - if (data->out_buf == NULL) { - os_free(next); + + data->tls_out = tls_connection_server_handshake(sm->ssl_ctx, + data->conn, + data->tls_in, NULL); + if (data->tls_out == NULL) { + wpa_printf(MSG_INFO, "SSL: TLS processing failed"); return -1; } + if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { + /* TLS processing has failed - return error */ + wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " + "report error"); + return -1; + } + return 0; } @@ -299,7 +301,7 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, return 1; } - if (data->in_buf && + if (data->tls_in && eap_server_tls_process_cont(data, *pos, end - *pos) < 0) return -1; @@ -317,10 +319,10 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, data->state = MSG; } - if (data->in_buf == NULL) { + if (data->tls_in == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&data->tmpbuf, *pos, end - *pos); - data->in_buf = &data->tmpbuf; + data->tls_in = &data->tmpbuf; } return 0; @@ -329,36 +331,25 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, static void eap_server_tls_free_in_buf(struct eap_ssl_data *data) { - if (data->in_buf != &data->tmpbuf) - wpabuf_free(data->in_buf); - data->in_buf = NULL; + if (data->tls_in != &data->tmpbuf) + wpabuf_free(data->tls_in); + data->tls_in = NULL; } struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const u8 *plain, size_t plain_len) + const struct wpabuf *plain) { - int res; struct wpabuf *buf; - size_t buf_len; - /* reserve some extra room for encryption overhead */ - buf_len = plain_len + 300; - buf = wpabuf_alloc(buf_len); - if (buf == NULL) - return NULL; - res = tls_connection_encrypt(sm->ssl_ctx, data->conn, - plain, plain_len, wpabuf_put(buf, 0), - buf_len); - if (res < 0) { + buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, + plain); + if (buf == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); - wpabuf_free(buf); return NULL; } - wpabuf_put(buf, res); - return buf; } diff --git a/src/eap_server/eap_tnc.c b/src/eap_server/eap_server_tnc.c similarity index 85% rename from src/eap_server/eap_tnc.c rename to src/eap_server/eap_server_tnc.c index 4cb3ecfb0565..f3b70edabfcd 100644 --- a/src/eap_server/eap_tnc.c +++ b/src/eap_server/eap_server_tnc.c @@ -1,6 +1,6 @@ /* * EAP server method: EAP-TNC (Trusted Network Connect) - * Copyright (c) 2007-2008, Jouni Malinen + * Copyright (c) 2007-2010, Jouni Malinen * * 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 @@ -21,14 +21,18 @@ struct eap_tnc_data { - enum { START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE, - FAIL } state; + enum eap_tnc_state { + START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE, + FAIL + } state; enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation; struct tncs_data *tncs; struct wpabuf *in_buf; struct wpabuf *out_buf; size_t out_used; size_t fragment_size; + unsigned int was_done:1; + unsigned int was_fail:1; }; @@ -41,6 +45,38 @@ struct eap_tnc_data { #define EAP_TNC_VERSION 1 +static const char * eap_tnc_state_txt(enum eap_tnc_state state) +{ + switch (state) { + case START: + return "START"; + case CONTINUE: + return "CONTINUE"; + case RECOMMENDATION: + return "RECOMMENDATION"; + case FRAG_ACK: + return "FRAG_ACK"; + case WAIT_FRAG_ACK: + return "WAIT_FRAG_ACK"; + case DONE: + return "DONE"; + case FAIL: + return "FAIL"; + } + return "??"; +} + + +static void eap_tnc_set_state(struct eap_tnc_data *data, + enum eap_tnc_state new_state) +{ + wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s", + eap_tnc_state_txt(data->state), + eap_tnc_state_txt(new_state)); + data->state = new_state; +} + + static void * eap_tnc_init(struct eap_sm *sm) { struct eap_tnc_data *data; @@ -48,7 +84,7 @@ static void * eap_tnc_init(struct eap_sm *sm) data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; - data->state = START; + eap_tnc_set_state(data, START); data->tncs = tncs_init(); if (data->tncs == NULL) { os_free(data); @@ -81,13 +117,13 @@ static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm, if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for " "request"); - data->state = FAIL; + eap_tnc_set_state(data, FAIL); return NULL; } wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION); - data->state = CONTINUE; + eap_tnc_set_state(data, CONTINUE); return req; } @@ -146,17 +182,17 @@ static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm, { switch (data->recommendation) { case ALLOW: - data->state = DONE; + eap_tnc_set_state(data, DONE); break; case ISOLATE: - data->state = FAIL; + eap_tnc_set_state(data, FAIL); /* TODO: support assignment to a different VLAN */ break; case NO_ACCESS: - data->state = FAIL; + eap_tnc_set_state(data, FAIL); break; case NO_RECOMMENDATION: - data->state = DONE; + eap_tnc_set_state(data, DONE); break; default: wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation"); @@ -171,12 +207,13 @@ static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) { struct wpabuf *msg; - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id); + msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); if (msg == NULL) { wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " "for fragment ack"); return NULL; } + wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); @@ -226,12 +263,20 @@ static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id) wpabuf_free(data->out_buf); data->out_buf = NULL; data->out_used = 0; + if (data->was_fail) + eap_tnc_set_state(data, FAIL); + else if (data->was_done) + eap_tnc_set_state(data, DONE); } else { wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " "(%lu more to send)", (unsigned long) send_len, (unsigned long) wpabuf_len(data->out_buf) - data->out_used); - data->state = WAIT_FRAG_ACK; + if (data->state == FAIL) + data->was_fail = 1; + else if (data->state == DONE) + data->was_done = 1; + eap_tnc_set_state(data, WAIT_FRAG_ACK); } return req; @@ -327,27 +372,27 @@ static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf) switch (res) { case TNCCS_RECOMMENDATION_ALLOW: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access"); - data->state = RECOMMENDATION; + eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = ALLOW; break; case TNCCS_RECOMMENDATION_NO_RECOMMENDATION: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation"); - data->state = RECOMMENDATION; + eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = NO_RECOMMENDATION; break; case TNCCS_RECOMMENDATION_ISOLATE: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation"); - data->state = RECOMMENDATION; + eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = ISOLATE; break; case TNCCS_RECOMMENDATION_NO_ACCESS: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access"); - data->state = RECOMMENDATION; + eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = NO_ACCESS; break; case TNCCS_PROCESS_ERROR: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error"); - data->state = FAIL; + eap_tnc_set_state(data, FAIL); break; default: break; @@ -361,7 +406,7 @@ static int eap_tnc_process_cont(struct eap_tnc_data *data, /* Process continuation of a pending message */ if (len > wpabuf_tailroom(data->in_buf)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); - data->state = FAIL; + eap_tnc_set_state(data, FAIL); return -1; } @@ -435,7 +480,7 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv, if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); - data->state = FAIL; + eap_tnc_set_state(data, FAIL); return; } message_length = WPA_GET_BE32(pos); @@ -445,7 +490,7 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv, wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); - data->state = FAIL; + eap_tnc_set_state(data, FAIL); return; } } @@ -453,32 +498,32 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv, "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { - if (len != 0) { + if (len > 1) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload " "in WAIT_FRAG_ACK state"); - data->state = FAIL; + eap_tnc_set_state(data, FAIL); return; } wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); - data->state = CONTINUE; + eap_tnc_set_state(data, CONTINUE); return; } if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { - data->state = FAIL; + eap_tnc_set_state(data, FAIL); return; } if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { if (eap_tnc_process_fragment(data, flags, message_length, pos, end - pos) < 0) - data->state = FAIL; + eap_tnc_set_state(data, FAIL); else - data->state = FRAG_ACK; + eap_tnc_set_state(data, FRAG_ACK); return; } else if (data->state == FRAG_ACK) { wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); - data->state = CONTINUE; + eap_tnc_set_state(data, CONTINUE); } if (data->in_buf == NULL) { diff --git a/src/eap_server/eap_ttls.c b/src/eap_server/eap_server_ttls.c similarity index 93% rename from src/eap_server/eap_ttls.c rename to src/eap_server/eap_server_ttls.c index 21e4b21b15db..702c50c3566e 100644 --- a/src/eap_server/eap_ttls.c +++ b/src/eap_server/eap_server_ttls.c @@ -15,12 +15,12 @@ #include "includes.h" #include "common.h" +#include "crypto/ms_funcs.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "eap_server/eap_i.h" #include "eap_server/eap_tls_common.h" -#include "ms_funcs.h" -#include "sha1.h" #include "eap_common/chap.h" -#include "tls.h" #include "eap_common/eap_ttls.h" @@ -163,14 +163,14 @@ struct eap_ttls_avp { }; -static int eap_ttls_avp_parse(u8 *buf, size_t len, struct eap_ttls_avp *parse) +static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse) { struct ttls_avp *avp; u8 *pos; int left; - pos = buf; - left = len; + pos = wpabuf_mhead(buf); + left = wpabuf_len(buf); os_memset(parse, 0, sizeof(*parse)); while (left > 0) { @@ -449,8 +449,6 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req( struct eap_sm *sm, struct eap_ttls_data *data, u8 id) { struct wpabuf *buf, *encr_req; - u8 *req; - size_t req_len; buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); @@ -467,12 +465,10 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req( return NULL; } - req = wpabuf_mhead(buf); - req_len = wpabuf_len(buf); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated Phase " - "2 data", req, req_len); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated " + "Phase 2 data", buf); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); wpabuf_free(buf); return encr_req; @@ -482,10 +478,9 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req( static struct wpabuf * eap_ttls_build_phase2_mschapv2( struct eap_sm *sm, struct eap_ttls_data *data) { - struct wpabuf *encr_req; + struct wpabuf *encr_req, msgbuf; u8 *req, *pos, *end; int ret; - size_t req_len; pos = req = os_malloc(100); if (req == NULL) @@ -510,11 +505,11 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2( AVP_PAD(req, pos); } - req_len = pos - req; - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " - "data", req, req_len); + wpabuf_set(&msgbuf, req, pos - req); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " + "data", &msgbuf); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); os_free(req); return encr_req; @@ -524,25 +519,8 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2( static struct wpabuf * eap_ttls_build_phase_finished( struct eap_sm *sm, struct eap_ttls_data *data, int final) { - int len; - struct wpabuf *req; - const int max_len = 300; - - req = wpabuf_alloc(max_len); - if (req == NULL) - return NULL; - - len = tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, final, - wpabuf_mhead(req), - max_len); - if (len < 0) { - wpabuf_free(req); - return NULL; - } - wpabuf_put(req, len); - - return req; + return tls_connection_ia_send_phase_finished(sm->ssl_ctx, + data->ssl.conn, final); } @@ -571,20 +549,20 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) } break; case PHASE2_METHOD: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_ttls_build_phase2_eap_req(sm, data, + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_ttls_build_phase2_eap_req(sm, data, id); break; case PHASE2_MSCHAPV2_RESP: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_ttls_build_phase2_mschapv2(sm, data); + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data); break; case PHASE_FINISHED: - wpabuf_free(data->ssl.out_buf); - data->ssl.out_used = 0; - data->ssl.out_buf = eap_ttls_build_phase_finished(sm, data, 1); + wpabuf_free(data->ssl.tls_out); + data->ssl.tls_out_pos = 0; + data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1); break; default: wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", @@ -1126,18 +1104,11 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, struct eap_ttls_data *data, struct wpabuf *in_buf) { - u8 *in_decrypted; - int len_decrypted; + struct wpabuf *in_decrypted; struct eap_ttls_avp parse; - size_t buf_len; - u8 *in_data; - size_t in_len; - - in_data = wpabuf_mhead(in_buf); - in_len = wpabuf_len(in_buf); wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) in_len); + " Phase 2", (unsigned long) wpabuf_len(in_buf)); if (data->pending_phase2_eap_resp) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response " @@ -1150,35 +1121,17 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, return; } - buf_len = in_len; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - in_decrypted = os_malloc(buf_len); + in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, + in_buf); if (in_decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory " - "for decryption"); - return; - } - - len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_data, in_len, - in_decrypted, buf_len); - if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " "data"); - os_free(in_decrypted); eap_ttls_state(data, FAILURE); return; } if (data->state == PHASE_FINISHED) { - if (len_decrypted == 0 && + if (wpabuf_len(in_decrypted) == 0 && tls_connection_ia_final_phase_finished(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished " @@ -1190,16 +1143,16 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, eap_ttls_state(data, FAILURE); } - os_free(in_decrypted); + wpabuf_free(in_decrypted); return; } - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", - in_decrypted, len_decrypted); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", + in_decrypted); - if (eap_ttls_avp_parse(in_decrypted, len_decrypted, &parse) < 0) { + if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs"); - os_free(in_decrypted); + wpabuf_free(in_decrypted); eap_ttls_state(data, FAILURE); return; } @@ -1221,14 +1174,14 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, } } -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (data->tnc_started && parse.eap == NULL) { wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP " "response from peer"); eap_ttls_state(data, FAILURE); goto done; } -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ if (parse.eap) { eap_ttls_process_phase2_eap(sm, data, parse.eap, @@ -1257,14 +1210,14 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, } done: - os_free(in_decrypted); + wpabuf_free(in_decrypted); os_free(parse.eap); } static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data) { -#ifdef EAP_TNC +#ifdef EAP_SERVER_TNC if (!sm->tnc || data->state != SUCCESS || data->tnc_started) return; @@ -1277,7 +1230,7 @@ static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data) data->tnc_started = 1; eap_ttls_state(data, PHASE2_METHOD); -#endif /* EAP_TNC */ +#endif /* EAP_SERVER_TNC */ } @@ -1318,11 +1271,11 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, case PHASE2_START: case PHASE2_METHOD: case PHASE_FINISHED: - eap_ttls_process_phase2(sm, data, data->ssl.in_buf); + eap_ttls_process_phase2(sm, data, data->ssl.tls_in); eap_ttls_start_tnc(sm, data); break; case PHASE2_MSCHAPV2_RESP: - if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.in_buf) == + if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.tls_in) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " "acknowledged response"); @@ -1337,7 +1290,7 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, "frame from peer (payload len %lu, " "expected empty frame)", (unsigned long) - wpabuf_len(data->ssl.in_buf)); + wpabuf_len(data->ssl.tls_in)); eap_ttls_state(data, FAILURE); } eap_ttls_start_tnc(sm, data); diff --git a/src/eap_server/eap_vendor_test.c b/src/eap_server/eap_server_vendor_test.c similarity index 100% rename from src/eap_server/eap_vendor_test.c rename to src/eap_server/eap_server_vendor_test.c diff --git a/src/eap_server/eap_wsc.c b/src/eap_server/eap_server_wsc.c similarity index 92% rename from src/eap_server/eap_wsc.c rename to src/eap_server/eap_server_wsc.c index 3c17577889b7..77cf9e2af2b1 100644 --- a/src/eap_server/eap_wsc.c +++ b/src/eap_server/eap_server_wsc.c @@ -22,7 +22,7 @@ struct eap_wsc_data { - enum { START, MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; + enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; int registrar; struct wpabuf *in_buf; struct wpabuf *out_buf; @@ -34,13 +34,14 @@ struct eap_wsc_data { }; +#ifndef CONFIG_NO_STDOUT_DEBUG static const char * eap_wsc_state_txt(int state) { switch (state) { case START: return "START"; - case MSG: - return "MSG"; + case MESG: + return "MESG"; case FRAG_ACK: return "FRAG_ACK"; case WAIT_FRAG_ACK: @@ -53,6 +54,7 @@ static const char * eap_wsc_state_txt(int state) return "?"; } } +#endif /* CONFIG_NO_STDOUT_DEBUG */ static void eap_wsc_state(struct eap_wsc_data *data, int state) @@ -102,7 +104,7 @@ static void * eap_wsc_init(struct eap_sm *sm) data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; - data->state = registrar ? START : MSG; + data->state = registrar ? START : MESG; data->registrar = registrar; os_memset(&cfg, 0, sizeof(cfg)); @@ -117,15 +119,24 @@ static void * eap_wsc_init(struct eap_sm *sm) } } else { if (sm->user == NULL || sm->user->password == NULL) { - wpa_printf(MSG_INFO, "EAP-WSC: No AP PIN (password) " - "configured for Enrollee functionality"); - os_free(data); - return NULL; + /* + * In theory, this should not really be needed, but + * Windows 7 uses Registrar mode to probe AP's WPS + * capabilities before trying to use Enrollee and fails + * if the AP does not allow that probing to happen.. + */ + wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) " + "configured for Enrollee functionality - " + "allow for probing capabilities (M1)"); + } else { + cfg.pin = sm->user->password; + cfg.pin_len = sm->user->password_len; } - cfg.pin = sm->user->password; - cfg.pin_len = sm->user->password_len; } cfg.assoc_wps_ie = sm->assoc_wps_ie; + cfg.peer_addr = sm->peer_addr; + if (0 /* TODO: could provide option for forcing PSK format */) + cfg.use_psk_key = 1; data->wps = wps_init(&cfg); if (data->wps == NULL) { os_free(data); @@ -212,7 +223,7 @@ static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id) wpabuf_free(data->out_buf); data->out_buf = NULL; data->out_used = 0; - eap_wsc_state(data, MSG); + eap_wsc_state(data, MESG); } else { wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " "(%lu more to send)", (unsigned long) send_len, @@ -232,7 +243,7 @@ static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) switch (data->state) { case START: return eap_wsc_build_start(sm, data, id); - case MSG: + case MESG: if (data->out_buf == NULL) { data->out_buf = wps_get_msg(data->wps, &data->out_op_code); @@ -385,7 +396,7 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, return; } wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); - eap_wsc_state(data, MSG); + eap_wsc_state(data, MESG); return; } @@ -427,14 +438,14 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, eap_wsc_state(data, FAIL); break; case WPS_CONTINUE: - eap_wsc_state(data, MSG); + eap_wsc_state(data, MESG); break; case WPS_FAILURE: wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); eap_wsc_state(data, FAIL); break; case WPS_PENDING: - eap_wsc_state(data, MSG); + eap_wsc_state(data, MESG); sm->method_pending = METHOD_PENDING_WAIT; eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c index ed0bd3cd1332..aba919aa5512 100644 --- a/src/eap_server/eap_sim_db.c +++ b/src/eap_server/eap_sim_db.c @@ -1023,7 +1023,7 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity, } -#ifdef EAP_AKA_PRIME +#ifdef EAP_SERVER_AKA_PRIME /** * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry * @priv: Private data pointer from eap_sim_db_init() @@ -1062,7 +1062,7 @@ int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, return 0; } -#endif /* EAP_AKA_PRIME */ +#endif /* EAP_SERVER_AKA_PRIME */ /** diff --git a/src/eap_server/eap_sim_db.h b/src/eap_server/eap_sim_db.h index 66221817b220..ab89ae97d5a0 100644 --- a/src/eap_server/eap_sim_db.h +++ b/src/eap_server/eap_sim_db.h @@ -15,8 +15,6 @@ #ifndef EAP_SIM_DB_H #define EAP_SIM_DB_H -#ifdef EAP_SIM - #include "eap_common/eap_sim_common.h" /* Identity prefixes */ @@ -90,18 +88,4 @@ int eap_sim_db_resynchronize(void *priv, const u8 *identity, size_t identity_len, const u8 *auts, const u8 *_rand); -#else /* EAP_SIM */ -static inline void * -eap_sim_db_init(const char *config, - void (*get_complete_cb)(void *ctx, void *session_ctx), - void *ctx) -{ - return (void *) 1; -} - -static inline void eap_sim_db_deinit(void *priv) -{ -} -#endif /* EAP_SIM */ - #endif /* EAP_SIM_DB_H */ diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h index ce8dd252bc6d..c34c40108b24 100644 --- a/src/eap_server/eap_tls_common.h +++ b/src/eap_server/eap_tls_common.h @@ -1,6 +1,6 @@ /* - * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2008, Jouni Malinen + * EAP-TLS/PEAP/TTLS/FAST server common functions + * Copyright (c) 2004-2009, Jouni Malinen * * 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 @@ -15,19 +15,46 @@ #ifndef EAP_TLS_COMMON_H #define EAP_TLS_COMMON_H +/** + * struct eap_ssl_data - TLS data for EAP methods + */ struct eap_ssl_data { + /** + * conn - TLS connection context data from tls_connection_init() + */ struct tls_connection *conn; + /** + * tls_out - TLS message to be sent out in fragments + */ + struct wpabuf *tls_out; + + /** + * tls_out_pos - The current position in the outgoing TLS message + */ + size_t tls_out_pos; + + /** + * tls_out_limit - Maximum fragment size for outgoing TLS messages + */ size_t tls_out_limit; + /** + * tls_in - Received TLS message buffer for re-assembly + */ + struct wpabuf *tls_in; + + /** + * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) + */ int phase2; + /** + * eap - EAP state machine allocated with eap_server_sm_init() + */ struct eap_sm *eap; enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state; - struct wpabuf *in_buf; - struct wpabuf *out_buf; - size_t out_used; struct wpabuf tmpbuf; }; @@ -53,7 +80,7 @@ struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version); int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data); struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const u8 *plain, size_t plain_len); + const struct wpabuf *plain); int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, struct wpabuf *respData, void *priv, int eap_type, int (*proc_version)(struct eap_sm *sm, void *priv, diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c index 46767c501405..435ba2624933 100644 --- a/src/eap_server/ikev2.c +++ b/src/eap_server/ikev2.c @@ -15,7 +15,7 @@ #include "includes.h" #include "common.h" -#include "dh_groups.h" +#include "crypto/dh_groups.h" #include "ikev2.h" diff --git a/src/eap_server/tncs.c b/src/eap_server/tncs.c index 21d83b3bd961..497b51a0f3e5 100644 --- a/src/eap_server/tncs.c +++ b/src/eap_server/tncs.c @@ -1231,6 +1231,7 @@ void tncs_global_deinit(void) } os_free(tncs_global_data); + tncs_global_data = NULL; } diff --git a/src/eapol_auth/Makefile b/src/eapol_auth/Makefile new file mode 100644 index 000000000000..9c41962fd7e1 --- /dev/null +++ b/src/eapol_auth/Makefile @@ -0,0 +1,8 @@ +all: + @echo Nothing to be made. + +clean: + rm -f *~ *.o *.d + +install: + @echo Nothing to be made. diff --git a/src/eapol_auth/eapol_auth_dump.c b/src/eapol_auth/eapol_auth_dump.c new file mode 100644 index 000000000000..a0f0e8d61669 --- /dev/null +++ b/src/eapol_auth/eapol_auth_dump.c @@ -0,0 +1,231 @@ +/* + * IEEE 802.1X-2004 Authenticator - State dump + * Copyright (c) 2002-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eap_server/eap.h" +#include "eapol_auth_sm.h" +#include "eapol_auth_sm_i.h" + +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 +} diff --git a/hostapd/eapol_sm.c b/src/eapol_auth/eapol_auth_sm.c similarity index 75% rename from hostapd/eapol_sm.c rename to src/eapol_auth/eapol_auth_sm.c index 8e9d56c7964f..a1976e8f0a29 100644 --- a/hostapd/eapol_sm.c +++ b/src/eapol_auth/eapol_auth_sm.c @@ -1,6 +1,6 @@ /* - * hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine - * Copyright (c) 2002-2008, Jouni Malinen + * IEEE 802.1X-2004 Authenticator - EAPOL state machine + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -14,16 +14,15 @@ #include "includes.h" -#include "hostapd.h" -#include "ieee802_1x.h" -#include "eapol_sm.h" +#include "common.h" #include "eloop.h" -#include "wpa.h" -#include "preauth.h" -#include "sta_info.h" -#include "eap_server/eap.h" #include "state_machine.h" +#include "common/eapol_common.h" +#include "eap_common/eap_defs.h" #include "eap_common/eap_common.h" +#include "eap_server/eap.h" +#include "eapol_auth_sm.h" +#include "eapol_auth_sm_i.h" #define STATE_MACHINE_DATA struct eapol_state_machine #define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X" @@ -34,35 +33,36 @@ 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) +sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1) #define setPortUnauthorized() \ -sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 0) +sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, 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 abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta) +#define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, 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_initialize(struct eapol_state_machine *sm); static void eapol_auth_logger(struct eapol_authenticator *eapol, - const u8 *addr, logger_level level, + const u8 *addr, eapol_logger_level level, const char *txt) { if (eapol->cb.logger == NULL) return; - eapol->cb.logger(eapol->conf.hapd, addr, level, txt); + eapol->cb.logger(eapol->conf.ctx, addr, level, txt); } static void eapol_auth_vlogger(struct eapol_authenticator *eapol, - const u8 *addr, logger_level level, + const u8 *addr, eapol_logger_level level, const char *fmt, ...) { char *format; @@ -101,7 +101,8 @@ static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm, 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, + sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta, + IEEE802_1X_TYPE_EAP_PACKET, (u8 *) &eap, sizeof(eap)); sm->dot1xAuthEapolFramesTx++; } @@ -129,7 +130,8 @@ static void eapol_auth_tx_req(struct eapol_state_machine *sm) 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, + sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta, + IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(sm->eap_if->eapReqData), wpabuf_len(sm->eap_if->eapReqData)); sm->dot1xAuthEapolFramesTx++; @@ -222,7 +224,7 @@ SM_STATE(AUTH_PAE, DISCONNECTED) sm->reAuthCount = 0; sm->eapolLogoff = FALSE; if (!from_initialize) { - sm->eapol->cb.finished(sm->hapd, sm->sta, 0, + sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, sm->flags & EAPOL_SM_PREAUTH); } } @@ -272,14 +274,14 @@ SM_STATE(AUTH_PAE, HELD) 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)); + eap_server_get_name(0, 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)); + eap_server_get_name(0, sm->eap_type_supp)); } - sm->eapol->cb.finished(sm->hapd, sm->sta, 0, + sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, sm->flags & EAPOL_SM_PREAUTH); } @@ -298,13 +300,14 @@ SM_STATE(AUTH_PAE, AUTHENTICATED) sm->reAuthCount = 0; if (sm->flags & EAPOL_SM_PREAUTH) extra = " (pre-authentication)"; - else if (wpa_auth_sta_get_pmksa(sm->sta->wpa_sm)) + else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE) 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, + eap_server_get_name(0, sm->eap_type_authsrv), + extra); + sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1, sm->flags & EAPOL_SM_PREAUTH); } @@ -611,7 +614,8 @@ 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->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, + EAPOL_AUTH_REAUTHENTICATE); } @@ -664,7 +668,7 @@ SM_STEP(AUTH_KEY_TX) 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->keyRun && !(sm->flags & EAPOL_SM_USES_WPA)) SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT); break; case AUTH_KEY_TX_KEY_TRANSMIT: @@ -758,15 +762,13 @@ SM_STEP(CTRL_DIR) struct eapol_state_machine * eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, - int preauth, struct sta_info *sta) + int flags, const struct wpabuf *assoc_wps_ie, void *sta_ctx) { 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) { @@ -776,12 +778,10 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, } sm->radius_identifier = -1; os_memcpy(sm->addr, addr, ETH_ALEN); - if (preauth) - sm->flags |= EAPOL_SM_PREAUTH; + sm->flags = flags; - sm->hapd = hapd; sm->eapol = eapol; - sm->sta = sta; + sm->sta = sta_ctx; /* Set default values for state machine constants */ sm->auth_pae_state = AUTH_PAE_INITIALIZE; @@ -804,7 +804,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, sm->portControl = Auto; if (!eapol->conf.wpa && - (hapd->default_wep_key || eapol->conf.individual_wep_key_len > 0)) + (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0)) sm->keyTxEnabled = TRUE; else sm->keyTxEnabled = FALSE; @@ -816,6 +816,7 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, 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.msg_ctx = eapol->conf.msg_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; @@ -827,7 +828,8 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, 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; + eap_conf.assoc_wps_ie = assoc_wps_ie; + eap_conf.peer_addr = addr; sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf); if (sm->eap == NULL) { eapol_auth_free(sm); @@ -857,7 +859,7 @@ void eapol_auth_free(struct eapol_state_machine *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); + return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr); } @@ -928,14 +930,15 @@ restart: return; } sm->eapol->cb.aaa_send( - sm->hapd, sm->sta, + sm->eapol->conf.ctx, 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); + sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, + EAPOL_AUTH_SM_CHANGE); } @@ -965,7 +968,7 @@ void eapol_auth_step(struct eapol_state_machine *sm) } -void eapol_auth_initialize(struct eapol_state_machine *sm) +static void eapol_auth_initialize(struct eapol_state_machine *sm) { sm->initializing = TRUE; /* Initialize the state machines by asserting initialize and then @@ -982,227 +985,13 @@ void eapol_auth_initialize(struct eapol_state_machine *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); + return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity, + identity_len, phase2, user); } @@ -1216,8 +1005,8 @@ static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len) 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, + eapol_sm_get_eap_user, + eapol_sm_get_eap_req_id_text }; @@ -1236,12 +1025,13 @@ int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx) static int eapol_auth_conf_clone(struct eapol_auth_config *dst, struct eapol_auth_config *src) { - dst->hapd = src->hapd; + dst->ctx = src->ctx; 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->msg_ctx = src->msg_ctx; dst->eap_sim_db_priv = src->eap_sim_db_priv; os_free(dst->eap_req_id_text); if (src->eap_req_id_text) { @@ -1318,6 +1108,11 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, return NULL; } + if (conf->individual_wep_key_len > 0) { + /* use key0 in individual key and key1 in broadcast key */ + eapol->default_wep_key_idx = 1; + } + eapol->cb.eapol_send = cb->eapol_send; eapol->cb.aaa_send = cb->aaa_send; eapol->cb.finished = cb->finished; @@ -1327,6 +1122,7 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, eapol->cb.set_port_authorized = cb->set_port_authorized; eapol->cb.abort_auth = cb->abort_auth; eapol->cb.tx_key = cb->tx_key; + eapol->cb.eapol_event = cb->eapol_event; return eapol; } @@ -1338,5 +1134,6 @@ void eapol_auth_deinit(struct eapol_authenticator *eapol) return; eapol_auth_conf_free(&eapol->conf); + os_free(eapol->default_wep_key); os_free(eapol); } diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h new file mode 100644 index 000000000000..ef943ad47813 --- /dev/null +++ b/src/eapol_auth/eapol_auth_sm.h @@ -0,0 +1,89 @@ +/* + * IEEE 802.1X-2004 Authenticator - EAPOL state machine + * Copyright (c) 2002-2009, Jouni Malinen + * + * 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_AUTH_SM_H +#define EAPOL_AUTH_SM_H + +#define EAPOL_SM_PREAUTH BIT(0) +#define EAPOL_SM_WAIT_START BIT(1) +#define EAPOL_SM_USES_WPA BIT(2) +#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3) + +struct eapol_auth_config { + int eap_reauth_period; + int wpa; + int individual_wep_key_len; + int eap_server; + void *ssl_ctx; + void *msg_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; + + /* Opaque context pointer to owner data for callback functions */ + void *ctx; +}; + +struct eap_user; + +typedef enum { + EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING +} eapol_logger_level; + +enum eapol_event { + EAPOL_AUTH_SM_CHANGE, + EAPOL_AUTH_REAUTHENTICATE +}; + +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); + void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type); +}; + + +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 flags, const struct wpabuf *assoc_wps_ie, void *sta_ctx); +void eapol_auth_free(struct eapol_state_machine *sm); +void eapol_auth_step(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_AUTH_SM_H */ diff --git a/hostapd/eapol_sm.h b/src/eapol_auth/eapol_auth_sm_i.h similarity index 65% rename from hostapd/eapol_sm.h rename to src/eapol_auth/eapol_auth_sm_i.h index 7a13e8e7c003..1000da4df148 100644 --- a/hostapd/eapol_sm.h +++ b/src/eapol_auth/eapol_auth_sm_i.h @@ -1,6 +1,6 @@ /* - * hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine - * Copyright (c) 2002-2007, Jouni Malinen + * IEEE 802.1X-2004 Authenticator - EAPOL state machine (internal definitions) + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -12,10 +12,11 @@ * See README and COPYING for more details. */ -#ifndef EAPOL_SM_H -#define EAPOL_SM_H +#ifndef EAPOL_AUTH_SM_I_H +#define EAPOL_AUTH_SM_I_H -#include "defs.h" +#include "common/defs.h" +#include "radius/radius.h" /* IEEE Std 802.1X-2004, Ch. 8.2 */ @@ -25,68 +26,6 @@ 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 @@ -94,6 +33,9 @@ struct eapol_auth_cb { struct eapol_authenticator { struct eapol_auth_config conf; struct eapol_auth_cb cb; + + u8 *default_wep_key; + u8 default_wep_key_idx; }; @@ -206,8 +148,6 @@ struct eapol_state_machine { /* 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 */ @@ -237,24 +177,7 @@ struct eapol_state_machine { 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; + void *sta; /* station context pointer to use in callbacks */ }; - -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 */ +#endif /* EAPOL_AUTH_SM_I_H */ diff --git a/src/eapol_supp/Makefile b/src/eapol_supp/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/eapol_supp/Makefile +++ b/src/eapol_supp/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index d163049ccef0..77cd564b0d43 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -15,14 +15,14 @@ #include "includes.h" #include "common.h" -#include "eapol_supp_sm.h" -#include "eap_peer/eap.h" -#include "eloop.h" -#include "eapol_common.h" -#include "md5.h" -#include "rc4.h" #include "state_machine.h" #include "wpabuf.h" +#include "eloop.h" +#include "crypto/crypto.h" +#include "crypto/md5.h" +#include "common/eapol_common.h" +#include "eap_peer/eap.h" +#include "eapol_supp_sm.h" #define STATE_MACHINE_DATA struct eapol_sm #define STATE_MACHINE_DEBUG_PREFIX "EAPOL" @@ -193,6 +193,8 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm); static void eapol_sm_abortSupp(struct eapol_sm *sm); static void eapol_sm_abort_cached(struct eapol_sm *sm); static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx); +static void eapol_sm_set_port_authorized(struct eapol_sm *sm); +static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm); /* Port Timers state machine - implemented as a function that will be called @@ -250,6 +252,7 @@ SM_STATE(SUPP_PAE, LOGOFF) eapol_sm_txLogoff(sm); sm->logoffSent = TRUE; sm->suppPortStatus = Unauthorized; + eapol_sm_set_port_unauthorized(sm); } @@ -260,6 +263,7 @@ SM_STATE(SUPP_PAE, DISCONNECTED) sm->startCount = 0; sm->logoffSent = FALSE; sm->suppPortStatus = Unauthorized; + eapol_sm_set_port_unauthorized(sm); sm->suppAbort = TRUE; sm->unicast_key_received = FALSE; @@ -315,6 +319,7 @@ SM_STATE(SUPP_PAE, HELD) sm->heldWhile = sm->heldPeriod; eapol_enable_timer_tick(sm); sm->suppPortStatus = Unauthorized; + eapol_sm_set_port_unauthorized(sm); sm->cb_status = EAPOL_CB_FAILURE; } @@ -323,6 +328,7 @@ SM_STATE(SUPP_PAE, AUTHENTICATED) { SM_ENTRY(SUPP_PAE, AUTHENTICATED); sm->suppPortStatus = Authorized; + eapol_sm_set_port_authorized(sm); sm->cb_status = EAPOL_CB_SUCCESS; } @@ -338,6 +344,7 @@ SM_STATE(SUPP_PAE, S_FORCE_AUTH) { SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); sm->suppPortStatus = Authorized; + eapol_sm_set_port_authorized(sm); sm->sPortMode = ForceAuthorized; } @@ -346,6 +353,7 @@ SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) { SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); sm->suppPortStatus = Unauthorized; + eapol_sm_set_port_unauthorized(sm); sm->sPortMode = ForceUnauthorized; eapol_sm_txLogoff(sm); } @@ -862,6 +870,20 @@ static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) } +static void eapol_sm_set_port_authorized(struct eapol_sm *sm) +{ + if (sm->ctx->port_cb) + sm->ctx->port_cb(sm->ctx->ctx, 1); +} + + +static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm) +{ + if (sm->ctx->port_cb) + sm->ctx->port_cb(sm->ctx->ctx, 0); +} + + /** * eapol_sm_step - EAPOL state machine step function * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() @@ -1456,6 +1478,7 @@ void eapol_sm_notify_cached(struct eapol_sm *sm) wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL"); sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED; sm->suppPortStatus = Authorized; + eapol_sm_set_port_authorized(sm); sm->portValid = TRUE; eap_notify_success(sm->eap); eapol_sm_step(sm); @@ -1492,6 +1515,7 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm) sm->cached_pmk = FALSE; sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; sm->suppPortStatus = Unauthorized; + eapol_sm_set_port_unauthorized(sm); /* Make sure we do not start sending EAPOL-Start frames first, but * instead move to RESTART state to start EAPOL authentication. */ @@ -1830,11 +1854,9 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) sm->authPeriod = 30; os_memset(&conf, 0, sizeof(conf)); -#ifdef EAP_TLS_OPENSSL conf.opensc_engine_path = ctx->opensc_engine_path; conf.pkcs11_engine_path = ctx->pkcs11_engine_path; conf.pkcs11_module_path = ctx->pkcs11_module_path; -#endif /* EAP_TLS_OPENSSL */ conf.wps = ctx->wps; sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 57d7bc1ab12e..1d2a32bb7cbf 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -15,7 +15,7 @@ #ifndef EAPOL_SUPP_SM_H #define EAPOL_SUPP_SM_H -#include "defs.h" +#include "common/defs.h" typedef enum { Unauthorized, Authorized } PortStatus; typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl; @@ -173,7 +173,6 @@ struct eapol_ctx { */ void (*aborted_cached)(void *ctx); -#ifdef EAP_TLS_OPENSSL /** * opensc_engine_path - Path to the OpenSSL engine for opensc * @@ -198,7 +197,6 @@ struct eapol_ctx { * module is not loaded. */ const char *pkcs11_module_path; -#endif /* EAP_TLS_OPENSSL */ /** * wps - WPS context data @@ -215,6 +213,13 @@ struct eapol_ctx { */ void (*eap_param_needed)(void *ctx, const char *field, const char *txt); + + /** + * port_cb - Set port authorized/unauthorized callback (optional) + * @ctx: Callback context (ctx) + * @authorized: Whether the supplicant port is now in authorized state + */ + void (*port_cb)(void *ctx, int authorized); }; diff --git a/src/hlr_auc_gw/hlr_auc_gw.c b/src/hlr_auc_gw/hlr_auc_gw.c deleted file mode 100644 index e318903543ad..000000000000 --- a/src/hlr_auc_gw/hlr_auc_gw.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator - * Copyright (c) 2005-2007, Jouni Malinen - * - * 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. - * - * This is an example implementation of the EAP-SIM/AKA database/authentication - * gateway interface to HLR/AuC. It is expected to be replaced with an - * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or - * a local implementation of SIM triplet and AKA authentication data generator. - * - * hostapd will send SIM/AKA authentication queries over a UNIX domain socket - * to and external program, e.g., this hlr_auc_gw. This interface uses simple - * text-based format: - * - * EAP-SIM / GSM triplet query/response: - * SIM-REQ-AUTH - * SIM-RESP-AUTH Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3] - * SIM-RESP-AUTH FAILURE - * - * EAP-AKA / UMTS query/response: - * AKA-REQ-AUTH - * AKA-RESP-AUTH - * AKA-RESP-AUTH FAILURE - * - * EAP-AKA / UMTS AUTS (re-synchronization): - * AKA-AUTS - * - * IMSI and max_chal are sent as an ASCII string, - * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings. - * - * The example implementation here reads GSM authentication triplets from a - * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex - * strings. This is used to simulate an HLR/AuC. As such, it is not very useful - * for real life authentication, but it is useful both as an example - * implementation and for EAP-SIM testing. - */ - -#include "includes.h" -#include - -#include "common.h" -#include "milenage.h" - -static const char *default_socket_path = "/tmp/hlr_auc_gw.sock"; -static const char *socket_path; -static int serv_sock = -1; - -/* GSM triplets */ -struct gsm_triplet { - struct gsm_triplet *next; - char imsi[20]; - u8 kc[8]; - u8 sres[4]; - u8 _rand[16]; -}; - -static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL; - -/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */ -struct milenage_parameters { - struct milenage_parameters *next; - char imsi[20]; - u8 ki[16]; - u8 opc[16]; - u8 amf[2]; - u8 sqn[6]; -}; - -static struct milenage_parameters *milenage_db = NULL; - -#define EAP_SIM_MAX_CHAL 3 - -#define EAP_AKA_RAND_LEN 16 -#define EAP_AKA_AUTN_LEN 16 -#define EAP_AKA_AUTS_LEN 14 -#define EAP_AKA_RES_MAX_LEN 16 -#define EAP_AKA_IK_LEN 16 -#define EAP_AKA_CK_LEN 16 - - -static int open_socket(const char *path) -{ - struct sockaddr_un addr; - int s; - - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(PF_UNIX)"); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("bind(PF_UNIX)"); - close(s); - return -1; - } - - return s; -} - - -static int read_gsm_triplets(const char *fname) -{ - FILE *f; - char buf[200], *pos, *pos2; - struct gsm_triplet *g = NULL; - int line, ret = 0; - - if (fname == NULL) - return -1; - - f = fopen(fname, "r"); - if (f == NULL) { - printf("Could not open GSM tripler data file '%s'\n", fname); - return -1; - } - - line = 0; - while (fgets(buf, sizeof(buf), f)) { - line++; - - /* Parse IMSI:Kc:SRES:RAND */ - buf[sizeof(buf) - 1] = '\0'; - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0' && *pos != '\n') - pos++; - if (*pos == '\n') - *pos = '\0'; - pos = buf; - if (*pos == '\0') - continue; - - g = os_zalloc(sizeof(*g)); - if (g == NULL) { - ret = -1; - break; - } - - /* IMSI */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) >= sizeof(g->imsi)) { - printf("%s:%d - Too long IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - os_strlcpy(g->imsi, pos, sizeof(g->imsi)); - pos = pos2 + 1; - - /* Kc */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { - printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; - - /* SRES */ - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - printf("%s:%d - Invalid SRES (%s)\n", fname, line, - pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) { - printf("%s:%d - Invalid SRES (%s)\n", fname, line, - pos); - ret = -1; - break; - } - pos = pos2 + 1; - - /* RAND */ - pos2 = strchr(pos, ':'); - if (pos2) - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) { - printf("%s:%d - Invalid RAND (%s)\n", fname, line, - pos); - ret = -1; - break; - } - pos = pos2 + 1; - - g->next = gsm_db; - gsm_db = g; - g = NULL; - } - free(g); - - fclose(f); - - return ret; -} - - -static struct gsm_triplet * get_gsm_triplet(const char *imsi) -{ - struct gsm_triplet *g = gsm_db_pos; - - while (g) { - if (strcmp(g->imsi, imsi) == 0) { - gsm_db_pos = g->next; - return g; - } - g = g->next; - } - - g = gsm_db; - while (g && g != gsm_db_pos) { - if (strcmp(g->imsi, imsi) == 0) { - gsm_db_pos = g->next; - return g; - } - g = g->next; - } - - return NULL; -} - - -static int read_milenage(const char *fname) -{ - FILE *f; - char buf[200], *pos, *pos2; - struct milenage_parameters *m = NULL; - int line, ret = 0; - - if (fname == NULL) - return -1; - - f = fopen(fname, "r"); - if (f == NULL) { - printf("Could not open Milenage data file '%s'\n", fname); - return -1; - } - - line = 0; - while (fgets(buf, sizeof(buf), f)) { - line++; - - /* Parse IMSI Ki OPc AMF SQN */ - buf[sizeof(buf) - 1] = '\0'; - if (buf[0] == '#') - continue; - pos = buf; - while (*pos != '\0' && *pos != '\n') - pos++; - if (*pos == '\n') - *pos = '\0'; - pos = buf; - if (*pos == '\0') - continue; - - m = os_zalloc(sizeof(*m)); - if (m == NULL) { - ret = -1; - break; - } - - /* IMSI */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) >= sizeof(m->imsi)) { - printf("%s:%d - Too long IMSI (%s)\n", - fname, line, pos); - ret = -1; - break; - } - os_strlcpy(m->imsi, pos, sizeof(m->imsi)); - pos = pos2 + 1; - - /* Ki */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) { - printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; - - /* OPc */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) { - printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; - - /* AMF */ - pos2 = strchr(pos, ' '); - if (pos2 == NULL) { - printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); - ret = -1; - break; - } - *pos2 = '\0'; - if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { - printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; - - /* SQN */ - pos2 = strchr(pos, ' '); - if (pos2) - *pos2 = '\0'; - if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) { - printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos); - ret = -1; - break; - } - pos = pos2 + 1; - - m->next = milenage_db; - milenage_db = m; - m = NULL; - } - free(m); - - fclose(f); - - return ret; -} - - -static struct milenage_parameters * get_milenage(const char *imsi) -{ - struct milenage_parameters *m = milenage_db; - - while (m) { - if (strcmp(m->imsi, imsi) == 0) - break; - m = m->next; - } - - return m; -} - - -static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, - char *imsi) -{ - int count, max_chal, ret; - char *pos; - char reply[1000], *rpos, *rend; - struct milenage_parameters *m; - struct gsm_triplet *g; - - reply[0] = '\0'; - - pos = strchr(imsi, ' '); - if (pos) { - *pos++ = '\0'; - max_chal = atoi(pos); - if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL) - max_chal = EAP_SIM_MAX_CHAL; - } else - max_chal = EAP_SIM_MAX_CHAL; - - rend = &reply[sizeof(reply)]; - rpos = reply; - ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi); - if (ret < 0 || ret >= rend - rpos) - return; - rpos += ret; - - m = get_milenage(imsi); - if (m) { - u8 _rand[16], sres[4], kc[8]; - for (count = 0; count < max_chal; count++) { - if (os_get_random(_rand, 16) < 0) - return; - gsm_milenage(m->opc, m->ki, _rand, sres, kc); - *rpos++ = ' '; - rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8); - *rpos++ = ':'; - rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4); - *rpos++ = ':'; - rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16); - } - *rpos = '\0'; - goto send; - } - - count = 0; - while (count < max_chal && (g = get_gsm_triplet(imsi))) { - if (strcmp(g->imsi, imsi) != 0) - continue; - - if (rpos < rend) - *rpos++ = ' '; - rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8); - if (rpos < rend) - *rpos++ = ':'; - rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4); - if (rpos < rend) - *rpos++ = ':'; - rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16); - count++; - } - - if (count == 0) { - printf("No GSM triplets found for %s\n", imsi); - ret = snprintf(rpos, rend - rpos, " FAILURE"); - if (ret < 0 || ret >= rend - rpos) - return; - rpos += ret; - } - -send: - printf("Send: %s\n", reply); - if (sendto(s, reply, rpos - reply, 0, - (struct sockaddr *) from, fromlen) < 0) - perror("send"); -} - - -static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, - char *imsi) -{ - /* AKA-RESP-AUTH */ - char reply[1000], *pos, *end; - u8 _rand[EAP_AKA_RAND_LEN]; - u8 autn[EAP_AKA_AUTN_LEN]; - u8 ik[EAP_AKA_IK_LEN]; - u8 ck[EAP_AKA_CK_LEN]; - u8 res[EAP_AKA_RES_MAX_LEN]; - size_t res_len; - int ret; - struct milenage_parameters *m; - - m = get_milenage(imsi); - if (m) { - if (os_get_random(_rand, EAP_AKA_RAND_LEN) < 0) - return; - res_len = EAP_AKA_RES_MAX_LEN; - inc_byte_array(m->sqn, 6); - printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n", - m->sqn[0], m->sqn[1], m->sqn[2], - m->sqn[3], m->sqn[4], m->sqn[5]); - milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand, - autn, ik, ck, res, &res_len); - } else { - printf("Unknown IMSI: %s\n", imsi); -#ifdef AKA_USE_FIXED_TEST_VALUES - printf("Using fixed test values for AKA\n"); - memset(_rand, '0', EAP_AKA_RAND_LEN); - memset(autn, '1', EAP_AKA_AUTN_LEN); - memset(ik, '3', EAP_AKA_IK_LEN); - memset(ck, '4', EAP_AKA_CK_LEN); - memset(res, '2', EAP_AKA_RES_MAX_LEN); - res_len = EAP_AKA_RES_MAX_LEN; -#else /* AKA_USE_FIXED_TEST_VALUES */ - return; -#endif /* AKA_USE_FIXED_TEST_VALUES */ - } - - pos = reply; - end = &reply[sizeof(reply)]; - ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi); - if (ret < 0 || ret >= end - pos) - return; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN); - *pos++ = ' '; - pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN); - *pos++ = ' '; - pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN); - *pos++ = ' '; - pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN); - *pos++ = ' '; - pos += wpa_snprintf_hex(pos, end - pos, res, res_len); - - printf("Send: %s\n", reply); - - if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from, - fromlen) < 0) - perror("send"); -} - - -static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen, - char *imsi) -{ - char *auts, *__rand; - u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6]; - struct milenage_parameters *m; - - /* AKA-AUTS */ - - auts = strchr(imsi, ' '); - if (auts == NULL) - return; - *auts++ = '\0'; - - __rand = strchr(auts, ' '); - if (__rand == NULL) - return; - *__rand++ = '\0'; - - printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand); - if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) || - hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) { - printf("Could not parse AUTS/RAND\n"); - return; - } - - m = get_milenage(imsi); - if (m == NULL) { - printf("Unknown IMSI: %s\n", imsi); - return; - } - - if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) { - printf("AKA-AUTS: Incorrect MAC-S\n"); - } else { - memcpy(m->sqn, sqn, 6); - printf("AKA-AUTS: Re-synchronized: " - "SQN=%02x%02x%02x%02x%02x%02x\n", - sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]); - } -} - - -static int process(int s) -{ - char buf[1000]; - struct sockaddr_un from; - socklen_t fromlen; - ssize_t res; - - fromlen = sizeof(from); - res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from, - &fromlen); - if (res < 0) { - perror("recvfrom"); - return -1; - } - - if (res == 0) - return 0; - - if ((size_t) res >= sizeof(buf)) - res = sizeof(buf) - 1; - buf[res] = '\0'; - - printf("Received: %s\n", buf); - - if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0) - sim_req_auth(s, &from, fromlen, buf + 13); - else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0) - aka_req_auth(s, &from, fromlen, buf + 13); - else if (strncmp(buf, "AKA-AUTS ", 9) == 0) - aka_auts(s, &from, fromlen, buf + 9); - else - printf("Unknown request: %s\n", buf); - - return 0; -} - - -static void cleanup(void) -{ - struct gsm_triplet *g, *gprev; - struct milenage_parameters *m, *prev; - - g = gsm_db; - while (g) { - gprev = g; - g = g->next; - free(gprev); - } - - m = milenage_db; - while (m) { - prev = m; - m = m->next; - free(prev); - } - - close(serv_sock); - unlink(socket_path); -} - - -static void handle_term(int sig) -{ - printf("Signal %d - terminate\n", sig); - exit(0); -} - - -static void usage(void) -{ - printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA " - "database/authenticator\n" - "Copyright (c) 2005-2007, Jouni Malinen \n" - "\n" - "usage:\n" - "hlr_auc_gw [-h] [-s] [-g] " - "[-m]\n" - "\n" - "options:\n" - " -h = show this usage help\n" - " -s = path for UNIX domain socket\n" - " (default: %s)\n" - " -g = path for GSM authentication triplets\n" - " -m = path for Milenage keys\n", - default_socket_path); -} - - -int main(int argc, char *argv[]) -{ - int c; - char *milenage_file = NULL; - char *gsm_triplet_file = NULL; - - socket_path = default_socket_path; - - for (;;) { - c = getopt(argc, argv, "g:hm:s:"); - if (c < 0) - break; - switch (c) { - case 'g': - gsm_triplet_file = optarg; - break; - case 'h': - usage(); - return 0; - case 'm': - milenage_file = optarg; - break; - case 's': - socket_path = optarg; - break; - default: - usage(); - return -1; - } - } - - if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0) - return -1; - - if (milenage_file && read_milenage(milenage_file) < 0) - return -1; - - serv_sock = open_socket(socket_path); - if (serv_sock < 0) - return -1; - - printf("Listening for requests on %s\n", socket_path); - - atexit(cleanup); - signal(SIGTERM, handle_term); - signal(SIGINT, handle_term); - - for (;;) - process(serv_sock); - - return 0; -} diff --git a/src/hlr_auc_gw/hlr_auc_gw.milenage_db b/src/hlr_auc_gw/hlr_auc_gw.milenage_db deleted file mode 100644 index ecd06d72096d..000000000000 --- a/src/hlr_auc_gw/hlr_auc_gw.milenage_db +++ /dev/null @@ -1,13 +0,0 @@ -# Parameters for Milenage (Example algorithms for AKA). -# The example Ki, OPc, and AMF values here are from 3GPP TS 35.208 v6.0.0 -# 4.3.20 Test Set 20. SQN is the last used SQN value. -# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM) -# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but -# dummy values will need to be included in this file. - -# IMSI Ki OPc AMF SQN -232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 - -# These values are from Test Set 19 which has the AMF separation bit set to 1 -# and as such, is suitable for EAP-AKA' test. -555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1 diff --git a/src/hlr_auc_gw/milenage.c b/src/hlr_auc_gw/milenage.c deleted file mode 100644 index 0ce5ef3ff671..000000000000 --- a/src/hlr_auc_gw/milenage.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* - * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) - * Copyright (c) 2006-2007 - * - * 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. - * - * This file implements an example authentication algorithm defined for 3GPP - * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow - * EAP-AKA to be tested properly with real USIM cards. - * - * This implementations assumes that the r1..r5 and c1..c5 constants defined in - * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, - * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to - * be AES (Rijndael). - */ - -#include "includes.h" - -#include "common.h" -#include "milenage.h" -#include "aes_wrap.h" - - -/** - * milenage_f1 - Milenage f1 and f1* algorithms - * @opc: OPc = 128-bit value derived from OP and K - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @sqn: SQN = 48-bit sequence number - * @amf: AMF = 16-bit authentication management field - * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL - * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL - * Returns: 0 on success, -1 on failure - */ -static int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, - const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) -{ - u8 tmp1[16], tmp2[16], tmp3[16]; - int i; - - /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp1[i] = _rand[i] ^ opc[i]; - if (aes_128_encrypt_block(k, tmp1, tmp1)) - return -1; - - /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ - os_memcpy(tmp2, sqn, 6); - os_memcpy(tmp2 + 6, amf, 2); - os_memcpy(tmp2 + 8, tmp2, 8); - - /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ - - /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ - for (i = 0; i < 16; i++) - tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; - /* XOR with TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp3[i] ^= tmp1[i]; - /* XOR with c1 (= ..00, i.e., NOP) */ - - /* f1 || f1* = E_K(tmp3) XOR OP_c */ - if (aes_128_encrypt_block(k, tmp3, tmp1)) - return -1; - for (i = 0; i < 16; i++) - tmp1[i] ^= opc[i]; - if (mac_a) - os_memcpy(mac_a, tmp1, 8); /* f1 */ - if (mac_s) - os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ - return 0; -} - - -/** - * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms - * @opc: OPc = 128-bit value derived from OP and K - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL - * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL - * Returns: 0 on success, -1 on failure - */ -static int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, - u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) -{ - u8 tmp1[16], tmp2[16], tmp3[16]; - int i; - - /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp1[i] = _rand[i] ^ opc[i]; - if (aes_128_encrypt_block(k, tmp1, tmp2)) - return -1; - - /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ - /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ - /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ - /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ - - /* f2 and f5 */ - /* rotate by r2 (= 0, i.e., NOP) */ - for (i = 0; i < 16; i++) - tmp1[i] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 1; /* XOR c2 (= ..01) */ - /* f5 || f2 = E_K(tmp1) XOR OP_c */ - if (aes_128_encrypt_block(k, tmp1, tmp3)) - return -1; - for (i = 0; i < 16; i++) - tmp3[i] ^= opc[i]; - if (res) - os_memcpy(res, tmp3 + 8, 8); /* f2 */ - if (ak) - os_memcpy(ak, tmp3, 6); /* f5 */ - - /* f3 */ - if (ck) { - /* rotate by r3 = 0x20 = 4 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 2; /* XOR c3 (= ..02) */ - if (aes_128_encrypt_block(k, tmp1, ck)) - return -1; - for (i = 0; i < 16; i++) - ck[i] ^= opc[i]; - } - - /* f4 */ - if (ik) { - /* rotate by r4 = 0x40 = 8 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 4; /* XOR c4 (= ..04) */ - if (aes_128_encrypt_block(k, tmp1, ik)) - return -1; - for (i = 0; i < 16; i++) - ik[i] ^= opc[i]; - } - - /* f5* */ - if (akstar) { - /* rotate by r5 = 0x60 = 12 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 8; /* XOR c5 (= ..08) */ - if (aes_128_encrypt_block(k, tmp1, tmp1)) - return -1; - for (i = 0; i < 6; i++) - akstar[i] = tmp1[i] ^ opc[i]; - } - - return 0; -} - - -/** - * milenage_generate - Generate AKA AUTN,IK,CK,RES - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @amf: AMF = 16-bit authentication management field - * @k: K = 128-bit subscriber key - * @sqn: SQN = 48-bit sequence number - * @_rand: RAND = 128-bit random challenge - * @autn: Buffer for AUTN = 128-bit authentication token - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @res_len: Max length for res; set to used length or 0 on failure - */ -void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, - const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len) -{ - int i; - u8 mac_a[8], ak[6]; - - if (*res_len < 8) { - *res_len = 0; - return; - } - if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || - milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { - *res_len = 0; - return; - } - *res_len = 8; - - /* AUTN = (SQN ^ AK) || AMF || MAC */ - for (i = 0; i < 6; i++) - autn[i] = sqn[i] ^ ak[i]; - os_memcpy(autn + 6, amf, 2); - os_memcpy(autn + 8, mac_a, 8); -} - - -/** - * milenage_auts - Milenage AUTS validation - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @auts: AUTS = 112-bit authentication token from client - * @sqn: Buffer for SQN = 48-bit sequence number - * Returns: 0 = success (sqn filled), -1 on failure - */ -int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, - u8 *sqn) -{ - u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ - u8 ak[6], mac_s[8]; - int i; - - if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) - return -1; - for (i = 0; i < 6; i++) - sqn[i] = auts[i] ^ ak[i]; - if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || - memcmp(mac_s, auts + 6, 8) != 0) - return -1; - return 0; -} - - -/** - * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @sres: Buffer for SRES = 32-bit SRES - * @kc: Buffer for Kc = 64-bit Kc - * Returns: 0 on success, -1 on failure - */ -int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) -{ - u8 res[8], ck[16], ik[16]; - int i; - - if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) - return -1; - - for (i = 0; i < 8; i++) - kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; - -#ifdef GSM_MILENAGE_ALT_SRES - os_memcpy(sres, res, 4); -#else /* GSM_MILENAGE_ALT_SRES */ - for (i = 0; i < 4; i++) - sres[i] = res[i] ^ res[i + 4]; -#endif /* GSM_MILENAGE_ALT_SRES */ - return 0; -} - - -/** - * milenage_generate - Generate AKA AUTN,IK,CK,RES - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @sqn: SQN = 48-bit sequence number - * @_rand: RAND = 128-bit random challenge - * @autn: AUTN = 128-bit authentication token - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @res_len: Variable that will be set to RES length - * @auts: 112-bit buffer for AUTS - * Returns: 0 on success, -1 on failure, or -2 on synchronization failure - */ -int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, - const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, - u8 *auts) -{ - int i; - u8 mac_a[8], ak[6], rx_sqn[6]; - const u8 *amf; - - wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); - wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); - - if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) - return -1; - - *res_len = 8; - wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); - wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); - wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); - wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); - - /* AUTN = (SQN ^ AK) || AMF || MAC */ - for (i = 0; i < 6; i++) - rx_sqn[i] = autn[i] ^ ak[i]; - wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); - - if (os_memcmp(rx_sqn, sqn, 6) <= 0) { - u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ - if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) - return -1; - wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); - for (i = 0; i < 6; i++) - auts[i] = sqn[i] ^ ak[i]; - if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) - return -1; - wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); - return -2; - } - - amf = autn + 6; - wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); - if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) - return -1; - - wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); - - if (os_memcmp(mac_a, autn + 8, 8) != 0) { - wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); - wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", - autn + 8, 8); - return -1; - } - - return 0; -} - - -#ifdef TEST_MAIN_MILENAGE - -extern int wpa_debug_level; - - -/** - * milenage_opc - Determine OPc from OP and K - * @op: OP = 128-bit operator variant algorithm configuration field - * @k: K = 128-bit subscriber key - * @opc: Buffer for OPc = 128-bit value derived from OP and K - */ -static void milenage_opc(const u8 *op, const u8 *k, u8 *opc) -{ - int i; - /* OP_C = OP XOR E_K(OP) */ - aes_128_encrypt_block(k, op, opc); - for (i = 0; i < 16; i++) - opc[i] ^= op[i]; -} - - -struct gsm_milenage_test_set { - u8 ki[16]; - u8 rand[16]; - u8 opc[16]; - u8 sres1[4]; - u8 sres2[4]; - u8 kc[8]; -}; - -static const struct gsm_milenage_test_set gsm_test_sets[] = -{ - { - /* 3GPP TS 55.205 v6.0.0 - Test Set 1 */ - { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f, - 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc }, - { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d, - 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 }, - { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e, - 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf }, - { 0x46, 0xf8, 0x41, 0x6a }, - { 0xa5, 0x42, 0x11, 0xd5 }, - { 0xea, 0xe4, 0xbe, 0x82, 0x3a, 0xf9, 0xa0, 0x8b } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 2 */ - { 0xfe, 0xc8, 0x6b, 0xa6, 0xeb, 0x70, 0x7e, 0xd0, - 0x89, 0x05, 0x75, 0x7b, 0x1b, 0xb4, 0x4b, 0x8f }, - { 0x9f, 0x7c, 0x8d, 0x02, 0x1a, 0xcc, 0xf4, 0xdb, - 0x21, 0x3c, 0xcf, 0xf0, 0xc7, 0xf7, 0x1a, 0x6a }, - { 0x10, 0x06, 0x02, 0x0f, 0x0a, 0x47, 0x8b, 0xf6, - 0xb6, 0x99, 0xf1, 0x5c, 0x06, 0x2e, 0x42, 0xb3 }, - { 0x8c, 0x30, 0x8a, 0x5e }, - { 0x80, 0x11, 0xc4, 0x8c }, - { 0xaa, 0x01, 0x73, 0x9b, 0x8c, 0xaa, 0x97, 0x6d } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 3 */ - { 0x9e, 0x59, 0x44, 0xae, 0xa9, 0x4b, 0x81, 0x16, - 0x5c, 0x82, 0xfb, 0xf9, 0xf3, 0x2d, 0xb7, 0x51 }, - { 0xce, 0x83, 0xdb, 0xc5, 0x4a, 0xc0, 0x27, 0x4a, - 0x15, 0x7c, 0x17, 0xf8, 0x0d, 0x01, 0x7b, 0xd6 }, - { 0xa6, 0x4a, 0x50, 0x7a, 0xe1, 0xa2, 0xa9, 0x8b, - 0xb8, 0x8e, 0xb4, 0x21, 0x01, 0x35, 0xdc, 0x87 }, - { 0xcf, 0xbc, 0xe3, 0xfe }, - { 0xf3, 0x65, 0xcd, 0x68 }, - { 0x9a, 0x8e, 0xc9, 0x5f, 0x40, 0x8c, 0xc5, 0x07 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 4 */ - { 0x4a, 0xb1, 0xde, 0xb0, 0x5c, 0xa6, 0xce, 0xb0, - 0x51, 0xfc, 0x98, 0xe7, 0x7d, 0x02, 0x6a, 0x84 }, - { 0x74, 0xb0, 0xcd, 0x60, 0x31, 0xa1, 0xc8, 0x33, - 0x9b, 0x2b, 0x6c, 0xe2, 0xb8, 0xc4, 0xa1, 0x86 }, - { 0xdc, 0xf0, 0x7c, 0xbd, 0x51, 0x85, 0x52, 0x90, - 0xb9, 0x2a, 0x07, 0xa9, 0x89, 0x1e, 0x52, 0x3e }, - { 0x96, 0x55, 0xe2, 0x65 }, - { 0x58, 0x60, 0xfc, 0x1b }, - { 0xcd, 0xc1, 0xdc, 0x08, 0x41, 0xb8, 0x1a, 0x22 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 5 */ - { 0x6c, 0x38, 0xa1, 0x16, 0xac, 0x28, 0x0c, 0x45, - 0x4f, 0x59, 0x33, 0x2e, 0xe3, 0x5c, 0x8c, 0x4f }, - { 0xee, 0x64, 0x66, 0xbc, 0x96, 0x20, 0x2c, 0x5a, - 0x55, 0x7a, 0xbb, 0xef, 0xf8, 0xba, 0xbf, 0x63 }, - { 0x38, 0x03, 0xef, 0x53, 0x63, 0xb9, 0x47, 0xc6, - 0xaa, 0xa2, 0x25, 0xe5, 0x8f, 0xae, 0x39, 0x34 }, - { 0x13, 0x68, 0x8f, 0x17 }, - { 0x16, 0xc8, 0x23, 0x3f }, - { 0xdf, 0x75, 0xbc, 0x5e, 0xa8, 0x99, 0x87, 0x9f } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 6 */ - { 0x2d, 0x60, 0x9d, 0x4d, 0xb0, 0xac, 0x5b, 0xf0, - 0xd2, 0xc0, 0xde, 0x26, 0x70, 0x14, 0xde, 0x0d }, - { 0x19, 0x4a, 0xa7, 0x56, 0x01, 0x38, 0x96, 0xb7, - 0x4b, 0x4a, 0x2a, 0x3b, 0x0a, 0xf4, 0x53, 0x9e }, - { 0xc3, 0x5a, 0x0a, 0xb0, 0xbc, 0xbf, 0xc9, 0x25, - 0x2c, 0xaf, 0xf1, 0x5f, 0x24, 0xef, 0xbd, 0xe0 }, - { 0x55, 0x3d, 0x00, 0xb3 }, - { 0x8c, 0x25, 0xa1, 0x6c }, - { 0x84, 0xb4, 0x17, 0xae, 0x3a, 0xea, 0xb4, 0xf3 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 7 */ - { 0xa5, 0x30, 0xa7, 0xfe, 0x42, 0x8f, 0xad, 0x10, - 0x82, 0xc4, 0x5e, 0xdd, 0xfc, 0xe1, 0x38, 0x84 }, - { 0x3a, 0x4c, 0x2b, 0x32, 0x45, 0xc5, 0x0e, 0xb5, - 0xc7, 0x1d, 0x08, 0x63, 0x93, 0x95, 0x76, 0x4d }, - { 0x27, 0x95, 0x3e, 0x49, 0xbc, 0x8a, 0xf6, 0xdc, - 0xc6, 0xe7, 0x30, 0xeb, 0x80, 0x28, 0x6b, 0xe3 }, - { 0x59, 0xf1, 0xa4, 0x4a }, - { 0xa6, 0x32, 0x41, 0xe1 }, - { 0x3b, 0x4e, 0x24, 0x4c, 0xdc, 0x60, 0xce, 0x03 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 8 */ - { 0xd9, 0x15, 0x1c, 0xf0, 0x48, 0x96, 0xe2, 0x58, - 0x30, 0xbf, 0x2e, 0x08, 0x26, 0x7b, 0x83, 0x60 }, - { 0xf7, 0x61, 0xe5, 0xe9, 0x3d, 0x60, 0x3f, 0xeb, - 0x73, 0x0e, 0x27, 0x55, 0x6c, 0xb8, 0xa2, 0xca }, - { 0xc4, 0xc9, 0x3e, 0xff, 0xe8, 0xa0, 0x81, 0x38, - 0xc2, 0x03, 0xd4, 0xc2, 0x7c, 0xe4, 0xe3, 0xd9 }, - { 0x50, 0x58, 0x88, 0x61 }, - { 0x4a, 0x90, 0xb2, 0x17 }, - { 0x8d, 0x4e, 0xc0, 0x1d, 0xe5, 0x97, 0xac, 0xfe } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 9 */ - { 0xa0, 0xe2, 0x97, 0x1b, 0x68, 0x22, 0xe8, 0xd3, - 0x54, 0xa1, 0x8c, 0xc2, 0x35, 0x62, 0x4e, 0xcb }, - { 0x08, 0xef, 0xf8, 0x28, 0xb1, 0x3f, 0xdb, 0x56, - 0x27, 0x22, 0xc6, 0x5c, 0x7f, 0x30, 0xa9, 0xb2 }, - { 0x82, 0xa2, 0x6f, 0x22, 0xbb, 0xa9, 0xe9, 0x48, - 0x8f, 0x94, 0x9a, 0x10, 0xd9, 0x8e, 0x9c, 0xc4 }, - { 0xcd, 0xe6, 0xb0, 0x27 }, - { 0x4b, 0xc2, 0x21, 0x2d }, - { 0xd8, 0xde, 0xbc, 0x4f, 0xfb, 0xcd, 0x60, 0xaa } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 10 */ - { 0x0d, 0xa6, 0xf7, 0xba, 0x86, 0xd5, 0xea, 0xc8, - 0xa1, 0x9c, 0xf5, 0x63, 0xac, 0x58, 0x64, 0x2d }, - { 0x67, 0x9a, 0xc4, 0xdb, 0xac, 0xd7, 0xd2, 0x33, - 0xff, 0x9d, 0x68, 0x06, 0xf4, 0x14, 0x9c, 0xe3 }, - { 0x0d, 0xb1, 0x07, 0x1f, 0x87, 0x67, 0x56, 0x2c, - 0xa4, 0x3a, 0x0a, 0x64, 0xc4, 0x1e, 0x8d, 0x08 }, - { 0x02, 0xd1, 0x3a, 0xcd }, - { 0x6f, 0xc3, 0x0f, 0xee }, - { 0xf0, 0xea, 0xa5, 0x0a, 0x1e, 0xdc, 0xeb, 0xb7 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 11 */ - { 0x77, 0xb4, 0x58, 0x43, 0xc8, 0x8e, 0x58, 0xc1, - 0x0d, 0x20, 0x26, 0x84, 0x51, 0x5e, 0xd4, 0x30 }, - { 0x4c, 0x47, 0xeb, 0x30, 0x76, 0xdc, 0x55, 0xfe, - 0x51, 0x06, 0xcb, 0x20, 0x34, 0xb8, 0xcd, 0x78 }, - { 0xd4, 0x83, 0xaf, 0xae, 0x56, 0x24, 0x09, 0xa3, - 0x26, 0xb5, 0xbb, 0x0b, 0x20, 0xc4, 0xd7, 0x62 }, - { 0x44, 0x38, 0x9d, 0x01 }, - { 0xae, 0xfa, 0x35, 0x7b }, - { 0x82, 0xdb, 0xab, 0x7f, 0x83, 0xf0, 0x63, 0xda } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 12 */ - { 0x72, 0x9b, 0x17, 0x72, 0x92, 0x70, 0xdd, 0x87, - 0xcc, 0xdf, 0x1b, 0xfe, 0x29, 0xb4, 0xe9, 0xbb }, - { 0x31, 0x1c, 0x4c, 0x92, 0x97, 0x44, 0xd6, 0x75, - 0xb7, 0x20, 0xf3, 0xb7, 0xe9, 0xb1, 0xcb, 0xd0 }, - { 0x22, 0x8c, 0x2f, 0x2f, 0x06, 0xac, 0x32, 0x68, - 0xa9, 0xe6, 0x16, 0xee, 0x16, 0xdb, 0x4b, 0xa1 }, - { 0x03, 0xe0, 0xfd, 0x84 }, - { 0x98, 0xdb, 0xbd, 0x09 }, - { 0x3c, 0x66, 0xcb, 0x98, 0xca, 0xb2, 0xd3, 0x3d } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 13 */ - { 0xd3, 0x2d, 0xd2, 0x3e, 0x89, 0xdc, 0x66, 0x23, - 0x54, 0xca, 0x12, 0xeb, 0x79, 0xdd, 0x32, 0xfa }, - { 0xcf, 0x7d, 0x0a, 0xb1, 0xd9, 0x43, 0x06, 0x95, - 0x0b, 0xf1, 0x20, 0x18, 0xfb, 0xd4, 0x68, 0x87 }, - { 0xd2, 0x2a, 0x4b, 0x41, 0x80, 0xa5, 0x32, 0x57, - 0x08, 0xa5, 0xff, 0x70, 0xd9, 0xf6, 0x7e, 0xc7 }, - { 0xbe, 0x73, 0xb3, 0xdc }, - { 0xaf, 0x4a, 0x41, 0x1e }, - { 0x96, 0x12, 0xb5, 0xd8, 0x8a, 0x41, 0x30, 0xbb } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 14 */ - { 0xaf, 0x7c, 0x65, 0xe1, 0x92, 0x72, 0x21, 0xde, - 0x59, 0x11, 0x87, 0xa2, 0xc5, 0x98, 0x7a, 0x53 }, - { 0x1f, 0x0f, 0x85, 0x78, 0x46, 0x4f, 0xd5, 0x9b, - 0x64, 0xbe, 0xd2, 0xd0, 0x94, 0x36, 0xb5, 0x7a }, - { 0xa4, 0xcf, 0x5c, 0x81, 0x55, 0xc0, 0x8a, 0x7e, - 0xff, 0x41, 0x8e, 0x54, 0x43, 0xb9, 0x8e, 0x55 }, - { 0x8f, 0xe0, 0x19, 0xc7 }, - { 0x7b, 0xff, 0xa5, 0xc2 }, - { 0x75, 0xa1, 0x50, 0xdf, 0x3c, 0x6a, 0xed, 0x08 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 15 */ - { 0x5b, 0xd7, 0xec, 0xd3, 0xd3, 0x12, 0x7a, 0x41, - 0xd1, 0x25, 0x39, 0xbe, 0xd4, 0xe7, 0xcf, 0x71 }, - { 0x59, 0xb7, 0x5f, 0x14, 0x25, 0x1c, 0x75, 0x03, - 0x1d, 0x0b, 0xcb, 0xac, 0x1c, 0x2c, 0x04, 0xc7 }, - { 0x76, 0x08, 0x9d, 0x3c, 0x0f, 0xf3, 0xef, 0xdc, - 0x6e, 0x36, 0x72, 0x1d, 0x4f, 0xce, 0xb7, 0x47 }, - { 0x27, 0x20, 0x2b, 0x82 }, - { 0x7e, 0x3f, 0x44, 0xc7 }, - { 0xb7, 0xf9, 0x2e, 0x42, 0x6a, 0x36, 0xfe, 0xc5 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 16 */ - { 0x6c, 0xd1, 0xc6, 0xce, 0xb1, 0xe0, 0x1e, 0x14, - 0xf1, 0xb8, 0x23, 0x16, 0xa9, 0x0b, 0x7f, 0x3d }, - { 0xf6, 0x9b, 0x78, 0xf3, 0x00, 0xa0, 0x56, 0x8b, - 0xce, 0x9f, 0x0c, 0xb9, 0x3c, 0x4b, 0xe4, 0xc9 }, - { 0xa2, 0x19, 0xdc, 0x37, 0xf1, 0xdc, 0x7d, 0x66, - 0x73, 0x8b, 0x58, 0x43, 0xc7, 0x99, 0xf2, 0x06 }, - { 0xdd, 0xd7, 0xef, 0xe6 }, - { 0x70, 0xf6, 0xbd, 0xb9 }, - { 0x88, 0xd9, 0xde, 0x10, 0xa2, 0x20, 0x04, 0xc5 } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 17 */ - { 0xb7, 0x3a, 0x90, 0xcb, 0xcf, 0x3a, 0xfb, 0x62, - 0x2d, 0xba, 0x83, 0xc5, 0x8a, 0x84, 0x15, 0xdf }, - { 0xb1, 0x20, 0xf1, 0xc1, 0xa0, 0x10, 0x2a, 0x2f, - 0x50, 0x7d, 0xd5, 0x43, 0xde, 0x68, 0x28, 0x1f }, - { 0xdf, 0x0c, 0x67, 0x86, 0x8f, 0xa2, 0x5f, 0x74, - 0x8b, 0x70, 0x44, 0xc6, 0xe7, 0xc2, 0x45, 0xb8 }, - { 0x67, 0xe4, 0xff, 0x3f }, - { 0x47, 0x9d, 0xd2, 0x5c }, - { 0xa8, 0x19, 0xe5, 0x77, 0xa8, 0xd6, 0x17, 0x5b } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 18 */ - { 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72, - 0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 }, - { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e, - 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 }, - { 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e, - 0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf }, - { 0x8a, 0x3b, 0x8d, 0x17 }, - { 0x28, 0xd7, 0xb0, 0xf2 }, - { 0x9a, 0x8d, 0x0e, 0x88, 0x3f, 0xf0, 0x88, 0x7a } - }, { - /* 3GPP TS 55.205 v6.0.0 - Test Set 19 */ - { 0x90, 0xdc, 0xa4, 0xed, 0xa4, 0x5b, 0x53, 0xcf, - 0x0f, 0x12, 0xd7, 0xc9, 0xc3, 0xbc, 0x6a, 0x89 }, - { 0x9f, 0xdd, 0xc7, 0x20, 0x92, 0xc6, 0xad, 0x03, - 0x6b, 0x6e, 0x46, 0x47, 0x89, 0x31, 0x5b, 0x78 }, - { 0xcb, 0x9c, 0xcc, 0xc4, 0xb9, 0x25, 0x8e, 0x6d, - 0xca, 0x47, 0x60, 0x37, 0x9f, 0xb8, 0x25, 0x81 }, - { 0xdf, 0x58, 0x52, 0x2f }, - { 0xa9, 0x51, 0x00, 0xe2 }, - { 0xed, 0x29, 0xb2, 0xf1, 0xc2, 0x7f, 0x9f, 0x34 } - } -}; - -#define NUM_GSM_TESTS (sizeof(gsm_test_sets) / sizeof(gsm_test_sets[0])) - - -struct milenage_test_set { - u8 k[16]; - u8 rand[16]; - u8 sqn[6]; - u8 amf[2]; - u8 op[16]; - u8 opc[16]; - u8 f1[8]; - u8 f1star[8]; - u8 f2[8]; - u8 f3[16]; - u8 f4[16]; - u8 f5[6]; - u8 f5star[6]; -}; - -static const struct milenage_test_set test_sets[] = -{ - { - /* 3GPP TS 35.208 v6.0.0 - 4.3.1 Test Set 1 */ - { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f, - 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc }, - { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d, - 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 }, - { 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 }, - { 0xb9, 0xb9 }, - { 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6, - 0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 }, - { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e, - 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf }, - { 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 }, - { 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 }, - { 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf }, - { 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05, - 0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb }, - { 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04, - 0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 }, - { 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 }, - { 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.2 Test Set 2 */ - { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f, - 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc }, - { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d, - 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 }, - { 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 }, - { 0xb9, 0xb9 }, - { 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6, - 0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 }, - { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e, - 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf }, - { 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 }, - { 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 }, - { 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf }, - { 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05, - 0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb }, - { 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04, - 0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 }, - { 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 }, - { 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.3 Test Set 3 */ - { 0xfe, 0xc8, 0x6b, 0xa6, 0xeb, 0x70, 0x7e, 0xd0, - 0x89, 0x05, 0x75, 0x7b, 0x1b, 0xb4, 0x4b, 0x8f }, - { 0x9f, 0x7c, 0x8d, 0x02, 0x1a, 0xcc, 0xf4, 0xdb, - 0x21, 0x3c, 0xcf, 0xf0, 0xc7, 0xf7, 0x1a, 0x6a }, - { 0x9d, 0x02, 0x77, 0x59, 0x5f, 0xfc }, - { 0x72, 0x5c }, - { 0xdb, 0xc5, 0x9a, 0xdc, 0xb6, 0xf9, 0xa0, 0xef, - 0x73, 0x54, 0x77, 0xb7, 0xfa, 0xdf, 0x83, 0x74 }, - { 0x10, 0x06, 0x02, 0x0f, 0x0a, 0x47, 0x8b, 0xf6, - 0xb6, 0x99, 0xf1, 0x5c, 0x06, 0x2e, 0x42, 0xb3 }, - { 0x9c, 0xab, 0xc3, 0xe9, 0x9b, 0xaf, 0x72, 0x81 }, - { 0x95, 0x81, 0x4b, 0xa2, 0xb3, 0x04, 0x43, 0x24 }, - { 0x80, 0x11, 0xc4, 0x8c, 0x0c, 0x21, 0x4e, 0xd2 }, - { 0x5d, 0xbd, 0xbb, 0x29, 0x54, 0xe8, 0xf3, 0xcd, - 0xe6, 0x65, 0xb0, 0x46, 0x17, 0x9a, 0x50, 0x98 }, - { 0x59, 0xa9, 0x2d, 0x3b, 0x47, 0x6a, 0x04, 0x43, - 0x48, 0x70, 0x55, 0xcf, 0x88, 0xb2, 0x30, 0x7b }, - { 0x33, 0x48, 0x4d, 0xc2, 0x13, 0x6b }, - { 0xde, 0xac, 0xdd, 0x84, 0x8c, 0xc6 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.4 Test Set 4 */ - { 0x9e, 0x59, 0x44, 0xae, 0xa9, 0x4b, 0x81, 0x16, - 0x5c, 0x82, 0xfb, 0xf9, 0xf3, 0x2d, 0xb7, 0x51 }, - { 0xce, 0x83, 0xdb, 0xc5, 0x4a, 0xc0, 0x27, 0x4a, - 0x15, 0x7c, 0x17, 0xf8, 0x0d, 0x01, 0x7b, 0xd6 }, - { 0x0b, 0x60, 0x4a, 0x81, 0xec, 0xa8 }, - { 0x9e, 0x09 }, - { 0x22, 0x30, 0x14, 0xc5, 0x80, 0x66, 0x94, 0xc0, - 0x07, 0xca, 0x1e, 0xee, 0xf5, 0x7f, 0x00, 0x4f }, - { 0xa6, 0x4a, 0x50, 0x7a, 0xe1, 0xa2, 0xa9, 0x8b, - 0xb8, 0x8e, 0xb4, 0x21, 0x01, 0x35, 0xdc, 0x87 }, - { 0x74, 0xa5, 0x82, 0x20, 0xcb, 0xa8, 0x4c, 0x49 }, - { 0xac, 0x2c, 0xc7, 0x4a, 0x96, 0x87, 0x18, 0x37 }, - { 0xf3, 0x65, 0xcd, 0x68, 0x3c, 0xd9, 0x2e, 0x96 }, - { 0xe2, 0x03, 0xed, 0xb3, 0x97, 0x15, 0x74, 0xf5, - 0xa9, 0x4b, 0x0d, 0x61, 0xb8, 0x16, 0x34, 0x5d }, - { 0x0c, 0x45, 0x24, 0xad, 0xea, 0xc0, 0x41, 0xc4, - 0xdd, 0x83, 0x0d, 0x20, 0x85, 0x4f, 0xc4, 0x6b }, - { 0xf0, 0xb9, 0xc0, 0x8a, 0xd0, 0x2e }, - { 0x60, 0x85, 0xa8, 0x6c, 0x6f, 0x63 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.5 Test Set 5 */ - { 0x4a, 0xb1, 0xde, 0xb0, 0x5c, 0xa6, 0xce, 0xb0, - 0x51, 0xfc, 0x98, 0xe7, 0x7d, 0x02, 0x6a, 0x84 }, - { 0x74, 0xb0, 0xcd, 0x60, 0x31, 0xa1, 0xc8, 0x33, - 0x9b, 0x2b, 0x6c, 0xe2, 0xb8, 0xc4, 0xa1, 0x86 }, - { 0xe8, 0x80, 0xa1, 0xb5, 0x80, 0xb6 }, - { 0x9f, 0x07 }, - { 0x2d, 0x16, 0xc5, 0xcd, 0x1f, 0xdf, 0x6b, 0x22, - 0x38, 0x35, 0x84, 0xe3, 0xbe, 0xf2, 0xa8, 0xd8 }, - { 0xdc, 0xf0, 0x7c, 0xbd, 0x51, 0x85, 0x52, 0x90, - 0xb9, 0x2a, 0x07, 0xa9, 0x89, 0x1e, 0x52, 0x3e }, - { 0x49, 0xe7, 0x85, 0xdd, 0x12, 0x62, 0x6e, 0xf2 }, - { 0x9e, 0x85, 0x79, 0x03, 0x36, 0xbb, 0x3f, 0xa2 }, - { 0x58, 0x60, 0xfc, 0x1b, 0xce, 0x35, 0x1e, 0x7e }, - { 0x76, 0x57, 0x76, 0x6b, 0x37, 0x3d, 0x1c, 0x21, - 0x38, 0xf3, 0x07, 0xe3, 0xde, 0x92, 0x42, 0xf9 }, - { 0x1c, 0x42, 0xe9, 0x60, 0xd8, 0x9b, 0x8f, 0xa9, - 0x9f, 0x27, 0x44, 0xe0, 0x70, 0x8c, 0xcb, 0x53 }, - { 0x31, 0xe1, 0x1a, 0x60, 0x91, 0x18 }, - { 0xfe, 0x25, 0x55, 0xe5, 0x4a, 0xa9 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.6 Test Set 6 */ - { 0x6c, 0x38, 0xa1, 0x16, 0xac, 0x28, 0x0c, 0x45, - 0x4f, 0x59, 0x33, 0x2e, 0xe3, 0x5c, 0x8c, 0x4f }, - { 0xee, 0x64, 0x66, 0xbc, 0x96, 0x20, 0x2c, 0x5a, - 0x55, 0x7a, 0xbb, 0xef, 0xf8, 0xba, 0xbf, 0x63 }, - { 0x41, 0x4b, 0x98, 0x22, 0x21, 0x81 }, - { 0x44, 0x64 }, - { 0x1b, 0xa0, 0x0a, 0x1a, 0x7c, 0x67, 0x00, 0xac, - 0x8c, 0x3f, 0xf3, 0xe9, 0x6a, 0xd0, 0x87, 0x25 }, - { 0x38, 0x03, 0xef, 0x53, 0x63, 0xb9, 0x47, 0xc6, - 0xaa, 0xa2, 0x25, 0xe5, 0x8f, 0xae, 0x39, 0x34 }, - { 0x07, 0x8a, 0xdf, 0xb4, 0x88, 0x24, 0x1a, 0x57 }, - { 0x80, 0x24, 0x6b, 0x8d, 0x01, 0x86, 0xbc, 0xf1 }, - { 0x16, 0xc8, 0x23, 0x3f, 0x05, 0xa0, 0xac, 0x28 }, - { 0x3f, 0x8c, 0x75, 0x87, 0xfe, 0x8e, 0x4b, 0x23, - 0x3a, 0xf6, 0x76, 0xae, 0xde, 0x30, 0xba, 0x3b }, - { 0xa7, 0x46, 0x6c, 0xc1, 0xe6, 0xb2, 0xa1, 0x33, - 0x7d, 0x49, 0xd3, 0xb6, 0x6e, 0x95, 0xd7, 0xb4 }, - { 0x45, 0xb0, 0xf6, 0x9a, 0xb0, 0x6c }, - { 0x1f, 0x53, 0xcd, 0x2b, 0x11, 0x13 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.7 Test Set 7 */ - { 0x2d, 0x60, 0x9d, 0x4d, 0xb0, 0xac, 0x5b, 0xf0, - 0xd2, 0xc0, 0xde, 0x26, 0x70, 0x14, 0xde, 0x0d }, - { 0x19, 0x4a, 0xa7, 0x56, 0x01, 0x38, 0x96, 0xb7, - 0x4b, 0x4a, 0x2a, 0x3b, 0x0a, 0xf4, 0x53, 0x9e }, - { 0x6b, 0xf6, 0x94, 0x38, 0xc2, 0xe4 }, - { 0x5f, 0x67 }, - { 0x46, 0x0a, 0x48, 0x38, 0x54, 0x27, 0xaa, 0x39, - 0x26, 0x4a, 0xac, 0x8e, 0xfc, 0x9e, 0x73, 0xe8 }, - { 0xc3, 0x5a, 0x0a, 0xb0, 0xbc, 0xbf, 0xc9, 0x25, - 0x2c, 0xaf, 0xf1, 0x5f, 0x24, 0xef, 0xbd, 0xe0 }, - { 0xbd, 0x07, 0xd3, 0x00, 0x3b, 0x9e, 0x5c, 0xc3 }, - { 0xbc, 0xb6, 0xc2, 0xfc, 0xad, 0x15, 0x22, 0x50 }, - { 0x8c, 0x25, 0xa1, 0x6c, 0xd9, 0x18, 0xa1, 0xdf }, - { 0x4c, 0xd0, 0x84, 0x60, 0x20, 0xf8, 0xfa, 0x07, - 0x31, 0xdd, 0x47, 0xcb, 0xdc, 0x6b, 0xe4, 0x11 }, - { 0x88, 0xab, 0x80, 0xa4, 0x15, 0xf1, 0x5c, 0x73, - 0x71, 0x12, 0x54, 0xa1, 0xd3, 0x88, 0xf6, 0x96 }, - { 0x7e, 0x64, 0x55, 0xf3, 0x4c, 0xf3 }, - { 0xdc, 0x6d, 0xd0, 0x1e, 0x8f, 0x15 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.8 Test Set 8 */ - { 0xa5, 0x30, 0xa7, 0xfe, 0x42, 0x8f, 0xad, 0x10, - 0x82, 0xc4, 0x5e, 0xdd, 0xfc, 0xe1, 0x38, 0x84 }, - { 0x3a, 0x4c, 0x2b, 0x32, 0x45, 0xc5, 0x0e, 0xb5, - 0xc7, 0x1d, 0x08, 0x63, 0x93, 0x95, 0x76, 0x4d }, - { 0xf6, 0x3f, 0x5d, 0x76, 0x87, 0x84 }, - { 0xb9, 0x0e }, - { 0x51, 0x1c, 0x6c, 0x4e, 0x83, 0xe3, 0x8c, 0x89, - 0xb1, 0xc5, 0xd8, 0xdd, 0xe6, 0x24, 0x26, 0xfa }, - { 0x27, 0x95, 0x3e, 0x49, 0xbc, 0x8a, 0xf6, 0xdc, - 0xc6, 0xe7, 0x30, 0xeb, 0x80, 0x28, 0x6b, 0xe3 }, - { 0x53, 0x76, 0x1f, 0xbd, 0x67, 0x9b, 0x0b, 0xad }, - { 0x21, 0xad, 0xfd, 0x33, 0x4a, 0x10, 0xe7, 0xce }, - { 0xa6, 0x32, 0x41, 0xe1, 0xff, 0xc3, 0xe5, 0xab }, - { 0x10, 0xf0, 0x5b, 0xab, 0x75, 0xa9, 0x9a, 0x5f, - 0xbb, 0x98, 0xa9, 0xc2, 0x87, 0x67, 0x9c, 0x3b }, - { 0xf9, 0xec, 0x08, 0x65, 0xeb, 0x32, 0xf2, 0x23, - 0x69, 0xca, 0xde, 0x40, 0xc5, 0x9c, 0x3a, 0x44 }, - { 0x88, 0x19, 0x6c, 0x47, 0x98, 0x6f }, - { 0xc9, 0x87, 0xa3, 0xd2, 0x31, 0x15 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.9 Test Set 9 */ - { 0xd9, 0x15, 0x1c, 0xf0, 0x48, 0x96, 0xe2, 0x58, - 0x30, 0xbf, 0x2e, 0x08, 0x26, 0x7b, 0x83, 0x60 }, - { 0xf7, 0x61, 0xe5, 0xe9, 0x3d, 0x60, 0x3f, 0xeb, - 0x73, 0x0e, 0x27, 0x55, 0x6c, 0xb8, 0xa2, 0xca }, - { 0x47, 0xee, 0x01, 0x99, 0x82, 0x0a }, - { 0x91, 0x13 }, - { 0x75, 0xfc, 0x22, 0x33, 0xa4, 0x42, 0x94, 0xee, - 0x8e, 0x6d, 0xe2, 0x5c, 0x43, 0x53, 0xd2, 0x6b }, - { 0xc4, 0xc9, 0x3e, 0xff, 0xe8, 0xa0, 0x81, 0x38, - 0xc2, 0x03, 0xd4, 0xc2, 0x7c, 0xe4, 0xe3, 0xd9 }, - { 0x66, 0xcc, 0x4b, 0xe4, 0x48, 0x62, 0xaf, 0x1f }, - { 0x7a, 0x4b, 0x8d, 0x7a, 0x87, 0x53, 0xf2, 0x46 }, - { 0x4a, 0x90, 0xb2, 0x17, 0x1a, 0xc8, 0x3a, 0x76 }, - { 0x71, 0x23, 0x6b, 0x71, 0x29, 0xf9, 0xb2, 0x2a, - 0xb7, 0x7e, 0xa7, 0xa5, 0x4c, 0x96, 0xda, 0x22 }, - { 0x90, 0x52, 0x7e, 0xba, 0xa5, 0x58, 0x89, 0x68, - 0xdb, 0x41, 0x72, 0x73, 0x25, 0xa0, 0x4d, 0x9e }, - { 0x82, 0xa0, 0xf5, 0x28, 0x7a, 0x71 }, - { 0x52, 0x7d, 0xbf, 0x41, 0xf3, 0x5f } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.10 Test Set 10 */ - { 0xa0, 0xe2, 0x97, 0x1b, 0x68, 0x22, 0xe8, 0xd3, - 0x54, 0xa1, 0x8c, 0xc2, 0x35, 0x62, 0x4e, 0xcb }, - { 0x08, 0xef, 0xf8, 0x28, 0xb1, 0x3f, 0xdb, 0x56, - 0x27, 0x22, 0xc6, 0x5c, 0x7f, 0x30, 0xa9, 0xb2 }, - { 0xdb, 0x5c, 0x06, 0x64, 0x81, 0xe0 }, - { 0x71, 0x6b }, - { 0x32, 0x37, 0x92, 0xfa, 0xca, 0x21, 0xfb, 0x4d, - 0x5d, 0x6f, 0x13, 0xc1, 0x45, 0xa9, 0xd2, 0xc1 }, - { 0x82, 0xa2, 0x6f, 0x22, 0xbb, 0xa9, 0xe9, 0x48, - 0x8f, 0x94, 0x9a, 0x10, 0xd9, 0x8e, 0x9c, 0xc4 }, - { 0x94, 0x85, 0xfe, 0x24, 0x62, 0x1c, 0xb9, 0xf6 }, - { 0xbc, 0xe3, 0x25, 0xce, 0x03, 0xe2, 0xe9, 0xb9 }, - { 0x4b, 0xc2, 0x21, 0x2d, 0x86, 0x24, 0x91, 0x0a }, - { 0x08, 0xce, 0xf6, 0xd0, 0x04, 0xec, 0x61, 0x47, - 0x1a, 0x3c, 0x3c, 0xda, 0x04, 0x81, 0x37, 0xfa }, - { 0xed, 0x03, 0x18, 0xca, 0x5d, 0xeb, 0x92, 0x06, - 0x27, 0x2f, 0x6e, 0x8f, 0xa6, 0x4b, 0xa4, 0x11 }, - { 0xa2, 0xf8, 0x58, 0xaa, 0x9e, 0x5d }, - { 0x74, 0xe7, 0x6f, 0xbb, 0xec, 0x38 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.11 Test Set 11 */ - { 0x0d, 0xa6, 0xf7, 0xba, 0x86, 0xd5, 0xea, 0xc8, - 0xa1, 0x9c, 0xf5, 0x63, 0xac, 0x58, 0x64, 0x2d }, - { 0x67, 0x9a, 0xc4, 0xdb, 0xac, 0xd7, 0xd2, 0x33, - 0xff, 0x9d, 0x68, 0x06, 0xf4, 0x14, 0x9c, 0xe3 }, - { 0x6e, 0x23, 0x31, 0xd6, 0x92, 0xad }, - { 0x22, 0x4a }, - { 0x4b, 0x9a, 0x26, 0xfa, 0x45, 0x9e, 0x3a, 0xcb, - 0xff, 0x36, 0xf4, 0x01, 0x5d, 0xe3, 0xbd, 0xc1 }, - { 0x0d, 0xb1, 0x07, 0x1f, 0x87, 0x67, 0x56, 0x2c, - 0xa4, 0x3a, 0x0a, 0x64, 0xc4, 0x1e, 0x8d, 0x08 }, - { 0x28, 0x31, 0xd7, 0xae, 0x90, 0x88, 0xe4, 0x92 }, - { 0x9b, 0x2e, 0x16, 0x95, 0x11, 0x35, 0xd5, 0x23 }, - { 0x6f, 0xc3, 0x0f, 0xee, 0x6d, 0x12, 0x35, 0x23 }, - { 0x69, 0xb1, 0xca, 0xe7, 0xc7, 0x42, 0x9d, 0x97, - 0x5e, 0x24, 0x5c, 0xac, 0xb0, 0x5a, 0x51, 0x7c }, - { 0x74, 0xf2, 0x4e, 0x8c, 0x26, 0xdf, 0x58, 0xe1, - 0xb3, 0x8d, 0x7d, 0xcd, 0x4f, 0x1b, 0x7f, 0xbd }, - { 0x4c, 0x53, 0x9a, 0x26, 0xe1, 0xfa }, - { 0x07, 0x86, 0x1e, 0x12, 0x69, 0x28 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.12 Test Set 12 */ - { 0x77, 0xb4, 0x58, 0x43, 0xc8, 0x8e, 0x58, 0xc1, - 0x0d, 0x20, 0x26, 0x84, 0x51, 0x5e, 0xd4, 0x30 }, - { 0x4c, 0x47, 0xeb, 0x30, 0x76, 0xdc, 0x55, 0xfe, - 0x51, 0x06, 0xcb, 0x20, 0x34, 0xb8, 0xcd, 0x78 }, - { 0xfe, 0x1a, 0x87, 0x31, 0x00, 0x5d }, - { 0xad, 0x25 }, - { 0xbf, 0x32, 0x86, 0xc7, 0xa5, 0x14, 0x09, 0xce, - 0x95, 0x72, 0x4d, 0x50, 0x3b, 0xfe, 0x6e, 0x70 }, - { 0xd4, 0x83, 0xaf, 0xae, 0x56, 0x24, 0x09, 0xa3, - 0x26, 0xb5, 0xbb, 0x0b, 0x20, 0xc4, 0xd7, 0x62 }, - { 0x08, 0x33, 0x2d, 0x7e, 0x9f, 0x48, 0x45, 0x70 }, - { 0xed, 0x41, 0xb7, 0x34, 0x48, 0x9d, 0x52, 0x07 }, - { 0xae, 0xfa, 0x35, 0x7b, 0xea, 0xc2, 0xa8, 0x7a }, - { 0x90, 0x8c, 0x43, 0xf0, 0x56, 0x9c, 0xb8, 0xf7, - 0x4b, 0xc9, 0x71, 0xe7, 0x06, 0xc3, 0x6c, 0x5f }, - { 0xc2, 0x51, 0xdf, 0x0d, 0x88, 0x8d, 0xd9, 0x32, - 0x9b, 0xcf, 0x46, 0x65, 0x5b, 0x22, 0x6e, 0x40 }, - { 0x30, 0xff, 0x25, 0xcd, 0xad, 0xf6 }, - { 0xe8, 0x4e, 0xd0, 0xd4, 0x67, 0x7e } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.13 Test Set 13 */ - { 0x72, 0x9b, 0x17, 0x72, 0x92, 0x70, 0xdd, 0x87, - 0xcc, 0xdf, 0x1b, 0xfe, 0x29, 0xb4, 0xe9, 0xbb }, - { 0x31, 0x1c, 0x4c, 0x92, 0x97, 0x44, 0xd6, 0x75, - 0xb7, 0x20, 0xf3, 0xb7, 0xe9, 0xb1, 0xcb, 0xd0 }, - { 0xc8, 0x5c, 0x4c, 0xf6, 0x59, 0x16 }, - { 0x5b, 0xb2 }, - { 0xd0, 0x4c, 0x9c, 0x35, 0xbd, 0x22, 0x62, 0xfa, - 0x81, 0x0d, 0x29, 0x24, 0xd0, 0x36, 0xfd, 0x13 }, - { 0x22, 0x8c, 0x2f, 0x2f, 0x06, 0xac, 0x32, 0x68, - 0xa9, 0xe6, 0x16, 0xee, 0x16, 0xdb, 0x4b, 0xa1 }, - { 0xff, 0x79, 0x4f, 0xe2, 0xf8, 0x27, 0xeb, 0xf8 }, - { 0x24, 0xfe, 0x4d, 0xc6, 0x1e, 0x87, 0x4b, 0x52 }, - { 0x98, 0xdb, 0xbd, 0x09, 0x9b, 0x3b, 0x40, 0x8d }, - { 0x44, 0xc0, 0xf2, 0x3c, 0x54, 0x93, 0xcf, 0xd2, - 0x41, 0xe4, 0x8f, 0x19, 0x7e, 0x1d, 0x10, 0x12 }, - { 0x0c, 0x9f, 0xb8, 0x16, 0x13, 0x88, 0x4c, 0x25, - 0x35, 0xdd, 0x0e, 0xab, 0xf3, 0xb4, 0x40, 0xd8 }, - { 0x53, 0x80, 0xd1, 0x58, 0xcf, 0xe3 }, - { 0x87, 0xac, 0x3b, 0x55, 0x9f, 0xb6 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.14 Test Set 14 */ - { 0xd3, 0x2d, 0xd2, 0x3e, 0x89, 0xdc, 0x66, 0x23, - 0x54, 0xca, 0x12, 0xeb, 0x79, 0xdd, 0x32, 0xfa }, - { 0xcf, 0x7d, 0x0a, 0xb1, 0xd9, 0x43, 0x06, 0x95, - 0x0b, 0xf1, 0x20, 0x18, 0xfb, 0xd4, 0x68, 0x87 }, - { 0x48, 0x41, 0x07, 0xe5, 0x6a, 0x43 }, - { 0xb5, 0xe6 }, - { 0xfe, 0x75, 0x90, 0x5b, 0x9d, 0xa4, 0x7d, 0x35, - 0x62, 0x36, 0xd0, 0x31, 0x4e, 0x09, 0xc3, 0x2e }, - { 0xd2, 0x2a, 0x4b, 0x41, 0x80, 0xa5, 0x32, 0x57, - 0x08, 0xa5, 0xff, 0x70, 0xd9, 0xf6, 0x7e, 0xc7 }, - { 0xcf, 0x19, 0xd6, 0x2b, 0x6a, 0x80, 0x98, 0x66 }, - { 0x5d, 0x26, 0x95, 0x37, 0xe4, 0x5e, 0x2c, 0xe6 }, - { 0xaf, 0x4a, 0x41, 0x1e, 0x11, 0x39, 0xf2, 0xc2 }, - { 0x5a, 0xf8, 0x6b, 0x80, 0xed, 0xb7, 0x0d, 0xf5, - 0x29, 0x2c, 0xc1, 0x12, 0x1c, 0xba, 0xd5, 0x0c }, - { 0x7f, 0x4d, 0x6a, 0xe7, 0x44, 0x0e, 0x18, 0x78, - 0x9a, 0x8b, 0x75, 0xad, 0x3f, 0x42, 0xf0, 0x3a }, - { 0x21, 0x7a, 0xf4, 0x92, 0x72, 0xad }, - { 0x90, 0x0e, 0x10, 0x1c, 0x67, 0x7e } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.15 Test Set 15 */ - { 0xaf, 0x7c, 0x65, 0xe1, 0x92, 0x72, 0x21, 0xde, - 0x59, 0x11, 0x87, 0xa2, 0xc5, 0x98, 0x7a, 0x53 }, - { 0x1f, 0x0f, 0x85, 0x78, 0x46, 0x4f, 0xd5, 0x9b, - 0x64, 0xbe, 0xd2, 0xd0, 0x94, 0x36, 0xb5, 0x7a }, - { 0x3d, 0x62, 0x7b, 0x01, 0x41, 0x8d }, - { 0x84, 0xf6 }, - { 0x0c, 0x7a, 0xcb, 0x8d, 0x95, 0xb7, 0xd4, 0xa3, - 0x1c, 0x5a, 0xca, 0x6d, 0x26, 0x34, 0x5a, 0x88 }, - { 0xa4, 0xcf, 0x5c, 0x81, 0x55, 0xc0, 0x8a, 0x7e, - 0xff, 0x41, 0x8e, 0x54, 0x43, 0xb9, 0x8e, 0x55 }, - { 0xc3, 0x7c, 0xae, 0x78, 0x05, 0x64, 0x20, 0x32 }, - { 0x68, 0xcd, 0x09, 0xa4, 0x52, 0xd8, 0xdb, 0x7c }, - { 0x7b, 0xff, 0xa5, 0xc2, 0xf4, 0x1f, 0xbc, 0x05 }, - { 0x3f, 0x8c, 0x3f, 0x3c, 0xcf, 0x76, 0x25, 0xbf, - 0x77, 0xfc, 0x94, 0xbc, 0xfd, 0x22, 0xfd, 0x26 }, - { 0xab, 0xcb, 0xae, 0x8f, 0xd4, 0x61, 0x15, 0xe9, - 0x96, 0x1a, 0x55, 0xd0, 0xda, 0x5f, 0x20, 0x78 }, - { 0x83, 0x7f, 0xd7, 0xb7, 0x44, 0x19 }, - { 0x56, 0xe9, 0x7a, 0x60, 0x90, 0xb1 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.16 Test Set 16 */ - { 0x5b, 0xd7, 0xec, 0xd3, 0xd3, 0x12, 0x7a, 0x41, - 0xd1, 0x25, 0x39, 0xbe, 0xd4, 0xe7, 0xcf, 0x71 }, - { 0x59, 0xb7, 0x5f, 0x14, 0x25, 0x1c, 0x75, 0x03, - 0x1d, 0x0b, 0xcb, 0xac, 0x1c, 0x2c, 0x04, 0xc7 }, - { 0xa2, 0x98, 0xae, 0x89, 0x29, 0xdc }, - { 0xd0, 0x56 }, - { 0xf9, 0x67, 0xf7, 0x60, 0x38, 0xb9, 0x20, 0xa9, - 0xcd, 0x25, 0xe1, 0x0c, 0x08, 0xb4, 0x99, 0x24 }, - { 0x76, 0x08, 0x9d, 0x3c, 0x0f, 0xf3, 0xef, 0xdc, - 0x6e, 0x36, 0x72, 0x1d, 0x4f, 0xce, 0xb7, 0x47 }, - { 0xc3, 0xf2, 0x5c, 0xd9, 0x43, 0x09, 0x10, 0x7e }, - { 0xb0, 0xc8, 0xba, 0x34, 0x36, 0x65, 0xaf, 0xcc }, - { 0x7e, 0x3f, 0x44, 0xc7, 0x59, 0x1f, 0x6f, 0x45 }, - { 0xd4, 0x2b, 0x2d, 0x61, 0x5e, 0x49, 0xa0, 0x3a, - 0xc2, 0x75, 0xa5, 0xae, 0xf9, 0x7a, 0xf8, 0x92 }, - { 0x0b, 0x3f, 0x8d, 0x02, 0x4f, 0xe6, 0xbf, 0xaf, - 0xaa, 0x98, 0x2b, 0x8f, 0x82, 0xe3, 0x19, 0xc2 }, - { 0x5b, 0xe1, 0x14, 0x95, 0x52, 0x5d }, - { 0x4d, 0x6a, 0x34, 0xa1, 0xe4, 0xeb } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.17 Test Set 17 */ - { 0x6c, 0xd1, 0xc6, 0xce, 0xb1, 0xe0, 0x1e, 0x14, - 0xf1, 0xb8, 0x23, 0x16, 0xa9, 0x0b, 0x7f, 0x3d }, - { 0xf6, 0x9b, 0x78, 0xf3, 0x00, 0xa0, 0x56, 0x8b, - 0xce, 0x9f, 0x0c, 0xb9, 0x3c, 0x4b, 0xe4, 0xc9 }, - { 0xb4, 0xfc, 0xe5, 0xfe, 0xb0, 0x59 }, - { 0xe4, 0xbb }, - { 0x07, 0x8b, 0xfc, 0xa9, 0x56, 0x46, 0x59, 0xec, - 0xd8, 0x85, 0x1e, 0x84, 0xe6, 0xc5, 0x9b, 0x48 }, - { 0xa2, 0x19, 0xdc, 0x37, 0xf1, 0xdc, 0x7d, 0x66, - 0x73, 0x8b, 0x58, 0x43, 0xc7, 0x99, 0xf2, 0x06 }, - { 0x69, 0xa9, 0x08, 0x69, 0xc2, 0x68, 0xcb, 0x7b }, - { 0x2e, 0x0f, 0xdc, 0xf9, 0xfd, 0x1c, 0xfa, 0x6a }, - { 0x70, 0xf6, 0xbd, 0xb9, 0xad, 0x21, 0x52, 0x5f }, - { 0x6e, 0xda, 0xf9, 0x9e, 0x5b, 0xd9, 0xf8, 0x5d, - 0x5f, 0x36, 0xd9, 0x1c, 0x12, 0x72, 0xfb, 0x4b }, - { 0xd6, 0x1c, 0x85, 0x3c, 0x28, 0x0d, 0xd9, 0xc4, - 0x6f, 0x29, 0x7b, 0xae, 0xc3, 0x86, 0xde, 0x17 }, - { 0x1c, 0x40, 0x8a, 0x85, 0x8b, 0x3e }, - { 0xaa, 0x4a, 0xe5, 0x2d, 0xaa, 0x30 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.18 Test Set 18 */ - { 0xb7, 0x3a, 0x90, 0xcb, 0xcf, 0x3a, 0xfb, 0x62, - 0x2d, 0xba, 0x83, 0xc5, 0x8a, 0x84, 0x15, 0xdf }, - { 0xb1, 0x20, 0xf1, 0xc1, 0xa0, 0x10, 0x2a, 0x2f, - 0x50, 0x7d, 0xd5, 0x43, 0xde, 0x68, 0x28, 0x1f }, - { 0xf1, 0xe8, 0xa5, 0x23, 0xa3, 0x6d }, - { 0x47, 0x1b }, - { 0xb6, 0x72, 0x04, 0x7e, 0x00, 0x3b, 0xb9, 0x52, - 0xdc, 0xa6, 0xcb, 0x8a, 0xf0, 0xe5, 0xb7, 0x79 }, - { 0xdf, 0x0c, 0x67, 0x86, 0x8f, 0xa2, 0x5f, 0x74, - 0x8b, 0x70, 0x44, 0xc6, 0xe7, 0xc2, 0x45, 0xb8 }, - { 0xeb, 0xd7, 0x03, 0x41, 0xbc, 0xd4, 0x15, 0xb0 }, - { 0x12, 0x35, 0x9f, 0x5d, 0x82, 0x22, 0x0c, 0x14 }, - { 0x47, 0x9d, 0xd2, 0x5c, 0x20, 0x79, 0x2d, 0x63 }, - { 0x66, 0x19, 0x5d, 0xbe, 0xd0, 0x31, 0x32, 0x74, - 0xc5, 0xca, 0x77, 0x66, 0x61, 0x5f, 0xa2, 0x5e }, - { 0x66, 0xbe, 0xc7, 0x07, 0xeb, 0x2a, 0xfc, 0x47, - 0x6d, 0x74, 0x08, 0xa8, 0xf2, 0x92, 0x7b, 0x36 }, - { 0xae, 0xfd, 0xaa, 0x5d, 0xdd, 0x99 }, - { 0x12, 0xec, 0x2b, 0x87, 0xfb, 0xb1 } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.19 Test Set 19 */ - { 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72, - 0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 }, - { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e, - 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 }, - { 0x16, 0xf3, 0xb3, 0xf7, 0x0f, 0xc2 }, - { 0xc3, 0xab }, - { 0xc9, 0xe8, 0x76, 0x32, 0x86, 0xb5, 0xb9, 0xff, - 0xbd, 0xf5, 0x6e, 0x12, 0x97, 0xd0, 0x88, 0x7b }, - { 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e, - 0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf }, - { 0x2a, 0x5c, 0x23, 0xd1, 0x5e, 0xe3, 0x51, 0xd5 }, - { 0x62, 0xda, 0xe3, 0x85, 0x3f, 0x3a, 0xf9, 0xd2 }, - { 0x28, 0xd7, 0xb0, 0xf2, 0xa2, 0xec, 0x3d, 0xe5 }, - { 0x53, 0x49, 0xfb, 0xe0, 0x98, 0x64, 0x9f, 0x94, - 0x8f, 0x5d, 0x2e, 0x97, 0x3a, 0x81, 0xc0, 0x0f }, - { 0x97, 0x44, 0x87, 0x1a, 0xd3, 0x2b, 0xf9, 0xbb, - 0xd1, 0xdd, 0x5c, 0xe5, 0x4e, 0x3e, 0x2e, 0x5a }, - { 0xad, 0xa1, 0x5a, 0xeb, 0x7b, 0xb8 }, - { 0xd4, 0x61, 0xbc, 0x15, 0x47, 0x5d } - }, { - /* 3GPP TS 35.208 v6.0.0 - 4.3.20 Test Set 20 */ - { 0x90, 0xdc, 0xa4, 0xed, 0xa4, 0x5b, 0x53, 0xcf, - 0x0f, 0x12, 0xd7, 0xc9, 0xc3, 0xbc, 0x6a, 0x89 }, - { 0x9f, 0xdd, 0xc7, 0x20, 0x92, 0xc6, 0xad, 0x03, - 0x6b, 0x6e, 0x46, 0x47, 0x89, 0x31, 0x5b, 0x78 }, - { 0x20, 0xf8, 0x13, 0xbd, 0x41, 0x41 }, - { 0x61, 0xdf }, - { 0x3f, 0xfc, 0xfe, 0x5b, 0x7b, 0x11, 0x11, 0x58, - 0x99, 0x20, 0xd3, 0x52, 0x8e, 0x84, 0xe6, 0x55 }, - { 0xcb, 0x9c, 0xcc, 0xc4, 0xb9, 0x25, 0x8e, 0x6d, - 0xca, 0x47, 0x60, 0x37, 0x9f, 0xb8, 0x25, 0x81 }, - { 0x09, 0xdb, 0x94, 0xea, 0xb4, 0xf8, 0x14, 0x9e }, - { 0xa2, 0x94, 0x68, 0xaa, 0x97, 0x75, 0xb5, 0x27 }, - { 0xa9, 0x51, 0x00, 0xe2, 0x76, 0x09, 0x52, 0xcd }, - { 0xb5, 0xf2, 0xda, 0x03, 0x88, 0x3b, 0x69, 0xf9, - 0x6b, 0xf5, 0x2e, 0x02, 0x9e, 0xd9, 0xac, 0x45 }, - { 0xb4, 0x72, 0x13, 0x68, 0xbc, 0x16, 0xea, 0x67, - 0x87, 0x5c, 0x55, 0x98, 0x68, 0x8b, 0xb0, 0xef }, - { 0x83, 0xcf, 0xd5, 0x4d, 0xb9, 0x13 }, - { 0x4f, 0x20, 0x39, 0x39, 0x2d, 0xdc } - } -}; - -#define NUM_TESTS (sizeof(test_sets) / sizeof(test_sets[0])) - - -int main(int argc, char *argv[]) -{ - u8 buf[16], buf2[16], buf3[16], buf4[16], buf5[16], opc[16]; - u8 auts[14], sqn[6], _rand[16]; - int ret = 0, res, i; - const struct milenage_test_set *t; - size_t res_len; - - wpa_debug_level = 0; - - printf("Milenage test sets\n"); - for (i = 0; i < NUM_TESTS; i++) { - t = &test_sets[i]; - printf("Test Set %d\n", i + 1); - - milenage_opc(t->op, t->k, opc); - if (memcmp(opc, t->opc, 16) != 0) { - printf("- milenage_opc failed\n"); - ret++; - } - - if (milenage_f1(opc, t->k, t->rand, t->sqn, t->amf, buf, buf2) - || memcmp(buf, t->f1, 8) != 0) { - printf("- milenage_f1 failed\n"); - ret++; - } - if (memcmp(buf2, t->f1star, 8) != 0) { - printf("- milenage_f1* failed\n"); - ret++; - } - - if (milenage_f2345(opc, t->k, t->rand, buf, buf2, buf3, buf4, - buf5) || - memcmp(buf, t->f2, 8) != 0) { - printf("- milenage_f2 failed\n"); - ret++; - } - if (memcmp(buf2, t->f3, 16) != 0) { - printf("- milenage_f3 failed\n"); - ret++; - } - if (memcmp(buf3, t->f4, 16) != 0) { - printf("- milenage_f4 failed\n"); - ret++; - } - if (memcmp(buf4, t->f5, 6) != 0) { - printf("- milenage_f5 failed\n"); - ret++; - } - if (memcmp(buf5, t->f5star, 6) != 0) { - printf("- milenage_f5* failed\n"); - ret++; - } - } - - printf("milenage_auts test:\n"); - os_memcpy(auts, "\x4f\x20\x39\x39\x2d\xdd", 6); - os_memcpy(auts + 6, "\x4b\xb4\x31\x6e\xd4\xa1\x46\x88", 8); - res = milenage_auts(t->opc, t->k, t->rand, auts, buf); - printf("AUTS for test set %d: %d / SQN=%02x%02x%02x%02x%02x%02x\n", - i, res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); - if (res) - ret++; - - os_memset(_rand, 0xaa, sizeof(_rand)); - os_memcpy(auts, - "\x43\x68\x1a\xd3\xda\xf0\x06\xbc\xde\x40\x5a\x20\x72\x67", - 14); - res = milenage_auts(t->opc, t->k, _rand, auts, buf); - printf("AUTS from a test USIM: %d / SQN=%02x%02x%02x%02x%02x%02x\n", - res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); - if (res) - ret++; - - printf("milenage_generate test:\n"); - os_memcpy(sqn, "\x00\x00\x00\x00\x40\x44", 6); - os_memcpy(_rand, "\x12\x69\xb8\x23\x41\x39\x35\x66\xfb\x99\x41\xe9\x84" - "\x4f\xe6\x2f", 16); - res_len = 8; - milenage_generate(t->opc, t->amf, t->k, sqn, _rand, buf, buf2, buf3, - buf4, &res_len); - wpa_hexdump(MSG_DEBUG, "SQN", sqn, 6); - wpa_hexdump(MSG_DEBUG, "RAND", _rand, 16); - wpa_hexdump(MSG_DEBUG, "AUTN", buf, 16); - wpa_hexdump(MSG_DEBUG, "IK", buf2, 16); - wpa_hexdump(MSG_DEBUG, "CK", buf3, 16); - wpa_hexdump(MSG_DEBUG, "RES", buf4, res_len); - - printf("GSM-Milenage test sets\n"); - for (i = 0; i < NUM_GSM_TESTS; i++) { - const struct gsm_milenage_test_set *g; - u8 sres[4], kc[8]; - g = &gsm_test_sets[i]; - printf("Test Set %d\n", i + 1); - gsm_milenage(g->opc, g->ki, g->rand, sres, kc); - if (memcmp(g->kc, kc, 8) != 0) { - printf("- gsm_milenage Kc failed\n"); - ret++; - } -#ifdef GSM_MILENAGE_ALT_SRES - if (memcmp(g->sres2, sres, 4) != 0) { - printf("- gsm_milenage SRES#2 failed\n"); - ret++; - } -#else /* GSM_MILENAGE_ALT_SRES */ - if (memcmp(g->sres1, sres, 4) != 0) { - printf("- gsm_milenage SRES#1 failed\n"); - ret++; - } -#endif /* GSM_MILENAGE_ALT_SRES */ - } - - if (ret) - printf("Something failed\n"); - else - printf("OK\n"); - - return ret; -} -#endif /* TEST_MAIN_MILENAGE */ diff --git a/src/l2_packet/Makefile b/src/l2_packet/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/l2_packet/Makefile +++ b/src/l2_packet/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c index d1034aa76271..009e02c79c66 100644 --- a/src/l2_packet/l2_packet_freebsd.c +++ b/src/l2_packet/l2_packet_freebsd.c @@ -14,7 +14,7 @@ */ #include "includes.h" -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__GLIBC__) #include #endif /* __APPLE__ */ #include diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c index 7de58808d63c..6ce29aa20ec9 100644 --- a/src/l2_packet/l2_packet_ndis.c +++ b/src/l2_packet/l2_packet_ndis.c @@ -137,11 +137,17 @@ int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, DWORD err = GetLastError(); #ifndef _WIN32_WCE if (err == ERROR_IO_PENDING) { - /* For now, just assume that the packet will be sent in - * time before the next write happens. This could be - * cleaned up at some point to actually wait for - * completion before starting new writes. - */ + wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending " + "write to complete"); + res = GetOverlappedResult( + driver_ndis_get_ndisuio_handle(), &overlapped, + &written, TRUE); + if (!res) { + wpa_printf(MSG_DEBUG, "L2(NDISUIO): " + "GetOverlappedResult failed: %d", + (int) GetLastError()); + return -1; + } return 0; } #endif /* _WIN32_WCE */ diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c index c0e7c495a142..79d29681565a 100644 --- a/src/l2_packet/l2_packet_privsep.c +++ b/src/l2_packet/l2_packet_privsep.c @@ -18,7 +18,7 @@ #include "common.h" #include "eloop.h" #include "l2_packet.h" -#include "privsep_commands.h" +#include "common/privsep_commands.h" struct l2_packet_data { diff --git a/src/lib.rules b/src/lib.rules new file mode 100644 index 000000000000..b260d25a050c --- /dev/null +++ b/src/lib.rules @@ -0,0 +1,21 @@ +ifndef CC +CC=gcc +endif + +ifndef CFLAGS +CFLAGS = -MMD -O2 -Wall -g +endif + +CFLAGS += -I.. -I../utils + + +Q=@ +E=echo +ifeq ($(V), 1) +Q= +E=true +endif + +%.o: %.c + $(Q)$(CC) -c -o $@ $(CFLAGS) $< + @$(E) " CC " $< diff --git a/src/radius/.gitignore b/src/radius/.gitignore new file mode 100644 index 000000000000..a89a1f92753d --- /dev/null +++ b/src/radius/.gitignore @@ -0,0 +1 @@ +libradius.a diff --git a/src/radius/Makefile b/src/radius/Makefile index cffba620da04..b199be8b1970 100644 --- a/src/radius/Makefile +++ b/src/radius/Makefile @@ -1,9 +1,22 @@ -all: - @echo Nothing to be made. +all: libradius.a clean: - for d in $(SUBDIRS); do make -C $$d clean; done - rm -f *~ *.o *.d + rm -f *~ *.o *.d libradius.a install: @echo Nothing to be made. + + +include ../lib.rules + +CFLAGS += -DCONFIG_IPV6 + +LIB_OBJS= \ + radius.o \ + radius_client.o \ + radius_server.o + +libradius.a: $(LIB_OBJS) + $(AR) crT $@ $? + +-include $(OBJS:%.o=%.d) diff --git a/src/radius/radius.c b/src/radius/radius.c index 71bbfb52ee7c..70754ef5dd72 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -1,6 +1,6 @@ /* - * hostapd / RADIUS message processing - * Copyright (c) 2002-2008, Jouni Malinen + * RADIUS message processing + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -12,62 +12,82 @@ * See README and COPYING for more details. */ -#include "includes.h" +#include "utils/includes.h" -#include "common.h" +#include "utils/common.h" +#include "utils/wpabuf.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" #include "radius.h" -#include "md5.h" -#include "crypto.h" + + +/** + * struct radius_msg - RADIUS message structure for new and parsed messages + */ +struct radius_msg { + /** + * buf - Allocated buffer for RADIUS message + */ + struct wpabuf *buf; + + /** + * hdr - Pointer to the RADIUS header in buf + */ + struct radius_hdr *hdr; + + /** + * attr_pos - Array of indexes to attributes + * + * The values are number of bytes from buf to the beginning of + * struct radius_attr_hdr. + */ + size_t *attr_pos; + + /** + * attr_size - Total size of the attribute pointer array + */ + size_t attr_size; + + /** + * attr_used - Total number of attributes in the array + */ + size_t attr_used; +}; + + +struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) +{ + return msg->hdr; +} + + +struct wpabuf * radius_msg_get_buf(struct radius_msg *msg) +{ + return msg->buf; +} static struct radius_attr_hdr * radius_get_attr_hdr(struct radius_msg *msg, int idx) { - return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]); + return (struct radius_attr_hdr *) + (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); } -struct radius_msg *radius_msg_new(u8 code, u8 identifier) +static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) { - struct radius_msg *msg; - - msg = os_malloc(sizeof(*msg)); - if (msg == NULL) - return NULL; - - if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) { - os_free(msg); - return NULL; - } - - radius_msg_set_hdr(msg, code, identifier); - - return msg; + msg->hdr->code = code; + msg->hdr->identifier = identifier; } -int radius_msg_initialize(struct radius_msg *msg, size_t init_len) +static int radius_msg_initialize(struct radius_msg *msg) { - if (msg == NULL || init_len < sizeof(struct radius_hdr)) - return -1; - - os_memset(msg, 0, sizeof(*msg)); - msg->buf = os_zalloc(init_len); - if (msg->buf == NULL) - return -1; - - msg->buf_size = init_len; - msg->hdr = (struct radius_hdr *) msg->buf; - msg->buf_used = sizeof(*msg->hdr); - msg->attr_pos = os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos)); - if (msg->attr_pos == NULL) { - os_free(msg->buf); - msg->buf = NULL; - msg->hdr = NULL; + if (msg->attr_pos == NULL) return -1; - } msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; msg->attr_used = 0; @@ -76,23 +96,48 @@ int radius_msg_initialize(struct radius_msg *msg, size_t init_len) } -void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) +/** + * radius_msg_new - Create a new RADIUS message + * @code: Code for RADIUS header + * @identifier: Identifier for RADIUS header + * Returns: Context for RADIUS message or %NULL on failure + * + * The caller is responsible for freeing the returned data with + * radius_msg_free(). + */ +struct radius_msg * radius_msg_new(u8 code, u8 identifier) { - msg->hdr->code = code; - msg->hdr->identifier = identifier; + struct radius_msg *msg; + + msg = os_zalloc(sizeof(*msg)); + if (msg == NULL) + return NULL; + + msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); + if (msg->buf == NULL || radius_msg_initialize(msg)) { + radius_msg_free(msg); + return NULL; + } + msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); + + radius_msg_set_hdr(msg, code, identifier); + + return msg; } +/** + * radius_msg_free - Free a RADIUS message + * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() + */ void radius_msg_free(struct radius_msg *msg) { - os_free(msg->buf); - msg->buf = NULL; - msg->hdr = NULL; - msg->buf_size = msg->buf_used = 0; + if (msg == NULL) + return; + wpabuf_free(msg->buf); os_free(msg->attr_pos); - msg->attr_pos = NULL; - msg->attr_size = msg->attr_used = 0; + os_free(msg); } @@ -305,19 +350,19 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { - printf("WARNING: Could not add " - "Message-Authenticator\n"); + wpa_printf(MSG_WARNING, "RADIUS: Could not add " + "Message-Authenticator"); return -1; } - msg->hdr->length = htons(msg->buf_used); - hmac_md5(secret, secret_len, msg->buf, msg->buf_used, - (u8 *) (attr + 1)); + msg->hdr->length = htons(wpabuf_len(msg->buf)); + hmac_md5(secret, secret_len, wpabuf_head(msg->buf), + wpabuf_len(msg->buf), (u8 *) (attr + 1)); } else - msg->hdr->length = htons(msg->buf_used); + msg->hdr->length = htons(wpabuf_len(msg->buf)); - if (msg->buf_used > 0xffff) { - printf("WARNING: too long RADIUS message (%lu)\n", - (unsigned long) msg->buf_used); + if (wpabuf_len(msg->buf) > 0xffff) { + wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", + (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; @@ -339,26 +384,26 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, printf("WARNING: Could not add Message-Authenticator\n"); return -1; } - msg->hdr->length = htons(msg->buf_used); + msg->hdr->length = htons(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_authenticator, sizeof(msg->hdr->authenticator)); - hmac_md5(secret, secret_len, msg->buf, msg->buf_used, - (u8 *) (attr + 1)); + hmac_md5(secret, secret_len, wpabuf_head(msg->buf), + wpabuf_len(msg->buf), (u8 *) (attr + 1)); /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = req_authenticator; len[1] = MD5_MAC_LEN; - addr[2] = (u8 *) (msg->hdr + 1); - len[2] = msg->buf_used - sizeof(*msg->hdr); + addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); + len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, msg->hdr->authenticator); - if (msg->buf_used > 0xffff) { - printf("WARNING: too long RADIUS message (%lu)\n", - (unsigned long) msg->buf_used); + if (wpabuf_len(msg->buf) > 0xffff) { + wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", + (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; @@ -371,17 +416,17 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, const u8 *addr[2]; size_t len[2]; - msg->hdr->length = htons(msg->buf_used); + msg->hdr->length = htons(wpabuf_len(msg->buf)); os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); - addr[0] = msg->buf; - len[0] = msg->buf_used; + addr[0] = wpabuf_head(msg->buf); + len[0] = wpabuf_len(msg->buf); addr[1] = secret; len[1] = secret_len; md5_vector(2, addr, len, msg->hdr->authenticator); - if (msg->buf_used > 0xffff) { - printf("WARNING: too long RADIUS messages (%lu)\n", - (unsigned long) msg->buf_used); + if (wpabuf_len(msg->buf) > 0xffff) { + wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", + (unsigned long) wpabuf_len(msg->buf)); } } @@ -402,7 +447,8 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg, msg->attr_size = nlen; } - msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf; + msg->attr_pos[msg->attr_used++] = + (unsigned char *) attr - wpabuf_head_u8(msg->buf); return 0; } @@ -420,31 +466,19 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, return NULL; } - buf_needed = msg->buf_used + sizeof(*attr) + data_len; + buf_needed = sizeof(*attr) + data_len; - if (msg->buf_size < buf_needed) { + if (wpabuf_tailroom(msg->buf) < buf_needed) { /* allocate more space for message buffer */ - unsigned char *nbuf; - size_t nlen = msg->buf_size; - - while (nlen < buf_needed) - nlen *= 2; - nbuf = os_realloc(msg->buf, nlen); - if (nbuf == NULL) + if (wpabuf_resize(&msg->buf, buf_needed) < 0) return NULL; - msg->buf = nbuf; - msg->hdr = (struct radius_hdr *) msg->buf; - os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size); - msg->buf_size = nlen; + msg->hdr = wpabuf_mhead(msg->buf); } - attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used); + attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); attr->type = type; attr->length = sizeof(*attr) + data_len; - if (data_len > 0) - os_memcpy(attr + 1, data, data_len); - - msg->buf_used += sizeof(*attr) + data_len; + wpabuf_put_data(msg->buf, data, data_len); if (radius_msg_add_attr_to_array(msg, attr)) return NULL; @@ -453,7 +487,16 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, } -struct radius_msg *radius_msg_parse(const u8 *data, size_t len) +/** + * radius_msg_parse - Parse a RADIUS message + * @data: RADIUS message to be parsed + * @len: Length of data buffer in octets + * Returns: Parsed RADIUS message or %NULL on failure + * + * This parses a RADIUS message and makes a copy of its data. The caller is + * responsible for freeing the returned data with radius_msg_free(). + */ +struct radius_msg * radius_msg_parse(const u8 *data, size_t len) { struct radius_msg *msg; struct radius_hdr *hdr; @@ -468,30 +511,29 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len) msg_len = ntohs(hdr->length); if (msg_len < sizeof(*hdr) || msg_len > len) { - printf("Invalid RADIUS message length\n"); + wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); return NULL; } if (msg_len < len) { - printf("Ignored %lu extra bytes after RADIUS message\n", - (unsigned long) len - msg_len); + wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " + "RADIUS message", (unsigned long) len - msg_len); } - msg = os_malloc(sizeof(*msg)); + msg = os_zalloc(sizeof(*msg)); if (msg == NULL) return NULL; - if (radius_msg_initialize(msg, msg_len)) { - os_free(msg); + msg->buf = wpabuf_alloc_copy(data, msg_len); + if (msg->buf == NULL || radius_msg_initialize(msg)) { + radius_msg_free(msg); return NULL; } - - os_memcpy(msg->buf, data, msg_len); - msg->buf_size = msg->buf_used = msg_len; + msg->hdr = wpabuf_mhead(msg->buf); /* parse attributes */ - pos = (unsigned char *) (msg->hdr + 1); - end = msg->buf + msg->buf_used; + pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); + end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); while (pos < end) { if ((size_t) (end - pos) < sizeof(*attr)) goto fail; @@ -513,7 +555,6 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len) fail: radius_msg_free(msg); - os_free(msg); return NULL; } @@ -615,7 +656,8 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, os_memcpy(msg->hdr->authenticator, req_auth, sizeof(msg->hdr->authenticator)); } - hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth); + hmac_md5(secret, secret_len, wpabuf_head(msg->buf), + wpabuf_len(msg->buf), auth); os_memcpy(attr + 1, orig, MD5_MAC_LEN); if (req_auth) { os_memcpy(msg->hdr->authenticator, orig_authenticator, @@ -654,8 +696,8 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret, len[0] = 1 + 1 + 2; addr[1] = sent_msg->hdr->authenticator; len[1] = MD5_MAC_LEN; - addr[2] = (u8 *) (msg->hdr + 1); - len[2] = msg->buf_used - sizeof(*msg->hdr); + addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); + len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); @@ -1232,3 +1274,44 @@ int radius_msg_get_vlanid(struct radius_msg *msg) return -1; } + + +void radius_free_class(struct radius_class_data *c) +{ + size_t i; + if (c == NULL) + return; + for (i = 0; i < c->count; i++) + os_free(c->attr[i].data); + os_free(c->attr); + c->attr = NULL; + c->count = 0; +} + + +int radius_copy_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; +} diff --git a/src/radius/radius.h b/src/radius/radius.h index c30621dc2eaf..a3cdac0dac0a 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -1,6 +1,6 @@ /* - * hostapd / RADIUS message processing - * Copyright (c) 2002-2007, Jouni Malinen + * RADIUS message processing + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -173,21 +173,7 @@ struct radius_ms_mppe_keys { }; -/* RADIUS message structure for new and parsed messages */ -struct radius_msg { - unsigned char *buf; - size_t buf_size; /* total size allocated for buf */ - size_t buf_used; /* bytes used in buf */ - - struct radius_hdr *hdr; - - size_t *attr_pos; /* array of indexes to attributes (number of bytes - * from buf to the beginning of - * struct radius_attr_hdr). */ - size_t attr_size; /* total size of the attribute pointer array */ - size_t attr_used; /* total number of attributes in the array */ -}; - +struct radius_msg; /* Default size to be allocated for new RADIUS messages */ #define RADIUS_DEFAULT_MSG_SIZE 1024 @@ -202,9 +188,9 @@ struct radius_msg { /* MAC address ASCII format for non-802.1X use */ #define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x" -struct radius_msg *radius_msg_new(u8 code, u8 identifier); -int radius_msg_initialize(struct radius_msg *msg, size_t init_len); -void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier); +struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg); +struct wpabuf * radius_msg_get_buf(struct radius_msg *msg); +struct radius_msg * radius_msg_new(u8 code, u8 identifier); void radius_msg_free(struct radius_msg *msg); void radius_msg_dump(struct radius_msg *msg); int radius_msg_finish(struct radius_msg *msg, const u8 *secret, @@ -213,9 +199,9 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_authenticator); void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, size_t secret_len); -struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, - const u8 *data, size_t data_len); -struct radius_msg *radius_msg_parse(const u8 *data, size_t len); +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, + const u8 *data, size_t data_len); +struct radius_msg * radius_msg_parse(const u8 *data, size_t len); int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len); u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len); @@ -269,4 +255,19 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, size_t *len, const u8 *start); int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len); + +struct radius_attr_data { + u8 *data; + size_t len; +}; + +struct radius_class_data { + struct radius_attr_data *attr; + size_t count; +}; + +void radius_free_class(struct radius_class_data *c); +int radius_copy_class(struct radius_class_data *dst, + const struct radius_class_data *src); + #endif /* RADIUS_H */ diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 826acad67840..171af2927b0f 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -1,6 +1,6 @@ /* - * hostapd / RADIUS client - * Copyright (c) 2002-2005, Jouni Malinen + * RADIUS client + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -20,68 +20,217 @@ #include "eloop.h" /* Defaults for RADIUS retransmit values (exponential backoff) */ -#define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */ -#define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */ -#define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts - * before entry is removed from retransmit - * list */ -#define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit - * list (oldest will be removed, if this - * limit is exceeded) */ -#define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this - * many failed retry attempts */ + +/** + * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds + */ +#define RADIUS_CLIENT_FIRST_WAIT 3 + +/** + * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds + */ +#define RADIUS_CLIENT_MAX_WAIT 120 + +/** + * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries + * + * Maximum number of retransmit attempts before the entry is removed from + * retransmit list. + */ +#define RADIUS_CLIENT_MAX_RETRIES 10 + +/** + * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages + * + * Maximum number of entries in retransmit list (oldest entries will be + * removed, if this limit is exceeded). + */ +#define RADIUS_CLIENT_MAX_ENTRIES 30 + +/** + * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point + * + * The number of failed retry attempts after which the RADIUS server will be + * changed (if one of more backup servers are configured). + */ +#define RADIUS_CLIENT_NUM_FAILOVER 4 +/** + * struct radius_rx_handler - RADIUS client RX handler + * + * This data structure is used internally inside the RADIUS client module to + * store registered RX handlers. These handlers are registered by calls to + * radius_client_register() and unregistered when the RADIUS client is + * deinitialized with a call to radius_client_deinit(). + */ struct radius_rx_handler { + /** + * handler - Received RADIUS message handler + */ RadiusRxResult (*handler)(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data); + + /** + * data - Context data for the handler + */ void *data; }; -/* RADIUS message retransmit list */ +/** + * struct radius_msg_list - RADIUS client message retransmit list + * + * This data structure is used internally inside the RADIUS client module to + * store pending RADIUS requests that may still need to be retransmitted. + */ struct radius_msg_list { - u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages - * for the same STA. */ + /** + * addr - STA/client address + * + * This is used to find RADIUS messages for the same STA. + */ + u8 addr[ETH_ALEN]; + + /** + * msg - RADIUS message + */ struct radius_msg *msg; + + /** + * msg_type - Message type + */ RadiusType msg_type; + + /** + * first_try - Time of the first transmission attempt + */ os_time_t first_try; + + /** + * next_try - Time for the next transmission attempt + */ os_time_t next_try; + + /** + * attempts - Number of transmission attempts + */ int attempts; + + /** + * next_wait - Next retransmission wait time in seconds + */ int next_wait; + + /** + * last_attempt - Time of the last transmission attempt + */ struct os_time last_attempt; - u8 *shared_secret; + /** + * shared_secret - Shared secret with the target RADIUS server + */ + const u8 *shared_secret; + + /** + * shared_secret_len - shared_secret length in octets + */ size_t shared_secret_len; /* TODO: server config with failover to backup server(s) */ + /** + * next - Next message in the list + */ struct radius_msg_list *next; }; +/** + * struct radius_client_data - Internal RADIUS client data + * + * This data structure is used internally inside the RADIUS client module. + * External users allocate this by calling radius_client_init() and free it by + * calling radius_client_deinit(). The pointer to this opaque data is used in + * calls to other functions as an identifier for the RADIUS client instance. + */ struct radius_client_data { + /** + * ctx - Context pointer for hostapd_logger() callbacks + */ void *ctx; + + /** + * conf - RADIUS client configuration (list of RADIUS servers to use) + */ struct hostapd_radius_servers *conf; - int auth_serv_sock; /* socket for authentication RADIUS messages */ - int acct_serv_sock; /* socket for accounting RADIUS messages */ - int auth_serv_sock6; - int acct_serv_sock6; - int auth_sock; /* currently used socket */ - int acct_sock; /* currently used socket */ + /** + * auth_serv_sock - IPv4 socket for RADIUS authentication messages + */ + int auth_serv_sock; + /** + * acct_serv_sock - IPv4 socket for RADIUS accounting messages + */ + int acct_serv_sock; + + /** + * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages + */ + int auth_serv_sock6; + + /** + * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages + */ + int acct_serv_sock6; + + /** + * auth_sock - Currently used socket for RADIUS authentication server + */ + int auth_sock; + + /** + * acct_sock - Currently used socket for RADIUS accounting server + */ + int acct_sock; + + /** + * auth_handlers - Authentication message handlers + */ struct radius_rx_handler *auth_handlers; + + /** + * num_auth_handlers - Number of handlers in auth_handlers + */ size_t num_auth_handlers; + + /** + * acct_handlers - Accounting message handlers + */ struct radius_rx_handler *acct_handlers; + + /** + * num_acct_handlers - Number of handlers in acct_handlers + */ size_t num_acct_handlers; + /** + * msgs - Pending outgoing RADIUS messages + */ struct radius_msg_list *msgs; + + /** + * num_msgs - Number of pending messages in the msgs list + */ size_t num_msgs; + /** + * next_radius_identifier - Next RADIUS message identifier to use + */ u8 next_radius_identifier; }; @@ -98,11 +247,26 @@ static int radius_client_init_auth(struct radius_client_data *radius); static void radius_client_msg_free(struct radius_msg_list *req) { radius_msg_free(req->msg); - os_free(req->msg); os_free(req); } +/** + * radius_client_register - Register a RADIUS client RX handler + * @radius: RADIUS client context from radius_client_init() + * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT) + * @handler: Handler for received RADIUS messages + * @data: Context pointer for handler callbacks + * Returns: 0 on success, -1 on failure + * + * This function is used to register a handler for processing received RADIUS + * authentication and accounting messages. The handler() callback function will + * be called whenever a RADIUS message is received from the active server. + * + * There can be multiple registered RADIUS message handlers. The handlers will + * be called in order until one of them indicates that it has processed or + * queued the message. + */ int radius_client_register(struct radius_client_data *radius, RadiusType msg_type, RadiusRxResult (*handler)(struct radius_msg *msg, @@ -166,6 +330,7 @@ static int radius_client_retransmit(struct radius_client_data *radius, { struct hostapd_radius_servers *conf = radius->conf; int s; + struct wpabuf *buf; if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) { @@ -190,10 +355,11 @@ static int radius_client_retransmit(struct radius_client_data *radius, entry->attempts++; hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", - entry->msg->hdr->identifier); + radius_msg_get_hdr(entry->msg)->identifier); os_get_time(&entry->last_attempt); - if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0) + buf = radius_msg_get_buf(entry->msg); + if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) radius_client_handle_send_error(radius, s, entry->msg_type); entry->next_try = now + entry->next_wait; @@ -351,7 +517,8 @@ static void radius_client_update_timeout(struct radius_client_data *radius) static void radius_client_list_add(struct radius_client_data *radius, struct radius_msg *msg, - RadiusType msg_type, u8 *shared_secret, + RadiusType msg_type, + const u8 *shared_secret, size_t shared_secret_len, const u8 *addr) { struct radius_msg_list *entry, *prev; @@ -360,7 +527,6 @@ static void radius_client_list_add(struct radius_client_data *radius, /* No point in adding entries to retransmit queue since event * loop has already been terminated. */ radius_msg_free(msg); - os_free(msg); return; } @@ -368,7 +534,6 @@ static void radius_client_list_add(struct radius_client_data *radius, if (entry == NULL) { printf("Failed to add RADIUS packet into retransmit list\n"); radius_msg_free(msg); - os_free(msg); return; } @@ -437,15 +602,38 @@ static void radius_client_list_del(struct radius_client_data *radius, } +/** + * radius_client_send - Send a RADIUS request + * @radius: RADIUS client context from radius_client_init() + * @msg: RADIUS message to be sent + * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM) + * @addr: MAC address of the device related to this message or %NULL + * Returns: 0 on success, -1 on failure + * + * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or + * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference + * between accounting and interim accounting messages is that the interim + * message will override any pending interim accounting updates while a new + * accounting message does not remove any pending messages. + * + * The message is added on the retransmission queue and will be retransmitted + * automatically until a response is received or maximum number of retries + * (RADIUS_CLIENT_MAX_RETRIES) is reached. + * + * The related device MAC address can be used to identify pending messages that + * can be removed with radius_client_flush_auth() or with interim accounting + * updates. + */ int radius_client_send(struct radius_client_data *radius, struct radius_msg *msg, RadiusType msg_type, const u8 *addr) { struct hostapd_radius_servers *conf = radius->conf; - u8 *shared_secret; + const u8 *shared_secret; size_t shared_secret_len; char *name; int s, res; + struct wpabuf *buf; if (msg_type == RADIUS_ACCT_INTERIM) { /* Remove any pending interim acct update for the same STA. */ @@ -488,7 +676,8 @@ int radius_client_send(struct radius_client_data *radius, if (conf->msg_dumps) radius_msg_dump(msg); - res = send(s, msg->buf, msg->buf_used, 0); + buf = radius_msg_get_buf(msg); + res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); if (res < 0) radius_client_handle_send_error(radius, s, msg_type); @@ -507,6 +696,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) int len, roundtrip; unsigned char buf[3000]; struct radius_msg *msg; + struct radius_hdr *hdr; struct radius_rx_handler *handlers; size_t num_handlers, i; struct radius_msg_list *req, *prev_req; @@ -544,13 +734,14 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) rconf->malformed_responses++; return; } + hdr = radius_msg_get_hdr(msg); hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); if (conf->msg_dumps) radius_msg_dump(msg); - switch (msg->hdr->code) { + switch (hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: rconf->access_accepts++; break; @@ -573,7 +764,8 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) if ((req->msg_type == msg_type || (req->msg_type == RADIUS_ACCT_INTERIM && msg_type == RADIUS_ACCT)) && - req->msg->hdr->identifier == msg->hdr->identifier) + radius_msg_get_hdr(req->msg)->identifier == + hdr->identifier) break; prev_req = req; @@ -585,7 +777,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) HOSTAPD_LEVEL_DEBUG, "No matching RADIUS request found (type=%d " "id=%d) - dropping packet", - msg_type, msg->hdr->identifier); + msg_type, hdr->identifier); goto fail; } @@ -614,7 +806,6 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) switch (res) { case RADIUS_RX_PROCESSED: radius_msg_free(msg); - os_free(msg); /* continue */ case RADIUS_RX_QUEUED: radius_client_msg_free(req); @@ -635,17 +826,24 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " "(type=%d code=%d id=%d)%s - dropping packet", - msg_type, msg->hdr->code, msg->hdr->identifier, + msg_type, hdr->code, hdr->identifier, invalid_authenticator ? " [INVALID AUTHENTICATOR]" : ""); radius_client_msg_free(req); fail: radius_msg_free(msg); - os_free(msg); } +/** + * radius_client_get_id - Get an identifier for a new RADIUS message + * @radius: RADIUS client context from radius_client_init() + * Returns: Allocated identifier + * + * This function is used to fetch a unique (among pending requests) identifier + * for a new RADIUS message. + */ u8 radius_client_get_id(struct radius_client_data *radius) { struct radius_msg_list *entry, *prev, *_remove; @@ -656,7 +854,7 @@ u8 radius_client_get_id(struct radius_client_data *radius) entry = radius->msgs; prev = NULL; while (entry) { - if (entry->msg->hdr->identifier == id) { + if (radius_msg_get_hdr(entry->msg)->identifier == id) { hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, @@ -681,6 +879,11 @@ u8 radius_client_get_id(struct radius_client_data *radius) } +/** + * radius_client_flush - Flush all pending RADIUS client messages + * @radius: RADIUS client context from radius_client_init() + * @only_auth: Whether only authentication messages are removed + */ void radius_client_flush(struct radius_client_data *radius, int only_auth) { struct radius_msg_list *entry, *prev, *tmp; @@ -714,7 +917,7 @@ void radius_client_flush(struct radius_client_data *radius, int only_auth) static void radius_client_update_acct_msgs(struct radius_client_data *radius, - u8 *shared_secret, + const u8 *shared_secret, size_t shared_secret_len) { struct radius_msg_list *entry; @@ -1037,6 +1240,16 @@ static int radius_client_init_acct(struct radius_client_data *radius) } +/** + * radius_client_init - Initialize RADIUS client + * @ctx: Callback context to be used in hostapd_logger() calls + * @conf: RADIUS client configuration (RADIUS servers) + * Returns: Pointer to private RADIUS client context or %NULL on failure + * + * The caller is responsible for keeping the configuration data available for + * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is + * called for the returned context pointer. + */ struct radius_client_data * radius_client_init(void *ctx, struct hostapd_radius_servers *conf) { @@ -1071,6 +1284,10 @@ radius_client_init(void *ctx, struct hostapd_radius_servers *conf) } +/** + * radius_client_deinit - Deinitialize RADIUS client + * @radius: RADIUS client context from radius_client_init() + */ void radius_client_deinit(struct radius_client_data *radius) { if (!radius) @@ -1096,7 +1313,18 @@ void radius_client_deinit(struct radius_client_data *radius) } -void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr) +/** + * radius_client_flush_auth - Flush pending RADIUS messages for an address + * @radius: RADIUS client context from radius_client_init() + * @addr: MAC address of the related device + * + * This function can be used to remove pending RADIUS authentication messages + * that are related to a specific device. The addr parameter is matched with + * the one used in radius_client_send() call that was used to transmit the + * authentication request. + */ +void radius_client_flush_auth(struct radius_client_data *radius, + const u8 *addr) { struct radius_msg_list *entry, *prev, *tmp; @@ -1224,6 +1452,13 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen, } +/** + * radius_client_get_mib - Get RADIUS client MIB information + * @radius: RADIUS client context from radius_client_init() + * @buf: Buffer for returning MIB data in text format + * @buflen: Maximum buf length in octets + * Returns: Number of octets written into the buffer + */ int radius_client_get_mib(struct radius_client_data *radius, char *buf, size_t buflen) { @@ -1254,48 +1489,3 @@ int radius_client_get_mib(struct radius_client_data *radius, char *buf, return count; } - - -static int radius_servers_diff(struct hostapd_radius_server *nserv, - struct hostapd_radius_server *oserv, - int num) -{ - int i; - - for (i = 0; i < num; i++) { - if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) || - nserv[i].port != oserv[i].port || - nserv[i].shared_secret_len != oserv[i].shared_secret_len || - os_memcmp(nserv[i].shared_secret, oserv[i].shared_secret, - nserv[i].shared_secret_len) != 0) - return 1; - } - - return 0; -} - - -struct radius_client_data * -radius_client_reconfig(struct radius_client_data *old, void *ctx, - struct hostapd_radius_servers *oldconf, - struct hostapd_radius_servers *newconf) -{ - radius_client_flush(old, 0); - - if (newconf->retry_primary_interval != - oldconf->retry_primary_interval || - newconf->num_auth_servers != oldconf->num_auth_servers || - newconf->num_acct_servers != oldconf->num_acct_servers || - radius_servers_diff(newconf->auth_servers, oldconf->auth_servers, - newconf->num_auth_servers) || - radius_servers_diff(newconf->acct_servers, oldconf->acct_servers, - newconf->num_acct_servers)) { - hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_DEBUG, - "Reconfiguring RADIUS client"); - radius_client_deinit(old); - return radius_client_init(ctx, newconf); - } - - return old; -} diff --git a/src/radius/radius_client.h b/src/radius/radius_client.h index 4fe9ba9a42c7..644ea234fd25 100644 --- a/src/radius/radius_client.h +++ b/src/radius/radius_client.h @@ -1,6 +1,6 @@ /* - * hostapd / RADIUS client - * Copyright (c) 2002-2005, Jouni Malinen + * RADIUS client + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -19,63 +19,222 @@ struct radius_msg; +/** + * struct hostapd_radius_server - RADIUS server information for RADIUS client + * + * This structure contains information about a RADIUS server. The values are + * mainly for MIB information. The MIB variable prefix (radiusAuth or + * radiusAcc) depends on whether this is an authentication or accounting + * server. + * + * radiusAuthClientPendingRequests (or radiusAccClientPendingRequests) is the + * number struct radius_client_data::msgs for matching msg_type. + */ struct hostapd_radius_server { - /* MIB prefix for shared variables: - * @ = radiusAuth or radiusAcc depending on the type of the server */ - struct hostapd_ip_addr addr; /* @ServerAddress */ - int port; /* @ClientServerPortNumber */ + /** + * addr - radiusAuthServerAddress or radiusAccServerAddress + */ + struct hostapd_ip_addr addr; + + /** + * port - radiusAuthClientServerPortNumber or radiusAccClientServerPortNumber + */ + int port; + + /** + * shared_secret - Shared secret for authenticating RADIUS messages + */ u8 *shared_secret; + + /** + * shared_secret_len - Length of shared_secret in octets + */ size_t shared_secret_len; /* Dynamic (not from configuration file) MIB data */ - int index; /* @ServerIndex */ - int round_trip_time; /* @ClientRoundTripTime; in hundredths of a - * second */ - u32 requests; /* @Client{Access,}Requests */ - u32 retransmissions; /* @Client{Access,}Retransmissions */ - u32 access_accepts; /* radiusAuthClientAccessAccepts */ - u32 access_rejects; /* radiusAuthClientAccessRejects */ - u32 access_challenges; /* radiusAuthClientAccessChallenges */ - u32 responses; /* radiusAccClientResponses */ - u32 malformed_responses; /* @ClientMalformed{Access,}Responses */ - u32 bad_authenticators; /* @ClientBadAuthenticators */ - u32 timeouts; /* @ClientTimeouts */ - u32 unknown_types; /* @ClientUnknownTypes */ - u32 packets_dropped; /* @ClientPacketsDropped */ - /* @ClientPendingRequests: length of hapd->radius->msgs for matching - * msg_type */ + + /** + * index - radiusAuthServerIndex or radiusAccServerIndex + */ + int index; + + /** + * round_trip_time - radiusAuthClientRoundTripTime or radiusAccClientRoundTripTime + * Round-trip time in hundredths of a second. + */ + int round_trip_time; + + /** + * requests - radiusAuthClientAccessRequests or radiusAccClientRequests + */ + u32 requests; + + /** + * retransmissions - radiusAuthClientAccessRetransmissions or radiusAccClientRetransmissions + */ + u32 retransmissions; + + /** + * access_accepts - radiusAuthClientAccessAccepts + */ + u32 access_accepts; + + /** + * access_rejects - radiusAuthClientAccessRejects + */ + u32 access_rejects; + + /** + * access_challenges - radiusAuthClientAccessChallenges + */ + u32 access_challenges; + + /** + * responses - radiusAccClientResponses + */ + u32 responses; + + /** + * malformed_responses - radiusAuthClientMalformedAccessResponses or radiusAccClientMalformedResponses + */ + u32 malformed_responses; + + /** + * bad_authenticators - radiusAuthClientBadAuthenticators or radiusAccClientBadAuthenticators + */ + u32 bad_authenticators; + + /** + * timeouts - radiusAuthClientTimeouts or radiusAccClientTimeouts + */ + u32 timeouts; + + /** + * unknown_types - radiusAuthClientUnknownTypes or radiusAccClientUnknownTypes + */ + u32 unknown_types; + + /** + * packets_dropped - radiusAuthClientPacketsDropped or radiusAccClientPacketsDropped + */ + u32 packets_dropped; }; +/** + * struct hostapd_radius_servers - RADIUS servers for RADIUS client + */ struct hostapd_radius_servers { - /* RADIUS Authentication and Accounting servers in priority order */ - struct hostapd_radius_server *auth_servers, *auth_server; + /** + * auth_servers - RADIUS Authentication servers in priority order + */ + struct hostapd_radius_server *auth_servers; + + /** + * num_auth_servers - Number of auth_servers entries + */ int num_auth_servers; - struct hostapd_radius_server *acct_servers, *acct_server; + + /** + * auth_server - The current Authentication server + */ + struct hostapd_radius_server *auth_server; + + /** + * acct_servers - RADIUS Accounting servers in priority order + */ + struct hostapd_radius_server *acct_servers; + + /** + * num_acct_servers - Number of acct_servers entries + */ int num_acct_servers; - int retry_primary_interval; - int acct_interim_interval; + /** + * acct_server - The current Accounting server + */ + struct hostapd_radius_server *acct_server; + /** + * retry_primary_interval - Retry interval for trying primary server + * + * This specifies a retry interval in sexconds for trying to return to + * the primary RADIUS server. 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 (non-zero), the primary server + * will be retried after the specified number of seconds has passed + * even if the current used secondary server is still working. + */ + int retry_primary_interval; + + /** + * msg_dumps - Whether RADIUS message details are shown in stdout + */ int msg_dumps; + /** + * client_addr - Client (local) address to use if force_client_addr + */ struct hostapd_ip_addr client_addr; + + /** + * force_client_addr - Whether to force client (local) address + */ int force_client_addr; }; +/** + * RadiusType - RADIUS server type for RADIUS client + */ typedef enum { + /** + * RADIUS authentication + */ RADIUS_AUTH, + + /** + * RADIUS_ACCT - RADIUS accounting + */ RADIUS_ACCT, - RADIUS_ACCT_INTERIM /* used only with radius_client_send(); just like - * RADIUS_ACCT, but removes any pending interim - * RADIUS Accounting packages for the same STA - * before sending the new interim update */ + + /** + * RADIUS_ACCT_INTERIM - RADIUS interim accounting message + * + * Used only with radius_client_send(). This behaves just like + * RADIUS_ACCT, but removes any pending interim RADIUS Accounting + * messages for the same STA before sending the new interim update. + */ + RADIUS_ACCT_INTERIM } RadiusType; +/** + * RadiusRxResult - RADIUS client RX handler result + */ typedef enum { + /** + * RADIUS_RX_PROCESSED - Message processed + * + * This stops handler calls and frees the message. + */ RADIUS_RX_PROCESSED, + + /** + * RADIUS_RX_QUEUED - Message has been queued + * + * This stops handler calls, but does not free the message; the handler + * that returned this is responsible for eventually freeing the + * message. + */ RADIUS_RX_QUEUED, + + /** + * RADIUS_RX_UNKNOWN - Message is not for this handler + */ RADIUS_RX_UNKNOWN, + + /** + * RADIUS_RX_INVALID_AUTHENTICATOR - Message has invalid Authenticator + */ RADIUS_RX_INVALID_AUTHENTICATOR } RadiusRxResult; @@ -92,17 +251,13 @@ int radius_client_send(struct radius_client_data *radius, struct radius_msg *msg, RadiusType msg_type, const u8 *addr); u8 radius_client_get_id(struct radius_client_data *radius); - void radius_client_flush(struct radius_client_data *radius, int only_auth); struct radius_client_data * radius_client_init(void *ctx, struct hostapd_radius_servers *conf); void radius_client_deinit(struct radius_client_data *radius); -void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr); +void radius_client_flush_auth(struct radius_client_data *radius, + const u8 *addr); int radius_client_get_mib(struct radius_client_data *radius, char *buf, size_t buflen); -struct radius_client_data * -radius_client_reconfig(struct radius_client_data *old, void *ctx, - struct hostapd_radius_servers *oldconf, - struct hostapd_radius_servers *newconf); #endif /* RADIUS_CLIENT_H */ diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index 4f399bcfd18d..f8780a692947 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -1,6 +1,6 @@ /* - * hostapd / RADIUS authentication server - * Copyright (c) 2005-2008, Jouni Malinen + * RADIUS authentication server + * Copyright (c) 2005-2009, Jouni Malinen * * 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 @@ -18,12 +18,22 @@ #include "common.h" #include "radius.h" #include "eloop.h" -#include "defs.h" #include "eap_server/eap.h" #include "radius_server.h" +/** + * RADIUS_SESSION_TIMEOUT - Session timeout in seconds + */ #define RADIUS_SESSION_TIMEOUT 60 + +/** + * RADIUS_MAX_SESSION - Maximum number of active sessions + */ #define RADIUS_MAX_SESSION 100 + +/** + * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages + */ #define RADIUS_MAX_MSG_LEN 3000 static struct eapol_callbacks radius_server_eapol_cb; @@ -31,6 +41,9 @@ static struct eapol_callbacks radius_server_eapol_cb; struct radius_client; struct radius_server_data; +/** + * struct radius_server_counters - RADIUS server statistics counters + */ struct radius_server_counters { u32 access_requests; u32 invalid_requests; @@ -44,6 +57,9 @@ struct radius_server_counters { u32 unknown_types; }; +/** + * struct radius_session - Internal RADIUS server data for a session + */ struct radius_session { struct radius_session *next; struct radius_client *client; @@ -62,6 +78,9 @@ struct radius_session { u8 last_authenticator[16]; }; +/** + * struct radius_client - Internal RADIUS server data for a client + */ struct radius_client { struct radius_client *next; struct in_addr addr; @@ -76,31 +95,196 @@ struct radius_client { struct radius_server_counters counters; }; +/** + * struct radius_server_data - Internal RADIUS server data + */ struct radius_server_data { + /** + * auth_sock - Socket for RADIUS authentication messages + */ int auth_sock; + + /** + * clients - List of authorized RADIUS clients + */ struct radius_client *clients; + + /** + * next_sess_id - Next session identifier + */ unsigned int next_sess_id; + + /** + * conf_ctx - Context pointer for callbacks + * + * This is used as the ctx argument in get_eap_user() calls. + */ void *conf_ctx; + + /** + * num_sess - Number of active sessions + */ int num_sess; + + /** + * eap_sim_db_priv - EAP-SIM/AKA database context + * + * This is passed to the EAP-SIM/AKA server implementation as a + * callback context. + */ void *eap_sim_db_priv; + + /** + * ssl_ctx - TLS context + * + * This is passed to the EAP server implementation as a callback + * context for TLS operations. + */ void *ssl_ctx; + + /** + * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST + * + * This parameter is used to set a key for EAP-FAST to encrypt the + * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If + * set, must point to a 16-octet key. + */ u8 *pac_opaque_encr_key; + + /** + * eap_fast_a_id - EAP-FAST authority identity (A-ID) + * + * If EAP-FAST is not used, this can be set to %NULL. In theory, this + * is a variable length field, but due to some existing implementations + * requiring A-ID to be 16 octets in length, it is recommended to use + * that length for the field to provide interoperability with deployed + * peer implementations. + */ u8 *eap_fast_a_id; + + /** + * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets + */ size_t eap_fast_a_id_len; + + /** + * eap_fast_a_id_info - EAP-FAST authority identifier information + * + * This A-ID-Info contains a user-friendly name for the A-ID. For + * example, this could be the enterprise and server names in + * human-readable format. This field is encoded as UTF-8. If EAP-FAST + * is not used, this can be set to %NULL. + */ char *eap_fast_a_id_info; + + /** + * eap_fast_prov - EAP-FAST provisioning modes + * + * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, + * 2 = only authenticated provisioning allowed, 3 = both provisioning + * modes allowed. + */ int eap_fast_prov; + + /** + * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds + * + * This is the hard limit on how long a provisioned PAC-Key can be + * used. + */ int pac_key_lifetime; + + /** + * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds + * + * This is a soft limit on the PAC-Key. The server will automatically + * generate a new PAC-Key when this number of seconds (or fewer) of the + * lifetime remains. + */ int pac_key_refresh_time; + + /** + * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication + * + * This controls whether the protected success/failure indication + * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. + */ int eap_sim_aka_result_ind; + + /** + * tnc - Trusted Network Connect (TNC) + * + * This controls whether TNC is enabled and 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. + */ int tnc; + + /** + * wps - Wi-Fi Protected Setup context + * + * If WPS is used with an external RADIUS server (which is quite + * unlikely configuration), this is used to provide a pointer to WPS + * context data. Normally, this can be set to %NULL. + */ struct wps_context *wps; + + /** + * ipv6 - Whether to enable IPv6 support in the RADIUS server + */ int ipv6; + + /** + * start_time - Timestamp of server start + */ struct os_time start_time; + + /** + * counters - Statistics counters for server operations + * + * These counters are the sum over all clients. + */ struct radius_server_counters counters; + + /** + * get_eap_user - Callback for fetching EAP user information + * @ctx: Context data from conf_ctx + * @identity: User identity + * @identity_len: identity buffer length in octets + * @phase2: Whether this is for Phase 2 identity + * @user: Data structure for filling in the user information + * Returns: 0 on success, -1 on failure + * + * This is used to fetch information from user database. The callback + * will fill in information about allowed EAP methods and the user + * password. The password field will be an allocated copy of the + * password data and RADIUS server will free it after use. + */ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user); + + /** + * eap_req_id_text - Optional data for EAP-Request/Identity + * + * This can be used to configure an optional, displayable message that + * will be sent in EAP-Request/Identity. This string can contain an + * ASCII-0 character (nul) to separate network infromation per RFC + * 4284. The actual string length is explicit provided in + * eap_req_id_text_len since nul character will not be used as a string + * terminator. + */ char *eap_req_id_text; + + /** + * eap_req_id_text_len - Length of eap_req_id_text buffer in octets + */ size_t eap_req_id_text_len; + + /* + * msg_ctx - Context data for wpa_msg() calls + */ + void *msg_ctx; }; @@ -182,15 +366,9 @@ static void radius_server_session_free(struct radius_server_data *data, eloop_cancel_timeout(radius_server_session_timeout, data, sess); eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); eap_server_sm_deinit(sess->eap); - if (sess->last_msg) { - radius_msg_free(sess->last_msg); - os_free(sess->last_msg); - } + radius_msg_free(sess->last_msg); os_free(sess->last_from_addr); - if (sess->last_reply) { - radius_msg_free(sess->last_reply); - os_free(sess->last_reply); - } + radius_msg_free(sess->last_reply); os_free(sess); data->num_sess--; } @@ -313,6 +491,7 @@ radius_server_get_new_session(struct radius_server_data *data, os_memset(&eap_conf, 0, sizeof(eap_conf)); eap_conf.ssl_ctx = data->ssl_ctx; + eap_conf.msg_ctx = data->msg_ctx; eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; eap_conf.backend_auth = TRUE; eap_conf.eap_server = 1; @@ -353,6 +532,7 @@ radius_server_encapsulate_eap(struct radius_server_data *data, struct radius_msg *msg; int code; unsigned int sess_id; + struct radius_hdr *hdr = radius_msg_get_hdr(request); if (sess->eap_if->eapFail) { sess->eap_if->eapFail = FALSE; @@ -365,7 +545,7 @@ radius_server_encapsulate_eap(struct radius_server_data *data, code = RADIUS_CODE_ACCESS_CHALLENGE; } - msg = radius_msg_new(code, request->hdr->identifier); + msg = radius_msg_new(code, hdr->identifier); if (msg == NULL) { RADIUS_DEBUG("Failed to allocate reply message"); return NULL; @@ -391,7 +571,7 @@ radius_server_encapsulate_eap(struct radius_server_data *data, } else { len = sess->eap_if->eapKeyDataLen / 2; } - if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator, + if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, (u8 *) client->shared_secret, client->shared_secret_len, sess->eap_if->eapKeyData + len, @@ -404,13 +584,12 @@ radius_server_encapsulate_eap(struct radius_server_data *data, if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); radius_msg_free(msg); - os_free(msg); return NULL; } if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, - request->hdr->authenticator) < 0) { + hdr->authenticator) < 0) { RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); } @@ -427,12 +606,13 @@ static int radius_server_reject(struct radius_server_data *data, struct radius_msg *msg; int ret = 0; struct eap_hdr eapfail; + struct wpabuf *buf; + struct radius_hdr *hdr = radius_msg_get_hdr(request); RADIUS_DEBUG("Reject invalid request from %s:%d", from_addr, from_port); - msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, - request->hdr->identifier); + msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); if (msg == NULL) { return -1; } @@ -449,13 +629,13 @@ static int radius_server_reject(struct radius_server_data *data, if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); radius_msg_free(msg); - os_free(msg); return -1; } if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, - request->hdr->authenticator) < 0) { + hdr->authenticator) < + 0) { RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); } @@ -465,14 +645,14 @@ static int radius_server_reject(struct radius_server_data *data, data->counters.access_rejects++; client->counters.access_rejects++; - if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0, + buf = radius_msg_get_buf(msg); + if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, (struct sockaddr *) from, sizeof(*from)) < 0) { perror("sendto[RADIUS SRV]"); ret = -1; } radius_msg_free(msg); - os_free(msg); return ret; } @@ -526,16 +706,18 @@ static int radius_server_request(struct radius_server_data *data, } if (sess->last_from_port == from_port && - sess->last_identifier == msg->hdr->identifier && - os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) == - 0) { + sess->last_identifier == radius_msg_get_hdr(msg)->identifier && + os_memcmp(sess->last_authenticator, + radius_msg_get_hdr(msg)->authenticator, 16) == 0) { RADIUS_DEBUG("Duplicate message from %s", from_addr); data->counters.dup_access_requests++; client->counters.dup_access_requests++; if (sess->last_reply) { - res = sendto(data->auth_sock, sess->last_reply->buf, - sess->last_reply->buf_used, 0, + struct wpabuf *buf; + buf = radius_msg_get_buf(sess->last_reply); + res = sendto(data->auth_sock, wpabuf_head(buf), + wpabuf_len(buf), 0, (struct sockaddr *) from, fromlen); if (res < 0) { perror("sendto[RADIUS SRV]"); @@ -583,10 +765,7 @@ static int radius_server_request(struct radius_server_data *data, RADIUS_DEBUG("No EAP data from the state machine, but eapFail " "set"); } else if (eap_sm_method_pending(sess->eap)) { - if (sess->last_msg) { - radius_msg_free(sess->last_msg); - os_free(sess->last_msg); - } + radius_msg_free(sess->last_msg); sess->last_msg = msg; sess->last_from_port = from_port; os_free(sess->last_from_addr); @@ -609,12 +788,15 @@ static int radius_server_request(struct radius_server_data *data, reply = radius_server_encapsulate_eap(data, client, sess, msg); if (reply) { + struct wpabuf *buf; + struct radius_hdr *hdr; + RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(reply); } - switch (reply->hdr->code) { + switch (radius_msg_get_hdr(reply)->code) { case RADIUS_CODE_ACCESS_ACCEPT: data->counters.access_accepts++; client->counters.access_accepts++; @@ -628,20 +810,19 @@ static int radius_server_request(struct radius_server_data *data, client->counters.access_challenges++; break; } - res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0, + buf = radius_msg_get_buf(reply); + res = sendto(data->auth_sock, wpabuf_head(buf), + wpabuf_len(buf), 0, (struct sockaddr *) from, fromlen); if (res < 0) { perror("sendto[RADIUS SRV]"); } - if (sess->last_reply) { - radius_msg_free(sess->last_reply); - os_free(sess->last_reply); - } + radius_msg_free(sess->last_reply); sess->last_reply = reply; sess->last_from_port = from_port; - sess->last_identifier = msg->hdr->identifier; - os_memcpy(sess->last_authenticator, msg->hdr->authenticator, - 16); + hdr = radius_msg_get_hdr(msg); + sess->last_identifier = hdr->identifier; + os_memcpy(sess->last_authenticator, hdr->authenticator, 16); } else { data->counters.packets_dropped++; client->counters.packets_dropped++; @@ -740,8 +921,9 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx, radius_msg_dump(msg); } - if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) { - RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code); + if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { + RADIUS_DEBUG("Unexpected RADIUS code %d", + radius_msg_get_hdr(msg)->code); data->counters.unknown_types++; client->counters.unknown_types++; goto fail; @@ -764,10 +946,7 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx, return; /* msg was stored with the session */ fail: - if (msg) { - radius_msg_free(msg); - os_free(msg); - } + radius_msg_free(msg); os_free(buf); } @@ -1026,6 +1205,15 @@ radius_server_read_clients(const char *client_file, int ipv6) } +/** + * radius_server_init - Initialize RADIUS server + * @conf: Configuration for the RADIUS server + * Returns: Pointer to private RADIUS server context or %NULL on failure + * + * This initializes a RADIUS server instance and returns a context pointer that + * will be used in other calls to the RADIUS server module. The server can be + * deinitialize by calling radius_server_deinit(). + */ struct radius_server_data * radius_server_init(struct radius_server_conf *conf) { @@ -1047,6 +1235,7 @@ radius_server_init(struct radius_server_conf *conf) data->conf_ctx = conf->conf_ctx; data->eap_sim_db_priv = conf->eap_sim_db_priv; data->ssl_ctx = conf->ssl_ctx; + data->msg_ctx = conf->msg_ctx; data->ipv6 = conf->ipv6; if (conf->pac_opaque_encr_key) { data->pac_opaque_encr_key = os_malloc(16); @@ -1110,6 +1299,10 @@ radius_server_init(struct radius_server_conf *conf) } +/** + * radius_server_deinit - Deinitialize RADIUS server + * @data: RADIUS server context from radius_server_init() + */ void radius_server_deinit(struct radius_server_data *data) { if (data == NULL) @@ -1130,6 +1323,13 @@ void radius_server_deinit(struct radius_server_data *data) } +/** + * radius_server_get_mib - Get RADIUS server MIB information + * @data: RADIUS server context from radius_server_init() + * @buf: Buffer for returning the MIB data in text format + * @buflen: buf length in octets + * Returns: Number of octets written into buf + */ int radius_server_get_mib(struct radius_server_data *data, char *buf, size_t buflen) { @@ -1269,6 +1469,14 @@ static struct eapol_callbacks radius_server_eapol_cb = }; +/** + * radius_server_eap_pending_cb - Pending EAP data notification + * @data: RADIUS server context from radius_server_init() + * @ctx: Pending EAP context pointer + * + * This function is used to notify EAP server module that a pending operation + * has been completed and processing of the EAP session can proceed. + */ void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) { struct radius_client *cli; @@ -1307,5 +1515,4 @@ void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) return; /* msg was stored with the session */ radius_msg_free(msg); - os_free(msg); } diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h index d5fb6a1e3fee..f9c951d05f24 100644 --- a/src/radius/radius_server.h +++ b/src/radius/radius_server.h @@ -1,6 +1,6 @@ /* - * hostapd / RADIUS authentication server - * Copyright (c) 2005-2007, Jouni Malinen + * RADIUS authentication server + * Copyright (c) 2005-2009, Jouni Malinen * * 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 @@ -18,32 +18,185 @@ struct radius_server_data; struct eap_user; +/** + * struct radius_server_conf - RADIUS server configuration + */ struct radius_server_conf { + /** + * auth_port - UDP port to listen to as an authentication server + */ int auth_port; + + /** + * client_file - RADIUS client configuration file + * + * This file contains the RADIUS clients and the shared secret to be + * used with them in a format where each client is on its own line. The + * first item on the line is the IPv4 or IPv6 address of the client + * with an optional address mask to allow full network to be specified + * (e.g., 192.168.1.2 or 192.168.1.0/24). This is followed by white + * space (space or tabulator) and the shared secret. Lines starting + * with '#' are skipped and can be used as comments. + */ char *client_file; + + /** + * conf_ctx - Context pointer for callbacks + * + * This is used as the ctx argument in get_eap_user() calls. + */ void *conf_ctx; + + /** + * eap_sim_db_priv - EAP-SIM/AKA database context + * + * This is passed to the EAP-SIM/AKA server implementation as a + * callback context. + */ void *eap_sim_db_priv; + + /** + * ssl_ctx - TLS context + * + * This is passed to the EAP server implementation as a callback + * context for TLS operations. + */ void *ssl_ctx; + + /** + * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST + * + * This parameter is used to set a key for EAP-FAST to encrypt the + * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If + * set, must point to a 16-octet key. + */ u8 *pac_opaque_encr_key; + + /** + * eap_fast_a_id - EAP-FAST authority identity (A-ID) + * + * If EAP-FAST is not used, this can be set to %NULL. In theory, this + * is a variable length field, but due to some existing implementations + * requiring A-ID to be 16 octets in length, it is recommended to use + * that length for the field to provide interoperability with deployed + * peer implementations. + */ u8 *eap_fast_a_id; + + /** + * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets + */ size_t eap_fast_a_id_len; + + /** + * eap_fast_a_id_info - EAP-FAST authority identifier information + * + * This A-ID-Info contains a user-friendly name for the A-ID. For + * example, this could be the enterprise and server names in + * human-readable format. This field is encoded as UTF-8. If EAP-FAST + * is not used, this can be set to %NULL. + */ char *eap_fast_a_id_info; + + /** + * eap_fast_prov - EAP-FAST provisioning modes + * + * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, + * 2 = only authenticated provisioning allowed, 3 = both provisioning + * modes allowed. + */ int eap_fast_prov; + + /** + * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds + * + * This is the hard limit on how long a provisioned PAC-Key can be + * used. + */ int pac_key_lifetime; + + /** + * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds + * + * This is a soft limit on the PAC-Key. The server will automatically + * generate a new PAC-Key when this number of seconds (or fewer) of the + * lifetime remains. + */ int pac_key_refresh_time; + + /** + * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication + * + * This controls whether the protected success/failure indication + * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. + */ int eap_sim_aka_result_ind; + + /** + * tnc - Trusted Network Connect (TNC) + * + * This controls whether TNC is enabled and 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. + */ int tnc; + + /** + * wps - Wi-Fi Protected Setup context + * + * If WPS is used with an external RADIUS server (which is quite + * unlikely configuration), this is used to provide a pointer to WPS + * context data. Normally, this can be set to %NULL. + */ struct wps_context *wps; + + /** + * ipv6 - Whether to enable IPv6 support in the RADIUS server + */ int ipv6; + + /** + * get_eap_user - Callback for fetching EAP user information + * @ctx: Context data from conf_ctx + * @identity: User identity + * @identity_len: identity buffer length in octets + * @phase2: Whether this is for Phase 2 identity + * @user: Data structure for filling in the user information + * Returns: 0 on success, -1 on failure + * + * This is used to fetch information from user database. The callback + * will fill in information about allowed EAP methods and the user + * password. The password field will be an allocated copy of the + * password data and RADIUS server will free it after use. + */ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user); + + /** + * eap_req_id_text - Optional data for EAP-Request/Identity + * + * This can be used to configure an optional, displayable message that + * will be sent in EAP-Request/Identity. This string can contain an + * ASCII-0 character (nul) to separate network infromation per RFC + * 4284. The actual string length is explicit provided in + * eap_req_id_text_len since nul character will not be used as a string + * terminator. + */ const char *eap_req_id_text; + + /** + * eap_req_id_text_len - Length of eap_req_id_text buffer in octets + */ size_t eap_req_id_text_len; + + /* + * msg_ctx - Context data for wpa_msg() calls + */ + void *msg_ctx; }; -#ifdef RADIUS_SERVER - struct radius_server_data * radius_server_init(struct radius_server_conf *conf); @@ -54,29 +207,4 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx); -#else /* RADIUS_SERVER */ - -static inline struct radius_server_data * -radius_server_init(struct radius_server_conf *conf) -{ - return NULL; -} - -static inline void radius_server_deinit(struct radius_server_data *data) -{ -} - -static inline int radius_server_get_mib(struct radius_server_data *data, - char *buf, size_t buflen) -{ - return 0; -} - -static inline void -radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) -{ -} - -#endif /* RADIUS_SERVER */ - #endif /* RADIUS_SERVER_H */ diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/rsn_supp/Makefile +++ b/src/rsn_supp/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c index 45c256a0277f..9d60d4acedf5 100644 --- a/src/rsn_supp/peerkey.c +++ b/src/rsn_supp/peerkey.c @@ -17,13 +17,13 @@ #ifdef CONFIG_PEERKEY #include "common.h" -#include "sha1.h" -#include "sha256.h" #include "eloop.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "common/ieee802_11_defs.h" #include "wpa.h" #include "wpa_i.h" #include "wpa_ie.h" -#include "ieee802_11_defs.h" #include "peerkey.h" @@ -255,7 +255,7 @@ static int wpa_supplicant_process_smk_m2( #endif /* CONFIG_IEEE80211W */ if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for PNonce"); wpa_supplicant_peerkey_free(sm, peerkey); return -1; @@ -371,7 +371,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm, peerkey->smkid, PMKID_LEN); if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "RSN: Failed to get random data for INonce (STK)"); os_free(mbuf); return; @@ -634,9 +634,11 @@ static int wpa_supplicant_process_smk_error( if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN) os_memcpy(peer, kde.mac_addr, ETH_ALEN); + else + os_memset(peer, 0, ETH_ALEN); os_memcpy(&error, kde.error, sizeof(error)); error_type = be_to_host16(error.error_type); - wpa_msg(sm->ctx->ctx, MSG_INFO, + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: SMK Error KDE received: MUI %d error_type %d peer " MACSTR, be_to_host16(error.mui), error_type, @@ -696,7 +698,7 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, } if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "RSN: Failed to get random data for PNonce"); return; } @@ -1096,7 +1098,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for INonce"); os_free(rbuf); wpa_supplicant_peerkey_free(sm, peerkey); diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index f8373de6dd3d..cac8c83e6eeb 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -15,12 +15,10 @@ #include "includes.h" #include "common.h" -#include "wpa.h" #include "eloop.h" -#include "sha1.h" -#include "sha256.h" -#include "wpa_i.h" #include "eapol_supp/eapol_supp_sm.h" +#include "wpa.h" +#include "wpa_i.h" #include "pmksa_cache.h" #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) @@ -38,39 +36,6 @@ struct rsn_pmksa_cache { }; -/** - * rsn_pmkid - Calculate PMK identifier - * @pmk: Pairwise master key - * @pmk_len: Length of pmk in bytes - * @aa: Authenticator address - * @spa: Supplicant address - * @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) - */ -static 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); @@ -167,7 +132,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, struct rsn_pmksa_cache_entry *entry, *pos, *prev; struct os_time now; - if (pmksa->sm->proto != WPA_PROTO_RSN || pmk_len > PMK_LEN) + if (pmk_len > PMK_LEN) return NULL; entry = os_zalloc(sizeof(*entry)); @@ -439,7 +404,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, /** * pmksa_cache_list - Dump text list of entries in PMKSA cache - * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @buf: Buffer for the list * @len: Length of the buffer * Returns: number of bytes written to buffer @@ -447,7 +412,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, * This function is used to generate a text format representation of the * current PMKSA cache contents for the ctrl_iface PMKSA command. */ -int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) +int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) { int i, ret; char *pos = buf; @@ -462,7 +427,7 @@ int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) return pos - buf; pos += ret; i = 0; - entry = sm->pmksa->pmksa; + entry = pmksa->pmksa; while (entry) { i++; ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index a329b25b08fd..a1447e526d5b 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -53,7 +53,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid); -int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len); +int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); 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, void *network_ctx, int akmp); @@ -93,7 +93,8 @@ pmksa_cache_get_current(struct wpa_sm *sm) return NULL; } -static inline int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) +static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, + size_t len) { return -1; } diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c index b00c004cf62c..6109f5e9f873 100644 --- a/src/rsn_supp/preauth.c +++ b/src/rsn_supp/preauth.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant - RSN pre-authentication - * Copyright (c) 2003-2008, Jouni Malinen + * RSN pre-authentication (supplicant) + * Copyright (c) 2003-2010, Jouni Malinen * * 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 @@ -16,14 +16,13 @@ #include "common.h" #include "wpa.h" -#include "drivers/driver.h" #include "eloop.h" #include "l2_packet/l2_packet.h" #include "eapol_supp/eapol_supp_sm.h" #include "preauth.h" #include "pmksa_cache.h" #include "wpa_i.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) @@ -32,7 +31,7 @@ struct rsn_pmksa_candidate { - struct rsn_pmksa_candidate *next; + struct dl_list list; u8 bssid[ETH_ALEN]; int priority; }; @@ -44,17 +43,15 @@ struct rsn_pmksa_candidate { */ void pmksa_candidate_free(struct wpa_sm *sm) { - struct rsn_pmksa_candidate *entry, *prev; + struct rsn_pmksa_candidate *entry, *n; if (sm == NULL) return; - entry = sm->pmksa_candidates; - sm->pmksa_candidates = NULL; - while (entry) { - prev = entry; - entry = entry->next; - os_free(prev); + dl_list_for_each_safe(entry, n, &sm->pmksa_candidates, + struct rsn_pmksa_candidate, list) { + dl_list_del(&entry->list); + os_free(entry); } } @@ -107,15 +104,15 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success, sm->network_ctx, WPA_KEY_MGMT_IEEE8021X); } else { - wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: failed to get " - "master session key from pre-auth EAPOL state " - "machines"); + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: failed to get master session key from " + "pre-auth EAPOL state machines"); success = 0; } } - wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: pre-authentication with " MACSTR - " %s", MAC2STR(sm->preauth_bssid), + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " + MACSTR " %s", MAC2STR(sm->preauth_bssid), success ? "completed successfully" : "failed"); rsn_preauth_deinit(sm); @@ -127,8 +124,8 @@ static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_sm *sm = eloop_ctx; - wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: pre-authentication with " MACSTR - " timed out", MAC2STR(sm->preauth_bssid)); + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " + MACSTR " timed out", MAC2STR(sm->preauth_bssid)); rsn_preauth_deinit(sm); rsn_preauth_candidate_process(sm); } @@ -183,8 +180,8 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, if (sm->preauth_eapol) return -1; - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: starting pre-authentication " - "with " MACSTR, MAC2STR(dst)); + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst)); sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr, ETH_P_RSN_PREAUTH, @@ -293,42 +290,42 @@ void rsn_preauth_deinit(struct wpa_sm *sm) */ void rsn_preauth_candidate_process(struct wpa_sm *sm) { - struct rsn_pmksa_candidate *candidate; + struct rsn_pmksa_candidate *candidate, *n; - if (sm->pmksa_candidates == NULL) + if (dl_list_empty(&sm->pmksa_candidates)) return; /* TODO: drop priority for old candidate entries */ - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: processing PMKSA candidate " + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate " "list"); if (sm->preauth_eapol || sm->proto != WPA_PROTO_RSN || wpa_sm_get_state(sm) != WPA_COMPLETED || (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) { - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: not in suitable state " - "for new pre-authentication"); + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable " + "state for new pre-authentication"); return; /* invalid state for new pre-auth */ } - while (sm->pmksa_candidates) { + dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, + struct rsn_pmksa_candidate, list) { struct rsn_pmksa_cache_entry *p = NULL; - candidate = sm->pmksa_candidates; p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL); if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && (p == NULL || p->opportunistic)) { - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA " + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " "candidate " MACSTR " selected for pre-authentication", MAC2STR(candidate->bssid)); - sm->pmksa_candidates = candidate->next; + dl_list_del(&candidate->list); rsn_preauth_init(sm, candidate->bssid, sm->eap_conf_ctx); os_free(candidate); return; } - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA candidate " + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate " MACSTR " does not need pre-authentication anymore", MAC2STR(candidate->bssid)); /* Some drivers (e.g., NDIS) expect to get notified about the @@ -337,10 +334,10 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid); } - sm->pmksa_candidates = candidate->next; + dl_list_del(&candidate->list); os_free(candidate); } - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: no more pending PMKSA " + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA " "candidates"); } @@ -359,7 +356,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, int prio, int preauth) { - struct rsn_pmksa_candidate *cand, *prev, *pos; + struct rsn_pmksa_candidate *cand, *pos; if (sm->network_ctx && sm->proactive_key_caching) pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx, @@ -373,21 +370,17 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, /* If BSSID already on candidate list, update the priority of the old * entry. Do not override priority based on normal scan results. */ - prev = NULL; - cand = sm->pmksa_candidates; - while (cand) { - if (os_memcmp(cand->bssid, bssid, ETH_ALEN) == 0) { - if (prev) - prev->next = cand->next; - else - sm->pmksa_candidates = cand->next; + cand = NULL; + dl_list_for_each(pos, &sm->pmksa_candidates, + struct rsn_pmksa_candidate, list) { + if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) { + cand = pos; break; } - prev = cand; - cand = cand->next; } if (cand) { + dl_list_del(&cand->list); if (prio < PMKID_CANDIDATE_PRIO_SCAN) cand->priority = prio; } else { @@ -400,21 +393,18 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, /* Add candidate to the list; order by increasing priority value. i.e., * highest priority (smallest value) first. */ - prev = NULL; - pos = sm->pmksa_candidates; - while (pos) { - if (cand->priority <= pos->priority) + dl_list_for_each(pos, &sm->pmksa_candidates, + struct rsn_pmksa_candidate, list) { + if (cand->priority <= pos->priority) { + dl_list_add(pos->list.prev, &cand->list); + cand = NULL; break; - prev = pos; - pos = pos->next; + } } - cand->next = pos; - if (prev) - prev->next = cand; - else - sm->pmksa_candidates = cand; + if (cand) + dl_list_add_tail(&sm->pmksa_candidates, &cand->list); - wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: added PMKSA cache " + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache " "candidate " MACSTR " prio %d", MAC2STR(bssid), prio); rsn_preauth_candidate_process(sm); } @@ -423,23 +413,18 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, /* TODO: schedule periodic scans if current AP supports preauth */ /** - * rsn_preauth_scan_results - Process scan results to find PMKSA candidates + * rsn_preauth_scan_results - Start processing scan results for canditates * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @results: Scan results + * Returns: 0 if ready to process results or -1 to skip processing * - * This functions goes through the scan results and adds all suitable APs - * (Authenticators) into PMKSA candidate list. + * This functions is used to notify RSN code about start of new scan results + * processing. The actual scan results will be provided by calling + * rsn_preauth_scan_result() for each BSS if this function returned 0. */ -void rsn_preauth_scan_results(struct wpa_sm *sm, - struct wpa_scan_results *results) +int rsn_preauth_scan_results(struct wpa_sm *sm) { - struct wpa_scan_res *r; - struct wpa_ie_data ie; - int i; - struct rsn_pmksa_cache_entry *pmksa; - if (sm->ssid_len == 0) - return; + return -1; /* * TODO: is it ok to free all candidates? What about the entries @@ -447,37 +432,41 @@ void rsn_preauth_scan_results(struct wpa_sm *sm, */ pmksa_candidate_free(sm); - for (i = results->num - 1; i >= 0; i--) { - const u8 *ssid, *rsn; + return 0; +} - r = results->res[i]; - ssid = wpa_scan_get_ie(r, WLAN_EID_SSID); - if (ssid == NULL || ssid[1] != sm->ssid_len || - os_memcmp(ssid + 2, sm->ssid, ssid[1]) != 0) - continue; +/** + * rsn_preauth_scan_result - Processing scan result for PMKSA canditates + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * + * Add all suitable APs (Authenticators) from scan results into PMKSA + * candidate list. + */ +void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, + const u8 *ssid, const u8 *rsn) +{ + struct wpa_ie_data ie; + struct rsn_pmksa_cache_entry *pmksa; - if (os_memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0) - continue; + if (ssid[1] != sm->ssid_len || + os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0) + return; /* Not for the current SSID */ - rsn = wpa_scan_get_ie(r, WLAN_EID_RSN); - if (rsn == NULL || wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) - continue; + if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0) + return; /* Ignore current AP */ - pmksa = pmksa_cache_get(sm->pmksa, r->bssid, NULL); - if (pmksa && - (!pmksa->opportunistic || - !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) - continue; + if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) + return; - /* - * Give less priority to candidates found from normal - * scan results. - */ - pmksa_candidate_add(sm, r->bssid, - PMKID_CANDIDATE_PRIO_SCAN, - ie.capabilities & WPA_CAPABILITY_PREAUTH); - } + pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL); + if (pmksa && (!pmksa->opportunistic || + !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) + return; + + /* Give less priority to candidates found from normal scan results. */ + pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN, + ie.capabilities & WPA_CAPABILITY_PREAUTH); } diff --git a/src/rsn_supp/preauth.h b/src/rsn_supp/preauth.h index b9ac57b531ba..f8240abef6df 100644 --- a/src/rsn_supp/preauth.h +++ b/src/rsn_supp/preauth.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - WPA2/RSN pre-authentication functions - * Copyright (c) 2003-2005, Jouni Malinen + * Copyright (c) 2003-2009, Jouni Malinen * * 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 @@ -23,8 +23,9 @@ void pmksa_candidate_free(struct wpa_sm *sm); int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, struct eap_peer_config *eap_conf); void rsn_preauth_deinit(struct wpa_sm *sm); -void rsn_preauth_scan_results(struct wpa_sm *sm, - struct wpa_scan_results *results); +int rsn_preauth_scan_results(struct wpa_sm *sm); +void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, + const u8 *ssid, const u8 *rsn); void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, int prio, int preauth); void rsn_preauth_candidate_process(struct wpa_sm *sm); @@ -51,8 +52,14 @@ static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, static inline void rsn_preauth_deinit(struct wpa_sm *sm) { } -static inline void rsn_preauth_scan_results(struct wpa_sm *sm, - struct wpa_scan_results *results) + +static inline int rsn_preauth_scan_results(struct wpa_sm *sm) +{ + return -1; +} + +static inline void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, + const u8 *ssid, const u8 *rsn) { } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index e611fc5e78a2..9439f97210b1 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - WPA state machine and EAPOL-Key processing - * Copyright (c) 2003-2008, Jouni Malinen + * Copyright (c) 2003-2010, Jouni Malinen * * 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 @@ -15,78 +15,17 @@ #include "includes.h" #include "common.h" -#include "rc4.h" -#include "aes_wrap.h" +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "common/ieee802_11_defs.h" +#include "eapol_supp/eapol_supp_sm.h" #include "wpa.h" #include "eloop.h" -#include "eapol_supp/eapol_supp_sm.h" #include "preauth.h" #include "pmksa_cache.h" #include "wpa_i.h" #include "wpa_ie.h" #include "peerkey.h" -#include "ieee802_11_defs.h" - - -/** - * wpa_cipher_txt - Convert cipher suite to a text string - * @cipher: Cipher suite (WPA_CIPHER_* enum) - * Returns: Pointer to a text string of the cipher suite name - */ -static const char * wpa_cipher_txt(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_NONE: - return "NONE"; - case WPA_CIPHER_WEP40: - return "WEP-40"; - case WPA_CIPHER_WEP104: - return "WEP-104"; - case WPA_CIPHER_TKIP: - return "TKIP"; - case WPA_CIPHER_CCMP: - return "CCMP"; - default: - return "UNKNOWN"; - } -} - - -/** - * wpa_key_mgmt_txt - Convert key management suite to a text string - * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) - * @proto: WPA/WPA2 version (WPA_PROTO_*) - * Returns: Pointer to a text string of the key management suite name - */ -static const char * wpa_key_mgmt_txt(int key_mgmt, int proto) -{ - switch (key_mgmt) { - case WPA_KEY_MGMT_IEEE8021X: - return proto == WPA_PROTO_RSN ? - "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; - case WPA_KEY_MGMT_PSK: - return proto == WPA_PROTO_RSN ? - "WPA2-PSK" : "WPA-PSK"; - case WPA_KEY_MGMT_NONE: - return "NONE"; - case WPA_KEY_MGMT_IEEE8021X_NO_WPA: - return "IEEE 802.1X (no WPA)"; -#ifdef CONFIG_IEEE80211R - case WPA_KEY_MGMT_FT_IEEE8021X: - return "FT-EAP"; - case WPA_KEY_MGMT_FT_PSK: - return "FT-PSK"; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - case WPA_KEY_MGMT_IEEE8021X_SHA256: - return "WPA2-EAP-SHA256"; - case WPA_KEY_MGMT_PSK_SHA256: - return "WPA2-PSK-SHA256"; -#endif /* CONFIG_IEEE80211W */ - default: - return "UNKNOWN"; - } -} /** @@ -119,11 +58,16 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, MAC2STR(dest)); } } - if (key_mic) - wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic); + if (key_mic && + wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) { + wpa_printf(MSG_ERROR, "WPA: Failed to generate EAPOL-Key " + "version %d MIC", ver); + goto out; + } wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); wpa_sm_ether_send(sm, dest, proto, msg, msg_len); eapol_sm_notify_tx_eapol_key(sm->eapol); +out: os_free(msg); } @@ -246,9 +190,11 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " "machines", sm->pmk, pmk_len); sm->pmk_len = pmk_len; - pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, src_addr, - sm->own_addr, sm->network_ctx, - sm->key_mgmt); + if (sm->proto == WPA_PROTO_RSN) { + pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, + src_addr, sm->own_addr, + sm->network_ctx, sm->key_mgmt); + } if (!sm->cur_pmksa && pmkid && pmksa_cache_get(sm->pmksa, src_addr, pmkid)) { wpa_printf(MSG_DEBUG, "RSN: the new PMK " @@ -256,10 +202,10 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, abort_cached = 0; } } else { - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get master session key from " "EAPOL state machines"); - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Key handshake aborted"); if (sm->cur_pmksa) { wpa_printf(MSG_DEBUG, "RSN: Cancelled PMKSA " @@ -285,6 +231,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, buf, buflen); os_free(buf); + return -2; } return -1; @@ -315,6 +262,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, size_t rlen; struct wpa_eapol_key *reply; u8 *rbuf; + u8 *rsn_ie_buf = NULL; if (wpa_ie == NULL) { wpa_printf(MSG_WARNING, "WPA: No wpa_ie set - cannot " @@ -322,13 +270,46 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, return -1; } +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->key_mgmt)) { + int res; + + /* + * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and + * FTIE from (Re)Association Response. + */ + rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN + + sm->assoc_resp_ies_len); + if (rsn_ie_buf == NULL) + return -1; + os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); + res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len, + sm->pmk_r1_name); + if (res < 0) { + os_free(rsn_ie_buf); + return -1; + } + wpa_ie_len += res; + + if (sm->assoc_resp_ies) { + os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies, + sm->assoc_resp_ies_len); + wpa_ie_len += sm->assoc_resp_ies_len; + } + + wpa_ie = rsn_ie_buf; + } +#endif /* CONFIG_IEEE80211R */ + wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*reply) + wpa_ie_len, &rlen, (void *) &reply); - if (rbuf == NULL) + if (rbuf == NULL) { + os_free(rsn_ie_buf); return -1; + } reply->type = sm->proto == WPA_PROTO_RSN ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; @@ -343,6 +324,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); os_memcpy(reply + 1, wpa_ie, wpa_ie_len); + os_free(rsn_ie_buf); os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); @@ -380,6 +362,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, struct wpa_eapol_ie_parse ie; struct wpa_ptk *ptk; u8 buf[8]; + int res; if (wpa_sm_get_network_ctx(sm) == NULL) { wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of " @@ -407,12 +390,18 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, } #endif /* CONFIG_NO_WPA2 */ - if (wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid)) + res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); + if (res == -2) { + wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - " + "requesting full EAP authentication"); + return; + } + if (res) goto failed; if (sm->renew_snonce) { if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for SNonce"); goto failed; } @@ -454,7 +443,8 @@ static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx) static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, const u8 *addr, int secure) { - wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Key negotiation completed with " + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Key negotiation completed with " MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr), wpa_cipher_txt(sm->pairwise_cipher), wpa_cipher_txt(sm->group_cipher)); @@ -487,7 +477,7 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->key_mgmt)) { /* Prepare for the next transition */ - wpa_ft_prepare_auth_request(sm); + wpa_ft_prepare_auth_request(sm, NULL); } #endif /* CONFIG_IEEE80211R */ } @@ -505,7 +495,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, const struct wpa_eapol_key *key) { int keylen, rsclen; - wpa_alg alg; + enum wpa_alg alg; const u8 *key_rsc; u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -559,7 +549,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, static int wpa_supplicant_check_group_cipher(int group_cipher, int keylen, int maxkeylen, - int *key_rsc_len, wpa_alg *alg) + int *key_rsc_len, + enum wpa_alg *alg) { int ret = 0; @@ -613,7 +604,7 @@ static int wpa_supplicant_check_group_cipher(int group_cipher, struct wpa_gtk_data { - wpa_alg alg; + enum wpa_alg alg; int tx, key_rsc_len, keyidx; u8 gtk[32]; int gtk_len; @@ -774,7 +765,7 @@ static void wpa_report_ie_mismatch(struct wpa_sm *sm, const u8 *wpa_ie, size_t wpa_ie_len, const u8 *rsn_ie, size_t rsn_ie_len) { - wpa_msg(sm->ctx->ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")", + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")", reason, MAC2STR(src_addr)); if (sm->ap_wpa_ie) { @@ -807,6 +798,135 @@ static void wpa_report_ie_mismatch(struct wpa_sm *sm, } +#ifdef CONFIG_IEEE80211R + +static int ft_validate_mdie(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_ie_parse *ie, + const u8 *assoc_resp_mdie) +{ + struct rsn_mdie *mdie; + + mdie = (struct rsn_mdie *) (ie->mdie + 2); + if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) || + os_memcmp(mdie->mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: MDIE in msg 3/4 did not " + "match with the current mobility domain"); + return -1; + } + + if (assoc_resp_mdie && + (assoc_resp_mdie[1] != ie->mdie[1] || + os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) { + wpa_printf(MSG_DEBUG, "FT: MDIE mismatch"); + wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4", + ie->mdie, 2 + ie->mdie[1]); + wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response", + assoc_resp_mdie, 2 + assoc_resp_mdie[1]); + return -1; + } + + return 0; +} + + +static int ft_validate_ftie(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_ie_parse *ie, + const u8 *assoc_resp_ftie) +{ + if (ie->ftie == NULL) { + wpa_printf(MSG_DEBUG, "FT: No FTIE in EAPOL-Key msg 3/4"); + return -1; + } + + if (assoc_resp_ftie == NULL) + return 0; + + if (assoc_resp_ftie[1] != ie->ftie[1] || + os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) { + wpa_printf(MSG_DEBUG, "FT: FTIE mismatch"); + wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4", + ie->ftie, 2 + ie->ftie[1]); + wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response", + assoc_resp_ftie, 2 + assoc_resp_ftie[1]); + return -1; + } + + return 0; +} + + +static int ft_validate_rsnie(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_ie_parse *ie) +{ + struct wpa_ie_data rsn; + + if (!ie->rsn_ie) + return 0; + + /* + * Verify that PMKR1Name from EAPOL-Key message 3/4 + * matches with the value we derived. + */ + if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 || + rsn.num_pmkid != 1 || rsn.pmkid == NULL) { + wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in " + "FT 4-way handshake message 3/4"); + return -1; + } + + if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: PMKR1Name mismatch in " + "FT 4-way handshake message 3/4"); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator", + rsn.pmkid, WPA_PMK_NAME_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); + return -1; + } + + return 0; +} + + +static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_ie_parse *ie) +{ + const u8 *pos, *end, *mdie = NULL, *ftie = NULL; + + if (sm->assoc_resp_ies) { + pos = sm->assoc_resp_ies; + end = pos + sm->assoc_resp_ies_len; + while (pos + 2 < end) { + if (pos + 2 + pos[1] > end) + break; + switch (*pos) { + case WLAN_EID_MOBILITY_DOMAIN: + mdie = pos; + break; + case WLAN_EID_FAST_BSS_TRANSITION: + ftie = pos; + break; + } + pos += 2 + pos[1]; + } + } + + if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 || + ft_validate_ftie(sm, src_addr, ie, ftie) < 0 || + ft_validate_rsnie(sm, src_addr, ie) < 0) + return -1; + + return 0; +} + +#endif /* CONFIG_IEEE80211R */ + + static int wpa_supplicant_validate_ie(struct wpa_sm *sm, const unsigned char *src_addr, struct wpa_eapol_ie_parse *ie) @@ -836,8 +956,9 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, (ie->wpa_ie_len != sm->ap_wpa_ie_len || os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) || (ie->rsn_ie && sm->ap_rsn_ie && - (ie->rsn_ie_len != sm->ap_rsn_ie_len || - os_memcmp(ie->rsn_ie, sm->ap_rsn_ie, ie->rsn_ie_len) != 0))) { + wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), + sm->ap_rsn_ie, sm->ap_rsn_ie_len, + ie->rsn_ie, ie->rsn_ie_len))) { wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " "with IE in Beacon/ProbeResp", src_addr, ie->wpa_ie, ie->wpa_ie_len, @@ -857,19 +978,9 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, } #ifdef CONFIG_IEEE80211R - if (wpa_key_mgmt_ft(sm->key_mgmt)) { - struct rsn_mdie *mdie; - /* TODO: verify that full MDIE matches with the one from scan - * results, not only mobility domain */ - mdie = (struct rsn_mdie *) (ie->mdie + 2); - if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, sm->mobility_domain, - MOBILITY_DOMAIN_ID_LEN) != 0) { - wpa_printf(MSG_DEBUG, "FT: MDIE in msg 3/4 did not " - "match with the current mobility domain"); - return -1; - } - } + if (wpa_key_mgmt_ft(sm->key_mgmt) && + wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0) + return -1; #endif /* CONFIG_IEEE80211R */ return 0; @@ -1128,7 +1239,10 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, return -1; } os_memcpy(gd->gtk, key + 1, keydatalen); - rc4_skip(ek, 32, 256, gd->gtk, keydatalen); + if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { + wpa_printf(MSG_ERROR, "WPA: RC4 failed"); + return -1; + } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { if (keydatalen % 8) { wpa_printf(MSG_WARNING, "WPA: Unsupported AES-WRAP " @@ -1233,7 +1347,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, goto failed; if (rekey) { - wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Group rekeying " + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " "completed with " MACSTR " [GTK=%s]", MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); wpa_sm_cancel_auth_timeout(sm); @@ -1319,7 +1433,10 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, u8 ek[32]; os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); - rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen); + if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { + wpa_printf(MSG_ERROR, "WPA: RC4 failed"); + return -1; + } } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { u8 *buf; @@ -1605,7 +1722,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, extra_len = data_len - sizeof(*hdr) - sizeof(*key); if (WPA_GET_BE16(key->key_data_length) > extra_len) { - wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " "frame - key_data overflow (%d > %lu)", WPA_GET_BE16(key->key_data_length), (unsigned long) extra_len); @@ -1855,6 +1972,7 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) sm = os_zalloc(sizeof(*sm)); if (sm == NULL) return NULL; + dl_list_init(&sm->pmksa_candidates); sm->renew_snonce = 1; sm->ctx = ctx; @@ -1890,6 +2008,9 @@ void wpa_sm_deinit(struct wpa_sm *sm) os_free(sm->ap_rsn_ie); os_free(sm->ctx); peerkey_deinit(sm); +#ifdef CONFIG_IEEE80211R + os_free(sm->assoc_resp_ies); +#endif /* CONFIG_IEEE80211R */ os_free(sm); } @@ -1919,10 +2040,15 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) #ifdef CONFIG_IEEE80211R if (wpa_ft_is_completed(sm)) { + /* + * Clear portValid to kick EAPOL state machine to re-enter + * AUTHENTICATED state to get the EAPOL port Authorized. + */ + eapol_sm_notify_portValid(sm->eapol, FALSE); wpa_supplicant_key_neg_complete(sm, sm->bssid, 1); /* Prepare for the next transition */ - wpa_ft_prepare_auth_request(sm); + wpa_ft_prepare_auth_request(sm, NULL); clear_ptk = 0; } @@ -2164,6 +2290,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_RSN_ENABLED: sm->rsn_enabled = value; break; + case WPA_PARAM_MFP: + sm->mfp = value; + break; default: break; } @@ -2406,3 +2535,32 @@ int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data) return -2; return 0; } + + +int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) +{ +#ifndef CONFIG_NO_WPA2 + return pmksa_cache_list(sm->pmksa, buf, len); +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + + +void wpa_sm_drop_sa(struct wpa_sm *sm) +{ + wpa_printf(MSG_DEBUG, "WPA: Clear old PMK and PTK"); + sm->ptk_set = 0; + sm->tptk_set = 0; + os_memset(sm->pmk, 0, sizeof(sm->pmk)); + os_memset(&sm->ptk, 0, sizeof(sm->ptk)); + os_memset(&sm->tptk, 0, sizeof(sm->tptk)); +} + + +int wpa_sm_has_ptk(struct wpa_sm *sm) +{ + if (sm == NULL) + return 0; + return sm->ptk_set; +} diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index bdf778544f41..f1a5554133ce 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -15,17 +15,9 @@ #ifndef WPA_H #define WPA_H -#include "defs.h" -#include "eapol_common.h" -#include "wpa_common.h" - -#ifndef ETH_P_EAPOL -#define ETH_P_EAPOL 0x888e -#endif - -#ifndef ETH_P_RSN_PREAUTH -#define ETH_P_RSN_PREAUTH 0x88c7 -#endif +#include "common/defs.h" +#include "common/eapol_common.h" +#include "common/wpa_common.h" struct wpa_sm; struct eapol_sm; @@ -33,12 +25,13 @@ struct wpa_config_blob; struct wpa_sm_ctx { void *ctx; /* pointer to arbitrary upper level context */ + void *msg_ctx; /* upper level context for wpa_msg() calls */ - void (*set_state)(void *ctx, wpa_states state); - wpa_states (*get_state)(void *ctx); + void (*set_state)(void *ctx, enum wpa_states state); + enum wpa_states (*get_state)(void *ctx); void (*deauthenticate)(void * ctx, int reason_code); void (*disassociate)(void *ctx, int reason_code); - int (*set_key)(void *ctx, wpa_alg alg, + int (*set_key)(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len); @@ -61,6 +54,7 @@ struct wpa_sm_ctx { size_t ies_len); int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap, const u8 *ies, size_t ies_len); + int (*mark_authenticated)(void *ctx, const u8 *target_ap); }; @@ -73,7 +67,8 @@ enum wpa_sm_conf_params { WPA_PARAM_GROUP, WPA_PARAM_KEY_MGMT, WPA_PARAM_MGMT_GROUP, - WPA_PARAM_RSN_ENABLED + WPA_PARAM_RSN_ENABLED, + WPA_PARAM_MFP }; struct rsn_supp_config { @@ -127,6 +122,9 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm); int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len); int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data); +int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len); +void wpa_sm_drop_sa(struct wpa_sm *sm); +int wpa_sm_has_ptk(struct wpa_sm *sm); #else /* CONFIG_NO_WPA */ @@ -258,6 +256,21 @@ static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, return -1; } +static inline int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, + size_t len) +{ + return -1; +} + +static inline void wpa_sm_drop_sa(struct wpa_sm *sm) +{ +} + +static inline int wpa_sm_has_ptk(struct wpa_sm *sm) +{ + return 0; +} + #endif /* CONFIG_NO_WPA */ #ifdef CONFIG_PEERKEY @@ -271,27 +284,27 @@ static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) #ifdef CONFIG_IEEE80211R -int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, - const u8 *r0kh_id, size_t r0kh_id_len, - const u8 *r1kh_id); -int wpa_ft_prepare_auth_request(struct wpa_sm *sm); +int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len); +int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie); int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, - int ft_action, const u8 *target_ap); + int ft_action, const u8 *target_ap, + const u8 *ric_ies, size_t ric_ies_len); int wpa_ft_is_completed(struct wpa_sm *sm); int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, const u8 *src_addr); -int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap); +int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, + const u8 *mdie); #else /* CONFIG_IEEE80211R */ static inline int -wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, - const u8 *r0kh_id, const u8 *r1kh_id) +wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) { return 0; } -static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm) +static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm, + const u8 *mdie) { return 0; } diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 557b3114d250..23063bc2d472 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -15,19 +15,44 @@ #include "includes.h" #include "common.h" +#include "crypto/aes_wrap.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "wpa.h" #include "wpa_i.h" #include "wpa_ie.h" -#include "aes_wrap.h" -#include "ieee802_11_defs.h" #ifdef CONFIG_IEEE80211R +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; + const u8 *tie; + size_t tie_len; + const u8 *igtk; + size_t igtk_len; + const u8 *ric; + size_t ric_len; +}; + +static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, + struct wpa_ft_ies *parse); + + int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk, size_t ptk_len) { - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; u8 ptk_name[WPA_PMK_NAME_LEN]; const u8 *anonce = key->key_nonce; @@ -45,11 +70,12 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", sm->pmk_r0_name, WPA_PMK_NAME_LEN); wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, - sm->own_addr, sm->pmk_r1, pmk_r1_name); + sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, + WPA_PMK_NAME_LEN); wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, - sm->bssid, pmk_r1_name, + sm->bssid, sm->pmk_r1_name, (u8 *) ptk, ptk_len, ptk_name); wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); @@ -61,31 +87,40 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, /** * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @mobility_domain: Mobility domain identifier (2 octets) - * @r0kh_id: PMK-R0 key holder identity (1-48 octets) - * @r0kh_id_len: R0KH-ID length (1-48) - * @r1kh_id: PMK-R1 key holder identity (16 octets) + * @ies: Association Response IEs or %NULL to clear FT parameters + * @ies_len: Length of ies buffer in octets * Returns: 0 on success, -1 on failure */ -int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, - const u8 *r0kh_id, size_t r0kh_id_len, - const u8 *r1kh_id) +int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) { - if (sm && mobility_domain) { + struct wpa_ft_ies ft; + + if (sm == NULL) + return 0; + + if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) + return -1; + + if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) + return -1; + + if (ft.mdie) { wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", - mobility_domain, MOBILITY_DOMAIN_ID_LEN); - os_memcpy(sm->mobility_domain, mobility_domain, + ft.mdie, MOBILITY_DOMAIN_ID_LEN); + os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN); - } else if (sm) + sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; + wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", + sm->mdie_ft_capab); + } else os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); - if (sm && r0kh_id) { - if (r0kh_id_len > FT_R0KH_ID_MAX_LEN) - return -1; - wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len); - os_memcpy(sm->r0kh_id, r0kh_id, r0kh_id_len); - sm->r0kh_id_len = r0kh_id_len; - } else if (sm) { + if (ft.r0kh_id) { + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", + ft.r0kh_id, ft.r0kh_id_len); + os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len); + sm->r0kh_id_len = ft.r0kh_id_len; + } else { /* FIX: When should R0KH-ID be cleared? We need to keep the * old R0KH-ID in order to be able to use this during FT. */ /* @@ -94,31 +129,55 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, */ } - if (sm && r1kh_id) { - wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN); - os_memcpy(sm->r1kh_id, r1kh_id, FT_R1KH_ID_LEN); - } else if (sm) + if (ft.r1kh_id) { + wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", + ft.r1kh_id, FT_R1KH_ID_LEN); + os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN); + } else os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); + os_free(sm->assoc_resp_ies); + sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); + if (sm->assoc_resp_ies) { + u8 *pos = sm->assoc_resp_ies; + if (ft.mdie) { + os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); + pos += ft.mdie_len + 2; + } + if (ft.ftie) { + os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); + pos += ft.ftie_len + 2; + } + sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies; + wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from " + "(Re)Association Response", + sm->assoc_resp_ies, sm->assoc_resp_ies_len); + } + return 0; } /** - * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth Request + * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request * @sm: Pointer to WPA state machine data from wpa_sm_init() * @len: Buffer for returning the length of the IEs * @anonce: ANonce or %NULL if not yet available * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List * @kck: 128-bit KCK for MIC or %NULL if no MIC is used * @target_ap: Target AP address + * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL + * @ric_ies_len: Length of ric_ies buffer in octets + * @ap_mdie: Mobility Domain IE from the target AP * Returns: Pointer to buffer with IEs or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(); */ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, const u8 *anonce, const u8 *pmk_name, - const u8 *kck, const u8 *target_ap) + const u8 *kck, const u8 *target_ap, + const u8 *ric_ies, size_t ric_ies_len, + const u8 *ap_mdie) { size_t buf_len; u8 *buf, *pos, *ftie_len, *ftie_pos; @@ -130,13 +189,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, sm->ft_completed = 0; buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + - 2 + sm->r0kh_id_len + 100; + 2 + sm->r0kh_id_len + ric_ies_len + 100; buf = os_zalloc(buf_len); if (buf == NULL) return NULL; pos = buf; - /* RSNIE[PMKR0Name] */ + /* RSNIE[PMKR0Name/PMKR1Name] */ rsnie = (struct rsn_ie_hdr *) pos; rsnie->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(rsnie->version, RSN_VERSION); @@ -223,9 +282,10 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, pos += sizeof(*mdie); os_memcpy(mdie->mobility_domain, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN); - mdie->ft_capab = 0; /* FIX: copy from the target AP's MDIE */ + mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : + sm->mdie_ft_capab; - /* FTIE[SNonce, R0KH-ID] */ + /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ ftie_pos = pos; *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ftie_len = pos++; @@ -234,6 +294,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); if (anonce) os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); + if (kck) { + /* R1KH-ID sub-element in third FT message */ + *pos++ = FTIE_SUBELEM_R1KH_ID; + *pos++ = FT_R1KH_ID_LEN; + os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); + pos += FT_R1KH_ID_LEN; + } /* R0KH-ID sub-element */ *pos++ = FTIE_SUBELEM_R0KH_ID; *pos++ = sm->r0kh_id_len; @@ -241,6 +308,12 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, pos += sm->r0kh_id_len; *ftie_len = pos - ftie_len - 1; + if (ric_ies) { + /* RIC Request */ + os_memcpy(pos, ric_ies, ric_ies_len); + pos += ric_ies_len; + } + if (kck) { /* * IEEE Std 802.11r-2008, 11A.8.4 @@ -253,12 +326,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, * FTIE (with MIC field set to 0) * RIC-Request (if present) */ - ftie->mic_control[1] = 3; /* Information element count */ + /* Information element count */ + ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, + ric_ies_len); if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5, ((u8 *) mdie) - 2, 2 + sizeof(*mdie), ftie_pos, 2 + *ftie_len, - (u8 *) rsnie, 2 + rsnie->len, NULL, 0, - ftie->mic) < 0) { + (u8 *) rsnie, 2 + rsnie->len, ric_ies, + ric_ies_len, ftie->mic) < 0) { wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); os_free(buf); return NULL; @@ -271,26 +346,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, } -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; - const u8 *tie; - size_t tie_len; - const u8 *igtk; - size_t igtk_len; -}; - - static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, struct wpa_ft_ies *parse) { @@ -346,6 +401,8 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, const u8 *end, *pos; struct wpa_ie_data data; int ret; + const struct rsn_ftie *ftie; + int prot_ie_count = 0; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) @@ -374,6 +431,10 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, parse->mdie_len = pos[1]; break; case WLAN_EID_FAST_BSS_TRANSITION: + if (pos[1] < sizeof(*ftie)) + return -1; + ftie = (const struct rsn_ftie *) (pos + 2); + prot_ie_count = ftie->mic_control[1]; if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) return -1; break; @@ -381,11 +442,55 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, parse->tie = pos + 2; parse->tie_len = pos[1]; break; + case WLAN_EID_RIC_DATA: + if (parse->ric == NULL) + parse->ric = pos; } pos += 2 + pos[1]; } + if (prot_ie_count == 0) + return 0; /* no MIC */ + + /* + * Check that the protected IE count matches with IEs included in the + * frame. + */ + if (parse->rsn) + prot_ie_count--; + if (parse->mdie) + prot_ie_count--; + if (parse->ftie) + prot_ie_count--; + if (parse->tie) + prot_ie_count--; + if (prot_ie_count < 0) { + wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " + "the protected IE count"); + return -1; + } + + if (prot_ie_count == 0 && parse->ric) { + wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " + "included in protected IE count"); + return -1; + } + + /* Determine the end of the RIC IE(s) */ + pos = parse->ric; + while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && + prot_ie_count) { + prot_ie_count--; + pos += 2 + pos[1]; + } + parse->ric_len = pos - parse->ric; + if (prot_ie_count) { + wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " + "frame", (int) prot_ie_count); + return -1; + } + return 0; } @@ -393,7 +498,7 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) { int keylen; - wpa_alg alg; + enum wpa_alg alg; u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); @@ -426,9 +531,10 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) /** * wpa_ft_prepare_auth_request - Generate over-the-air auth request * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @mdie: Target AP MDIE * Returns: 0 on success, -1 on failure */ -int wpa_ft_prepare_auth_request(struct wpa_sm *sm) +int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) { u8 *ft_ies; size_t ft_ies_len; @@ -440,7 +546,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm) } ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, - NULL, sm->bssid); + NULL, sm->bssid, NULL, 0, mdie); if (ft_ies) { wpa_sm_update_ft_ies(sm, sm->mobility_domain, ft_ies, ft_ies_len); @@ -452,7 +558,8 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm) int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, - int ft_action, const u8 *target_ap) + int ft_action, const u8 *target_ap, + const u8 *ric_ies, size_t ric_ies_len) { u8 *ft_ies; size_t ft_ies_len, ptk_len; @@ -464,6 +571,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, const u8 *bssid; wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); + wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); if (ft_action) { if (!sm->over_the_ds_in_progress) { @@ -506,6 +614,15 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, return -1; } + if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", + ftie->snonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", + sm->snonce, WPA_NONCE_LEN); + return -1; + } + if (parse.r0kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); return -1; @@ -538,6 +655,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); + os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); @@ -554,26 +672,40 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, - sm->pmk_r1_name, sm->ptk.kck, bssid); + sm->pmk_r1_name, sm->ptk.kck, bssid, + ric_ies, ric_ies_len, + parse.mdie ? parse.mdie - 2 : NULL); if (ft_ies) { wpa_sm_update_ft_ies(sm, sm->mobility_domain, ft_ies, ft_ies_len); os_free(ft_ies); } + wpa_sm_mark_authenticated(sm, bssid); ret = wpa_ft_install_ptk(sm, bssid); + if (ret) { + /* + * Some drivers do not support key configuration when we are + * not associated with the target AP. Work around this by + * trying again after the following reassociation gets + * completed. + */ + wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to " + "association - try again after reassociation"); + sm->set_ptk_after_assoc = 1; + } else + sm->set_ptk_after_assoc = 0; - if (ret == 0) { - sm->ft_completed = 1; - if (ft_action) { - /* TODO: trigger re-association to the Target AP; - * MLME is now doing this automatically, but it should - * really be done only if we get here successfully. */ - os_memcpy(sm->bssid, target_ap, ETH_ALEN); - } + sm->ft_completed = 1; + if (ft_action) { + /* + * The caller is expected trigger re-association with the + * Target AP. + */ + os_memcpy(sm->bssid, target_ap, ETH_ALEN); } - return ret; + return 0; } @@ -595,7 +727,7 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, { u8 gtk[32]; int keyidx; - wpa_alg alg; + enum wpa_alg alg; size_t gtk_len, keylen, rsc_len; if (gtk_elem == NULL) { @@ -606,14 +738,14 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", gtk_elem, gtk_elem_len); - if (gtk_elem_len < 10 + 24 || (gtk_elem_len - 10) % 8 || - gtk_elem_len - 18 > sizeof(gtk)) { + if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || + gtk_elem_len - 19 > sizeof(gtk)) { wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " "length %lu", (unsigned long) gtk_elem_len); return -1; } - gtk_len = gtk_elem_len - 18; - if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 10, gtk)) { + gtk_len = gtk_elem_len - 19; + if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) { wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " "decrypt GTK"); return -1; @@ -651,20 +783,20 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, return -1; } - /* Key Info[1] | Key Length[1] | RSC[8] | Key[5..32]. */ + /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ - keyidx = gtk_elem[0] & 0x03; + keyidx = WPA_GET_LE16(gtk_elem) & 0x03; - if (gtk_elem[1] != keylen) { + if (gtk_elem[2] != keylen) { wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " "negotiated %lu", - gtk_elem[1], (unsigned long) keylen); + gtk_elem[2], (unsigned long) keylen); return -1; } wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff", - keyidx, 0, gtk_elem + 2, rsc_len, gtk, keylen) < + keyidx, 0, gtk_elem + 3, rsc_len, gtk, keylen) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " "driver."); @@ -735,7 +867,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, struct wpa_ft_ies parse; struct rsn_mdie *mdie; struct rsn_ftie *ftie; - size_t count; + unsigned int count; u8 mic[16]; wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); @@ -766,6 +898,24 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return -1; } + if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", + ftie->snonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", + sm->snonce, WPA_NONCE_LEN); + return -1; + } + + if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); + wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", + ftie->anonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", + sm->anonce, WPA_NONCE_LEN); + return -1; + } + if (parse.r0kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); return -1; @@ -803,17 +953,18 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, count = 3; if (parse.tie) count++; - if (ftie->mic_control[1] != count) { - wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in FTIE (%d)", - ftie->mic_control[1]); + wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " + "Control: received %u expected %u", + ftie->mic_control[1], count); return -1; } if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6, parse.mdie - 2, parse.mdie_len + 2, parse.ftie - 2, parse.ftie_len + 2, - parse.rsn - 2, parse.rsn_len + 2, NULL, 0, + parse.rsn - 2, parse.rsn_len + 2, + parse.ric, parse.ric_len, mic) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); return -1; @@ -834,6 +985,20 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return -1; #endif /* CONFIG_IEEE80211W */ + if (sm->set_ptk_after_assoc) { + wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " + "are associated"); + if (wpa_ft_install_ptk(sm, src_addr) < 0) + return -1; + sm->set_ptk_after_assoc = 0; + } + + if (parse.ric) { + wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", + parse.ric, parse.ric_len); + /* TODO: parse response and inform driver about results */ + } + return 0; } @@ -841,9 +1006,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, /** * wpa_ft_start_over_ds - Generate over-the-DS auth request * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @target_ap: Target AP Address + * @mdie: Mobility Domain IE from the target AP * Returns: 0 on success, -1 on failure */ -int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap) +int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, + const u8 *mdie) { u8 *ft_ies; size_t ft_ies_len; @@ -858,7 +1026,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap) } ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, - NULL, target_ap); + NULL, target_ap, NULL, 0, mdie); if (ft_ies) { sm->over_the_ds_in_progress = 1; os_memcpy(sm->target_ap, target_ap, ETH_ALEN); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index e0dc6bd414e8..618c09028a45 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -1,6 +1,6 @@ /* - * wpa_supplicant - Internal WPA state machine definitions - * Copyright (c) 2004-2007, Jouni Malinen + * Internal WPA/RSN supplicant state machine definitions + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -15,7 +15,8 @@ #ifndef WPA_I_H #define WPA_I_H -struct rsn_pmksa_candidate; +#include "utils/list.h" + struct wpa_peerkey; struct wpa_eapol_key; @@ -38,7 +39,7 @@ struct wpa_sm { struct rsn_pmksa_cache *pmksa; /* PMKSA cache */ struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */ - struct rsn_pmksa_candidate *pmksa_candidates; + struct dl_list pmksa_candidates; struct l2_packet_data *l2_preauth; struct l2_packet_data *l2_preauth_br; @@ -81,6 +82,7 @@ struct wpa_sm { unsigned int mgmt_group_cipher; int rsn_enabled; /* Whether RSN is enabled in configuration */ + int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */ u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ size_t assoc_wpa_ie_len; @@ -105,17 +107,21 @@ struct wpa_sm { int ft_completed; int over_the_ds_in_progress; u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */ + int set_ptk_after_assoc; + u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */ + u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */ + size_t assoc_resp_ies_len; #endif /* CONFIG_IEEE80211R */ }; -static inline void wpa_sm_set_state(struct wpa_sm *sm, wpa_states state) +static inline void wpa_sm_set_state(struct wpa_sm *sm, enum wpa_states state) { WPA_ASSERT(sm->ctx->set_state); sm->ctx->set_state(sm->ctx->ctx, state); } -static inline wpa_states wpa_sm_get_state(struct wpa_sm *sm) +static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm) { WPA_ASSERT(sm->ctx->get_state); return sm->ctx->get_state(sm->ctx->ctx); @@ -133,7 +139,7 @@ static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code) sm->ctx->disassociate(sm->ctx->ctx, reason_code); } -static inline int wpa_sm_set_key(struct wpa_sm *sm, wpa_alg alg, +static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) @@ -223,6 +229,14 @@ static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action, return -1; } +static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm, + const u8 *target_ap) +{ + if (sm->ctx->mark_authenticated) + return sm->ctx->mark_authenticated(sm->ctx->ctx, target_ap); + return -1; +} + void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, int ver, const u8 *dest, u16 proto, diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 84f2811b8861..f447223bc3b9 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -17,7 +17,7 @@ #include "common.h" #include "wpa.h" #include "pmksa_cache.h" -#include "ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "wpa_i.h" #include "wpa_ie.h" @@ -332,8 +332,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, /* RSN Capabilities */ capab = 0; #ifdef CONFIG_IEEE80211W - if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) + if (sm->mfp) capab |= WPA_CAPABILITY_MFPC; + if (sm->mfp == 2) + capab |= WPA_CAPABILITY_MFPR; #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); pos += 2; @@ -414,6 +416,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, pos[2 + WPA_SELECTOR_LEN + 1] == 0) { ie->wpa_ie = pos; ie->wpa_ie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", + ie->wpa_ie, ie->wpa_ie_len); return 0; } @@ -421,6 +425,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", + pos, pos[1] + 2); return 0; } @@ -428,6 +434,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { ie->gtk = pos + 2 + RSN_SELECTOR_LEN; ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", + pos, pos[1] + 2); return 0; } @@ -435,6 +443,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, 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; + wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", + pos, pos[1] + 2); return 0; } @@ -443,6 +453,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { ie->smk = pos + 2 + RSN_SELECTOR_LEN; ie->smk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", + pos, pos[1] + 2); return 0; } @@ -450,6 +462,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { ie->nonce = pos + 2 + RSN_SELECTOR_LEN; ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", + pos, pos[1] + 2); return 0; } @@ -457,6 +471,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", + pos, pos[1] + 2); return 0; } @@ -464,6 +480,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { ie->error = pos + 2 + RSN_SELECTOR_LEN; ie->error_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", + pos, pos[1] + 2); return 0; } #endif /* CONFIG_PEERKEY */ @@ -473,6 +491,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { ie->igtk = pos + 2 + RSN_SELECTOR_LEN; ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", + pos, pos[1] + 2); return 0; } #endif /* CONFIG_IEEE80211W */ @@ -513,10 +533,35 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, if (*pos == WLAN_EID_RSN) { ie->rsn_ie = pos; ie->rsn_ie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", + ie->rsn_ie, ie->rsn_ie_len); #ifdef CONFIG_IEEE80211R } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { ie->mdie = pos; ie->mdie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", + ie->mdie, ie->mdie_len); + } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { + ie->ftie = pos; + ie->ftie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", + ie->ftie, ie->ftie_len); + } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { + if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { + ie->reassoc_deadline = pos; + wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " + "in EAPOL-Key", + ie->reassoc_deadline, pos[1] + 2); + } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { + ie->key_lifetime = pos; + wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " + "in EAPOL-Key", + ie->key_lifetime, pos[1] + 2); + } else { + wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " + "EAPOL-Key Key Data IE", + pos, 2 + pos[1]); + } #endif /* CONFIG_IEEE80211R */ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index 17e375aa21d8..94518d845787 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -42,6 +42,10 @@ struct wpa_eapol_ie_parse { #ifdef CONFIG_IEEE80211R const u8 *mdie; size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *reassoc_deadline; + const u8 *key_lifetime; #endif /* CONFIG_IEEE80211R */ }; diff --git a/src/tls/.gitignore b/src/tls/.gitignore new file mode 100644 index 000000000000..d43242d73390 --- /dev/null +++ b/src/tls/.gitignore @@ -0,0 +1 @@ +libtls.a diff --git a/src/tls/Makefile b/src/tls/Makefile index cffba620da04..a2da0965a5f9 100644 --- a/src/tls/Makefile +++ b/src/tls/Makefile @@ -1,9 +1,37 @@ -all: - @echo Nothing to be made. +all: libtls.a clean: - for d in $(SUBDIRS); do make -C $$d clean; done - rm -f *~ *.o *.d + rm -f *~ *.o *.d libtls.a install: @echo Nothing to be made. + + +include ../lib.rules + +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_CRYPTO_INTERNAL + +LIB_OBJS= \ + asn1.o \ + bignum.o \ + pkcs1.o \ + pkcs5.o \ + pkcs8.o \ + rsa.o \ + tlsv1_client.o \ + tlsv1_client_read.o \ + tlsv1_client_write.o \ + tlsv1_common.o \ + tlsv1_cred.o \ + tlsv1_record.o \ + tlsv1_server.o \ + tlsv1_server_read.o \ + tlsv1_server_write.o \ + x509v3.o + + +libtls.a: $(LIB_OBJS) + $(AR) crT $@ $? + +-include $(OBJS:%.o=%.d) diff --git a/src/tls/asn1.c b/src/tls/asn1.c index 96bc1ac78a9d..3391245fe3cd 100644 --- a/src/tls/asn1.c +++ b/src/tls/asn1.c @@ -15,9 +15,6 @@ #include "includes.h" #include "common.h" - -#ifdef CONFIG_INTERNAL_X509 - #include "asn1.h" int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) @@ -85,28 +82,16 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) } -int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, - const u8 **next) +int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) { - struct asn1_hdr hdr; const u8 *pos, *end; unsigned long val; u8 tmp; os_memset(oid, 0, sizeof(*oid)); - if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) - return -1; - - if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { - wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " - "tag 0x%x", hdr.class, hdr.tag); - return -1; - } - - pos = hdr.payload; - end = hdr.payload + hdr.length; - *next = end; + pos = buf; + end = buf + len; while (pos < end) { val = 0; @@ -141,6 +126,26 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, } +int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **next) +{ + struct asn1_hdr hdr; + + if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) + return -1; + + if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { + wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " + "tag 0x%x", hdr.class, hdr.tag); + return -1; + } + + *next = hdr.payload + hdr.length; + + return asn1_parse_oid(hdr.payload, hdr.length, oid); +} + + void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) { char *pos = buf; @@ -205,5 +210,3 @@ unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) return val; } - -#endif /* CONFIG_INTERNAL_X509 */ diff --git a/src/tls/asn1.h b/src/tls/asn1.h index c02ada8278a2..2ff571ea909d 100644 --- a/src/tls/asn1.h +++ b/src/tls/asn1.h @@ -63,6 +63,7 @@ struct asn1_oid { int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); +int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, const u8 **next); void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); diff --git a/src/tls/asn1_test.c b/src/tls/asn1_test.c deleted file mode 100644 index a5c77535309f..000000000000 --- a/src/tls/asn1_test.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Testing tool for ASN.1/X.509v3 routines - * Copyright (c) 2006, Jouni Malinen - * - * 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 "asn1.h" -#include "x509v3.h" - -extern int wpa_debug_level; - - -static const char * asn1_class_str(int class) -{ - switch (class) { - case ASN1_CLASS_UNIVERSAL: - return "Universal"; - case ASN1_CLASS_APPLICATION: - return "Application"; - case ASN1_CLASS_CONTEXT_SPECIFIC: - return "Context-specific"; - case ASN1_CLASS_PRIVATE: - return "Private"; - default: - return "?"; - } -} - - -int asn1_parse(const u8 *buf, size_t len, int level) -{ - const u8 *pos, *prev, *end; - char prefix[10], str[100]; - int _level; - struct asn1_hdr hdr; - struct asn1_oid oid; - u8 tmp; - - _level = level; - if ((size_t) _level > sizeof(prefix) - 1) - _level = sizeof(prefix) - 1; - memset(prefix, ' ', _level); - prefix[_level] = '\0'; - - pos = buf; - end = buf + len; - - while (pos < end) { - if (asn1_get_next(pos, end - pos, &hdr) < 0) - return -1; - - prev = pos; - pos = hdr.payload; - - wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) " - "Tag %u Length %u", - prefix, hdr.class, asn1_class_str(hdr.class), - hdr.constructed, - hdr.constructed ? "Constructed" : "Primitive", - hdr.tag, hdr.length); - - if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC && - hdr.constructed) { - if (asn1_parse(pos, hdr.length, level + 1) < 0) - return -1; - pos += hdr.length; - } - - if (hdr.class != ASN1_CLASS_UNIVERSAL) - continue; - - switch (hdr.tag) { - case ASN1_TAG_EOC: - if (hdr.length) { - wpa_printf(MSG_DEBUG, "ASN.1: Non-zero " - "end-of-contents length (%u)", - hdr.length); - return -1; - } - wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix); - break; - case ASN1_TAG_BOOLEAN: - if (hdr.length != 1) { - wpa_printf(MSG_DEBUG, "ASN.1: Unexpected " - "Boolean length (%u)", hdr.length); - return -1; - } - tmp = *pos++; - wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s", - prefix, tmp ? "TRUE" : "FALSE"); - break; - case ASN1_TAG_INTEGER: - wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_BITSTRING: - wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_OCTETSTRING: - wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_NULL: - if (hdr.length) { - wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null " - "length (%u)", hdr.length); - return -1; - } - wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix); - break; - case ASN1_TAG_OID: - if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) { - wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID"); - return -1; - } - asn1_oid_to_str(&oid, str, sizeof(str)); - wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str); - pos += hdr.length; - break; - case ANS1_TAG_RELATIVE_OID: - wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_SEQUENCE: - wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix); - if (asn1_parse(pos, hdr.length, level + 1) < 0) - return -1; - pos += hdr.length; - break; - case ASN1_TAG_SET: - wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix); - if (asn1_parse(pos, hdr.length, level + 1) < 0) - return -1; - pos += hdr.length; - break; - case ASN1_TAG_PRINTABLESTRING: - wpa_hexdump_ascii(MSG_MSGDUMP, - "ASN.1: PrintableString", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_IA5STRING: - wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_UTCTIME: - wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME", - pos, hdr.length); - pos += hdr.length; - break; - case ASN1_TAG_VISIBLESTRING: - wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString", - pos, hdr.length); - pos += hdr.length; - break; - default: - wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d", - hdr.tag); - return -1; - } - } - - return 0; -} - - -int main(int argc, char *argv[]) -{ - FILE *f; - u8 buf[3000]; - size_t len; - struct x509_certificate *cert; - - wpa_debug_level = 0; - - f = fopen(argv[1], "rb"); - if (f == NULL) - return -1; - len = fread(buf, 1, sizeof(buf), f); - fclose(f); - - if (asn1_parse(buf, len, 0) < 0) - printf("Failed to parse DER ASN.1\n"); - - printf("\n\n"); - - cert = x509_certificate_parse(buf, len); - if (cert == NULL) - printf("Failed to parse X.509 certificate\n"); - x509_certificate_free(cert); - - return 0; -} diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c new file mode 100644 index 000000000000..72ebd8764857 --- /dev/null +++ b/src/tls/pkcs1.c @@ -0,0 +1,201 @@ +/* + * PKCS #1 (RSA Encryption) + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 "rsa.h" +#include "pkcs1.h" + + +static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + size_t ps_len; + u8 *pos; + + /* + * PKCS #1 v1.5, 8.1: + * + * EB = 00 || BT || PS || 00 || D + * BT = 00 or 01 for private-key operation; 02 for public-key operation + * PS = k-3-||D||; at least eight octets + * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) + * k = length of modulus in octets (modlen) + */ + + if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " + "lengths (modlen=%lu outlen=%lu inlen=%lu)", + __func__, (unsigned long) modlen, + (unsigned long) *outlen, + (unsigned long) inlen); + return -1; + } + + pos = out; + *pos++ = 0x00; + *pos++ = block_type; /* BT */ + ps_len = modlen - inlen - 3; + switch (block_type) { + case 0: + os_memset(pos, 0x00, ps_len); + pos += ps_len; + break; + case 1: + os_memset(pos, 0xff, ps_len); + pos += ps_len; + break; + case 2: + if (os_get_random(pos, ps_len) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " + "random data for PS", __func__); + return -1; + } + while (ps_len--) { + if (*pos == 0x00) + *pos = 0x01; + pos++; + } + break; + default: + wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " + "%d", __func__, block_type); + return -1; + } + *pos++ = 0x00; + os_memcpy(pos, in, inlen); /* D */ + + return 0; +} + + +int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, + int use_private, const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + size_t modlen; + + modlen = crypto_rsa_get_modulus_len(key); + + if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, + out, outlen) < 0) + return -1; + + return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); +} + + +int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen) +{ + int res; + u8 *pos, *end; + + res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1); + if (res) + return res; + + if (*outlen < 2 || out[0] != 0 || out[1] != 2) + return -1; + + /* Skip PS (pseudorandom non-zero octets) */ + pos = out + 2; + end = out + *outlen; + while (*pos && pos < end) + pos++; + if (pos == end) + return -1; + pos++; + + *outlen -= pos - out; + + /* Strip PKCS #1 header */ + os_memmove(out, pos, *outlen); + + return 0; +} + + +int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len) +{ + size_t len; + u8 *pos; + + len = *plain_len; + if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0) + return -1; + + /* + * PKCS #1 v1.5, 8.1: + * + * EB = 00 || BT || PS || 00 || D + * BT = 00 or 01 + * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) + * k = length of modulus in octets + */ + + if (len < 3 + 8 + 16 /* min hash len */ || + plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " + "structure"); + return -1; + } + + pos = plain + 3; + if (plain[1] == 0x00) { + /* BT = 00 */ + if (plain[2] != 0x00) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " + "PS (BT=00)"); + return -1; + } + while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) + pos++; + } else { + /* BT = 01 */ + if (plain[2] != 0xff) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " + "PS (BT=01)"); + return -1; + } + while (pos < plain + len && *pos == 0xff) + pos++; + } + + if (pos - plain - 2 < 8) { + /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ + wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " + "padding"); + return -1; + } + + if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " + "structure (2)"); + return -1; + } + pos++; + len -= pos - plain; + + /* Strip PKCS #1 header */ + os_memmove(plain, pos, len); + *plain_len = len; + + return 0; +} diff --git a/src/tls/pkcs1.h b/src/tls/pkcs1.h new file mode 100644 index 000000000000..68872b1502ed --- /dev/null +++ b/src/tls/pkcs1.h @@ -0,0 +1,28 @@ +/* + * PKCS #1 (RSA Encryption) + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 PKCS1_H +#define PKCS1_H + +int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, + int use_private, const u8 *in, size_t inlen, + u8 *out, size_t *outlen); +int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen); +int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, + const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len); + +#endif /* PKCS1_H */ diff --git a/src/tls/pkcs5.c b/src/tls/pkcs5.c new file mode 100644 index 000000000000..4291b84f16d7 --- /dev/null +++ b/src/tls/pkcs5.c @@ -0,0 +1,238 @@ +/* + * PKCS #5 (Password-based Encryption) + * Copyright (c) 2009, Jouni Malinen + * + * 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 "crypto/crypto.h" +#include "crypto/md5.h" +#include "asn1.h" +#include "pkcs5.h" + + +struct pkcs5_params { + enum pkcs5_alg { + PKCS5_ALG_UNKNOWN, + PKCS5_ALG_MD5_DES_CBC + } alg; + u8 salt[8]; + size_t salt_len; + unsigned int iter_count; +}; + + +enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) +{ + if (oid->len == 7 && + oid->oid[0] == 1 /* iso */ && + oid->oid[1] == 2 /* member-body */ && + oid->oid[2] == 840 /* us */ && + oid->oid[3] == 113549 /* rsadsi */ && + oid->oid[4] == 1 /* pkcs */ && + oid->oid[5] == 5 /* pkcs-5 */ && + oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */) + return PKCS5_ALG_MD5_DES_CBC; + + return PKCS5_ALG_UNKNOWN; +} + + +static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, + struct pkcs5_params *params) +{ + struct asn1_hdr hdr; + const u8 *enc_alg_end, *pos, *end; + struct asn1_oid oid; + char obuf[80]; + + /* AlgorithmIdentifier */ + + enc_alg_end = enc_alg + enc_alg_len; + + os_memset(params, 0, sizeof(*params)); + + if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { + wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " + "(algorithm)"); + return -1; + } + + asn1_oid_to_str(&oid, obuf, sizeof(obuf)); + wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); + params->alg = pkcs5_get_alg(&oid); + if (params->alg == PKCS5_ALG_UNKNOWN) { + wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " + "algorithm %s", obuf); + return -1; + } + + /* + * PKCS#5, Section 8 + * PBEParameter ::= SEQUENCE { + * salt OCTET STRING SIZE(8), + * iterationCount INTEGER } + */ + + if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " + "(PBEParameter) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + pos = hdr.payload; + end = hdr.payload + hdr.length; + + /* salt OCTET STRING SIZE(8) */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING || + hdr.length != 8) { + wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " + "(salt) - found class %d tag 0x%x size %d", + hdr.class, hdr.tag, hdr.length); + return -1; + } + pos = hdr.payload + hdr.length; + os_memcpy(params->salt, hdr.payload, hdr.length); + params->salt_len = hdr.length; + wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", + params->salt, params->salt_len); + + /* iterationCount INTEGER */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { + wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " + "class %d tag 0x%x", hdr.class, hdr.tag); + return -1; + } + if (hdr.length == 1) + params->iter_count = *hdr.payload; + else if (hdr.length == 2) + params->iter_count = WPA_GET_BE16(hdr.payload); + else if (hdr.length == 4) + params->iter_count = WPA_GET_BE32(hdr.payload); + else { + wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " + " (iterationCount)", + hdr.payload, hdr.length); + return -1; + } + wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", + params->iter_count); + if (params->iter_count == 0 || params->iter_count > 0xffff) { + wpa_printf(MSG_INFO, "PKCS #5: Unsupported " + "iterationCount=0x%x", params->iter_count); + return -1; + } + + return 0; +} + + +static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, + const char *passwd) +{ + unsigned int i; + u8 hash[MD5_MAC_LEN]; + const u8 *addr[2]; + size_t len[2]; + + if (params->alg != PKCS5_ALG_MD5_DES_CBC) + return NULL; + + addr[0] = (const u8 *) passwd; + len[0] = os_strlen(passwd); + addr[1] = params->salt; + len[1] = params->salt_len; + if (md5_vector(2, addr, len, hash) < 0) + return NULL; + addr[0] = hash; + len[0] = MD5_MAC_LEN; + for (i = 1; i < params->iter_count; i++) { + if (md5_vector(1, addr, len, hash) < 0) + return NULL; + } + /* TODO: DES key parity bits(?) */ + wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); + wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); + + return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); +} + + +u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, + const u8 *enc_data, size_t enc_data_len, + const char *passwd, size_t *data_len) +{ + struct crypto_cipher *ctx; + u8 *eb, pad; + struct pkcs5_params params; + unsigned int i; + + if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); + return NULL; + } + + ctx = pkcs5_crypto_init(¶ms, passwd); + if (ctx == NULL) { + wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); + return NULL; + } + + /* PKCS #5, Section 7 - Decryption process */ + if (enc_data_len < 16 || enc_data_len % 8) { + wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " + "%d", (int) enc_data_len); + crypto_cipher_deinit(ctx); + return NULL; + } + + eb = os_malloc(enc_data_len); + if (eb == NULL) { + crypto_cipher_deinit(ctx); + return NULL; + } + + if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); + crypto_cipher_deinit(ctx); + os_free(eb); + return NULL; + } + crypto_cipher_deinit(ctx); + + pad = eb[enc_data_len - 1]; + if (pad > 8) { + wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); + os_free(eb); + return NULL; + } + for (i = enc_data_len - pad; i < enc_data_len; i++) { + if (eb[i] != pad) { + wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", + eb + enc_data_len - pad, pad); + os_free(eb); + return NULL; + } + } + + wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", + eb, enc_data_len - pad); + + *data_len = enc_data_len - pad; + return eb; +} diff --git a/src/tls/pkcs5.h b/src/tls/pkcs5.h new file mode 100644 index 000000000000..6ed39230b533 --- /dev/null +++ b/src/tls/pkcs5.h @@ -0,0 +1,22 @@ +/* + * PKCS #5 (Password-based Encryption) + * Copyright (c) 2009, Jouni Malinen + * + * 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 PKCS5_H +#define PKCS5_H + +u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, + const u8 *enc_data, size_t enc_data_len, + const char *passwd, size_t *data_len); + +#endif /* PKCS5_H */ diff --git a/src/tls/pkcs8.c b/src/tls/pkcs8.c new file mode 100644 index 000000000000..69ab262e5ebe --- /dev/null +++ b/src/tls/pkcs8.c @@ -0,0 +1,193 @@ +/* + * PKCS #8 (Private-key information syntax) + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 "asn1.h" +#include "bignum.h" +#include "rsa.h" +#include "pkcs5.h" +#include "pkcs8.h" + + +struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len) +{ + struct asn1_hdr hdr; + const u8 *pos, *end; + struct bignum *zero; + struct asn1_oid oid; + char obuf[80]; + + /* PKCS #8, Chapter 6 */ + + /* PrivateKeyInfo ::= SEQUENCE */ + if (asn1_get_next(buf, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " + "header (SEQUENCE); assume PKCS #8 not used"); + return NULL; + } + pos = hdr.payload; + end = pos + hdr.length; + + /* version Version (Version ::= INTEGER) */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { + wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found " + "class %d tag 0x%x; assume PKCS #8 not used", + hdr.class, hdr.tag); + return NULL; + } + + zero = bignum_init(); + if (zero == NULL) + return NULL; + + if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER"); + bignum_deinit(zero); + return NULL; + } + pos = hdr.payload + hdr.length; + + if (bignum_cmp_d(zero, 0) != 0) { + wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the " + "beginning of private key; not found; assume " + "PKCS #8 not used"); + bignum_deinit(zero); + return NULL; + } + bignum_deinit(zero); + + /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier + * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */ + if (asn1_get_next(pos, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " + "(AlgorithmIdentifier) - found class %d tag 0x%x; " + "assume PKCS #8 not used", + hdr.class, hdr.tag); + return NULL; + } + + if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) { + wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID " + "(algorithm); assume PKCS #8 not used"); + return NULL; + } + + asn1_oid_to_str(&oid, obuf, sizeof(obuf)); + wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf); + + if (oid.len != 7 || + oid.oid[0] != 1 /* iso */ || + oid.oid[1] != 2 /* member-body */ || + oid.oid[2] != 840 /* us */ || + oid.oid[3] != 113549 /* rsadsi */ || + oid.oid[4] != 1 /* pkcs */ || + oid.oid[5] != 1 /* pkcs-1 */ || + oid.oid[6] != 1 /* rsaEncryption */) { + wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key " + "algorithm %s", obuf); + return NULL; + } + + pos = hdr.payload + hdr.length; + + /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " + "(privateKey) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return NULL; + } + wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey"); + + return (struct crypto_private_key *) + crypto_rsa_import_private_key(hdr.payload, hdr.length); +} + + +struct crypto_private_key * +pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd) +{ + struct asn1_hdr hdr; + const u8 *pos, *end, *enc_alg; + size_t enc_alg_len; + u8 *data; + size_t data_len; + + if (passwd == NULL) + return NULL; + + /* + * PKCS #8, Chapter 7 + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData } + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * EncryptedData ::= OCTET STRING + */ + + if (asn1_get_next(buf, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " + "header (SEQUENCE); assume encrypted PKCS #8 not " + "used"); + return NULL; + } + pos = hdr.payload; + end = pos + hdr.length; + + /* encryptionAlgorithm EncryptionAlgorithmIdentifier */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " + "(AlgorithmIdentifier) - found class %d tag 0x%x; " + "assume encrypted PKCS #8 not used", + hdr.class, hdr.tag); + return NULL; + } + enc_alg = hdr.payload; + enc_alg_len = hdr.length; + pos = hdr.payload + hdr.length; + + /* encryptedData EncryptedData */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " + "(encryptedData) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return NULL; + } + + data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length, + passwd, &data_len); + if (data) { + struct crypto_private_key *key; + key = pkcs8_key_import(data, data_len); + os_free(data); + return key; + } + + return NULL; +} diff --git a/src/tls/pkcs8.h b/src/tls/pkcs8.h new file mode 100644 index 000000000000..dac517c91ac9 --- /dev/null +++ b/src/tls/pkcs8.h @@ -0,0 +1,22 @@ +/* + * PKCS #8 (Private-key information syntax) + * Copyright (c) 2006-2009, Jouni Malinen + * + * 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 PKCS8_H +#define PKCS8_H + +struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len); +struct crypto_private_key * +pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd); + +#endif /* PKCS8_H */ diff --git a/src/tls/rsa.c b/src/tls/rsa.c index 4965a2a311cc..3084adc17579 100644 --- a/src/tls/rsa.c +++ b/src/tls/rsa.c @@ -15,7 +15,6 @@ #include "includes.h" #include "common.h" -#include "crypto.h" #include "asn1.h" #include "bignum.h" #include "rsa.h" @@ -35,7 +34,6 @@ struct crypto_rsa_key { }; -#ifdef EAP_TLS_FUNCS static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end, struct bignum *num) { @@ -224,7 +222,6 @@ error: crypto_rsa_free(key); return NULL; } -#endif /* EAP_TLS_FUNCS */ /** diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index 0bf11742ca93..afb603175a11 100644 --- a/src/tls/tlsv1_client.c +++ b/src/tls/tlsv1_client.c @@ -15,8 +15,8 @@ #include "includes.h" #include "common.h" -#include "sha1.h" -#include "tls.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" @@ -605,7 +605,6 @@ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn) */ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers) { -#ifdef EAP_FAST size_t count; u16 *suites; @@ -635,9 +634,6 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers) } return 0; -#else /* EAP_FAST */ - return -1; -#endif /* EAP_FAST */ } diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index ee20330ce2c6..ed3f2606c8cc 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -15,10 +15,10 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "sha1.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "x509v3.h" -#include "tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c index e0c95cbe8ebe..b47425f232b7 100644 --- a/src/tls/tlsv1_client_write.c +++ b/src/tls/tlsv1_client_write.c @@ -15,10 +15,10 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "sha1.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "x509v3.h" -#include "tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" @@ -209,7 +209,6 @@ static int tls_write_client_certificate(struct tlsv1_client *conn, static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) { -#ifdef EAP_FAST /* ClientDiffieHellmanPublic */ u8 *csecret, *csecret_start, *dh_yc, *shared; size_t csecret_len, dh_yc_len, shared_len; @@ -321,10 +320,6 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) os_free(shared); tlsv1_client_free_dh(conn); return 0; -#else /* EAP_FAST */ - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); - return -1; -#endif /* EAP_FAST */ } diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h index 77505649a252..763a4af3d561 100644 --- a/src/tls/tlsv1_common.h +++ b/src/tls/tlsv1_common.h @@ -15,7 +15,7 @@ #ifndef TLSV1_COMMON_H #define TLSV1_COMMON_H -#include "crypto.h" +#include "crypto/crypto.h" #define TLS_VERSION 0x0301 /* TLSv1 */ #define TLS_RANDOM_LEN 32 diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c index d5564672c8e1..aa467efc8c3c 100644 --- a/src/tls/tlsv1_cred.c +++ b/src/tls/tlsv1_cred.c @@ -1,6 +1,6 @@ /* * TLSv1 credentials - * Copyright (c) 2006-2007, Jouni Malinen + * Copyright (c) 2006-2009, Jouni Malinen * * 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 @@ -16,7 +16,7 @@ #include "common.h" #include "base64.h" -#include "crypto.h" +#include "crypto/crypto.h" #include "x509v3.h" #include "tlsv1_cred.h" @@ -68,6 +68,12 @@ static int tlsv1_add_cert_der(struct x509_certificate **chain, static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----"; static const char *pem_cert_end = "-----END CERTIFICATE-----"; +static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----"; +static const char *pem_key_end = "-----END RSA PRIVATE KEY-----"; +static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----"; +static const char *pem_key2_end = "-----END PRIVATE KEY-----"; +static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; +static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----"; static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) @@ -209,10 +215,74 @@ int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, } -static int tlsv1_set_key(struct tlsv1_credentials *cred, - const u8 *key, size_t len) +static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len) { - cred->key = crypto_private_key_import(key, len); + const u8 *pos, *end; + unsigned char *der; + size_t der_len; + struct crypto_private_key *pkey; + + pos = search_tag(pem_key_begin, key, len); + if (!pos) { + pos = search_tag(pem_key2_begin, key, len); + if (!pos) + return NULL; + pos += os_strlen(pem_key2_begin); + end = search_tag(pem_key2_end, pos, key + len - pos); + if (!end) + return NULL; + } else { + pos += os_strlen(pem_key_begin); + end = search_tag(pem_key_end, pos, key + len - pos); + if (!end) + return NULL; + } + + der = base64_decode(pos, end - pos, &der_len); + if (!der) + return NULL; + pkey = crypto_private_key_import(der, der_len, NULL); + os_free(der); + return pkey; +} + + +static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key, + size_t len, + const char *passwd) +{ + const u8 *pos, *end; + unsigned char *der; + size_t der_len; + struct crypto_private_key *pkey; + + if (passwd == NULL) + return NULL; + pos = search_tag(pem_key_enc_begin, key, len); + if (!pos) + return NULL; + pos += os_strlen(pem_key_enc_begin); + end = search_tag(pem_key_enc_end, pos, key + len - pos); + if (!end) + return NULL; + + der = base64_decode(pos, end - pos, &der_len); + if (!der) + return NULL; + pkey = crypto_private_key_import(der, der_len, passwd); + os_free(der); + return pkey; +} + + +static int tlsv1_set_key(struct tlsv1_credentials *cred, + const u8 *key, size_t len, const char *passwd) +{ + cred->key = crypto_private_key_import(key, len, passwd); + if (cred->key == NULL) + cred->key = tlsv1_set_key_pem(key, len); + if (cred->key == NULL) + cred->key = tlsv1_set_key_enc_pem(key, len, passwd); if (cred->key == NULL) { wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key"); return -1; @@ -242,7 +312,8 @@ int tlsv1_set_private_key(struct tlsv1_credentials *cred, if (private_key_blob) return tlsv1_set_key(cred, private_key_blob, - private_key_blob_len); + private_key_blob_len, + private_key_passwd); if (private_key) { u8 *buf; @@ -256,7 +327,7 @@ int tlsv1_set_private_key(struct tlsv1_credentials *cred, return -1; } - ret = tlsv1_set_key(cred, buf, len); + ret = tlsv1_set_key(cred, buf, len, private_key_passwd); os_free(buf); return ret; } diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c index f226ac3f9b37..e811f0e33b44 100644 --- a/src/tls/tlsv1_record.c +++ b/src/tls/tlsv1_record.c @@ -15,8 +15,8 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "sha1.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" #include "tlsv1_common.h" #include "tlsv1_record.h" diff --git a/src/tls/tlsv1_record.h b/src/tls/tlsv1_record.h index 9170fb1a2fe4..9c7c0a4e644e 100644 --- a/src/tls/tlsv1_record.h +++ b/src/tls/tlsv1_record.h @@ -15,7 +15,7 @@ #ifndef TLSV1_RECORD_H #define TLSV1_RECORD_H -#include "crypto.h" +#include "crypto/crypto.h" #define TLS_MAX_WRITE_MAC_SECRET_LEN 20 #define TLS_MAX_WRITE_KEY_LEN 32 diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c index c204a4778a74..6a6123564553 100644 --- a/src/tls/tlsv1_server.c +++ b/src/tls/tlsv1_server.c @@ -15,8 +15,8 @@ #include "includes.h" #include "common.h" -#include "sha1.h" -#include "tls.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_server.h" @@ -546,7 +546,6 @@ int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn) */ int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers) { -#ifdef EAP_FAST size_t count; u16 *suites; @@ -572,9 +571,6 @@ int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers) } return 0; -#else /* EAP_FAST */ - return -1; -#endif /* EAP_FAST */ } diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 397d74a197ab..49e811ffcff5 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -15,10 +15,10 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "sha1.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "x509v3.h" -#include "tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_server.h" @@ -567,7 +567,6 @@ static int tls_process_client_key_exchange_rsa( static int tls_process_client_key_exchange_dh_anon( struct tlsv1_server *conn, const u8 *pos, const u8 *end) { -#ifdef EAP_FAST const u8 *dh_yc; u16 dh_yc_len; u8 *shared; @@ -665,9 +664,6 @@ static int tls_process_client_key_exchange_dh_anon( } return 0; -#else /* EAP_FAST */ - return -1; -#endif /* EAP_FAST */ } diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c index cf54f4265c3a..6d1df7ff34f4 100644 --- a/src/tls/tlsv1_server_write.c +++ b/src/tls/tlsv1_server_write.c @@ -15,10 +15,10 @@ #include "includes.h" #include "common.h" -#include "md5.h" -#include "sha1.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" #include "x509v3.h" -#include "tls.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_server.h" @@ -247,12 +247,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, { tls_key_exchange keyx; const struct tls_cipher_suite *suite; -#ifdef EAP_FAST u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; u8 *dh_ys; size_t dh_ys_len; -#endif /* EAP_FAST */ suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) @@ -272,7 +270,6 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, return -1; } -#ifdef EAP_FAST if (conn->cred == NULL || conn->cred->dh_p == NULL || conn->cred->dh_g == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " @@ -433,9 +430,6 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, *msgpos = pos; return 0; -#else /* EAP_FAST */ - return -1; -#endif /* EAP_FAST */ } diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 59bf4ff0524a..bc93df683787 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -15,25 +15,32 @@ #include "includes.h" #include "common.h" - -#ifdef CONFIG_INTERNAL_X509 - +#include "crypto/crypto.h" #include "asn1.h" -#include "crypto.h" #include "x509v3.h" static void x509_free_name(struct x509_name *name) { - os_free(name->cn); - os_free(name->c); - os_free(name->l); - os_free(name->st); - os_free(name->o); - os_free(name->ou); + size_t i; + + for (i = 0; i < name->num_attr; i++) { + os_free(name->attr[i].value); + name->attr[i].value = NULL; + name->attr[i].type = X509_NAME_ATTR_NOT_USED; + } + name->num_attr = 0; os_free(name->email); - name->cn = name->c = name->l = name->st = name->o = name->ou = NULL; name->email = NULL; + + os_free(name->alt_email); + os_free(name->dns); + os_free(name->uri); + os_free(name->ip); + name->alt_email = name->dns = name->uri = NULL; + name->ip = NULL; + name->ip_len = 0; + os_memset(&name->rid, 0, sizeof(name->rid)); } @@ -146,6 +153,7 @@ static int x509_str_compare(const char *a, const char *b) int x509_name_compare(struct x509_name *a, struct x509_name *b) { int res; + size_t i; if (!a && b) return -1; @@ -153,25 +161,20 @@ int x509_name_compare(struct x509_name *a, struct x509_name *b) return 1; if (!a && !b) return 0; + if (a->num_attr < b->num_attr) + return -1; + if (a->num_attr > b->num_attr) + return 1; - res = x509_str_compare(a->cn, b->cn); - if (res) - return res; - res = x509_str_compare(a->c, b->c); - if (res) - return res; - res = x509_str_compare(a->l, b->l); - if (res) - return res; - res = x509_str_compare(a->st, b->st); - if (res) - return res; - res = x509_str_compare(a->o, b->o); - if (res) - return res; - res = x509_str_compare(a->ou, b->ou); - if (res) - return res; + for (i = 0; i < a->num_attr; i++) { + if (a->attr[i].type < b->attr[i].type) + return -1; + if (a->attr[i].type > b->attr[i].type) + return -1; + res = x509_str_compare(a->attr[i].value, b->attr[i].value); + if (res) + return res; + } res = x509_str_compare(a->email, b->email); if (res) return res; @@ -298,7 +301,7 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, struct asn1_hdr hdr; const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; struct asn1_oid oid; - char **fieldp; + char *val; /* * Name ::= CHOICE { RDNSequence } @@ -328,6 +331,8 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, end = *next = pos + hdr.length; while (pos < end) { + enum x509_name_attr_type type; + if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) { @@ -375,34 +380,34 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, * pseudonym, generation qualifier. * MUST: domainComponent (RFC 2247). */ - fieldp = NULL; + type = X509_NAME_ATTR_NOT_USED; if (oid.len == 4 && oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { /* id-at ::= 2.5.4 */ switch (oid.oid[3]) { case 3: /* commonName */ - fieldp = &name->cn; + type = X509_NAME_ATTR_CN; break; case 6: /* countryName */ - fieldp = &name->c; + type = X509_NAME_ATTR_C; break; case 7: /* localityName */ - fieldp = &name->l; + type = X509_NAME_ATTR_L; break; case 8: /* stateOrProvinceName */ - fieldp = &name->st; + type = X509_NAME_ATTR_ST; break; case 10: /* organizationName */ - fieldp = &name->o; + type = X509_NAME_ATTR_O; break; case 11: /* organizationalUnitName */ - fieldp = &name->ou; + type = X509_NAME_ATTR_OU; break; } } else if (oid.len == 7 && @@ -411,10 +416,25 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, oid.oid[4] == 1 && oid.oid[5] == 9 && oid.oid[6] == 1) { /* 1.2.840.113549.1.9.1 - e-mailAddress */ - fieldp = &name->email; + os_free(name->email); + name->email = os_malloc(hdr.length + 1); + if (name->email == NULL) { + x509_free_name(name); + return -1; + } + os_memcpy(name->email, hdr.payload, hdr.length); + name->email[hdr.length] = '\0'; + continue; + } else if (oid.len == 7 && + oid.oid[0] == 0 && oid.oid[1] == 9 && + oid.oid[2] == 2342 && oid.oid[3] == 19200300 && + oid.oid[4] == 100 && oid.oid[5] == 1 && + oid.oid[6] == 25) { + /* 0.9.2342.19200300.100.1.25 - domainComponent */ + type = X509_NAME_ATTR_DC; } - if (fieldp == NULL) { + if (type == X509_NAME_ATTR_NOT_USED) { wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", (u8 *) oid.oid, oid.len * sizeof(oid.oid[0])); @@ -423,20 +443,60 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, continue; } - os_free(*fieldp); - *fieldp = os_malloc(hdr.length + 1); - if (*fieldp == NULL) { + if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) { + wpa_printf(MSG_INFO, "X509: Too many Name attributes"); x509_free_name(name); return -1; } - os_memcpy(*fieldp, hdr.payload, hdr.length); - (*fieldp)[hdr.length] = '\0'; + + val = os_malloc(hdr.length + 1); + if (val == NULL) { + x509_free_name(name); + return -1; + } + os_memcpy(val, hdr.payload, hdr.length); + val[hdr.length] = '\0'; + if (os_strlen(val) != hdr.length) { + wpa_printf(MSG_INFO, "X509: Reject certificate with " + "embedded NUL byte in a string (%s[NUL])", + val); + x509_free_name(name); + return -1; + } + + name->attr[name->num_attr].type = type; + name->attr[name->num_attr].value = val; + name->num_attr++; } return 0; } +static char * x509_name_attr_str(enum x509_name_attr_type type) +{ + switch (type) { + case X509_NAME_ATTR_NOT_USED: + return "[N/A]"; + case X509_NAME_ATTR_DC: + return "DC"; + case X509_NAME_ATTR_CN: + return "CN"; + case X509_NAME_ATTR_C: + return "C"; + case X509_NAME_ATTR_L: + return "L"; + case X509_NAME_ATTR_ST: + return "ST"; + case X509_NAME_ATTR_O: + return "O"; + case X509_NAME_ATTR_OU: + return "OU"; + } + return "?"; +} + + /** * x509_name_string - Convert an X.509 certificate name into a string * @name: Name to convert @@ -447,6 +507,7 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len) { char *pos, *end; int ret; + size_t i; if (len == 0) return; @@ -454,46 +515,20 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len) pos = buf; end = buf + len; - if (name->c) { - ret = os_snprintf(pos, end - pos, "C=%s, ", name->c); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - if (name->st) { - ret = os_snprintf(pos, end - pos, "ST=%s, ", name->st); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - if (name->l) { - ret = os_snprintf(pos, end - pos, "L=%s, ", name->l); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - if (name->o) { - ret = os_snprintf(pos, end - pos, "O=%s, ", name->o); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - if (name->ou) { - ret = os_snprintf(pos, end - pos, "OU=%s, ", name->ou); - if (ret < 0 || ret >= end - pos) - goto done; - pos += ret; - } - if (name->cn) { - ret = os_snprintf(pos, end - pos, "CN=%s, ", name->cn); + for (i = 0; i < name->num_attr; i++) { + ret = os_snprintf(pos, end - pos, "%s=%s, ", + x509_name_attr_str(name->attr[i].type), + name->attr[i].value); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { - *pos-- = '\0'; - *pos-- = '\0'; + pos--; + *pos = '\0'; + pos--; + *pos = '\0'; } if (name->email) { @@ -815,6 +850,237 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert, } +static int x509_parse_alt_name_rfc8222(struct x509_name *name, + const u8 *pos, size_t len) +{ + /* rfc822Name IA5String */ + wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len); + os_free(name->alt_email); + name->alt_email = os_zalloc(len + 1); + if (name->alt_email == NULL) + return -1; + os_memcpy(name->alt_email, pos, len); + if (os_strlen(name->alt_email) != len) { + wpa_printf(MSG_INFO, "X509: Reject certificate with " + "embedded NUL byte in rfc822Name (%s[NUL])", + name->alt_email); + os_free(name->alt_email); + name->alt_email = NULL; + return -1; + } + return 0; +} + + +static int x509_parse_alt_name_dns(struct x509_name *name, + const u8 *pos, size_t len) +{ + /* dNSName IA5String */ + wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len); + os_free(name->dns); + name->dns = os_zalloc(len + 1); + if (name->dns == NULL) + return -1; + os_memcpy(name->dns, pos, len); + if (os_strlen(name->dns) != len) { + wpa_printf(MSG_INFO, "X509: Reject certificate with " + "embedded NUL byte in dNSName (%s[NUL])", + name->dns); + os_free(name->dns); + name->dns = NULL; + return -1; + } + return 0; +} + + +static int x509_parse_alt_name_uri(struct x509_name *name, + const u8 *pos, size_t len) +{ + /* uniformResourceIdentifier IA5String */ + wpa_hexdump_ascii(MSG_MSGDUMP, + "X509: altName - uniformResourceIdentifier", + pos, len); + os_free(name->uri); + name->uri = os_zalloc(len + 1); + if (name->uri == NULL) + return -1; + os_memcpy(name->uri, pos, len); + if (os_strlen(name->uri) != len) { + wpa_printf(MSG_INFO, "X509: Reject certificate with " + "embedded NUL byte in uniformResourceIdentifier " + "(%s[NUL])", name->uri); + os_free(name->uri); + name->uri = NULL; + return -1; + } + return 0; +} + + +static int x509_parse_alt_name_ip(struct x509_name *name, + const u8 *pos, size_t len) +{ + /* iPAddress OCTET STRING */ + wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len); + os_free(name->ip); + name->ip = os_malloc(len); + if (name->ip == NULL) + return -1; + os_memcpy(name->ip, pos, len); + name->ip_len = len; + return 0; +} + + +static int x509_parse_alt_name_rid(struct x509_name *name, + const u8 *pos, size_t len) +{ + char buf[80]; + + /* registeredID OBJECT IDENTIFIER */ + if (asn1_parse_oid(pos, len, &name->rid) < 0) + return -1; + + asn1_oid_to_str(&name->rid, buf, sizeof(buf)); + wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf); + + return 0; +} + + +static int x509_parse_ext_alt_name(struct x509_name *name, + const u8 *pos, size_t len) +{ + struct asn1_hdr hdr; + const u8 *p, *end; + + /* + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + */ + + for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) { + int res; + + if (asn1_get_next(p, end - p, &hdr) < 0) { + wpa_printf(MSG_DEBUG, "X509: Failed to parse " + "SubjectAltName item"); + return -1; + } + + if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) + continue; + + switch (hdr.tag) { + case 1: + res = x509_parse_alt_name_rfc8222(name, hdr.payload, + hdr.length); + break; + case 2: + res = x509_parse_alt_name_dns(name, hdr.payload, + hdr.length); + break; + case 6: + res = x509_parse_alt_name_uri(name, hdr.payload, + hdr.length); + break; + case 7: + res = x509_parse_alt_name_ip(name, hdr.payload, + hdr.length); + break; + case 8: + res = x509_parse_alt_name_rid(name, hdr.payload, + hdr.length); + break; + case 0: /* TODO: otherName */ + case 3: /* TODO: x500Address */ + case 4: /* TODO: directoryName */ + case 5: /* TODO: ediPartyName */ + default: + res = 0; + break; + } + if (res < 0) + return res; + } + + return 0; +} + + +static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert, + const u8 *pos, size_t len) +{ + struct asn1_hdr hdr; + + /* SubjectAltName ::= GeneralNames */ + + if (asn1_get_next(pos, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " + "SubjectAltName; found %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + + wpa_printf(MSG_DEBUG, "X509: SubjectAltName"); + cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME; + + if (hdr.length == 0) + return 0; + + return x509_parse_ext_alt_name(&cert->subject, hdr.payload, + hdr.length); +} + + +static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert, + const u8 *pos, size_t len) +{ + struct asn1_hdr hdr; + + /* IssuerAltName ::= GeneralNames */ + + if (asn1_get_next(pos, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " + "IssuerAltName; found %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + + wpa_printf(MSG_DEBUG, "X509: IssuerAltName"); + cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME; + + if (hdr.length == 0) + return 0; + + return x509_parse_ext_alt_name(&cert->issuer, hdr.payload, + hdr.length); +} + + static int x509_parse_extension_data(struct x509_certificate *cert, struct asn1_oid *oid, const u8 *pos, size_t len) @@ -824,7 +1090,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert, /* TODO: add other extensions required by RFC 3280, Ch 4.2: * certificate policies (section 4.2.1.5) - * the subject alternative name (section 4.2.1.7) * name constraints (section 4.2.1.11) * policy constraints (section 4.2.1.12) * extended key usage (section 4.2.1.13) @@ -833,6 +1098,10 @@ static int x509_parse_extension_data(struct x509_certificate *cert, switch (oid->oid[3]) { case 15: /* id-ce-keyUsage */ return x509_parse_ext_key_usage(cert, pos, len); + case 17: /* id-ce-subjectAltName */ + return x509_parse_ext_subject_alt_name(cert, pos, len); + case 18: /* id-ce-issuerAltName */ + return x509_parse_ext_issuer_alt_name(cert, pos, len); case 19: /* id-ce-basicConstraints */ return x509_parse_ext_basic_constraints(cert, pos, len); default: @@ -1495,18 +1764,12 @@ skip_digest_oid: hash, hash_len); break; case 11: /* sha256WithRSAEncryption */ -#ifdef NEED_SHA256 sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, hash); hash_len = 32; wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", hash, hash_len); break; -#else /* NEED_SHA256 */ - wpa_printf(MSG_INFO, "X509: SHA256 support disabled"); - os_free(data); - return -1; -#endif /* NEED_SHA256 */ case 2: /* md2WithRSAEncryption */ case 12: /* sha384WithRSAEncryption */ case 13: /* sha512WithRSAEncryption */ @@ -1720,5 +1983,3 @@ int x509_certificate_self_signed(struct x509_certificate *cert) { return x509_name_compare(&cert->issuer, &cert->subject) == 0; } - -#endif /* CONFIG_INTERNAL_X509 */ diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h index a52bcf886453..37292d7e7dec 100644 --- a/src/tls/x509v3.h +++ b/src/tls/x509v3.h @@ -21,14 +21,34 @@ struct x509_algorithm_identifier { struct asn1_oid oid; }; +struct x509_name_attr { + enum x509_name_attr_type { + X509_NAME_ATTR_NOT_USED, + X509_NAME_ATTR_DC, + X509_NAME_ATTR_CN, + X509_NAME_ATTR_C, + X509_NAME_ATTR_L, + X509_NAME_ATTR_ST, + X509_NAME_ATTR_O, + X509_NAME_ATTR_OU + } type; + char *value; +}; + +#define X509_MAX_NAME_ATTRIBUTES 20 + struct x509_name { - char *cn; /* commonName */ - char *c; /* countryName */ - char *l; /* localityName */ - char *st; /* stateOrProvinceName */ - char *o; /* organizationName */ - char *ou; /* organizationalUnitName */ + struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES]; + size_t num_attr; char *email; /* emailAddress */ + + /* from alternative name extension */ + char *alt_email; /* rfc822Name */ + char *dns; /* dNSName */ + char *uri; /* uniformResourceIdentifier */ + u8 *ip; /* iPAddress */ + size_t ip_len; /* IPv4: 4, IPv6: 16 */ + struct asn1_oid rid; /* registeredID */ }; struct x509_certificate { @@ -52,6 +72,8 @@ struct x509_certificate { #define X509_EXT_BASIC_CONSTRAINTS (1 << 0) #define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1) #define X509_EXT_KEY_USAGE (1 << 2) +#define X509_EXT_SUBJECT_ALT_NAME (1 << 3) +#define X509_EXT_ISSUER_ALT_NAME (1 << 4) /* BasicConstraints */ int ca; /* cA */ @@ -89,8 +111,6 @@ enum { X509_VALIDATE_UNKNOWN_CA }; -#ifdef CONFIG_INTERNAL_X509 - void x509_certificate_free(struct x509_certificate *cert); struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len); void x509_name_string(struct x509_name *name, char *buf, size_t len); @@ -106,49 +126,4 @@ x509_certificate_get_subject(struct x509_certificate *chain, struct x509_name *name); int x509_certificate_self_signed(struct x509_certificate *cert); -#else /* CONFIG_INTERNAL_X509 */ - -static inline void x509_certificate_free(struct x509_certificate *cert) -{ -} - -static inline struct x509_certificate * -x509_certificate_parse(const u8 *buf, size_t len) -{ - return NULL; -} - -static inline void x509_name_string(struct x509_name *name, char *buf, - size_t len) -{ - if (len) - buf[0] = '\0'; -} - -static inline void x509_certificate_chain_free(struct x509_certificate *cert) -{ -} - -static inline int -x509_certificate_chain_validate(struct x509_certificate *trusted, - struct x509_certificate *chain, - int *reason) -{ - return -1; -} - -static inline struct x509_certificate * -x509_certificate_get_subject(struct x509_certificate *chain, - struct x509_name *name) -{ - return NULL; -} - -static inline int x509_certificate_self_signed(struct x509_certificate *cert) -{ - return -1; -} - -#endif /* CONFIG_INTERNAL_X509 */ - #endif /* X509V3_H */ diff --git a/src/utils/.gitignore b/src/utils/.gitignore new file mode 100644 index 000000000000..833734f887ac --- /dev/null +++ b/src/utils/.gitignore @@ -0,0 +1 @@ +libutils.a diff --git a/src/utils/Makefile b/src/utils/Makefile index cffba620da04..527cf3e73bb8 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -1,9 +1,36 @@ -all: - @echo Nothing to be made. +all: libutils.a clean: - for d in $(SUBDIRS); do make -C $$d clean; done - rm -f *~ *.o *.d + rm -f *~ *.o *.d libutils.a install: @echo Nothing to be made. + + +include ../lib.rules + +#CFLAGS += -DWPA_TRACE +CFLAGS += -DCONFIG_IPV6 + +LIB_OBJS= \ + base64.o \ + common.o \ + ip_addr.o \ + radiotap.o \ + trace.o \ + uuid.o \ + wpa_debug.o \ + wpabuf.o + +# Pick correct OS wrapper implementation +LIB_OBJS += os_unix.o + +# Pick correct event loop implementation +LIB_OBJS += eloop.o + +#LIB_OBJS += pcsc_funcs.o + +libutils.a: $(LIB_OBJS) + $(AR) crT $@ $? + +-include $(OBJS:%.o=%.d) diff --git a/src/utils/base64.c b/src/utils/base64.c index 13fc511dc614..155bfce83aa5 100644 --- a/src/utils/base64.c +++ b/src/utils/base64.c @@ -152,38 +152,3 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, *out_len = pos - out; return out; } - - -#ifdef TEST_MAIN - -int main(int argc, char *argv[]) -{ - FILE *f; - size_t len, elen; - unsigned char *buf, *e; - - if (argc != 4) { - printf("Usage: base64 \n"); - return -1; - } - - buf = os_readfile(argv[2], &len); - if (buf == NULL) - return -1; - - if (strcmp(argv[1], "encode") == 0) - e = base64_encode(buf, len, &elen); - else - e = base64_decode(buf, len, &elen); - if (e == NULL) - return -2; - f = fopen(argv[3], "w"); - if (f == NULL) - return -3; - fwrite(e, 1, elen, f); - fclose(f); - free(e); - - return 0; -} -#endif /* TEST_MAIN */ diff --git a/src/utils/build_config.h b/src/utils/build_config.h index 1e147fe36911..366677849231 100644 --- a/src/utils/build_config.h +++ b/src/utils/build_config.h @@ -28,7 +28,6 @@ #define CONFIG_ANSI_C_EXTRA #define CONFIG_WINPCAP #define IEEE8021X_EAPOL -#define EAP_TLS_FUNCS #define PKCS12_FUNCS #define PCSC_FUNCS #define CONFIG_CTRL_IFACE @@ -48,16 +47,8 @@ #define _CRT_SECURE_NO_DEPRECATE #ifdef USE_INTERNAL_CRYPTO -#define CONFIG_TLS_INTERNAL #define CONFIG_TLS_INTERNAL_CLIENT #define CONFIG_INTERNAL_LIBTOMMATH -#define INTERNAL_AES -#define INTERNAL_SHA1 -#define INTERNAL_SHA256 -#define INTERNAL_MD5 -#define INTERNAL_MD4 -#define INTERNAL_DES -#define CONFIG_INTERNAL_X509 #define CONFIG_CRYPTO_INTERNAL #endif /* USE_INTERNAL_CRYPTO */ #endif /* CONFIG_WIN32_DEFAULTS */ @@ -69,15 +60,7 @@ #define CONFIG_NO_HOSTAPD_LOGGER #define CONFIG_NO_STDOUT_DEBUG #define CONFIG_BACKEND_FILE -#define INTERNAL_AES -#define INTERNAL_SHA1 -#define INTERNAL_MD5 -#define INTERNAL_MD4 -#define INTERNAL_DES #define CONFIG_INTERNAL_LIBTOMMATH -#define CONFIG_INTERNAL_X509 -#define EAP_TLS_FUNCS -#define CONFIG_TLS_INTERNAL #define CONFIG_CRYPTO_INTERNAL #define IEEE8021X_EAPOL #define PKCS12_FUNCS @@ -92,4 +75,31 @@ #define EAP_FAST #endif /* __SYMBIAN32__ */ +#ifdef CONFIG_XCODE_DEFAULTS +#define CONFIG_DRIVER_OSX +#define CONFIG_BACKEND_FILE +#define IEEE8021X_EAPOL +#define PKCS12_FUNCS +#define CONFIG_CTRL_IFACE +#define CONFIG_CTRL_IFACE_UNIX +#define CONFIG_DEBUG_FILE +#define EAP_MD5 +#define EAP_TLS +#define EAP_MSCHAPv2 +#define EAP_PEAP +#define EAP_TTLS +#define EAP_GTC +#define EAP_OTP +#define EAP_LEAP +#define EAP_TNC +#define CONFIG_WPS +#define EAP_WSC + +#ifdef USE_INTERNAL_CRYPTO +#define CONFIG_TLS_INTERNAL_CLIENT +#define CONFIG_INTERNAL_LIBTOMMATH +#define CONFIG_CRYPTO_INTERNAL +#endif /* USE_INTERNAL_CRYPTO */ +#endif /* CONFIG_XCODE_DEFAULTS */ + #endif /* BUILD_CONFIG_H */ diff --git a/src/utils/common.c b/src/utils/common.c index 9a46ebe461da..1b8ea80e7d05 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -43,7 +43,7 @@ static int hex2byte(const char *hex) /** - * hwaddr_aton - Convert ASCII string to MAC address + * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) @@ -70,6 +70,36 @@ int hwaddr_aton(const char *txt, u8 *addr) } +/** + * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) + * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) + * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) + * Returns: Characters used (> 0) on success, -1 on failure + */ +int hwaddr_aton2(const char *txt, u8 *addr) +{ + int i; + const char *pos = txt; + + for (i = 0; i < 6; i++) { + int a, b; + + while (*pos == ':' || *pos == '.' || *pos == '-') + pos++; + + a = hex2num(*pos++); + if (a < 0) + return -1; + b = hex2num(*pos++); + if (b < 0) + return -1; + *addr++ = (a << 4) | b; + } + + return pos - txt; +} + + /** * hexstr2bin - Convert ASCII hex string into binary data * @hex: ASCII hex string (e.g., "01ab") diff --git a/src/utils/common.h b/src/utils/common.h index d649391e37b6..f17bf69ff547 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -17,7 +17,7 @@ #include "os.h" -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) #include #include #endif /* __linux__ */ @@ -314,6 +314,24 @@ static inline unsigned int wpa_swap_32(unsigned int v) #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_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ #ifdef __GNUC__ @@ -418,6 +436,7 @@ typedef u64 __bitwise le64; #endif /* __must_check */ int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); int hexstr2bin(const char *hex, u8 *buf, size_t len); void inc_byte_array(u8 *counter, size_t len); void wpa_get_ntp_timestamp(u8 *buf); diff --git a/src/utils/eloop.c b/src/utils/eloop.c index 4edb2a703396..4b615989c0bb 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -1,6 +1,6 @@ /* * Event loop based on select() loop - * Copyright (c) 2002-2005, Jouni Malinen + * Copyright (c) 2002-2009, Jouni Malinen * * 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 @@ -15,6 +15,8 @@ #include "includes.h" #include "common.h" +#include "trace.h" +#include "list.h" #include "eloop.h" @@ -23,14 +25,20 @@ struct eloop_sock { void *eloop_data; void *user_data; eloop_sock_handler handler; + WPA_TRACE_REF(eloop); + WPA_TRACE_REF(user); + WPA_TRACE_INFO }; struct eloop_timeout { + struct dl_list list; struct os_time time; void *eloop_data; void *user_data; eloop_timeout_handler handler; - struct eloop_timeout *next; + WPA_TRACE_REF(eloop); + WPA_TRACE_REF(user); + WPA_TRACE_INFO }; struct eloop_signal { @@ -47,15 +55,13 @@ struct eloop_sock_table { }; struct eloop_data { - void *user_data; - int max_sock; struct eloop_sock_table readers; struct eloop_sock_table writers; struct eloop_sock_table exceptions; - struct eloop_timeout *timeout; + struct dl_list timeout; int signal_count; struct eloop_signal *signals; @@ -69,10 +75,56 @@ struct eloop_data { static struct eloop_data eloop; -int eloop_init(void *user_data) +#ifdef WPA_TRACE + +static void eloop_sigsegv_handler(int sig) +{ + wpa_trace_show("eloop SIGSEGV"); + abort(); +} + +static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) +{ + int i; + if (table == NULL || table->table == NULL) + return; + for (i = 0; i < table->count; i++) { + wpa_trace_add_ref(&table->table[i], eloop, + table->table[i].eloop_data); + wpa_trace_add_ref(&table->table[i], user, + table->table[i].user_data); + } +} + + +static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) +{ + int i; + if (table == NULL || table->table == NULL) + return; + for (i = 0; i < table->count; i++) { + wpa_trace_remove_ref(&table->table[i], eloop, + table->table[i].eloop_data); + wpa_trace_remove_ref(&table->table[i], user, + table->table[i].user_data); + } +} + +#else /* WPA_TRACE */ + +#define eloop_trace_sock_add_ref(table) do { } while (0) +#define eloop_trace_sock_remove_ref(table) do { } while (0) + +#endif /* WPA_TRACE */ + + +int eloop_init(void) { os_memset(&eloop, 0, sizeof(eloop)); - eloop.user_data = user_data; + dl_list_init(&eloop.timeout); +#ifdef WPA_TRACE + signal(SIGSEGV, eloop_sigsegv_handler); +#endif /* WPA_TRACE */ return 0; } @@ -86,6 +138,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, if (table == NULL) return -1; + eloop_trace_sock_remove_ref(table); tmp = (struct eloop_sock *) os_realloc(table->table, (table->count + 1) * sizeof(struct eloop_sock)); @@ -96,11 +149,13 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, tmp[table->count].eloop_data = eloop_data; tmp[table->count].user_data = user_data; tmp[table->count].handler = handler; + wpa_trace_record(&tmp[table->count]); table->count++; table->table = tmp; if (sock > eloop.max_sock) eloop.max_sock = sock; table->changed = 1; + eloop_trace_sock_add_ref(table); return 0; } @@ -120,6 +175,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, } if (i == table->count) return; + eloop_trace_sock_remove_ref(table); if (i != table->count - 1) { os_memmove(&table->table[i], &table->table[i + 1], (table->count - i - 1) * @@ -127,6 +183,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, } table->count--; table->changed = 1; + eloop_trace_sock_add_ref(table); } @@ -171,12 +228,17 @@ static void eloop_sock_table_destroy(struct eloop_sock_table *table) if (table) { int i; for (i = 0; i < table->count && table->table; i++) { - printf("ELOOP: remaining socket: sock=%d " - "eloop_data=%p user_data=%p handler=%p\n", - table->table[i].sock, - table->table[i].eloop_data, - table->table[i].user_data, - table->table[i].handler); + wpa_printf(MSG_INFO, "ELOOP: remaining socket: " + "sock=%d eloop_data=%p user_data=%p " + "handler=%p", + table->table[i].sock, + table->table[i].eloop_data, + table->table[i].user_data, + table->table[i].handler); + wpa_trace_dump_funcname("eloop unregistered socket " + "handler", + table->table[i].handler); + wpa_trace_dump("eloop sock", &table->table[i]); } os_free(table->table); } @@ -237,9 +299,9 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data) { - struct eloop_timeout *timeout, *tmp, *prev; + struct eloop_timeout *timeout, *tmp; - timeout = os_malloc(sizeof(*timeout)); + timeout = os_zalloc(sizeof(*timeout)); if (timeout == NULL) return -1; if (os_get_time(&timeout->time) < 0) { @@ -255,60 +317,48 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs, timeout->eloop_data = eloop_data; timeout->user_data = user_data; timeout->handler = handler; - timeout->next = NULL; + wpa_trace_add_ref(timeout, eloop, eloop_data); + wpa_trace_add_ref(timeout, user, user_data); + wpa_trace_record(timeout); - if (eloop.timeout == NULL) { - eloop.timeout = timeout; - return 0; - } - - prev = NULL; - tmp = eloop.timeout; - while (tmp != NULL) { - if (os_time_before(&timeout->time, &tmp->time)) - break; - prev = tmp; - tmp = tmp->next; - } - - if (prev == NULL) { - timeout->next = eloop.timeout; - eloop.timeout = timeout; - } else { - timeout->next = prev->next; - prev->next = timeout; + /* Maintain timeouts in order of increasing time */ + dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { + if (os_time_before(&timeout->time, &tmp->time)) { + dl_list_add(tmp->list.prev, &timeout->list); + return 0; + } } + dl_list_add_tail(&eloop.timeout, &timeout->list); return 0; } +static void eloop_remove_timeout(struct eloop_timeout *timeout) +{ + dl_list_del(&timeout->list); + wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); + wpa_trace_remove_ref(timeout, user, timeout->user_data); + os_free(timeout); +} + + int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data) { - struct eloop_timeout *timeout, *prev, *next; + struct eloop_timeout *timeout, *prev; int removed = 0; - prev = NULL; - timeout = eloop.timeout; - while (timeout != NULL) { - next = timeout->next; - + dl_list_for_each_safe(timeout, prev, &eloop.timeout, + struct eloop_timeout, list) { if (timeout->handler == handler && (timeout->eloop_data == eloop_data || eloop_data == ELOOP_ALL_CTX) && (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX)) { - if (prev == NULL) - eloop.timeout = next; - else - prev->next = next; - os_free(timeout); + eloop_remove_timeout(timeout); removed++; - } else - prev = timeout; - - timeout = next; + } } return removed; @@ -320,14 +370,11 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler, { struct eloop_timeout *tmp; - tmp = eloop.timeout; - while (tmp != NULL) { + dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { if (tmp->handler == handler && tmp->eloop_data == eloop_data && tmp->user_data == user_data) return 1; - - tmp = tmp->next; } return 0; @@ -337,11 +384,11 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler, #ifndef CONFIG_NATIVE_WINDOWS static void eloop_handle_alarm(int sig) { - fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two " - "seconds. Looks like there\n" - "is a bug that ends up in a busy loop that " - "prevents clean shutdown.\n" - "Killing program forcefully.\n"); + wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " + "two seconds. Looks like there\n" + "is a bug that ends up in a busy loop that " + "prevents clean shutdown.\n" + "Killing program forcefully.\n"); exit(1); } #endif /* CONFIG_NATIVE_WINDOWS */ @@ -390,7 +437,6 @@ static void eloop_process_pending_signals(void) if (eloop.signals[i].signaled) { eloop.signals[i].signaled = 0; eloop.signals[i].handler(eloop.signals[i].sig, - eloop.user_data, eloop.signals[i].user_data); } } @@ -452,24 +498,21 @@ void eloop_run(void) rfds = os_malloc(sizeof(*rfds)); wfds = os_malloc(sizeof(*wfds)); efds = os_malloc(sizeof(*efds)); - if (rfds == NULL || wfds == NULL || efds == NULL) { - printf("eloop_run - malloc failed\n"); + if (rfds == NULL || wfds == NULL || efds == NULL) goto out; - } while (!eloop.terminate && - (eloop.timeout || eloop.readers.count > 0 || + (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0)) { - if (eloop.timeout) { + struct eloop_timeout *timeout; + timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, + list); + if (timeout) { os_get_time(&now); - if (os_time_before(&now, &eloop.timeout->time)) - os_time_sub(&eloop.timeout->time, &now, &tv); + if (os_time_before(&now, &timeout->time)) + os_time_sub(&timeout->time, &now, &tv); else tv.sec = tv.usec = 0; -#if 0 - printf("next timeout in %lu.%06lu sec\n", - tv.sec, tv.usec); -#endif _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; } @@ -478,7 +521,7 @@ void eloop_run(void) eloop_sock_table_set_fds(&eloop.writers, wfds); eloop_sock_table_set_fds(&eloop.exceptions, efds); res = select(eloop.max_sock + 1, rfds, wfds, efds, - eloop.timeout ? &_tv : NULL); + timeout ? &_tv : NULL); if (res < 0 && errno != EINTR && errno != 0) { perror("select"); goto out; @@ -486,16 +529,17 @@ void eloop_run(void) eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ - if (eloop.timeout) { - struct eloop_timeout *tmp; - + timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, + list); + if (timeout) { os_get_time(&now); - if (!os_time_before(&now, &eloop.timeout->time)) { - tmp = eloop.timeout; - eloop.timeout = eloop.timeout->next; - tmp->handler(tmp->eloop_data, - tmp->user_data); - os_free(tmp); + if (!os_time_before(&now, &timeout->time)) { + void *eloop_data = timeout->eloop_data; + void *user_data = timeout->user_data; + eloop_timeout_handler handler = + timeout->handler; + eloop_remove_timeout(timeout); + handler(eloop_data, user_data); } } @@ -526,24 +570,24 @@ void eloop_destroy(void) struct eloop_timeout *timeout, *prev; struct os_time now; - timeout = eloop.timeout; - if (timeout) - os_get_time(&now); - while (timeout != NULL) { + os_get_time(&now); + dl_list_for_each_safe(timeout, prev, &eloop.timeout, + struct eloop_timeout, list) { int sec, usec; - prev = timeout; - timeout = timeout->next; - sec = prev->time.sec - now.sec; - usec = prev->time.usec - now.usec; - if (prev->time.usec < now.usec) { + sec = timeout->time.sec - now.sec; + usec = timeout->time.usec - now.usec; + if (timeout->time.usec < now.usec) { sec--; usec += 1000000; } - printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p " - "user_data=%p handler=%p\n", - sec, usec, prev->eloop_data, prev->user_data, - prev->handler); - os_free(prev); + wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " + "eloop_data=%p user_data=%p handler=%p", + sec, usec, timeout->eloop_data, timeout->user_data, + timeout->handler); + wpa_trace_dump_funcname("eloop unregistered timeout handler", + timeout->handler); + wpa_trace_dump("eloop timeout", timeout); + eloop_remove_timeout(timeout); } eloop_sock_table_destroy(&eloop.readers); eloop_sock_table_destroy(&eloop.writers); @@ -569,9 +613,3 @@ void eloop_wait_for_read_sock(int sock) FD_SET(sock, &rfds); select(sock + 1, &rfds, NULL, NULL, NULL); } - - -void * eloop_get_user_data(void) -{ - return eloop.user_data; -} diff --git a/src/utils/eloop.h b/src/utils/eloop.h index cf83f3836555..1228f24d22c8 100644 --- a/src/utils/eloop.h +++ b/src/utils/eloop.h @@ -65,25 +65,19 @@ typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); /** * eloop_signal_handler - eloop signal event callback type * @sig: Signal number - * @eloop_ctx: Registered callback context data (global user_data from - * eloop_init() call) * @signal_ctx: Registered callback context data (user_data from * eloop_register_signal(), eloop_register_signal_terminate(), or * eloop_register_signal_reconfig() call) */ -typedef void (*eloop_signal_handler)(int sig, void *eloop_ctx, - void *signal_ctx); +typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); /** * eloop_init() - Initialize global event loop data - * @user_data: Pointer to global data passed as eloop_ctx to signal handlers * Returns: 0 on success, -1 on failure * - * This function must be called before any other eloop_* function. user_data - * can be used to configure a global (to the process) pointer that will be - * passed as eloop_ctx parameter to signal handlers. + * This function must be called before any other eloop_* function. */ -int eloop_init(void *user_data); +int eloop_init(void); /** * eloop_register_read_sock - Register handler for read events @@ -231,10 +225,6 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler, * handler has returned. This means that the normal limits for sighandlers * (i.e., only "safe functions" allowed) do not apply for the registered * callback. - * - * Signals are 'global' events and there is no local eloop_data pointer like - * with other handlers. The global user_data pointer registered with - * eloop_init() will be used as eloop_ctx for signal handlers. */ int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data); @@ -251,10 +241,6 @@ int eloop_register_signal(int sig, eloop_signal_handler handler, * sighandlers (i.e., only "safe functions" allowed) do not apply for the * registered callback. * - * Signals are 'global' events and there is no local eloop_data pointer like - * with other handlers. The global user_data pointer registered with - * eloop_init() will be used as eloop_ctx for signal handlers. - * * This function is a more portable version of eloop_register_signal() since * the knowledge of exact details of the signals is hidden in eloop * implementation. In case of operating systems using signal(), this function @@ -275,10 +261,6 @@ int eloop_register_signal_terminate(eloop_signal_handler handler, * limits for sighandlers (i.e., only "safe functions" allowed) do not apply * for the registered callback. * - * Signals are 'global' events and there is no local eloop_data pointer like - * with other handlers. The global user_data pointer registered with - * eloop_init() will be used as eloop_ctx for signal handlers. - * * This function is a more portable version of eloop_register_signal() since * the knowledge of exact details of the signals is hidden in eloop * implementation. In case of operating systems using signal(), this function @@ -331,10 +313,4 @@ int eloop_terminated(void); */ void eloop_wait_for_read_sock(int sock); -/** - * eloop_get_user_data - Get global user data - * Returns: user_data pointer that was registered with eloop_init() - */ -void * eloop_get_user_data(void); - #endif /* ELOOP_H */ diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c index 215030b2135f..18eae4e5a778 100644 --- a/src/utils/eloop_none.c +++ b/src/utils/eloop_none.c @@ -41,8 +41,6 @@ struct eloop_signal { }; struct eloop_data { - void *user_data; - int max_sock, reader_count; struct eloop_sock *readers; @@ -60,10 +58,9 @@ struct eloop_data { static struct eloop_data eloop; -int eloop_init(void *user_data) +int eloop_init(void) { memset(&eloop, 0, sizeof(eloop)); - eloop.user_data = user_data; return 0; } @@ -402,9 +399,3 @@ void eloop_wait_for_read_sock(int sock) * reading */ } - - -void * eloop_get_user_data(void) -{ - return eloop.user_data; -} diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c index c95aa76b7882..94cc72d04c6b 100644 --- a/src/utils/eloop_win.c +++ b/src/utils/eloop_win.c @@ -50,8 +50,6 @@ struct eloop_signal { }; struct eloop_data { - void *user_data; - int max_sock; size_t reader_count; struct eloop_sock *readers; @@ -79,10 +77,9 @@ struct eloop_data { static struct eloop_data eloop; -int eloop_init(void *user_data) +int eloop_init(void) { os_memset(&eloop, 0, sizeof(eloop)); - eloop.user_data = user_data; eloop.num_handles = 1; eloop.handles = os_malloc(eloop.num_handles * sizeof(eloop.handles[0])); @@ -372,7 +369,6 @@ static void eloop_process_pending_signals(void) if (eloop.signals[i].signaled) { eloop.signals[i].signaled = 0; eloop.signals[i].handler(eloop.signals[i].sig, - eloop.user_data, eloop.signals[i].user_data); } } @@ -380,7 +376,6 @@ static void eloop_process_pending_signals(void) if (eloop.term_signal.signaled) { eloop.term_signal.signaled = 0; eloop.term_signal.handler(eloop.term_signal.sig, - eloop.user_data, eloop.term_signal.user_data); } } @@ -614,9 +609,3 @@ void eloop_wait_for_read_sock(int sock) WSAEventSelect(sock, event, 0); WSACloseEvent(event); } - - -void * eloop_get_user_data(void) -{ - return eloop.user_data; -} diff --git a/src/utils/ip_addr.h b/src/utils/ip_addr.h index 192049a58311..28ccaefdea2b 100644 --- a/src/utils/ip_addr.h +++ b/src/utils/ip_addr.h @@ -16,13 +16,14 @@ #define IP_ADDR_H struct hostapd_ip_addr { + int af; /* AF_INET / AF_INET6 */ union { struct in_addr v4; #ifdef CONFIG_IPV6 struct in6_addr v6; #endif /* CONFIG_IPV6 */ + u8 max_len[16]; } u; - int af; /* AF_INET / AF_INET6 */ }; const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, diff --git a/src/utils/list.h b/src/utils/list.h new file mode 100644 index 000000000000..ed7c0227264f --- /dev/null +++ b/src/utils/list.h @@ -0,0 +1,89 @@ +/* + * Doubly-linked list + * Copyright (c) 2009, Jouni Malinen + * + * 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 LIST_H +#define LIST_H + +/** + * struct dl_list - Doubly-linked list + */ +struct dl_list { + struct dl_list *next; + struct dl_list *prev; +}; + +static inline void dl_list_init(struct dl_list *list) +{ + list->next = list; + list->prev = list; +} + +static inline void dl_list_add(struct dl_list *list, struct dl_list *item) +{ + item->next = list->next; + item->prev = list; + list->next->prev = item; + list->next = item; +} + +static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) +{ + dl_list_add(list->prev, item); +} + +static inline void dl_list_del(struct dl_list *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; + item->next = NULL; + item->prev = NULL; +} + +static inline int dl_list_empty(struct dl_list *list) +{ + return list->next == list; +} + +static inline unsigned int dl_list_len(struct dl_list *list) +{ + struct dl_list *item; + int count = 0; + for (item = list->next; item != list; item = item->next) + count++; + return count; +} + +#ifndef offsetof +#define offsetof(type, member) ((long) &((type *) 0)->member) +#endif + +#define dl_list_entry(item, type, member) \ + ((type *) ((char *) item - offsetof(type, member))) + +#define dl_list_first(list, type, member) \ + (dl_list_empty((list)) ? NULL : \ + dl_list_entry((list)->next, type, member)) + +#define dl_list_for_each(item, list, type, member) \ + for (item = dl_list_entry((list)->next, type, member); \ + &item->member != (list); \ + item = dl_list_entry(item->member.next, type, member)) + +#define dl_list_for_each_safe(item, n, list, type, member) \ + for (item = dl_list_entry((list)->next, type, member), \ + n = dl_list_entry(item->member.next, type, member); \ + &item->member != (list); \ + item = n, n = dl_list_entry(n->member.next, type, member)) + +#endif /* LIST_H */ diff --git a/src/utils/os.h b/src/utils/os.h index d6dfea682c2e..f4723d87525d 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -1,6 +1,6 @@ /* - * wpa_supplicant/hostapd / OS specific functions - * Copyright (c) 2005-2006, Jouni Malinen + * OS specific functions + * Copyright (c) 2005-2009, Jouni Malinen * * 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 @@ -379,6 +379,12 @@ int os_snprintf(char *str, size_t size, const char *format, ...); #else /* OS_NO_C_LIB_DEFINES */ +#ifdef WPA_TRACE +void * os_malloc(size_t size); +void * os_realloc(void *ptr, size_t size); +void os_free(void *ptr); +char * os_strdup(const char *s); +#else /* WPA_TRACE */ #ifndef os_malloc #define os_malloc(s) malloc((s)) #endif @@ -388,6 +394,14 @@ int os_snprintf(char *str, size_t size, const char *format, ...); #ifndef os_free #define os_free(p) free((p)) #endif +#ifndef os_strdup +#ifdef _MSC_VER +#define os_strdup(s) _strdup(s) +#else +#define os_strdup(s) strdup(s) +#endif +#endif +#endif /* WPA_TRACE */ #ifndef os_memcpy #define os_memcpy(d, s, n) memcpy((d), (s), (n)) @@ -402,13 +416,6 @@ int os_snprintf(char *str, size_t size, const char *format, ...); #define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) #endif -#ifndef os_strdup -#ifdef _MSC_VER -#define os_strdup(s) _strdup(s) -#else -#define os_strdup(s) strdup(s) -#endif -#endif #ifndef os_strlen #define os_strlen(s) strlen(s) #endif diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c index 7b74bbf4abc7..5260e232101f 100644 --- a/src/utils/os_internal.c +++ b/src/utils/os_internal.c @@ -206,7 +206,12 @@ char * os_readfile(const char *name, size_t *len) return NULL; } - fread(buf, 1, *len, f); + if (fread(buf, 1, *len, f) != *len) { + fclose(f); + os_free(buf); + return NULL; + } + fclose(f); return buf; diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index bc2fc40dd7eb..6f58fa46cf01 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -1,6 +1,6 @@ /* - * wpa_supplicant/hostapd / OS specific functions for UNIX/POSIX systems - * Copyright (c) 2005-2006, Jouni Malinen + * OS specific functions for UNIX/POSIX systems + * Copyright (c) 2005-2009, Jouni Malinen * * 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 @@ -16,6 +16,28 @@ #include "os.h" +#ifdef WPA_TRACE + +#include "common.h" +#include "list.h" +#include "wpa_debug.h" +#include "trace.h" + +static struct dl_list alloc_list; + +#define ALLOC_MAGIC 0xa84ef1b2 +#define FREED_MAGIC 0x67fd487a + +struct os_alloc_trace { + unsigned int magic; + struct dl_list list; + size_t len; + WPA_TRACE_INFO +}; + +#endif /* WPA_TRACE */ + + void os_sleep(os_time_t sec, os_time_t usec) { if (sec) @@ -172,16 +194,16 @@ char * os_rel2abs_path(const char *rel_path) int last_errno; if (rel_path[0] == '/') - return strdup(rel_path); + return os_strdup(rel_path); for (;;) { - buf = malloc(len); + buf = os_malloc(len); if (buf == NULL) return NULL; cwd = getcwd(buf, len); if (cwd == NULL) { last_errno = errno; - free(buf); + os_free(buf); if (last_errno != ERANGE) return NULL; len *= 2; @@ -193,29 +215,51 @@ char * os_rel2abs_path(const char *rel_path) } } - cwd_len = strlen(cwd); - rel_len = strlen(rel_path); + cwd_len = os_strlen(cwd); + rel_len = os_strlen(rel_path); ret_len = cwd_len + 1 + rel_len + 1; - ret = malloc(ret_len); + ret = os_malloc(ret_len); if (ret) { - memcpy(ret, cwd, cwd_len); + os_memcpy(ret, cwd, cwd_len); ret[cwd_len] = '/'; - memcpy(ret + cwd_len + 1, rel_path, rel_len); + os_memcpy(ret + cwd_len + 1, rel_path, rel_len); ret[ret_len - 1] = '\0'; } - free(buf); + os_free(buf); return ret; } int os_program_init(void) { +#ifdef WPA_TRACE + dl_list_init(&alloc_list); +#endif /* WPA_TRACE */ return 0; } void os_program_deinit(void) { +#ifdef WPA_TRACE + struct os_alloc_trace *a; + unsigned long total = 0; + dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { + total += a->len; + if (a->magic != ALLOC_MAGIC) { + wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " + "len %lu", + a, a->magic, (unsigned long) a->len); + continue; + } + wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", + a, (unsigned long) a->len); + wpa_trace_dump("memleak", a); + } + if (total) + wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", + (unsigned long) total); +#endif /* WPA_TRACE */ } @@ -250,7 +294,7 @@ char * os_readfile(const char *name, size_t *len) *len = ftell(f); fseek(f, 0, SEEK_SET); - buf = malloc(*len); + buf = os_malloc(*len); if (buf == NULL) { fclose(f); return NULL; @@ -258,7 +302,7 @@ char * os_readfile(const char *name, size_t *len) if (fread(buf, 1, *len, f) != *len) { fclose(f); - free(buf); + os_free(buf); return NULL; } @@ -268,10 +312,12 @@ char * os_readfile(const char *name, size_t *len) } +#ifndef WPA_TRACE void * os_zalloc(size_t size) { return calloc(1, size); } +#endif /* WPA_TRACE */ size_t os_strlcpy(char *dest, const char *src, size_t siz) @@ -297,3 +343,95 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz) return s - src - 1; } + + +#ifdef WPA_TRACE + +void * os_malloc(size_t size) +{ + struct os_alloc_trace *a; + a = malloc(sizeof(*a) + size); + if (a == NULL) + return NULL; + a->magic = ALLOC_MAGIC; + dl_list_add(&alloc_list, &a->list); + a->len = size; + wpa_trace_record(a); + return a + 1; +} + + +void * os_realloc(void *ptr, size_t size) +{ + struct os_alloc_trace *a; + size_t copy_len; + void *n; + + if (ptr == NULL) + return os_malloc(size); + + a = (struct os_alloc_trace *) ptr - 1; + if (a->magic != ALLOC_MAGIC) { + wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", + a, a->magic, + a->magic == FREED_MAGIC ? " (already freed)" : ""); + wpa_trace_show("Invalid os_realloc() call"); + abort(); + } + n = os_malloc(size); + if (n == NULL) + return NULL; + copy_len = a->len; + if (copy_len > size) + copy_len = size; + os_memcpy(n, a + 1, copy_len); + os_free(ptr); + return n; +} + + +void os_free(void *ptr) +{ + struct os_alloc_trace *a; + + if (ptr == NULL) + return; + a = (struct os_alloc_trace *) ptr - 1; + if (a->magic != ALLOC_MAGIC) { + wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", + a, a->magic, + a->magic == FREED_MAGIC ? " (already freed)" : ""); + wpa_trace_show("Invalid os_free() call"); + abort(); + } + dl_list_del(&a->list); + a->magic = FREED_MAGIC; + + wpa_trace_check_ref(ptr); + free(a); +} + + +void * os_zalloc(size_t size) +{ + void *ptr = os_malloc(size); + if (ptr) + os_memset(ptr, 0, size); + return ptr; +} + + +char * os_strdup(const char *s) +{ + size_t len; + char *d; + len = os_strlen(s); + d = os_malloc(len + 1); + if (d == NULL) + return NULL; + os_memcpy(d, s, len); + d[len] = '\0'; + return d; +} + +#endif /* WPA_TRACE */ diff --git a/hostapd/radiotap.c b/src/utils/radiotap.c similarity index 100% rename from hostapd/radiotap.c rename to src/utils/radiotap.c diff --git a/src/drivers/radiotap.h b/src/utils/radiotap.h similarity index 99% rename from src/drivers/radiotap.h rename to src/utils/radiotap.h index 508264c4cf33..ba23ed38e7a0 100644 --- a/src/drivers/radiotap.h +++ b/src/utils/radiotap.h @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ +/* $FreeBSD$ */ /* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ /*- diff --git a/hostapd/radiotap_iter.h b/src/utils/radiotap_iter.h similarity index 100% rename from hostapd/radiotap_iter.h rename to src/utils/radiotap_iter.h diff --git a/src/utils/trace.c b/src/utils/trace.c new file mode 100644 index 000000000000..bb3eb24d4c01 --- /dev/null +++ b/src/utils/trace.c @@ -0,0 +1,329 @@ +/* + * Backtrace debugging + * Copyright (c) 2009, Jouni Malinen + * + * 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 "trace.h" + +#ifdef WPA_TRACE + +static struct dl_list active_references = +{ &active_references, &active_references }; + +#ifdef WPA_TRACE_BFD +#include +#ifdef __linux__ +#include +#else /* __linux__ */ +#include +#endif /* __linux__ */ + +static char *prg_fname = NULL; +static bfd *cached_abfd = NULL; +static asymbol **syms = NULL; + +static void get_prg_fname(void) +{ + char exe[50], fname[512]; + int len; + os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid()); + len = readlink(exe, fname, sizeof(fname) - 1); + if (len < 0 || len >= (int) sizeof(fname)) { + perror("readlink"); + return; + } + fname[len] = '\0'; + prg_fname = strdup(fname); +} + + +static bfd * open_bfd(const char *fname) +{ + bfd *abfd; + char **matching; + + abfd = bfd_openr(prg_fname, NULL); + if (abfd == NULL) { + wpa_printf(MSG_INFO, "bfd_openr failed"); + return NULL; + } + + if (bfd_check_format(abfd, bfd_archive)) { + wpa_printf(MSG_INFO, "bfd_check_format failed"); + bfd_close(abfd); + return NULL; + } + + if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { + wpa_printf(MSG_INFO, "bfd_check_format_matches failed"); + free(matching); + bfd_close(abfd); + return NULL; + } + + return abfd; +} + + +static void read_syms(bfd *abfd) +{ + long storage, symcount; + bfd_boolean dynamic = FALSE; + + if (syms) + return; + + if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) { + wpa_printf(MSG_INFO, "No symbols"); + return; + } + + storage = bfd_get_symtab_upper_bound(abfd); + if (storage == 0) { + storage = bfd_get_dynamic_symtab_upper_bound(abfd); + dynamic = TRUE; + } + if (storage < 0) { + wpa_printf(MSG_INFO, "Unknown symtab upper bound"); + return; + } + + syms = malloc(storage); + if (syms == NULL) { + wpa_printf(MSG_INFO, "Failed to allocate memory for symtab " + "(%ld bytes)", storage); + return; + } + if (dynamic) + symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); + else + symcount = bfd_canonicalize_symtab(abfd, syms); + if (symcount < 0) { + wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab", + dynamic ? "dynamic " : ""); + free(syms); + syms = NULL; + return; + } +} + + +struct bfd_data { + bfd_vma pc; + bfd_boolean found; + const char *filename; + const char *function; + unsigned int line; +}; + + +static void find_addr_sect(bfd *abfd, asection *section, void *obj) +{ + struct bfd_data *data = obj; + bfd_vma vma; + bfd_size_type size; + + if (data->found) + return; + + if (!(bfd_get_section_vma(abfd, section))) + return; + + vma = bfd_get_section_vma(abfd, section); + if (data->pc < vma) + return; + + size = bfd_get_section_size(section); + if (data->pc >= vma + size) + return; + + data->found = bfd_find_nearest_line(abfd, section, syms, + data->pc - vma, + &data->filename, + &data->function, + &data->line); +} + + +static void wpa_trace_bfd_addr(void *pc) +{ + bfd *abfd = cached_abfd; + struct bfd_data data; + const char *name; + char *aname = NULL; + const char *filename; + + if (abfd == NULL) + return; + + data.pc = (bfd_vma) pc; + data.found = FALSE; + bfd_map_over_sections(abfd, find_addr_sect, &data); + + if (!data.found) + return; + + do { + if (data.function) + aname = bfd_demangle(abfd, data.function, + DMGL_ANSI | DMGL_PARAMS); + name = aname ? aname : data.function; + filename = data.filename; + if (filename) { + char *end = os_strrchr(filename, '/'); + int i = 0; + while (*filename && *filename == prg_fname[i] && + filename <= end) { + filename++; + i++; + } + } + wpa_printf(MSG_INFO, " %s() %s:%u", + name, filename, data.line); + free(aname); + + data.found = bfd_find_inliner_info(abfd, &data.filename, + &data.function, &data.line); + } while (data.found); +} + + +static const char * wpa_trace_bfd_addr2func(void *pc) +{ + bfd *abfd = cached_abfd; + struct bfd_data data; + + if (abfd == NULL) + return NULL; + + data.pc = (bfd_vma) pc; + data.found = FALSE; + bfd_map_over_sections(abfd, find_addr_sect, &data); + + if (!data.found) + return NULL; + + return data.function; +} + + +static void wpa_trace_bfd_init(void) +{ + if (!prg_fname) { + get_prg_fname(); + if (!prg_fname) + return; + } + + if (!cached_abfd) { + cached_abfd = open_bfd(prg_fname); + if (!cached_abfd) { + wpa_printf(MSG_INFO, "Failed to open bfd"); + return; + } + } + + read_syms(cached_abfd); + if (!syms) { + wpa_printf(MSG_INFO, "Failed to read symbols"); + return; + } +} + + +void wpa_trace_dump_funcname(const char *title, void *pc) +{ + wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc); + wpa_trace_bfd_init(); + wpa_trace_bfd_addr(pc); +} + +#else /* WPA_TRACE_BFD */ + +#define wpa_trace_bfd_init() do { } while (0) +#define wpa_trace_bfd_addr(pc) do { } while (0) +#define wpa_trace_bfd_addr2func(pc) NULL + +#endif /* WPA_TRACE_BFD */ + +void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num) +{ + char **sym; + int i; + enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state; + + wpa_trace_bfd_init(); + wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title); + sym = backtrace_symbols(btrace, btrace_num); + state = TRACE_HEAD; + for (i = 0; i < btrace_num; i++) { + const char *func = wpa_trace_bfd_addr2func(btrace[i]); + if (state == TRACE_HEAD && func && + (os_strcmp(func, "wpa_trace_add_ref_func") == 0 || + os_strcmp(func, "wpa_trace_check_ref") == 0 || + os_strcmp(func, "wpa_trace_show") == 0)) + continue; + if (state == TRACE_TAIL && sym && sym[i] && + os_strstr(sym[i], "__libc_start_main")) + break; + if (state == TRACE_HEAD) + state = TRACE_RELEVANT; + if (sym) + wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]); + else + wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]); + wpa_trace_bfd_addr(btrace[i]); + if (state == TRACE_RELEVANT && func && + os_strcmp(func, "main") == 0) + state = TRACE_TAIL; + } + free(sym); + wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title); +} + + +void wpa_trace_show(const char *title) +{ + struct info { + WPA_TRACE_INFO + } info; + wpa_trace_record(&info); + wpa_trace_dump(title, &info); +} + + +void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr) +{ + if (addr == NULL) + return; + ref->addr = addr; + wpa_trace_record(ref); + dl_list_add(&active_references, &ref->list); +} + + +void wpa_trace_check_ref(const void *addr) +{ + struct wpa_trace_ref *ref; + dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) { + if (addr != ref->addr) + continue; + wpa_trace_show("Freeing referenced memory"); + wpa_trace_dump("Reference registration", ref); + abort(); + } +} + +#endif /* WPA_TRACE */ diff --git a/src/utils/trace.h b/src/utils/trace.h new file mode 100644 index 000000000000..22d3de035acb --- /dev/null +++ b/src/utils/trace.h @@ -0,0 +1,74 @@ +/* + * Backtrace debugging + * Copyright (c) 2009, Jouni Malinen + * + * 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 TRACE_H +#define TRACE_H + +#define WPA_TRACE_LEN 16 + +#ifdef WPA_TRACE +#include + +#include "list.h" + +#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num; + +struct wpa_trace_ref { + struct dl_list list; + const void *addr; + WPA_TRACE_INFO +}; +#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name + +#define wpa_trace_dump(title, ptr) \ + wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num) +void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num); +#define wpa_trace_record(ptr) \ + (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN) +void wpa_trace_show(const char *title); +#define wpa_trace_add_ref(ptr, name, addr) \ + wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr)) +void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr); +#define wpa_trace_remove_ref(ptr, name, addr) \ + do { \ + if ((addr)) \ + dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \ + } while (0) +void wpa_trace_check_ref(const void *addr); + +#else /* WPA_TRACE */ + +#define WPA_TRACE_INFO +#define WPA_TRACE_REF(n) +#define wpa_trace_dump(title, ptr) do { } while (0) +#define wpa_trace_record(ptr) do { } while (0) +#define wpa_trace_show(title) do { } while (0) +#define wpa_trace_add_ref(ptr, name, addr) do { } while (0) +#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0) +#define wpa_trace_check_ref(addr) do { } while (0) + +#endif /* WPA_TRACE */ + + +#ifdef WPA_TRACE_BFD + +void wpa_trace_dump_funcname(const char *title, void *pc); + +#else /* WPA_TRACE_BFD */ + +#define wpa_trace_dump_funcname(title, pc) do { } while (0) + +#endif /* WPA_TRACE_BFD */ + +#endif /* TRACE_H */ diff --git a/src/utils/uuid.c b/src/utils/uuid.c index 620d3d610cd8..d8cc26754b39 100644 --- a/src/utils/uuid.c +++ b/src/utils/uuid.c @@ -15,8 +15,6 @@ #include "includes.h" #include "common.h" -#include "crypto.h" -#include "sha1.h" #include "uuid.h" int uuid_str2bin(const char *str, u8 *bin) @@ -77,31 +75,3 @@ int is_nil_uuid(const u8 *uuid) return 0; return 1; } - - -void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid) -{ - const u8 *addr[2]; - size_t len[2]; - u8 hash[SHA1_MAC_LEN]; - u8 nsid[16] = { - 0x52, 0x64, 0x80, 0xf8, - 0xc9, 0x9b, - 0x4b, 0xe5, - 0xa6, 0x55, - 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 - }; - - addr[0] = nsid; - len[0] = sizeof(nsid); - addr[1] = mac_addr; - len[1] = 6; - sha1_vector(2, addr, len, hash); - os_memcpy(uuid, hash, 16); - - /* Version: 5 = named-based version using SHA-1 */ - uuid[6] = (5 << 4) | (uuid[6] & 0x0f); - - /* Variant specified in RFC 4122 */ - uuid[8] = 0x80 | (uuid[8] & 0x3f); -} diff --git a/src/utils/uuid.h b/src/utils/uuid.h index 9fc2ba06822f..075916525357 100644 --- a/src/utils/uuid.h +++ b/src/utils/uuid.h @@ -20,6 +20,5 @@ int uuid_str2bin(const char *str, u8 *bin); int uuid_bin2str(const u8 *bin, char *str, size_t max_len); int is_nil_uuid(const u8 *uuid); -void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid); #endif /* UUID_H */ diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 4dd073230d57..6f6fc69ccc44 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -16,6 +16,12 @@ #include "common.h" +#ifdef CONFIG_DEBUG_SYSLOG +#include + +static int wpa_debug_syslog = 0; +#endif /* CONFIG_DEBUG_SYSLOG */ + #ifdef CONFIG_DEBUG_FILE static FILE *out_file = NULL; @@ -45,6 +51,39 @@ void wpa_debug_print_timestamp(void) } +#ifdef CONFIG_DEBUG_SYSLOG +void wpa_debug_open_syslog(void) +{ + openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_DAEMON); + wpa_debug_syslog++; +} + + +void wpa_debug_close_syslog(void) +{ + if (wpa_debug_syslog) + closelog(); +} + + +static int syslog_priority(int level) +{ + switch (level) { + case MSG_MSGDUMP: + case MSG_DEBUG: + return LOG_DEBUG; + case MSG_INFO: + return LOG_NOTICE; + case MSG_WARNING: + return LOG_WARNING; + case MSG_ERROR: + return LOG_ERR; + } + return LOG_INFO; +} +#endif /* CONFIG_DEBUG_SYSLOG */ + + /** * wpa_printf - conditional printf * @level: priority level (MSG_*) of the message @@ -62,6 +101,11 @@ void wpa_printf(int level, const char *fmt, ...) va_start(ap, fmt); if (level >= wpa_debug_level) { +#ifdef CONFIG_DEBUG_SYSLOG + if (wpa_debug_syslog) { + vsyslog(syslog_priority(level), fmt, ap); + } else { +#endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE if (out_file) { @@ -74,6 +118,9 @@ void wpa_printf(int level, const char *fmt, ...) #ifdef CONFIG_DEBUG_FILE } #endif /* CONFIG_DEBUG_FILE */ +#ifdef CONFIG_DEBUG_SYSLOG + } +#endif /* CONFIG_DEBUG_SYSLOG */ } va_end(ap); } @@ -343,6 +390,9 @@ void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, va_end(ap); if (hostapd_logger_cb) hostapd_logger_cb(ctx, addr, module, level, buf, len); + else if (addr) + wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", + MAC2STR(addr), buf); else wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); os_free(buf); diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index b4010d542760..6e5e79e281c4 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -221,6 +221,23 @@ enum hostapd_logger_level { }; +#ifdef CONFIG_DEBUG_SYSLOG + +void wpa_debug_open_syslog(void); +void wpa_debug_close_syslog(void); + +#else /* CONFIG_DEBUG_SYSLOG */ + +static inline void wpa_debug_open_syslog(void) +{ +} + +static inline void wpa_debug_close_syslog(void) +{ +} + +#endif /* CONFIG_DEBUG_SYSLOG */ + #ifdef EAPOL_TEST #define WPA_ASSERT(a) \ diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c index 8181912ea9f7..eda779eaff4f 100644 --- a/src/utils/wpabuf.c +++ b/src/utils/wpabuf.c @@ -15,13 +15,37 @@ #include "includes.h" #include "common.h" +#include "trace.h" #include "wpabuf.h" +#ifdef WPA_TRACE +#define WPABUF_MAGIC 0x51a974e3 + +struct wpabuf_trace { + unsigned int magic; +}; + +static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) +{ + return (struct wpabuf_trace *) + ((const u8 *) buf - sizeof(struct wpabuf_trace)); +} +#endif /* WPA_TRACE */ + + static void wpabuf_overflow(const struct wpabuf *buf, size_t len) { +#ifdef WPA_TRACE + struct wpabuf_trace *trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", + trace->magic); + } +#endif /* WPA_TRACE */ wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", buf, (unsigned long) buf->size, (unsigned long) buf->used, (unsigned long) len); + wpa_trace_show("wpabuf overflow"); abort(); } @@ -29,10 +53,25 @@ static void wpabuf_overflow(const struct wpabuf *buf, size_t len) int wpabuf_resize(struct wpabuf **_buf, size_t add_len) { struct wpabuf *buf = *_buf; +#ifdef WPA_TRACE + struct wpabuf_trace *trace; +#endif /* WPA_TRACE */ + if (buf == NULL) { *_buf = wpabuf_alloc(add_len); return *_buf == NULL ? -1 : 0; } + +#ifdef WPA_TRACE + trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", + trace->magic); + wpa_trace_show("wpabuf_resize invalid magic"); + abort(); + } +#endif /* WPA_TRACE */ + if (buf->used + add_len > buf->size) { unsigned char *nbuf; if (buf->ext_data) { @@ -42,6 +81,18 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len) os_memset(nbuf + buf->used, 0, add_len); buf->ext_data = nbuf; } else { +#ifdef WPA_TRACE + nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + + buf->used + add_len); + if (nbuf == NULL) + return -1; + trace = (struct wpabuf_trace *) nbuf; + buf = (struct wpabuf *) (trace + 1); + os_memset(nbuf + sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + buf->used, 0, + add_len); +#else /* WPA_TRACE */ nbuf = os_realloc(buf, sizeof(struct wpabuf) + buf->used + add_len); if (nbuf == NULL) @@ -49,6 +100,7 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len) buf = (struct wpabuf *) nbuf; os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, add_len); +#endif /* WPA_TRACE */ *_buf = buf; } buf->size = buf->used + add_len; @@ -65,9 +117,20 @@ int wpabuf_resize(struct wpabuf **_buf, size_t add_len) */ struct wpabuf * wpabuf_alloc(size_t len) { +#ifdef WPA_TRACE + struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + len); + struct wpabuf *buf; + if (trace == NULL) + return NULL; + trace->magic = WPABUF_MAGIC; + buf = (struct wpabuf *) (trace + 1); +#else /* WPA_TRACE */ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); if (buf == NULL) return NULL; +#endif /* WPA_TRACE */ + buf->size = len; return buf; } @@ -75,9 +138,19 @@ struct wpabuf * wpabuf_alloc(size_t len) struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) { +#ifdef WPA_TRACE + struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf)); + struct wpabuf *buf; + if (trace == NULL) + return NULL; + trace->magic = WPABUF_MAGIC; + buf = (struct wpabuf *) (trace + 1); +#else /* WPA_TRACE */ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); if (buf == NULL) return NULL; +#endif /* WPA_TRACE */ buf->size = len; buf->used = len; @@ -111,10 +184,25 @@ struct wpabuf * wpabuf_dup(const struct wpabuf *src) */ void wpabuf_free(struct wpabuf *buf) { +#ifdef WPA_TRACE + struct wpabuf_trace *trace; + if (buf == NULL) + return; + trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", + trace->magic); + wpa_trace_show("wpabuf_free magic mismatch"); + abort(); + } + os_free(buf->ext_data); + os_free(trace); +#else /* WPA_TRACE */ if (buf == NULL) return; os_free(buf->ext_data); os_free(buf); +#endif /* WPA_TRACE */ } diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h index bd8f09e94f84..a150455a5a65 100644 --- a/src/utils/wpabuf.h +++ b/src/utils/wpabuf.h @@ -111,6 +111,12 @@ static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) *pos = data; } +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_LE16(pos, data); +} + static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) { u8 *pos = wpabuf_put(buf, 2); diff --git a/src/wps/Makefile b/src/wps/Makefile index cffba620da04..9c41962fd7e1 100644 --- a/src/wps/Makefile +++ b/src/wps/Makefile @@ -2,7 +2,6 @@ all: @echo Nothing to be made. clean: - for d in $(SUBDIRS); do make -C $$d clean; done rm -f *~ *.o *.d install: diff --git a/src/wps/http.h b/src/wps/http.h new file mode 100644 index 000000000000..2fee3a8f87a6 --- /dev/null +++ b/src/wps/http.h @@ -0,0 +1,29 @@ +/* + * HTTP for WPS + * Copyright (c) 2000-2003 Intel Corporation + * Copyright (c) 2006-2007 Sony Corporation + * Copyright (c) 2008-2009 Atheros Communications + * Copyright (c) 2009, Jouni Malinen + * + * See wps_upnp.c for more details on licensing and code history. + */ + +#ifndef HTTP_H +#define HTTP_H + +enum http_reply_code { + HTTP_OK = 200, + HTTP_BAD_REQUEST = 400, + UPNP_INVALID_ACTION = 401, + UPNP_INVALID_ARGS = 402, + HTTP_NOT_FOUND = 404, + HTTP_PRECONDITION_FAILED = 412, + HTTP_INTERNAL_SERVER_ERROR = 500, + HTTP_UNIMPLEMENTED = 501, + UPNP_ACTION_FAILED = 501, + UPNP_ARG_VALUE_INVALID = 600, + UPNP_ARG_VALUE_OUT_OF_RANGE = 601, + UPNP_OUT_OF_MEMORY = 603 +}; + +#endif /* HTTP_H */ diff --git a/src/wps/http_client.c b/src/wps/http_client.c new file mode 100644 index 000000000000..fea2a04ea973 --- /dev/null +++ b/src/wps/http_client.c @@ -0,0 +1,371 @@ +/* + * http_client - HTTP client + * Copyright (c) 2009, Jouni Malinen + * + * 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 + +#include "common.h" +#include "eloop.h" +#include "httpread.h" +#include "http_client.h" + + +#define HTTP_CLIENT_TIMEOUT 30 + + +struct http_client { + struct sockaddr_in dst; + int sd; + struct wpabuf *req; + size_t req_pos; + size_t max_response; + + void (*cb)(void *ctx, struct http_client *c, + enum http_client_event event); + void *cb_ctx; + struct httpread *hread; + struct wpabuf body; +}; + + +static void http_client_timeout(void *eloop_data, void *user_ctx) +{ + struct http_client *c = eloop_data; + wpa_printf(MSG_DEBUG, "HTTP: Timeout"); + c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); +} + + +static void http_client_got_response(struct httpread *handle, void *cookie, + enum httpread_event e) +{ + struct http_client *c = cookie; + + eloop_cancel_timeout(http_client_timeout, c, NULL); + switch (e) { + case HTTPREAD_EVENT_FILE_READY: + if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY) + { + int reply_code = httpread_reply_code_get(c->hread); + if (reply_code == 200 /* OK */) { + wpa_printf(MSG_DEBUG, "HTTP: Response OK from " + "%s:%d", + inet_ntoa(c->dst.sin_addr), + ntohs(c->dst.sin_port)); + c->cb(c->cb_ctx, c, HTTP_CLIENT_OK); + } else { + wpa_printf(MSG_DEBUG, "HTTP: Error %d from " + "%s:%d", reply_code, + inet_ntoa(c->dst.sin_addr), + ntohs(c->dst.sin_port)); + c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); + } + } else + c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); + break; + case HTTPREAD_EVENT_TIMEOUT: + c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); + break; + case HTTPREAD_EVENT_ERROR: + c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); + break; + } +} + + +static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct http_client *c = eloop_ctx; + int res; + + wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu " + "bytes remaining)", + inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port), + (unsigned long) wpabuf_len(c->req), + (unsigned long) wpabuf_len(c->req) - c->req_pos); + + res = send(c->sd, wpabuf_head(c->req) + c->req_pos, + wpabuf_len(c->req) - c->req_pos, 0); + if (res < 0) { + wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s", + strerror(errno)); + eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); + c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); + return; + } + + if ((size_t) res < wpabuf_len(c->req) - c->req_pos) { + wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes " + "remaining", + res, (unsigned long) wpabuf_len(c->req), + (unsigned long) wpabuf_len(c->req) - c->req_pos - + res); + c->req_pos += res; + return; + } + + wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d", + inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port)); + eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); + wpabuf_free(c->req); + c->req = NULL; + + c->hread = httpread_create(c->sd, http_client_got_response, c, + c->max_response, HTTP_CLIENT_TIMEOUT); + if (c->hread == NULL) { + c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); + return; + } +} + + +struct http_client * http_client_addr(struct sockaddr_in *dst, + struct wpabuf *req, size_t max_response, + void (*cb)(void *ctx, + struct http_client *c, + enum http_client_event event), + void *cb_ctx) +{ + struct http_client *c; + + c = os_zalloc(sizeof(*c)); + if (c == NULL) + return NULL; + c->sd = -1; + c->dst = *dst; + c->max_response = max_response; + c->cb = cb; + c->cb_ctx = cb_ctx; + + c->sd = socket(AF_INET, SOCK_STREAM, 0); + if (c->sd < 0) { + http_client_free(c); + return NULL; + } + + if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) { + wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + http_client_free(c); + return NULL; + } + + if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) { + if (errno != EINPROGRESS) { + wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s", + strerror(errno)); + http_client_free(c); + return NULL; + } + + /* + * Continue connecting in the background; eloop will call us + * once the connection is ready (or failed). + */ + } + + if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready, + c, NULL)) { + http_client_free(c); + return NULL; + } + + if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT, 0, http_client_timeout, + c, NULL)) { + http_client_free(c); + return NULL; + } + + c->req = req; + + return c; +} + + +char * http_client_url_parse(const char *url, struct sockaddr_in *dst, + char **ret_path) +{ + char *u, *addr, *port, *path; + + u = os_strdup(url); + if (u == NULL) + return NULL; + + os_memset(dst, 0, sizeof(*dst)); + dst->sin_family = AF_INET; + addr = u + 7; + path = os_strchr(addr, '/'); + port = os_strchr(addr, ':'); + if (path == NULL) { + path = "/"; + } else { + *path = '\0'; /* temporary nul termination for address */ + if (port > path) + port = NULL; + } + if (port) + *port++ = '\0'; + + if (inet_aton(addr, &dst->sin_addr) == 0) { + /* TODO: name lookup */ + wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' " + "(addr='%s' port='%s')", + url, addr, port); + os_free(u); + return NULL; + } + + if (port) + dst->sin_port = htons(atoi(port)); + else + dst->sin_port = htons(80); + + if (*path == '\0') { + /* remove temporary nul termination for address */ + *path = '/'; + } + + *ret_path = path; + + return u; +} + + +struct http_client * http_client_url(const char *url, + struct wpabuf *req, size_t max_response, + void (*cb)(void *ctx, + struct http_client *c, + enum http_client_event event), + void *cb_ctx) +{ + struct sockaddr_in dst; + struct http_client *c; + char *u, *path; + struct wpabuf *req_buf = NULL; + + if (os_strncmp(url, "http://", 7) != 0) + return NULL; + u = http_client_url_parse(url, &dst, &path); + if (u == NULL) + return NULL; + + if (req == NULL) { + req_buf = wpabuf_alloc(os_strlen(url) + 1000); + if (req_buf == NULL) { + os_free(u); + return NULL; + } + req = req_buf; + wpabuf_printf(req, + "GET %s HTTP/1.1\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n" + "Accept: text/xml, application/xml\r\n" + "User-Agent: wpa_supplicant\r\n" + "Host: %s:%d\r\n" + "\r\n", + path, inet_ntoa(dst.sin_addr), + ntohs(dst.sin_port)); + } + os_free(u); + + c = http_client_addr(&dst, req, max_response, cb, cb_ctx); + if (c == NULL) { + wpabuf_free(req_buf); + return NULL; + } + + return c; +} + + +void http_client_free(struct http_client *c) +{ + if (c == NULL) + return; + httpread_destroy(c->hread); + wpabuf_free(c->req); + if (c->sd >= 0) { + eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); + close(c->sd); + } + eloop_cancel_timeout(http_client_timeout, c, NULL); + os_free(c); +} + + +struct wpabuf * http_client_get_body(struct http_client *c) +{ + if (c->hread == NULL) + return NULL; + wpabuf_set(&c->body, httpread_data_get(c->hread), + httpread_length_get(c->hread)); + return &c->body; +} + + +char * http_client_get_hdr_line(struct http_client *c, const char *tag) +{ + if (c->hread == NULL) + return NULL; + return httpread_hdr_line_get(c->hread, tag); +} + + +char * http_link_update(char *url, const char *base) +{ + char *n; + size_t len; + const char *pos; + + /* RFC 2396, Chapter 5.2 */ + /* TODO: consider adding all cases described in RFC 2396 */ + + if (url == NULL) + return NULL; + + if (os_strncmp(url, "http://", 7) == 0) + return url; /* absolute link */ + + if (os_strncmp(base, "http://", 7) != 0) + return url; /* unable to handle base URL */ + + len = os_strlen(url) + 1 + os_strlen(base) + 1; + n = os_malloc(len); + if (n == NULL) + return url; /* failed */ + + if (url[0] == '/') { + pos = os_strchr(base + 7, '/'); + if (pos == NULL) { + os_snprintf(n, len, "%s%s", base, url); + } else { + os_memcpy(n, base, pos - base); + os_memcpy(n + (pos - base), url, os_strlen(url) + 1); + } + } else { + pos = os_strrchr(base + 7, '/'); + if (pos == NULL) { + os_snprintf(n, len, "%s/%s", base, url); + } else { + os_memcpy(n, base, pos - base + 1); + os_memcpy(n + (pos - base) + 1, url, os_strlen(url) + + 1); + } + } + + os_free(url); + + return n; +} diff --git a/src/wps/http_client.h b/src/wps/http_client.h new file mode 100644 index 000000000000..924d6ab4a2a4 --- /dev/null +++ b/src/wps/http_client.h @@ -0,0 +1,46 @@ +/* + * http_client - HTTP client + * Copyright (c) 2009, Jouni Malinen + * + * 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 HTTP_CLIENT_H +#define HTTP_CLIENT_H + +struct http_client; + +enum http_client_event { + HTTP_CLIENT_FAILED, + HTTP_CLIENT_TIMEOUT, + HTTP_CLIENT_OK, + HTTP_CLIENT_INVALID_REPLY, +}; + +char * http_client_url_parse(const char *url, struct sockaddr_in *dst, + char **path); +struct http_client * http_client_addr(struct sockaddr_in *dst, + struct wpabuf *req, size_t max_response, + void (*cb)(void *ctx, + struct http_client *c, + enum http_client_event event), + void *cb_ctx); +struct http_client * http_client_url(const char *url, + struct wpabuf *req, size_t max_response, + void (*cb)(void *ctx, + struct http_client *c, + enum http_client_event event), + void *cb_ctx); +void http_client_free(struct http_client *c); +struct wpabuf * http_client_get_body(struct http_client *c); +char * http_client_get_hdr_line(struct http_client *c, const char *tag); +char * http_link_update(char *url, const char *base); + +#endif /* HTTP_CLIENT_H */ diff --git a/src/wps/http_server.c b/src/wps/http_server.c new file mode 100644 index 000000000000..356f599abe05 --- /dev/null +++ b/src/wps/http_server.c @@ -0,0 +1,312 @@ +/* + * http_server - HTTP server + * Copyright (c) 2009, Jouni Malinen + * + * 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 + +#include "common.h" +#include "eloop.h" +#include "httpread.h" +#include "http_server.h" + +#define HTTP_SERVER_TIMEOUT 30 +#define HTTP_SERVER_MAX_REQ_LEN 8000 +#define HTTP_SERVER_MAX_CONNECTIONS 10 + +struct http_request { + struct http_request *next; + struct http_server *srv; + int fd; + struct sockaddr_in cli; + struct httpread *hread; +}; + +struct http_server { + void (*cb)(void *ctx, struct http_request *req); + void *cb_ctx; + + int fd; + int port; + + struct http_request *requests; + unsigned int request_count; +}; + + +static void http_request_cb(struct httpread *handle, void *cookie, + enum httpread_event en) +{ + struct http_request *req = cookie; + struct http_server *srv = req->srv; + + if (en == HTTPREAD_EVENT_FILE_READY) { + wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received", + inet_ntoa(req->cli.sin_addr), + ntohs(req->cli.sin_port)); + srv->cb(srv->cb_ctx, req); + return; + } + wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received " + "completely", inet_ntoa(req->cli.sin_addr), + ntohs(req->cli.sin_port)); + http_request_deinit(req); +} + + +static struct http_request * http_request_init(struct http_server *srv, int fd, + struct sockaddr_in *cli) +{ + struct http_request *req; + + if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) { + wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests"); + return NULL; + } + + req = os_zalloc(sizeof(*req)); + if (req == NULL) + return NULL; + + req->srv = srv; + req->fd = fd; + req->cli = *cli; + + req->hread = httpread_create(req->fd, http_request_cb, req, + HTTP_SERVER_MAX_REQ_LEN, + HTTP_SERVER_TIMEOUT); + if (req->hread == NULL) { + http_request_deinit(req); + return NULL; + } + + return req; +} + + +void http_request_deinit(struct http_request *req) +{ + struct http_request *r, *p; + struct http_server *srv; + + if (req == NULL) + return; + + srv = req->srv; + p = NULL; + r = srv->requests; + while (r) { + if (r == req) { + if (p) + p->next = r->next; + else + srv->requests = r->next; + srv->request_count--; + break; + } + p = r; + r = r->next; + } + + httpread_destroy(req->hread); + close(req->fd); + os_free(req); +} + + +static void http_request_free_all(struct http_request *req) +{ + struct http_request *prev; + while (req) { + prev = req; + req = req->next; + http_request_deinit(prev); + } +} + + +void http_request_send(struct http_request *req, struct wpabuf *resp) +{ + int res; + + wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d", + (unsigned long) wpabuf_len(resp), + inet_ntoa(req->cli.sin_addr), + ntohs(req->cli.sin_port)); + + res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0); + if (res < 0) { + wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s", + strerror(errno)); + } else if ((size_t) res < wpabuf_len(resp)) { + wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes", + res, (unsigned long) wpabuf_len(resp)); + /* TODO: add eloop handler for sending rest of the data */ + } + + wpabuf_free(resp); +} + + +void http_request_send_and_deinit(struct http_request *req, + struct wpabuf *resp) +{ + http_request_send(req, resp); + http_request_deinit(req); +} + + +enum httpread_hdr_type http_request_get_type(struct http_request *req) +{ + return httpread_hdr_type_get(req->hread); +} + + +char * http_request_get_uri(struct http_request *req) +{ + return httpread_uri_get(req->hread); +} + + +char * http_request_get_hdr(struct http_request *req) +{ + return httpread_hdr_get(req->hread); +} + + +char * http_request_get_data(struct http_request *req) +{ + return httpread_data_get(req->hread); +} + + +char * http_request_get_hdr_line(struct http_request *req, const char *tag) +{ + return httpread_hdr_line_get(req->hread, tag); +} + + +struct sockaddr_in * http_request_get_cli_addr(struct http_request *req) +{ + return &req->cli; +} + + +static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx) +{ + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + struct http_server *srv = eloop_ctx; + int conn; + struct http_request *req; + + conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len); + if (conn < 0) { + wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: " + "%s", strerror(errno)); + return; + } + wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d", + inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + req = http_request_init(srv, conn, &addr); + if (req == NULL) { + close(conn); + return; + } + + req->next = srv->requests; + srv->requests = req; + srv->request_count++; +} + + +struct http_server * http_server_init(struct in_addr *addr, int port, + void (*cb)(void *ctx, + struct http_request *req), + void *cb_ctx) +{ + struct sockaddr_in sin; + struct http_server *srv; + + srv = os_zalloc(sizeof(*srv)); + if (srv == NULL) + return NULL; + srv->cb = cb; + srv->cb_ctx = cb_ctx; + + srv->fd = socket(AF_INET, SOCK_STREAM, 0); + if (srv->fd < 0) + goto fail; + if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) + goto fail; + if (port < 0) + srv->port = 49152; + else + srv->port = port; + + os_memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = addr->s_addr; + + for (;;) { + sin.sin_port = htons(srv->port); + if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0) + break; + if (errno == EADDRINUSE) { + /* search for unused port */ + if (++srv->port == 65535 || port >= 0) + goto fail; + continue; + } + wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: " + "%s", srv->port, strerror(errno)); + goto fail; + } + if (listen(srv->fd, 10 /* max backlog */) < 0) + goto fail; + if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) + goto fail; + if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb, + srv, NULL)) + goto fail; + + wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d", + inet_ntoa(*addr), srv->port); + + return srv; + +fail: + http_server_deinit(srv); + return NULL; +} + + +void http_server_deinit(struct http_server *srv) +{ + if (srv == NULL) + return; + if (srv->fd >= 0) { + eloop_unregister_sock(srv->fd, EVENT_TYPE_READ); + close(srv->fd); + } + http_request_free_all(srv->requests); + + os_free(srv); +} + + +int http_server_get_port(struct http_server *srv) +{ + return srv->port; +} diff --git a/src/wps/http_server.h b/src/wps/http_server.h new file mode 100644 index 000000000000..219941c5ab5a --- /dev/null +++ b/src/wps/http_server.h @@ -0,0 +1,39 @@ +/* + * http_server - HTTP server + * Copyright (c) 2009, Jouni Malinen + * + * 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 HTTP_SERVER_H +#define HTTP_SERVER_H + +struct http_server; +struct http_request; + +void http_request_deinit(struct http_request *req); +void http_request_send(struct http_request *req, struct wpabuf *resp); +void http_request_send_and_deinit(struct http_request *req, + struct wpabuf *resp); +enum httpread_hdr_type http_request_get_type(struct http_request *req); +char * http_request_get_uri(struct http_request *req); +char * http_request_get_hdr(struct http_request *req); +char * http_request_get_data(struct http_request *req); +char * http_request_get_hdr_line(struct http_request *req, const char *tag); +struct sockaddr_in * http_request_get_cli_addr(struct http_request *req); + +struct http_server * http_server_init(struct in_addr *addr, int port, + void (*cb)(void *ctx, + struct http_request *req), + void *cb_ctx); +void http_server_deinit(struct http_server *srv); +int http_server_get_port(struct http_server *srv); + +#endif /* HTTP_SERVER_H */ diff --git a/src/wps/httpread.c b/src/wps/httpread.c index 0d7165e9c227..40422e4651d3 100644 --- a/src/wps/httpread.c +++ b/src/wps/httpread.c @@ -1,4 +1,4 @@ -/** +/* * httpread - Manage reading file(s) from HTTP/TCP socket * Author: Ted Merrill * Copyright 2008 Atheros Communications diff --git a/src/wps/httpread.h b/src/wps/httpread.h index fb1ecb7de36c..51aa21494665 100644 --- a/src/wps/httpread.h +++ b/src/wps/httpread.h @@ -1,4 +1,4 @@ -/** +/* * httpread - Manage reading file(s) from HTTP/TCP socket * Author: Ted Merrill * Copyright 2008 Atheros Communications diff --git a/src/wps/ndef.c b/src/wps/ndef.c new file mode 100644 index 000000000000..9baec7f4b27c --- /dev/null +++ b/src/wps/ndef.c @@ -0,0 +1,175 @@ +/* + * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup + * Reference is "NFCForum-TS-NDEF_1.0 2006-07-24". + * Copyright (c) 2009, Masashi Honma + * + * 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 "wps/wps.h" +#include "wps/wps_i.h" + +#define FLAG_MESSAGE_BEGIN (1 << 7) +#define FLAG_MESSAGE_END (1 << 6) +#define FLAG_CHUNK (1 << 5) +#define FLAG_SHORT_RECORD (1 << 4) +#define FLAG_ID_LENGTH_PRESENT (1 << 3) +#define FLAG_TNF_RFC2046 (0x02) + +struct ndef_record { + u8 *type; + u8 *id; + u8 *payload; + u8 type_length; + u8 id_length; + u32 payload_length; + u32 total_length; +}; + +static char wifi_handover_type[] = "application/vnd.wfa.wsc"; + +static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record) +{ + u8 *pos = data + 1; + + if (size < 2) + return -1; + record->type_length = *pos++; + if (data[0] & FLAG_SHORT_RECORD) { + if (size < 3) + return -1; + record->payload_length = *pos++; + } else { + if (size < 6) + return -1; + record->payload_length = ntohl(*(u32 *)pos); + pos += sizeof(u32); + } + + if (data[0] & FLAG_ID_LENGTH_PRESENT) { + if ((int) size < pos - data + 1) + return -1; + record->id_length = *pos++; + } else + record->id_length = 0; + + record->type = record->type_length == 0 ? NULL : pos; + pos += record->type_length; + + record->id = record->id_length == 0 ? NULL : pos; + pos += record->id_length; + + record->payload = record->payload_length == 0 ? NULL : pos; + pos += record->payload_length; + + record->total_length = pos - data; + if (record->total_length > size) + return -1; + return 0; +} + + +static struct wpabuf * ndef_parse_records(struct wpabuf *buf, + int (*filter)(struct ndef_record *)) +{ + struct ndef_record record; + int len = wpabuf_len(buf); + u8 *data = wpabuf_mhead(buf); + + while (len > 0) { + if (ndef_parse_record(data, len, &record) < 0) { + wpa_printf(MSG_ERROR, "NDEF : Failed to parse"); + return NULL; + } + if (filter == NULL || filter(&record)) + return wpabuf_alloc_copy(record.payload, + record.payload_length); + data += record.total_length; + len -= record.total_length; + } + wpa_printf(MSG_ERROR, "NDEF : Record not found"); + return NULL; +} + + +static struct wpabuf * ndef_build_record(u8 flags, void *type, + u8 type_length, void *id, + u8 id_length, void *payload, + u32 payload_length) +{ + struct wpabuf *record; + size_t total_len; + int short_record; + u8 local_flag; + + short_record = payload_length < 256 ? 1 : 0; + + total_len = 2; /* flag + type length */ + /* payload length */ + total_len += short_record ? sizeof(u8) : sizeof(u32); + if (id_length > 0) + total_len += 1; + total_len += type_length + id_length + payload_length; + record = wpabuf_alloc(total_len); + if (record == NULL) { + wpa_printf(MSG_ERROR, "NDEF : Failed to allocate " + "record for build"); + return NULL; + } + + local_flag = flags; + if (id_length > 0) + local_flag |= FLAG_ID_LENGTH_PRESENT; + if (short_record) + local_flag |= FLAG_SHORT_RECORD; + wpabuf_put_u8(record, local_flag); + + wpabuf_put_u8(record, type_length); + + if (short_record) + wpabuf_put_u8(record, payload_length); + else + wpabuf_put_be32(record, payload_length); + + if (id_length > 0) + wpabuf_put_u8(record, id_length); + wpabuf_put_data(record, type, type_length); + wpabuf_put_data(record, id, id_length); + wpabuf_put_data(record, payload, payload_length); + return record; +} + + +static int wifi_filter(struct ndef_record *record) +{ + if (record->type_length != os_strlen(wifi_handover_type)) + return 0; + if (os_memcmp(record->type, wifi_handover_type, + os_strlen(wifi_handover_type)) != 0) + return 0; + return 1; +} + + +struct wpabuf * ndef_parse_wifi(struct wpabuf *buf) +{ + return ndef_parse_records(buf, wifi_filter); +} + + +struct wpabuf * ndef_build_wifi(struct wpabuf *buf) +{ + return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END | + FLAG_TNF_RFC2046, wifi_handover_type, + os_strlen(wifi_handover_type), NULL, 0, + wpabuf_mhead(buf), wpabuf_len(buf)); +} diff --git a/src/wps/upnp_xml.c b/src/wps/upnp_xml.c new file mode 100644 index 000000000000..b1b1e2b165dd --- /dev/null +++ b/src/wps/upnp_xml.c @@ -0,0 +1,252 @@ +/* + * UPnP XML helper routines + * Copyright (c) 2000-2003 Intel Corporation + * Copyright (c) 2006-2007 Sony Corporation + * Copyright (c) 2008-2009 Atheros Communications + * Copyright (c) 2009, Jouni Malinen + * + * See wps_upnp.c for more details on licensing and code history. + */ + +#include "includes.h" + +#include "common.h" +#include "base64.h" +#include "http.h" +#include "upnp_xml.h" + + +/* + * XML parsing and formatting + * + * XML is a markup language based on unicode; usually (and in our case, + * always!) based on utf-8. utf-8 uses a variable number of bytes per + * character. utf-8 has the advantage that all non-ASCII unicode characters are + * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII + * characters are single ascii bytes, thus we can use typical text processing. + * + * (One other interesting thing about utf-8 is that it is possible to look at + * any random byte and determine if it is the first byte of a character as + * versus a continuation byte). + * + * The base syntax of XML uses a few ASCII punctionation characters; any + * characters that would appear in the payload data are rewritten using + * sequences, e.g., & for ampersand(&) and < for left angle bracket (<). + * Five such escapes total (more can be defined but that does not apply to our + * case). Thus we can safely parse for angle brackets etc. + * + * XML describes tree structures of tagged data, with each element beginning + * with an opening tag with + * matching label. (There is also a self-closing tag